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
49 static FcConfig *fc_config;
51 /** List of generic families supported by Fontconfig. Keys are
52 generic family names (including aliases) and values are real
53 generic family names. */
55 static MPlist *fc_generic_family_list;
57 #endif /* not HAVE_FONTCONFIG */
60 static MSymbol Municode_bmp, Municode_full, Miso10646_1, Miso8859_1;
61 /* Fontconfig's generic font family names. */
62 static MSymbol Mserif, Msans_serif, Mmonospace;
63 /* Font properties; Mnormal is already defined in face.c. */
64 static MSymbol Mmedium, Mr, Mnull;
66 static FT_Library ft_library;
72 enum MFontProperty prop;
76 static MFTtoProp ft_to_prop[] =
77 { { "italic", 0, MFONT_STYLE, "i" },
78 { "roman", 0, MFONT_STYLE, "r" },
79 { "oblique", 0, MFONT_STYLE, "p" },
80 { "regular", 0, MFONT_WEIGHT, "medium" },
81 { "normal", 0, MFONT_WEIGHT, "medium" },
82 /* We need this entry even if "bold" is in commone_weight[] to
83 handle such style names as "bolditalic" and "boldoblique". */
84 { "bold", 0, MFONT_WEIGHT, "bold" },
85 { "demi bold", 0, MFONT_WEIGHT, "demibold" },
86 { "demi", 0, MFONT_WEIGHT, "demibold" } };
87 static int ft_to_prop_size = sizeof ft_to_prop / sizeof ft_to_prop[0];
89 /** List of FreeType fonts. Keys are family names, values are plists
90 containing fonts of the corresponding family. In the deeper
91 plist, keys are Mt, values are (MFTInfo *). */
92 static MPlist *ft_font_list;
94 /** List of FreeType base fonts. Keys are family names, values are
96 static MPlist *ft_family_list;
98 static int all_fonts_scaned;
100 /** Return 0 if NAME implies TrueType or OpenType fonts. Othersize
104 check_otf_filename (const char *name)
106 int len = strlen (name);
107 const char *ext = name + (len - 4);
110 || (memcmp (ext, ".ttf", 4)
111 && memcmp (ext, ".TTF", 4)
112 && memcmp (ext, ".otf", 4)
113 && memcmp (ext, ".OTF", 4)))
118 /** Setup members of FT_INFO from FT_FACE. If the font is a base one
119 (i.e. medium-r-normal), set BASEP to 1. Otherwise set BASEP to 0.
120 Return the family name. */
123 set_font_info (FT_Face ft_face, MFTInfo *ft_info, MSymbol family, int *basep)
125 MFont *font = &ft_info->font;
128 MPlist *charmap_list;
129 int unicode_bmp = -1, unicode_full = -1, unicode = -1;
136 len = strlen (ft_face->family_name) + 1;
137 buf = (char *) alloca (len);
138 memcpy (buf, ft_face->family_name, len);
139 for (p = buf; *p; p++)
140 if (*p >= 'A' && *p <= 'Z')
142 family = msymbol (buf);
144 mfont__set_property (font, MFONT_FAMILY, family);
145 mfont__set_property (font, MFONT_WEIGHT, Mmedium);
146 mfont__set_property (font, MFONT_STYLE, Mr);
147 mfont__set_property (font, MFONT_STRETCH, Mnormal);
148 mfont__set_property (font, MFONT_ADSTYLE, Mnull);
151 if (ft_face->style_name)
153 len = strlen (ft_face->style_name) + 1;
154 buf = (char *) alloca (len);
155 memcpy (buf, ft_face->style_name, len);
156 for (p = buf; *p; p++)
157 if (*p >= 'A' && *p <= 'Z')
160 while (*p && (*p < 'a' || *p > 'z')) p++;
163 for (i = 0; i < ft_to_prop_size; i++)
164 if (! strncmp (ft_to_prop[i].ft_style, p, ft_to_prop[i].len))
166 mfont__set_property (font, ft_to_prop[i].prop,
167 msymbol (ft_to_prop[i].val));
168 p += ft_to_prop[i].len;
171 if (i == ft_to_prop_size)
176 while (*p1 >= 'a' && *p1 <= 'z') p1++;
177 sym = msymbol__with_len (p, p1 - p);
178 for (i = MFONT_WEIGHT; i <= MFONT_STYLE; i++)
179 if (msymbol_get (sym, mfont__property_table[i].property))
181 mfont__set_property (font, i, sym);
186 while (*p && (*p < 'a' || *p > 'z')) p++;
190 *basep = (FONT_PROPERTY (font, MFONT_WEIGHT) == Mmedium
191 && FONT_PROPERTY (font, MFONT_STYLE) == Mr
192 && FONT_PROPERTY (font, MFONT_STRETCH) == Mnormal);
194 charmap_list = mplist ();
195 mplist_add (charmap_list, Mt, (void *) -1);
196 for (i = 0; i < ft_face->num_charmaps; i++)
198 char registry_buf[16];
201 sprintf (registry_buf, "%d-%d",
202 ft_face->charmaps[i]->platform_id,
203 ft_face->charmaps[i]->encoding_id);
204 registry = msymbol (registry_buf);
205 mplist_add (charmap_list, registry, (void *) i);
207 if (ft_face->charmaps[i]->platform_id == 0)
209 if (ft_face->charmaps[i]->encoding_id == 3)
211 else if (ft_face->charmaps[i]->encoding_id == 4)
214 else if (ft_face->charmaps[i]->platform_id == 3)
216 if (ft_face->charmaps[i]->encoding_id == 1)
218 else if (ft_face->charmaps[i]->encoding_id == 10)
221 else if (ft_face->charmaps[i]->platform_id == 1
222 && ft_face->charmaps[i]->encoding_id == 0)
223 mplist_add (charmap_list, msymbol ("apple-roman"), (void *) i);
225 if (unicode_full >= 0)
227 mplist_add (charmap_list, Municode_full, (void *) unicode_full);
228 mplist_add (charmap_list, Municode_bmp, (void *) unicode_full);
229 mplist_add (charmap_list, Miso10646_1, (void *) unicode_full);
230 unicode = unicode_full;
232 else if (unicode_bmp >= 0)
234 mplist_add (charmap_list, Municode_bmp, (void *) unicode_bmp);
235 mplist_add (charmap_list, Miso10646_1, (void *) unicode_bmp);
236 unicode = unicode_bmp;
240 FT_Set_Charmap (ft_face, ft_face->charmaps[unicode]);
241 for (i = 255; i >= 32; i--)
245 if (FT_Get_Char_Index (ft_face, (FT_ULong) i) == 0)
249 mplist_add (charmap_list, Miso8859_1, (void *) unicode);
252 ft_info->charmap_list = charmap_list;
254 if (! FT_IS_SCALABLE (ft_face))
256 BDF_PropertyRec prop;
258 FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop);
259 font->property[MFONT_SIZE] = prop.u.integer * 10;
260 FT_Get_BDF_Property (ft_face, "RESOLUTION_Y", &prop);
261 font->property[MFONT_RESY] = prop.u.integer;
269 close_ft (void *object)
271 MFTInfo *ft_info = object;
273 if (ft_info->ft_face)
275 if (ft_info->extra_info)
276 M17N_OBJECT_UNREF (ft_info->extra_info);
277 FT_Done_Face (ft_info->ft_face);
280 OTF_close (ft_info->otf);
281 #endif /* HAVE_OTF */
283 free (ft_info->filename);
284 if (ft_info->languages)
285 free (ft_info->languages);
286 M17N_OBJECT_UNREF (ft_info->charmap_list);
291 add_font_info (char *filename, MSymbol family, void *langset, MPlist *plist)
294 BDF_PropertyRec prop;
295 MFTInfo *ft_info = NULL;
297 if (FT_New_Face (ft_library, filename, 0, &ft_face) == 0)
299 if (FT_IS_SCALABLE (ft_face)
300 || FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop) == 0)
305 M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
306 ft_info->filename = strdup (filename);
307 ft_info->otf_flag = check_otf_filename (filename);
308 #ifdef HAVE_FONTCONFIG
310 ft_info->langset = FcLangSetCopy (langset);
312 fam = set_font_info (ft_face, ft_info, family, &basep);
314 && ! (plist = mplist_get (ft_font_list, fam)))
317 mplist_push (ft_font_list, fam, plist);
319 mplist_push (plist, fam, ft_info);
322 mplist_put (ft_family_list, fam, ft_info);
323 else if (! mplist_get (ft_family_list, fam))
324 mplist_push (ft_family_list, fam, ft_info);
326 FT_Done_Face (ft_face);
330 /* Return an element of ft_font_list for FAMILY. If FAMILY is Mnil,
331 scan all fonts and return ft_font_list. */
333 ft_list_family (MSymbol family)
339 ft_font_list = mplist ();
340 ft_family_list = mplist ();
345 if (all_fonts_scaned)
350 plist = mplist_find_by_key (ft_font_list, family);
353 if (all_fonts_scaned)
356 mplist_push (ft_font_list, family, plist);
361 #ifdef HAVE_FONTCONFIG
375 fc_config = FcConfigGetCurrent ();
376 MPLIST_DO (plist, mfont_freetype_path)
377 if (MPLIST_STRING_P (plist)
378 && (pathname = MPLIST_STRING (plist))
379 && stat (pathname, &buf) == 0)
380 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
381 /* TODO: avoid duplicate addition by checking the current font
382 directory list given by FcConfigGetFontDirs (). */
385 pattern = FcPatternCreate ();
388 MSymbol generic = mplist_get (fc_generic_family_list, family);
392 plist = mplist_find_by_key (ft_font_list, family);
396 mplist_push (ft_font_list, family, plist);
398 FcPatternAddString (pattern, FC_FAMILY,
399 (FcChar8 *) (msymbol_name (family)));
401 && FcConfigSubstitute (fc_config, pattern, FcMatchPattern)
404 FcPatternDestroy (pattern);
409 os = FcObjectSetBuild (FC_FILE, FC_FAMILY, FC_LANG, NULL);
410 fs = FcFontList (fc_config, pattern, os);
412 for (i = 0; i < fs->nfont; i++)
417 if (FcPatternGetString (fs->fonts[i], FC_FILE, 0, &filename)
420 if (FcPatternGetLangSet (fs->fonts[i], FC_LANG, 0, &langset)
428 FcPatternGetString (fs->fonts[i], FC_FAMILY, 0, &fname);
429 fam = msymbol ((char *) fname);
430 plist = mplist_get (ft_font_list, fam);
434 mplist_push (ft_font_list, fam, plist);
435 add_font_info ((char *) filename, fam, langset, plist);
439 add_font_info ((char *) filename, family, langset, plist);
441 FcFontSetDestroy (fs);
442 FcObjectSetDestroy (os);
443 FcPatternDestroy (pattern);
447 MPLIST_DO (plist, fc_generic_family_list)
448 if (MPLIST_KEY (plist) == MPLIST_SYMBOL (plist)
449 && ! mplist_get (ft_font_list, MPLIST_KEY (plist)))
450 ft_list_family (MPLIST_KEY (plist));
451 all_fonts_scaned = 1;
455 #else /* not HAVE_FONTCONFIG */
461 MPLIST_DO (plist, mfont_freetype_path)
462 if (MPLIST_STRING_P (plist)
463 && (pathname = MPLIST_STRING (plist))
464 && stat (pathname, &buf) == 0)
466 if (S_ISREG (buf.st_mode))
467 add_font_info (pathname, Mnil, NULL, NULL);
468 else if (S_ISDIR (buf.st_mode))
470 int len = strlen (pathname);
472 DIR *dir = opendir (pathname);
477 strcpy (path, pathname);
478 strcpy (path + len, "/");
480 while ((dp = readdir (dir)) != NULL)
482 strcpy (path + len, dp->d_name);
483 add_font_info (path, Mnil, NULL, NULL);
492 plist = mplist_find_by_key (ft_font_list, family);
496 mplist_push (ft_font_list, family, plist);
500 #endif /* not HAVE_FONTCONFIG */
506 /* The FreeType font driver function SELECT. */
508 static MRealizedFont *
509 ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size)
511 MPlist *plist, *pl, *p;
514 MRealizedFont *rfont;
515 MSymbol family, registry;
517 family = FONT_PROPERTY (spec, MFONT_FAMILY);
519 family = FONT_PROPERTY (request, MFONT_FAMILY);
520 registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
521 if (registry == Mnil)
524 plist = ft_list_family (family);
527 MPLIST_DO (pl, plist)
529 MPLIST_DO (p, MPLIST_VAL (pl))
531 MFTInfo *ft_info = MPLIST_VAL (p);
534 if (! mplist_find_by_key (ft_info->charmap_list, registry))
536 /* We always ignore FOUNDRY. */
537 ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY];
538 score = mfont__score (&ft_info->font, spec, request, limited_size);
541 || best_score > score))
549 if (best_score == 0 || family != Mnil)
555 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
556 rfont->frame = frame;
558 rfont->request = *request;
559 rfont->font = best_font->font;
560 rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
561 rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
562 rfont->score = best_score;
563 rfont->info = best_font;
564 M17N_OBJECT_REF (best_font);
569 /* The FreeType font driver function OPEN. */
572 ft_open (MRealizedFont *rfont)
574 MFTInfo *base = rfont->info, *ft_info;
575 MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
576 int mdebug_mask = MDEBUG_FONT;
579 M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
580 ft_info->font = base->font;
581 ft_info->filename = strdup (base->filename);
582 ft_info->otf_flag = base->otf_flag;
583 ft_info->charmap_list = base->charmap_list;
584 M17N_OBJECT_REF (ft_info->charmap_list);
585 M17N_OBJECT_UNREF (base);
586 rfont->info = ft_info;
589 ft_info->ft_face = NULL;
590 if (FT_New_Face (ft_library, ft_info->filename, 0, &ft_info->ft_face))
592 if (registry == Mnil)
594 ft_info->charmap_index
595 = (int) mplist_get (((MFTInfo *) rfont->info)->charmap_list, registry);
596 if (ft_info->charmap_index >= 0
597 && FT_Set_Charmap (ft_info->ft_face,
598 ft_info->ft_face->charmaps[ft_info->charmap_index]))
600 size = rfont->font.property[MFONT_SIZE] / 10;
601 if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0, size))
604 MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename);
606 rfont->ascent = ft_info->ft_face->ascender >> 6;
607 rfont->descent = - (ft_info->ft_face->descender >> 6);
608 rfont->type = Mfreetype;
609 rfont->fontp = ft_info->ft_face;
613 MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename);
614 if (ft_info->ft_face)
615 FT_Done_Face (ft_info->ft_face);
616 M17N_OBJECT_UNREF (ft_info->charmap_list);
617 free (ft_info->filename);
623 /* The FreeType font driver function FIND_METRIC. */
626 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
629 MFTInfo *ft_info = (MFTInfo *) rfont->info;
630 FT_Face ft_face = ft_info->ft_face;
631 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
633 for (; g != gend; g++)
635 if (g->code == MCHAR_INVALID_CODE)
637 if (FT_IS_SCALABLE (ft_face))
639 unsigned unitsPerEm = ft_face->units_per_EM;
640 int size = rfont->font.property[MFONT_SIZE] / 10;
643 g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
644 g->width = ft_face->max_advance_width * size / unitsPerEm;
645 g->ascent = ft_face->ascender * size / unitsPerEm;
646 g->descent = (- ft_face->descender) * size / unitsPerEm;
650 BDF_PropertyRec prop;
653 g->rbearing = g->width = ft_face->available_sizes->width;
654 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
656 g->ascent = prop.u.integer;
657 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
658 g->descent = prop.u.integer;
662 g->ascent = ft_face->available_sizes->height;
669 FT_Glyph_Metrics *metrics;
671 FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
672 metrics = &ft_face->glyph->metrics;
673 g->lbearing = (metrics->horiBearingX >> 6);
674 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
675 g->width = metrics->horiAdvance >> 6;
676 g->ascent = metrics->horiBearingY >> 6;
677 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
682 /* The FreeType font driver function ENCODE_CHAR. */
685 ft_encode_char (MRealizedFont *rfont, unsigned code)
689 if (rfont->status == 0)
691 if ((rfont->driver->open) (rfont) < 0)
694 ft_info = (MFTInfo *) rfont->info;
695 code = (unsigned) FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) code);
697 return MCHAR_INVALID_CODE;
702 /* The FreeType font driver function RENDER. */
704 #define NUM_POINTS 0x1000
707 MDrawPoint points[NUM_POINTS];
712 ft_render (MDrawWindow win, int x, int y,
713 MGlyphString *gstring, MGlyph *from, MGlyph *to,
714 int reverse, MDrawRegion region)
718 MRealizedFace *rface = from->rface;
719 MFrame *frame = rface->frame;
720 FT_Int32 load_flags = FT_LOAD_RENDER;
723 MPointTable point_table[8];
728 /* It is assured that the all glyphs in the current range use the
729 same realized face. */
730 ft_info = (MFTInfo *) rface->rfont->info;
731 ft_face = ft_info->ft_face;
733 if (! gstring->anti_alias)
735 #ifdef FT_LOAD_TARGET_MONO
736 load_flags |= FT_LOAD_TARGET_MONO;
738 load_flags |= FT_LOAD_MONOCHROME;
742 for (i = 0; i < 8; i++)
743 point_table[i].p = point_table[i].points;
745 for (g = from; g < to; x += g++->width)
753 FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
754 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
755 bmp = ft_face->glyph->bitmap.buffer;
756 width = ft_face->glyph->bitmap.width;
757 pitch = ft_face->glyph->bitmap.pitch;
758 if (! gstring->anti_alias)
763 if (gstring->anti_alias)
764 for (i = 0; i < ft_face->glyph->bitmap.rows;
765 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
767 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
768 for (j = 0; j < width; j++, xoff++)
770 intensity = bmp[j] >> 5;
773 ptable = point_table + intensity;
777 if (ptable->p - ptable->points == NUM_POINTS)
779 (*frame->driver->draw_points)
781 reverse ? 7 - intensity : intensity,
782 ptable->points, NUM_POINTS, region);
783 ptable->p = ptable->points;
789 for (i = 0; i < ft_face->glyph->bitmap.rows;
790 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
792 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
793 for (j = 0; j < width; j++, xoff++)
795 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
798 ptable = point_table;
802 if (ptable->p - ptable->points == NUM_POINTS)
804 (*frame->driver->draw_points) (frame, win, rface,
806 ptable->points, NUM_POINTS, region);
807 ptable->p = ptable->points;
814 if (gstring->anti_alias)
816 for (i = 1; i < 8; i++)
817 if (point_table[i].p != point_table[i].points)
818 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
819 point_table[i].points,
820 point_table[i].p - point_table[i].points, region);
824 if (point_table[0].p != point_table[0].points)
825 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
826 point_table[0].points,
827 point_table[0].p - point_table[0].points, region);
832 ft_list (MFrame *frame, MPlist *plist, MFont *font, MSymbol language)
835 MSymbol family = font ? FONT_PROPERTY (font, MFONT_FAMILY) : Mnil;
836 #ifdef HAVE_FONTCONFIG
837 FcChar8 *lang = (language != Mnil ? (FcChar8 *) MSYMBOL_NAME (language)
841 pl = ft_list_family (Mnil);
846 MPLIST_DO (p, MPLIST_PLIST (pl))
848 MFTInfo *ft_info = MPLIST_VAL (p);
850 #ifdef HAVE_FONTCONFIG
851 if (lang && ft_info->langset
852 && FcLangSetHasLang (ft_info->langset, lang) == FcLangEqual)
855 if (! mfont__match_p (&ft_info->font, font, MFONT_REGISTRY))
857 mplist_push (plist, MPLIST_KEY (pl), &ft_info->font);
865 MPLIST_DO (p, ft_family_list)
867 MFTInfo *ft_info = MPLIST_VAL (p);
869 #ifdef HAVE_FONTCONFIG
870 if (lang && ft_info->langset
871 && FcLangSetHasLang (ft_info->langset, lang) == FcLangEqual)
874 mplist_push (plist, MPLIST_KEY (p), &ft_info->font);
882 MFontDriver mfont__ft_driver =
883 { ft_select, ft_open, ft_find_metric, ft_encode_char, ft_render, ft_list };
890 if (FT_Init_FreeType (&ft_library) != 0)
891 MERROR (MERROR_FONT_FT, -1);
893 for (i = 0; i < ft_to_prop_size; i++)
894 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
896 Municode_bmp = msymbol ("unicode-bmp");
897 Municode_full = msymbol ("unicode-full");
898 Miso10646_1 = msymbol ("iso10646-1");
899 Miso8859_1 = msymbol ("iso8859-1");
901 Mserif = msymbol ("serif");
902 Msans_serif = msymbol ("sans-serif");
903 Mmonospace = msymbol ("monospace");
905 Mmedium = msymbol ("medium");
907 Mnull = msymbol ("");
909 #ifdef HAVE_FONTCONFIG
910 fc_generic_family_list = mplist ();
911 mplist_push (fc_generic_family_list, Mserif, Mserif);
912 mplist_push (fc_generic_family_list, Msans_serif, Msans_serif);
913 mplist_push (fc_generic_family_list, Mmonospace, Mmonospace);
914 /* These are (deprecated) aliases. */
915 mplist_push (fc_generic_family_list, msymbol ("sans"), Msans_serif);
916 mplist_push (fc_generic_family_list, msymbol ("sans serif"), Msans_serif);
917 mplist_push (fc_generic_family_list, msymbol ("mono"), Mmonospace);
930 MPLIST_DO (plist, ft_font_list)
932 MPLIST_DO (p, MPLIST_VAL (plist))
934 MFTInfo *ft_info = MPLIST_VAL (p);
936 M17N_OBJECT_UNREF (ft_info);
938 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
940 M17N_OBJECT_UNREF (ft_font_list);
943 M17N_OBJECT_UNREF (ft_family_list);
944 ft_family_list = NULL;
946 FT_Done_FreeType (ft_library);
947 all_fonts_scaned = 0;
949 #ifdef HAVE_FONTCONFIG
950 m17n_object_unref (fc_generic_family_list);
956 #ifdef HAVE_FONTCONFIG
961 } FC_vs_M17N_font_prop;
963 static FC_vs_M17N_font_prop fc_weight_table[] =
964 { { FC_WEIGHT_ULTRALIGHT, "extralight" },
965 { FC_WEIGHT_LIGHT, "light" },
966 { FC_WEIGHT_NORMAL, "normal" },
967 { FC_WEIGHT_MEDIUM, "medium" },
968 { FC_WEIGHT_DEMIBOLD, "demibold" },
969 { FC_WEIGHT_EXTRABOLD, "extrabold" },
970 { FC_WEIGHT_BLACK, "black" },
971 { FC_WEIGHT_MEDIUM, NULL } };
973 static FC_vs_M17N_font_prop fc_slant_table[] =
974 { { FC_SLANT_ROMAN, "r" },
975 { FC_SLANT_ITALIC, "i" },
976 { FC_SLANT_OBLIQUE, "o" },
977 { FC_SLANT_ROMAN, NULL } };
979 static FC_vs_M17N_font_prop fc_width_table[] =
980 { { FC_WIDTH_CONDENSED, "condensed" },
981 { FC_WIDTH_SEMIEXPANDED, "semicondensed" },
982 { FC_WIDTH_NORMAL, "normal" },
983 { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
984 { FC_WIDTH_EXPANDED, "expanded" },
985 { FC_WIDTH_NORMAL, NULL } };
989 fc_decode_prop (int val, FC_vs_M17N_font_prop *table)
993 for (i = 0; table[i].m17n_value; i++)
994 if (val <= table[i].fc_value)
995 msymbol ("table[i].m17n_value");
996 return msymbol ("table[i - 1].m17n_value");
1000 fc_encode_prop (char *name, FC_vs_M17N_font_prop *table)
1004 for (i = 0; table[i].m17n_value && strcmp (name, table[i].m17n_value); i++);
1005 return table[i].fc_value;
1009 mfont__ft_parse_name (char *name, MFont *font)
1011 FcPattern *pat = FcNameParse ((FcChar8 *) name);
1018 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
1019 mfont__set_property (font, MFONT_FOUNDRY, msymbol ((char *) str));
1020 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1021 mfont__set_property (font, MFONT_FAMILY, msymbol ((char *) str));
1022 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
1023 mfont__set_property (font, MFONT_WEIGHT,
1024 fc_decode_prop (val, fc_weight_table));
1025 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
1026 mfont__set_property (font, MFONT_STYLE,
1027 fc_decode_prop (val, fc_slant_table));
1028 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
1029 mfont__set_property (font, MFONT_STRETCH,
1030 fc_decode_prop (val, fc_width_table));
1031 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
1032 font->property[MFONT_SIZE] = size * 10;
1033 FcPatternDestroy (pat);
1038 mfont__ft_unparse_name (MFont *font)
1040 FcPattern *pat = FcPatternCreate ();
1041 MSymbol sym, weight, style, stretch;
1044 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
1045 FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
1046 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
1047 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
1048 if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
1049 FcPatternAddInteger (pat, FC_WEIGHT, fc_encode_prop (MSYMBOL_NAME (weight),
1051 if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
1052 FcPatternAddInteger (pat, FC_SLANT, fc_encode_prop (MSYMBOL_NAME (style),
1054 if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
1055 FcPatternAddInteger (pat, FC_WIDTH, fc_encode_prop (MSYMBOL_NAME (stretch),
1057 name = (char *) FcNameUnparse (pat);
1058 FcPatternDestroy (pat);
1061 #endif /* HAVE_FONTCONFIG */
1066 #define DEVICE_DELTA(table, size) \
1067 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1068 ? (table).DeltaValue[(size) >= (table).StartSize] \
1072 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
1073 unsigned code, int size, int *x, int *y)
1075 if (anchor->AnchorFormat == 2)
1077 FT_Outline *outline;
1078 int ap = anchor->f.f1.AnchorPoint;
1080 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1081 outline = &ft_face->glyph->outline;
1082 if (ap < outline->n_points)
1084 *x = outline->points[ap].x;
1085 *y = outline->points[ap].y;
1088 else if (anchor->AnchorFormat == 3)
1090 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
1091 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
1096 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
1097 MSymbol script, MSymbol langsys,
1098 MSymbol gsub_features, MSymbol gpos_features)
1100 int len = to - from;
1101 MGlyph *g = MGLYPH (from);
1103 MRealizedFont *rfont;
1106 OTF_GlyphString otf_gstring;
1108 char *script_name, *language_name;
1109 char *gsub_feature_names, *gpos_feature_names;
1115 rfont = g->rface->rfont;
1116 ft_info = rfont->info;
1117 if (ft_info->otf_flag < 0)
1122 otf = OTF_open (ft_info->filename);
1123 if (otf && OTF_get_table (otf, "head") < 0)
1130 ft_info->otf_flag = -1;
1137 script_name = msymbol_name (script);
1140 if (langsys != Mnil)
1141 language_name = msymbol_name (langsys);
1143 language_name = NULL;
1145 = (gsub_features == Mt ? "*"
1146 : gsub_features == Mnil ? NULL
1147 : msymbol_name (gsub_features));
1148 if (gsub_feature_names && OTF_check_table (otf, "GSUB") < 0)
1149 gsub_feature_names = NULL;
1151 = (gpos_features == Mt ? "*"
1152 : gpos_features == Mnil ? NULL
1153 : msymbol_name (gpos_features));
1154 if (gpos_feature_names && OTF_check_table (otf, "GPOS") < 0)
1155 gpos_feature_names = NULL;
1157 otf_gstring.size = otf_gstring.used = len;
1158 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
1159 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1160 for (i = 0, need_cmap = 0; i < len; i++)
1162 if (gstring->glyphs[from + i].otf_encoded)
1164 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1165 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1169 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
1174 && OTF_drive_cmap (otf, &otf_gstring) < 0)
1177 OTF_drive_gdef (otf, &otf_gstring);
1178 gidx = gstring->used;
1180 if (gsub_feature_names)
1182 if (OTF_drive_gsub (otf, &otf_gstring, script_name, language_name,
1183 gsub_feature_names) < 0)
1185 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1187 MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
1190 temp.combining_code = 0;
1193 temp.code = otfg->glyph_id;
1194 temp.otf_encoded = 1;
1199 temp.otf_encoded = 0;
1201 temp.to = MGLYPH (from + otfg->f.index.to)->to;
1202 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1206 for (i = 0; i < len; i++)
1208 MGlyph temp = gstring->glyphs[from + i];
1210 if (otf_gstring.glyphs[i].glyph_id)
1212 temp.code = otf_gstring.glyphs[i].glyph_id;
1213 temp.otf_encoded = 1;
1215 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1218 ft_find_metric (rfont, gstring, gidx, gstring->used);
1220 if (gpos_feature_names)
1224 MGlyph *base = NULL, *mark = NULL;
1226 if (OTF_drive_gpos (otf, &otf_gstring, script_name, language_name,
1227 gpos_feature_names) < 0)
1230 u = otf->head->unitsPerEm;
1231 size10 = rfont->font.property[MFONT_SIZE];
1234 for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
1235 i < otf_gstring.used; i++, otfg++, g++)
1239 if (! otfg->glyph_id)
1241 switch (otfg->positioning_type)
1247 int format = otfg->f.f1.format;
1249 if (format & OTF_XPlacement)
1250 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
1251 if (format & OTF_XPlaDevice)
1252 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
1253 if (format & OTF_YPlacement)
1254 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
1255 if (format & OTF_YPlaDevice)
1256 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
1257 if (format & OTF_XAdvance)
1258 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
1259 if (format & OTF_XAdvDevice)
1260 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
1264 /* Not yet supported. */
1270 goto label_adjust_anchor;
1271 default: /* i.e. case 6 */
1276 label_adjust_anchor:
1278 int base_x, base_y, mark_x, mark_y;
1280 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
1281 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
1282 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
1283 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
1285 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
1286 adjust_anchor (otfg->f.f4.base_anchor, ft_info->ft_face,
1287 prev->code, size, &base_x, &base_y);
1288 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
1289 adjust_anchor (otfg->f.f4.mark_anchor, ft_info->ft_face,
1290 g->code, size, &mark_x, &mark_y);
1291 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
1292 g->yoff = prev->yoff + mark_y - base_y;
1293 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
1296 if (otfg->GlyphClass == OTF_GlyphClass0)
1298 else if (otfg->GlyphClass == OTF_GlyphClassMark)
1304 free (otf_gstring.glyphs);
1308 ft_find_metric (rfont, gstring, from, to);
1309 for (i = 0; i < len; i++)
1311 MGlyph temp = gstring->glyphs[from + i];
1312 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1314 free (otf_gstring.glyphs);
1320 mfont__ft_decode_otf (MGlyph *g)
1322 MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
1323 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
1325 return (c ? c : -1);
1328 #endif /* HAVE_OTF */
1330 #endif /* HAVE_FREETYPE */