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)
304 BDF_PropertyRec prop;
307 if (FT_New_Face (ft_library, filename, 0, &ft_face) == 0)
315 if (ft_face->family_name)
317 STRDUP_LOWER (buf, bufsize, ft_face->family_name);
318 family = msymbol (buf);
322 if (! (plist = mplist_get (ft_font_list, family)))
325 mplist_add (ft_font_list, family, plist);
328 if (ft_face->style_name)
330 STRDUP_LOWER (buf, bufsize, ft_face->style_name);
331 style = msymbol (buf);
336 if (! mplist_get (plist, style)
337 && (FT_IS_SCALABLE (ft_face)
339 || FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop) == 0
346 M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
347 ft_info->filename = strdup (filename);
348 ft_info->otf_flag = check_otf_filename (filename);
349 #ifdef HAVE_FONTCONFIG
351 ft_info->langset = FcLangSetCopy (langset);
353 set_font_info (ft_face, ft_info, family, style, &basep);
354 mplist_add (plist, style, ft_info);
357 mplist_put (ft_family_list, family, ft_info);
358 else if (! mplist_get (ft_family_list, family))
359 mplist_add (ft_family_list, family, ft_info);
361 FT_Done_Face (ft_face);
365 /* Return an element of ft_font_list for FAMILY. If FAMILY is Mnil,
366 scan all fonts and return ft_font_list. */
368 ft_list_family (MSymbol family)
370 MPlist *plist, *head;
374 ft_font_list = mplist ();
375 ft_family_list = mplist ();
382 head = mplist_find_by_key (ft_font_list, family);
385 head = mplist_add (ft_font_list, family, mplist ());
388 #ifdef HAVE_FONTCONFIG
389 if (! all_fonts_scaned)
398 pattern = FcPatternCreate ();
401 FcPatternAddString (pattern, FC_FAMILY,
402 (FcChar8 *) (msymbol_name (family)));
404 os = FcObjectSetBuild (FC_FILE, FC_LANG, NULL);
409 os = FcObjectSetBuild (FC_FILE, FC_FAMILY, FC_LANG, NULL);
411 fs = FcFontList (fc_config, pattern, os);
412 for (i = 0; i < fs->nfont; i++)
417 if (FcPatternGetString (fs->fonts[i], FC_FILE, 0,
418 (FcChar8 **) &filename) != FcResultMatch)
420 if (FcPatternGetLangSet (fs->fonts[i], FC_LANG, 0,
421 &langset) != FcResultMatch)
428 if (FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
429 (FcChar8 **) &fname) == FcResultMatch)
431 STRDUP_LOWER (buf, bufsize, fname);
433 if (! plist || MPLIST_KEY (plist) != fam)
435 plist = mplist_find_by_key (ft_font_list, fam);
437 plist = mplist_add (ft_font_list, fam, mplist ());
439 add_font_info (filename, fam, langset, MPLIST_PLIST (plist));
443 add_font_info (filename, family, langset, MPLIST_PLIST (plist));
446 FcFontSetDestroy (fs);
447 FcObjectSetDestroy (os);
448 FcPatternDestroy (pattern);
449 all_fonts_scaned = family == Mnil;
452 #else /* not HAVE_FONTCONFIG */
454 if (! all_fonts_scaned)
459 MPLIST_DO (plist, mfont_freetype_path)
460 if (MPLIST_STRING_P (plist)
461 && (pathname = MPLIST_STRING (plist))
462 && stat (pathname, &buf) == 0)
464 if (S_ISREG (buf.st_mode))
465 add_font_info (pathname, Mnil, NULL, NULL);
466 else if (S_ISDIR (buf.st_mode))
468 int len = strlen (pathname);
470 DIR *dir = opendir (pathname);
475 strcpy (path, pathname);
476 strcpy (path + len, "/");
478 while ((dp = readdir (dir)) != NULL)
480 strcpy (path + len, dp->d_name);
481 add_font_info (path, Mnil, NULL, NULL);
487 all_fonts_scaned = 1;
490 #endif /* not HAVE_FONTCONFIG */
496 ft_list_generic (MSymbol generic)
498 #ifdef HAVE_FONTCONFIG
499 GenericFamilyInfo *info = msymbol_get (generic, M_generic_family_info);
507 info->list = mplist ();
508 pattern = FcPatternCreate ();
509 FcPatternAddString (pattern, FC_FAMILY,
510 (FcChar8 *) info->name);
511 if (FcConfigSubstitute (fc_config, pattern, FcMatchPattern) == FcTrue)
517 while (FcPatternGetString (pattern, FC_FAMILY, i, (FcChar8 **) &family)
522 STRDUP_LOWER (buf, bufsize, family);
523 plist = ft_list_family (msymbol (buf));
524 mplist_add (info->list, MPLIST_KEY (plist), MPLIST_VAL (plist));
529 #else /* not HAVE_FONTCONFIG */
531 #endif /* not HAVE_FONTCONFIG */
535 /* The FreeType font driver function SELECT. */
537 static MRealizedFont *
538 ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size)
540 MPlist *plist, *pl, *p;
543 MRealizedFont *rfont;
544 MSymbol registry, family;
545 unsigned short spec_family_id, request_family_id;
547 registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
548 if (registry == Mnil)
550 family = FONT_PROPERTY (spec, MFONT_FAMILY);
551 spec_family_id = spec->property[MFONT_FAMILY];
552 request_family_id = request->property[MFONT_FAMILY];
556 plist = ft_list_generic (family);
560 spec->property[MFONT_FAMILY] = 0;
561 if (spec_family_id == request_family_id)
562 request->property[MFONT_FAMILY] = 0;
566 if (request_family_id
568 = ft_list_generic (FONT_PROPERTY (request, MFONT_FAMILY)))
569 && mplist_get (plist, family))
570 request->property[MFONT_FAMILY] = 0;
571 plist = ft_list_family (family);
576 if (request_family_id
577 && (plist = ft_list_generic (FONT_PROPERTY (request, MFONT_FAMILY))))
578 request->property[MFONT_FAMILY] = 0;
580 plist = ft_list_family (FONT_PROPERTY (request, MFONT_FAMILY));
585 MPLIST_DO (pl, plist)
587 MPLIST_DO (p, MPLIST_VAL (pl))
589 MFTInfo *ft_info = MPLIST_VAL (p);
592 if (! mplist_find_by_key (ft_info->charmap_list, registry))
595 /* Always ignore FOUNDRY. */
596 ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY];
597 score = mfont__score (&ft_info->font, spec, request, limited_size);
600 || best_score > score))
608 if (best_score == 0 || family != Mnil)
611 spec->property[MFONT_FAMILY] = spec_family_id;
612 request->property[MFONT_FAMILY] = request_family_id;
616 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
617 rfont->frame = frame;
619 rfont->request = *request;
620 rfont->font = best_font->font;
621 rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
622 rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
623 rfont->score = best_score;
624 rfont->info = best_font;
625 M17N_OBJECT_REF (best_font);
630 /* The FreeType font driver function OPEN. */
633 ft_open (MRealizedFont *rfont)
635 MFTInfo *base = rfont->info, *ft_info;
636 MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
637 int mdebug_mask = MDEBUG_FONT;
640 M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
641 ft_info->font = base->font;
642 ft_info->filename = strdup (base->filename);
643 ft_info->otf_flag = base->otf_flag;
644 ft_info->charmap_list = base->charmap_list;
645 M17N_OBJECT_REF (ft_info->charmap_list);
646 M17N_OBJECT_UNREF (base);
647 rfont->info = ft_info;
650 ft_info->ft_face = NULL;
651 if (FT_New_Face (ft_library, ft_info->filename, 0, &ft_info->ft_face))
653 if (registry == Mnil)
655 ft_info->charmap_index
656 = (int) mplist_get (((MFTInfo *) rfont->info)->charmap_list, registry);
657 if (ft_info->charmap_index >= 0
658 && FT_Set_Charmap (ft_info->ft_face,
659 ft_info->ft_face->charmaps[ft_info->charmap_index]))
661 size = rfont->font.property[MFONT_SIZE] / 10;
662 if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0, size))
665 MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename);
667 rfont->ascent = ft_info->ft_face->size->metrics.ascender >> 6;
668 rfont->descent = - (ft_info->ft_face->size->metrics.descender >> 6);
669 rfont->type = Mfreetype;
670 rfont->fontp = ft_info->ft_face;
674 MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename);
675 if (ft_info->ft_face)
676 FT_Done_Face (ft_info->ft_face);
677 M17N_OBJECT_UNREF (ft_info->charmap_list);
678 free (ft_info->filename);
684 /* The FreeType font driver function FIND_METRIC. */
687 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
690 MFTInfo *ft_info = (MFTInfo *) rfont->info;
691 FT_Face ft_face = ft_info->ft_face;
692 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
694 for (; g != gend; g++)
696 if (g->code == MCHAR_INVALID_CODE)
698 if (FT_IS_SCALABLE (ft_face))
700 unsigned unitsPerEm = ft_face->units_per_EM;
701 int size = rfont->font.property[MFONT_SIZE] / 10;
704 g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
705 g->width = ft_face->max_advance_width * size / unitsPerEm;
706 g->ascent = ft_face->ascender * size / unitsPerEm;
707 g->descent = (- ft_face->descender) * size / unitsPerEm;
712 BDF_PropertyRec prop;
716 g->rbearing = g->width = ft_face->available_sizes->width;
718 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
720 g->ascent = prop.u.integer;
721 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
722 g->descent = prop.u.integer;
727 g->ascent = ft_face->available_sizes->height;
734 FT_Glyph_Metrics *metrics;
736 FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
737 metrics = &ft_face->glyph->metrics;
738 g->lbearing = (metrics->horiBearingX >> 6);
739 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
740 g->width = metrics->horiAdvance >> 6;
741 g->ascent = metrics->horiBearingY >> 6;
742 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
747 /* The FreeType font driver function ENCODE_CHAR. */
750 ft_encode_char (MRealizedFont *rfont, unsigned code)
754 if (rfont->status == 0)
756 if ((rfont->driver->open) (rfont) < 0)
759 ft_info = (MFTInfo *) rfont->info;
760 code = (unsigned) FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) code);
762 return MCHAR_INVALID_CODE;
767 /* The FreeType font driver function RENDER. */
769 #define NUM_POINTS 0x1000
772 MDrawPoint points[NUM_POINTS];
777 ft_render (MDrawWindow win, int x, int y,
778 MGlyphString *gstring, MGlyph *from, MGlyph *to,
779 int reverse, MDrawRegion region)
783 MRealizedFace *rface = from->rface;
784 MFrame *frame = rface->frame;
785 FT_Int32 load_flags = FT_LOAD_RENDER;
788 MPointTable point_table[8];
793 /* It is assured that the all glyphs in the current range use the
794 same realized face. */
795 ft_info = (MFTInfo *) rface->rfont->info;
796 ft_face = ft_info->ft_face;
798 if (! gstring->anti_alias)
800 #ifdef FT_LOAD_TARGET_MONO
801 load_flags |= FT_LOAD_TARGET_MONO;
803 load_flags |= FT_LOAD_MONOCHROME;
807 for (i = 0; i < 8; i++)
808 point_table[i].p = point_table[i].points;
810 for (g = from; g < to; x += g++->width)
818 FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
819 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
820 bmp = ft_face->glyph->bitmap.buffer;
821 width = ft_face->glyph->bitmap.width;
822 pitch = ft_face->glyph->bitmap.pitch;
823 if (! gstring->anti_alias)
828 if (gstring->anti_alias)
829 for (i = 0; i < ft_face->glyph->bitmap.rows;
830 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
832 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
833 for (j = 0; j < width; j++, xoff++)
835 intensity = bmp[j] >> 5;
838 ptable = point_table + intensity;
842 if (ptable->p - ptable->points == NUM_POINTS)
844 (*frame->driver->draw_points)
846 reverse ? 7 - intensity : intensity,
847 ptable->points, NUM_POINTS, region);
848 ptable->p = ptable->points;
854 for (i = 0; i < ft_face->glyph->bitmap.rows;
855 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
857 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
858 for (j = 0; j < width; j++, xoff++)
860 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
863 ptable = point_table;
867 if (ptable->p - ptable->points == NUM_POINTS)
869 (*frame->driver->draw_points) (frame, win, rface,
871 ptable->points, NUM_POINTS, region);
872 ptable->p = ptable->points;
879 if (gstring->anti_alias)
881 for (i = 1; i < 8; i++)
882 if (point_table[i].p != point_table[i].points)
883 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
884 point_table[i].points,
885 point_table[i].p - point_table[i].points, region);
889 if (point_table[0].p != point_table[0].points)
890 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
891 point_table[0].points,
892 point_table[0].p - point_table[0].points, region);
897 ft_list (MFrame *frame, MPlist *plist, MFont *font, MSymbol language,
901 #ifdef HAVE_FONTCONFIG
902 FcChar8 *lang = (language != Mnil ? (FcChar8 *) MSYMBOL_NAME (language)
909 MSymbol family = FONT_PROPERTY (font, MFONT_FAMILY);
910 pl = ft_list_generic (family);
914 pl = ft_list_family (family);
917 MPLIST_DO (p, MPLIST_PLIST (pl))
919 MFTInfo *ft_info = MPLIST_VAL (p);
921 #ifdef HAVE_FONTCONFIG
922 if (lang && ft_info->langset
923 && FcLangSetHasLang (ft_info->langset, lang) != FcLangEqual)
926 mplist_add (plist, MPLIST_KEY (pl), &ft_info->font);
937 ft_list_family (Mnil);
938 MPLIST_DO (p, ft_family_list)
940 MFTInfo *ft_info = MPLIST_VAL (p);
942 #ifdef HAVE_FONTCONFIG
943 if (lang && ft_info->langset
944 && FcLangSetHasLang (ft_info->langset, lang) != FcLangEqual)
947 mplist_add (plist, MPLIST_KEY (p), &ft_info->font);
959 MFontDriver mfont__ft_driver =
960 { ft_select, ft_open, ft_find_metric, ft_encode_char, ft_render, ft_list };
967 if (FT_Init_FreeType (&ft_library) != 0)
968 MERROR (MERROR_FONT_FT, -1);
970 for (i = 0; i < ft_to_prop_size; i++)
971 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
973 Municode_bmp = msymbol ("unicode-bmp");
974 Municode_full = msymbol ("unicode-full");
975 Miso10646_1 = msymbol ("iso10646-1");
976 Miso8859_1 = msymbol ("iso8859-1");
978 Mmedium = msymbol ("medium");
980 Mnull = msymbol ("");
982 for (i = 0; i < GENERIC_FAMILY_MAX; i++)
983 generic_family_table[i].list = NULL;
984 M_generic_family_info = msymbol (" generic_family_info");
985 msymbol_put (msymbol ("serif"), M_generic_family_info,
986 generic_family_table + GENERIC_FAMILY_SERIF);
987 msymbol_put (msymbol ("sans-serif"), M_generic_family_info,
988 generic_family_table + GENERIC_FAMILY_SANS_SERIF);
989 msymbol_put (msymbol ("sans"), M_generic_family_info,
990 generic_family_table + GENERIC_FAMILY_SANS_SERIF);
991 msymbol_put (msymbol ("sans serif"), M_generic_family_info,
992 generic_family_table + GENERIC_FAMILY_SANS_SERIF);
993 msymbol_put (msymbol ("monospace"), M_generic_family_info,
994 generic_family_table + GENERIC_FAMILY_MONOSPACE);
995 msymbol_put (msymbol ("mono"), M_generic_family_info,
996 generic_family_table + GENERIC_FAMILY_MONOSPACE);
997 msymbol_put (msymbol ("m"), M_generic_family_info,
998 generic_family_table + GENERIC_FAMILY_MONOSPACE);
1000 #ifdef HAVE_FONTCONFIG
1008 fc_config = FcConfigGetCurrent ();
1009 MPLIST_DO (plist, mfont_freetype_path)
1010 if (MPLIST_STRING_P (plist)
1011 && (pathname = MPLIST_STRING (plist))
1012 && stat (pathname, &buf) == 0)
1014 FcStrList *strlist = FcConfigGetFontDirs (fc_config);
1017 while ((dir = FcStrListNext (strlist)))
1018 if (strcmp ((char *) dir, pathname) == 0)
1021 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
1022 FcStrListDone (strlist);
1036 for (i = 0; i < GENERIC_FAMILY_MAX; i++)
1037 if (generic_family_table[i].list)
1038 M17N_OBJECT_UNREF (generic_family_table[i].list);
1041 MPLIST_DO (plist, ft_font_list)
1043 MPLIST_DO (p, MPLIST_VAL (plist))
1045 MFTInfo *ft_info = MPLIST_VAL (p);
1047 M17N_OBJECT_UNREF (ft_info);
1049 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
1051 M17N_OBJECT_UNREF (ft_font_list);
1052 ft_font_list = NULL;
1054 M17N_OBJECT_UNREF (ft_family_list);
1055 ft_family_list = NULL;
1057 FT_Done_FreeType (ft_library);
1058 all_fonts_scaned = 0;
1062 #ifdef HAVE_FONTCONFIG
1067 } FC_vs_M17N_font_prop;
1069 static FC_vs_M17N_font_prop fc_weight_table[] =
1070 { { FC_WEIGHT_ULTRALIGHT, "extralight" },
1071 { FC_WEIGHT_LIGHT, "light" },
1072 { FC_WEIGHT_NORMAL, "normal" },
1073 { FC_WEIGHT_MEDIUM, "medium" },
1074 { FC_WEIGHT_DEMIBOLD, "demibold" },
1075 { FC_WEIGHT_EXTRABOLD, "extrabold" },
1076 { FC_WEIGHT_BLACK, "black" },
1077 { FC_WEIGHT_MEDIUM, NULL } };
1079 static FC_vs_M17N_font_prop fc_slant_table[] =
1080 { { FC_SLANT_ROMAN, "r" },
1081 { FC_SLANT_ITALIC, "i" },
1082 { FC_SLANT_OBLIQUE, "o" },
1083 { FC_SLANT_ROMAN, NULL } };
1085 static FC_vs_M17N_font_prop fc_width_table[] =
1086 { { FC_WIDTH_CONDENSED, "condensed" },
1087 { FC_WIDTH_SEMIEXPANDED, "semicondensed" },
1088 { FC_WIDTH_NORMAL, "normal" },
1089 { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
1090 { FC_WIDTH_EXPANDED, "expanded" },
1091 { FC_WIDTH_NORMAL, NULL } };
1095 fc_decode_prop (int val, FC_vs_M17N_font_prop *table)
1099 for (i = 0; table[i].m17n_value; i++)
1100 if (val <= table[i].fc_value)
1101 return msymbol ("table[i].m17n_value");
1102 return msymbol ("table[i - 1].m17n_value");
1106 fc_encode_prop (char *name, FC_vs_M17N_font_prop *table)
1110 for (i = 0; table[i].m17n_value && strcmp (name, table[i].m17n_value); i++);
1111 return table[i].fc_value;
1115 mfont__ft_parse_name (char *name, MFont *font)
1117 FcPattern *pat = FcNameParse ((FcChar8 *) name);
1124 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
1125 mfont__set_property (font, MFONT_FOUNDRY, msymbol ((char *) str));
1126 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1127 mfont__set_property (font, MFONT_FAMILY, msymbol ((char *) str));
1128 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
1129 mfont__set_property (font, MFONT_WEIGHT,
1130 fc_decode_prop (val, fc_weight_table));
1131 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
1132 mfont__set_property (font, MFONT_STYLE,
1133 fc_decode_prop (val, fc_slant_table));
1134 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
1135 mfont__set_property (font, MFONT_STRETCH,
1136 fc_decode_prop (val, fc_width_table));
1137 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
1138 font->property[MFONT_SIZE] = size * 10;
1139 FcPatternDestroy (pat);
1144 mfont__ft_unparse_name (MFont *font)
1146 FcPattern *pat = FcPatternCreate ();
1147 MSymbol sym, weight, style, stretch;
1150 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
1151 FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
1152 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
1153 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
1154 if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
1155 FcPatternAddInteger (pat, FC_WEIGHT, fc_encode_prop (MSYMBOL_NAME (weight),
1157 if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
1158 FcPatternAddInteger (pat, FC_SLANT, fc_encode_prop (MSYMBOL_NAME (style),
1160 if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
1161 FcPatternAddInteger (pat, FC_WIDTH, fc_encode_prop (MSYMBOL_NAME (stretch),
1163 name = (char *) FcNameUnparse (pat);
1164 FcPatternDestroy (pat);
1167 #endif /* HAVE_FONTCONFIG */
1172 #define DEVICE_DELTA(table, size) \
1173 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1174 ? (table).DeltaValue[(size) >= (table).StartSize] \
1178 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
1179 unsigned code, int size, int *x, int *y)
1181 if (anchor->AnchorFormat == 2)
1183 FT_Outline *outline;
1184 int ap = anchor->f.f1.AnchorPoint;
1186 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1187 outline = &ft_face->glyph->outline;
1188 if (ap < outline->n_points)
1190 *x = outline->points[ap].x;
1191 *y = outline->points[ap].y;
1194 else if (anchor->AnchorFormat == 3)
1196 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
1197 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
1202 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
1203 MSymbol script, MSymbol langsys,
1204 MSymbol gsub_features, MSymbol gpos_features)
1206 int len = to - from;
1207 MGlyph *g = MGLYPH (from);
1209 MRealizedFont *rfont;
1212 OTF_GlyphString otf_gstring;
1214 char *script_name, *language_name;
1215 char *gsub_feature_names, *gpos_feature_names;
1221 rfont = g->rface->rfont;
1222 ft_info = rfont->info;
1223 if (ft_info->otf_flag < 0)
1228 otf = OTF_open (ft_info->filename);
1229 if (otf && OTF_get_table (otf, "head") < 0)
1236 ft_info->otf_flag = -1;
1243 script_name = msymbol_name (script);
1246 if (langsys != Mnil)
1247 language_name = msymbol_name (langsys);
1249 language_name = NULL;
1251 = (gsub_features == Mt ? "*"
1252 : gsub_features == Mnil ? NULL
1253 : msymbol_name (gsub_features));
1254 if (gsub_feature_names && OTF_check_table (otf, "GSUB") < 0)
1255 gsub_feature_names = NULL;
1257 = (gpos_features == Mt ? "*"
1258 : gpos_features == Mnil ? NULL
1259 : msymbol_name (gpos_features));
1260 if (gpos_feature_names && OTF_check_table (otf, "GPOS") < 0)
1261 gpos_feature_names = NULL;
1263 otf_gstring.size = otf_gstring.used = len;
1264 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
1265 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1266 for (i = 0, need_cmap = 0; i < len; i++)
1268 if (gstring->glyphs[from + i].otf_encoded)
1270 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1271 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1275 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
1280 && OTF_drive_cmap (otf, &otf_gstring) < 0)
1283 OTF_drive_gdef (otf, &otf_gstring);
1284 gidx = gstring->used;
1286 if (gsub_feature_names)
1288 if (OTF_drive_gsub (otf, &otf_gstring, script_name, language_name,
1289 gsub_feature_names) < 0)
1291 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1293 MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
1296 temp.combining_code = 0;
1299 temp.code = otfg->glyph_id;
1300 temp.otf_encoded = 1;
1305 temp.otf_encoded = 0;
1307 temp.to = MGLYPH (from + otfg->f.index.to)->to;
1308 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1312 for (i = 0; i < len; i++)
1314 MGlyph temp = gstring->glyphs[from + i];
1316 if (otf_gstring.glyphs[i].glyph_id)
1318 temp.code = otf_gstring.glyphs[i].glyph_id;
1319 temp.otf_encoded = 1;
1321 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1324 ft_find_metric (rfont, gstring, gidx, gstring->used);
1326 if (gpos_feature_names)
1330 MGlyph *base = NULL, *mark = NULL;
1332 if (OTF_drive_gpos (otf, &otf_gstring, script_name, language_name,
1333 gpos_feature_names) < 0)
1336 u = otf->head->unitsPerEm;
1337 size10 = rfont->font.property[MFONT_SIZE];
1340 for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
1341 i < otf_gstring.used; i++, otfg++, g++)
1345 if (! otfg->glyph_id)
1347 switch (otfg->positioning_type)
1353 int format = otfg->f.f1.format;
1355 if (format & OTF_XPlacement)
1356 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
1357 if (format & OTF_XPlaDevice)
1358 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
1359 if (format & OTF_YPlacement)
1360 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
1361 if (format & OTF_YPlaDevice)
1362 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
1363 if (format & OTF_XAdvance)
1364 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
1365 if (format & OTF_XAdvDevice)
1366 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
1370 /* Not yet supported. */
1376 goto label_adjust_anchor;
1377 default: /* i.e. case 6 */
1382 label_adjust_anchor:
1384 int base_x, base_y, mark_x, mark_y;
1386 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
1387 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
1388 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
1389 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
1391 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
1392 adjust_anchor (otfg->f.f4.base_anchor, ft_info->ft_face,
1393 prev->code, size, &base_x, &base_y);
1394 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
1395 adjust_anchor (otfg->f.f4.mark_anchor, ft_info->ft_face,
1396 g->code, size, &mark_x, &mark_y);
1397 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
1398 g->yoff = prev->yoff + mark_y - base_y;
1399 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
1402 if (otfg->GlyphClass == OTF_GlyphClass0)
1404 else if (otfg->GlyphClass == OTF_GlyphClassMark)
1410 free (otf_gstring.glyphs);
1414 ft_find_metric (rfont, gstring, from, to);
1415 for (i = 0; i < len; i++)
1417 MGlyph temp = gstring->glyphs[from + i];
1418 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1420 free (otf_gstring.glyphs);
1426 mfont__ft_decode_otf (MGlyph *g)
1428 MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
1429 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
1431 return (c ? c : -1);
1434 #endif /* HAVE_OTF */
1436 #endif /* HAVE_FREETYPE */