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 #define STRDUP_LOWER(s1, size, s2) \
120 int len = strlen (s2) + 1; \
124 s1 = alloca (len), size = len; \
125 for (p1 = s1, p2 = s2; *p2; p1++, p2++) \
126 *p1 = (*p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2); \
130 /** Setup members of FT_INFO from FT_FACE. If the font is a base one
131 (i.e. medium-r-normal), set BASEP to 1. Otherwise set BASEP to 0.
132 Return the family name. */
135 set_font_info (FT_Face ft_face, MFTInfo *ft_info, MSymbol family, int *basep)
137 MFont *font = &ft_info->font;
138 MPlist *charmap_list;
139 int unicode_bmp = -1, unicode_full = -1, unicode = -1;
148 STRDUP_LOWER (buf, bufsize, ft_face->family_name);
149 family = msymbol (buf);
151 mfont__set_property (font, MFONT_FAMILY, family);
152 mfont__set_property (font, MFONT_WEIGHT, Mmedium);
153 mfont__set_property (font, MFONT_STYLE, Mr);
154 mfont__set_property (font, MFONT_STRETCH, Mnormal);
155 mfont__set_property (font, MFONT_ADSTYLE, Mnull);
158 if (ft_face->style_name)
162 STRDUP_LOWER (buf, bufsize, ft_face->style_name);
166 for (i = 0; i < ft_to_prop_size; i++)
167 if (! strncmp (ft_to_prop[i].ft_style, p, ft_to_prop[i].len))
169 mfont__set_property (font, ft_to_prop[i].prop,
170 msymbol (ft_to_prop[i].val));
171 p += ft_to_prop[i].len;
174 if (i == ft_to_prop_size)
179 while (*p1 >= 'a' && *p1 <= 'z') p1++;
180 sym = msymbol__with_len (p, p1 - p);
181 for (i = MFONT_WEIGHT; i <= MFONT_STYLE; i++)
182 if (msymbol_get (sym, mfont__property_table[i].property))
184 mfont__set_property (font, i, sym);
189 while (*p && (*p < 'a' || *p > 'z')) p++;
193 *basep = (FONT_PROPERTY (font, MFONT_WEIGHT) == Mmedium
194 && FONT_PROPERTY (font, MFONT_STYLE) == Mr
195 && FONT_PROPERTY (font, MFONT_STRETCH) == Mnormal);
197 charmap_list = mplist ();
198 mplist_add (charmap_list, Mt, (void *) -1);
199 for (i = 0; i < ft_face->num_charmaps; i++)
201 char registry_buf[16];
204 sprintf (registry_buf, "%d-%d",
205 ft_face->charmaps[i]->platform_id,
206 ft_face->charmaps[i]->encoding_id);
207 registry = msymbol (registry_buf);
208 mplist_add (charmap_list, registry, (void *) i);
210 if (ft_face->charmaps[i]->platform_id == 0)
212 if (ft_face->charmaps[i]->encoding_id == 3)
214 else if (ft_face->charmaps[i]->encoding_id == 4)
217 else if (ft_face->charmaps[i]->platform_id == 3)
219 if (ft_face->charmaps[i]->encoding_id == 1)
221 else if (ft_face->charmaps[i]->encoding_id == 10)
224 else if (ft_face->charmaps[i]->platform_id == 1
225 && ft_face->charmaps[i]->encoding_id == 0)
226 mplist_add (charmap_list, msymbol ("apple-roman"), (void *) i);
228 if (unicode_full >= 0)
230 mplist_add (charmap_list, Municode_full, (void *) unicode_full);
231 mplist_add (charmap_list, Municode_bmp, (void *) unicode_full);
232 mplist_add (charmap_list, Miso10646_1, (void *) unicode_full);
233 unicode = unicode_full;
235 else if (unicode_bmp >= 0)
237 mplist_add (charmap_list, Municode_bmp, (void *) unicode_bmp);
238 mplist_add (charmap_list, Miso10646_1, (void *) unicode_bmp);
239 unicode = unicode_bmp;
243 FT_Set_Charmap (ft_face, ft_face->charmaps[unicode]);
244 for (i = 255; i >= 32; i--)
248 if (FT_Get_Char_Index (ft_face, (FT_ULong) i) == 0)
252 mplist_add (charmap_list, Miso8859_1, (void *) unicode);
255 ft_info->charmap_list = charmap_list;
257 if (! FT_IS_SCALABLE (ft_face))
259 BDF_PropertyRec prop;
261 FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop);
262 font->property[MFONT_SIZE] = prop.u.integer * 10;
263 FT_Get_BDF_Property (ft_face, "RESOLUTION_Y", &prop);
264 font->property[MFONT_RESY] = prop.u.integer;
272 close_ft (void *object)
274 MFTInfo *ft_info = object;
276 if (ft_info->ft_face)
278 if (ft_info->extra_info)
279 M17N_OBJECT_UNREF (ft_info->extra_info);
280 FT_Done_Face (ft_info->ft_face);
283 OTF_close (ft_info->otf);
284 #endif /* HAVE_OTF */
286 free (ft_info->filename);
287 if (ft_info->languages)
288 free (ft_info->languages);
289 M17N_OBJECT_UNREF (ft_info->charmap_list);
294 add_font_info (char *filename, MSymbol family, void *langset, MPlist *plist)
297 BDF_PropertyRec prop;
298 MFTInfo *ft_info = NULL;
300 if (FT_New_Face (ft_library, filename, 0, &ft_face) == 0)
302 if (FT_IS_SCALABLE (ft_face)
303 || FT_Get_BDF_Property (ft_face, "PIXEL_SIZE", &prop) == 0)
308 M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
309 ft_info->filename = strdup (filename);
310 ft_info->otf_flag = check_otf_filename (filename);
311 #ifdef HAVE_FONTCONFIG
313 ft_info->langset = FcLangSetCopy (langset);
315 fam = set_font_info (ft_face, ft_info, family, &basep);
317 && ! (plist = mplist_get (ft_font_list, fam)))
320 mplist_push (ft_font_list, fam, plist);
322 mplist_push (plist, fam, ft_info);
325 mplist_put (ft_family_list, fam, ft_info);
326 else if (! mplist_get (ft_family_list, fam))
327 mplist_push (ft_family_list, fam, ft_info);
329 FT_Done_Face (ft_face);
333 /* Return an element of ft_font_list for FAMILY. If FAMILY is Mnil,
334 scan all fonts and return ft_font_list. */
336 ft_list_family (MSymbol family)
342 ft_font_list = mplist ();
343 ft_family_list = mplist ();
348 if (all_fonts_scaned)
353 plist = mplist_find_by_key (ft_font_list, family);
356 if (all_fonts_scaned)
359 mplist_push (ft_font_list, family, plist);
364 #ifdef HAVE_FONTCONFIG
380 fc_config = FcConfigGetCurrent ();
381 MPLIST_DO (plist, mfont_freetype_path)
382 if (MPLIST_STRING_P (plist)
383 && (pathname = MPLIST_STRING (plist))
384 && stat (pathname, &buf) == 0)
386 FcStrList *strlist = FcConfigGetFontDirs (fc_config);
389 while ((dir = FcStrListNext (strlist)))
390 if (strcmp ((char *) dir, pathname) == 0)
393 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
394 FcStrListDone (strlist);
398 pattern = FcPatternCreate ();
401 MSymbol generic = mplist_get (fc_generic_family_list, family);
405 plist = mplist_find_by_key (ft_font_list, family);
409 mplist_push (ft_font_list, family, plist);
411 FcPatternAddString (pattern, FC_FAMILY,
412 (FcChar8 *) (msymbol_name (family)));
414 && FcConfigSubstitute (fc_config, pattern, FcMatchPattern)
417 FcPatternDestroy (pattern);
422 os = FcObjectSetBuild (FC_FILE, FC_FAMILY, FC_LANG, NULL);
423 fs = FcFontList (fc_config, pattern, os);
425 for (i = 0; i < fs->nfont; i++)
430 if (FcPatternGetString (fs->fonts[i], FC_FILE, 0, &filename)
433 if (FcPatternGetLangSet (fs->fonts[i], FC_LANG, 0, &langset)
441 FcPatternGetString (fs->fonts[i], FC_FAMILY, 0,
442 (FcChar8 **) &fname);
443 STRDUP_LOWER (buf, bufsize, fname);
444 fam = msymbol ((char *) buf);
445 plist = mplist_get (ft_font_list, fam);
449 mplist_push (ft_font_list, fam, plist);
450 add_font_info ((char *) filename, fam, langset, plist);
454 add_font_info ((char *) filename, family, langset, plist);
456 FcFontSetDestroy (fs);
457 FcObjectSetDestroy (os);
458 FcPatternDestroy (pattern);
462 MPLIST_DO (plist, fc_generic_family_list)
463 if (MPLIST_KEY (plist) == MPLIST_SYMBOL (plist)
464 && ! mplist_get (ft_font_list, MPLIST_KEY (plist)))
465 ft_list_family (MPLIST_KEY (plist));
466 all_fonts_scaned = 1;
470 #else /* not HAVE_FONTCONFIG */
476 MPLIST_DO (plist, mfont_freetype_path)
477 if (MPLIST_STRING_P (plist)
478 && (pathname = MPLIST_STRING (plist))
479 && stat (pathname, &buf) == 0)
481 if (S_ISREG (buf.st_mode))
482 add_font_info (pathname, Mnil, NULL, NULL);
483 else if (S_ISDIR (buf.st_mode))
485 int len = strlen (pathname);
487 DIR *dir = opendir (pathname);
492 strcpy (path, pathname);
493 strcpy (path + len, "/");
495 while ((dp = readdir (dir)) != NULL)
497 strcpy (path + len, dp->d_name);
498 add_font_info (path, Mnil, NULL, NULL);
507 plist = mplist_find_by_key (ft_font_list, family);
511 mplist_push (ft_font_list, family, plist);
515 #endif /* not HAVE_FONTCONFIG */
521 /* The FreeType font driver function SELECT. */
523 static MRealizedFont *
524 ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size)
526 MPlist *plist, *pl, *p;
529 MRealizedFont *rfont;
530 MSymbol family, registry;
532 family = FONT_PROPERTY (spec, MFONT_FAMILY);
534 family = FONT_PROPERTY (request, MFONT_FAMILY);
535 registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
536 if (registry == Mnil)
539 plist = ft_list_family (family);
542 MPLIST_DO (pl, plist)
544 MPLIST_DO (p, MPLIST_VAL (pl))
546 MFTInfo *ft_info = MPLIST_VAL (p);
549 if (! mplist_find_by_key (ft_info->charmap_list, registry))
551 /* We always ignore FOUNDRY. */
552 ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY];
553 score = mfont__score (&ft_info->font, spec, request, limited_size);
556 || best_score > score))
564 if (best_score == 0 || family != Mnil)
570 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
571 rfont->frame = frame;
573 rfont->request = *request;
574 rfont->font = best_font->font;
575 rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
576 rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
577 rfont->score = best_score;
578 rfont->info = best_font;
579 M17N_OBJECT_REF (best_font);
584 /* The FreeType font driver function OPEN. */
587 ft_open (MRealizedFont *rfont)
589 MFTInfo *base = rfont->info, *ft_info;
590 MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
591 int mdebug_mask = MDEBUG_FONT;
594 M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
595 ft_info->font = base->font;
596 ft_info->filename = strdup (base->filename);
597 ft_info->otf_flag = base->otf_flag;
598 ft_info->charmap_list = base->charmap_list;
599 M17N_OBJECT_REF (ft_info->charmap_list);
600 M17N_OBJECT_UNREF (base);
601 rfont->info = ft_info;
604 ft_info->ft_face = NULL;
605 if (FT_New_Face (ft_library, ft_info->filename, 0, &ft_info->ft_face))
607 if (registry == Mnil)
609 ft_info->charmap_index
610 = (int) mplist_get (((MFTInfo *) rfont->info)->charmap_list, registry);
611 if (ft_info->charmap_index >= 0
612 && FT_Set_Charmap (ft_info->ft_face,
613 ft_info->ft_face->charmaps[ft_info->charmap_index]))
615 size = rfont->font.property[MFONT_SIZE] / 10;
616 if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0, size))
619 MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename);
621 rfont->ascent = ft_info->ft_face->ascender >> 6;
622 rfont->descent = - (ft_info->ft_face->descender >> 6);
623 rfont->type = Mfreetype;
624 rfont->fontp = ft_info->ft_face;
628 MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename);
629 if (ft_info->ft_face)
630 FT_Done_Face (ft_info->ft_face);
631 M17N_OBJECT_UNREF (ft_info->charmap_list);
632 free (ft_info->filename);
638 /* The FreeType font driver function FIND_METRIC. */
641 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
644 MFTInfo *ft_info = (MFTInfo *) rfont->info;
645 FT_Face ft_face = ft_info->ft_face;
646 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
648 for (; g != gend; g++)
650 if (g->code == MCHAR_INVALID_CODE)
652 if (FT_IS_SCALABLE (ft_face))
654 unsigned unitsPerEm = ft_face->units_per_EM;
655 int size = rfont->font.property[MFONT_SIZE] / 10;
658 g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
659 g->width = ft_face->max_advance_width * size / unitsPerEm;
660 g->ascent = ft_face->ascender * size / unitsPerEm;
661 g->descent = (- ft_face->descender) * size / unitsPerEm;
665 BDF_PropertyRec prop;
668 g->rbearing = g->width = ft_face->available_sizes->width;
669 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
671 g->ascent = prop.u.integer;
672 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
673 g->descent = prop.u.integer;
677 g->ascent = ft_face->available_sizes->height;
684 FT_Glyph_Metrics *metrics;
686 FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
687 metrics = &ft_face->glyph->metrics;
688 g->lbearing = (metrics->horiBearingX >> 6);
689 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
690 g->width = metrics->horiAdvance >> 6;
691 g->ascent = metrics->horiBearingY >> 6;
692 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
697 /* The FreeType font driver function ENCODE_CHAR. */
700 ft_encode_char (MRealizedFont *rfont, unsigned code)
704 if (rfont->status == 0)
706 if ((rfont->driver->open) (rfont) < 0)
709 ft_info = (MFTInfo *) rfont->info;
710 code = (unsigned) FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) code);
712 return MCHAR_INVALID_CODE;
717 /* The FreeType font driver function RENDER. */
719 #define NUM_POINTS 0x1000
722 MDrawPoint points[NUM_POINTS];
727 ft_render (MDrawWindow win, int x, int y,
728 MGlyphString *gstring, MGlyph *from, MGlyph *to,
729 int reverse, MDrawRegion region)
733 MRealizedFace *rface = from->rface;
734 MFrame *frame = rface->frame;
735 FT_Int32 load_flags = FT_LOAD_RENDER;
738 MPointTable point_table[8];
743 /* It is assured that the all glyphs in the current range use the
744 same realized face. */
745 ft_info = (MFTInfo *) rface->rfont->info;
746 ft_face = ft_info->ft_face;
748 if (! gstring->anti_alias)
750 #ifdef FT_LOAD_TARGET_MONO
751 load_flags |= FT_LOAD_TARGET_MONO;
753 load_flags |= FT_LOAD_MONOCHROME;
757 for (i = 0; i < 8; i++)
758 point_table[i].p = point_table[i].points;
760 for (g = from; g < to; x += g++->width)
768 FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
769 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
770 bmp = ft_face->glyph->bitmap.buffer;
771 width = ft_face->glyph->bitmap.width;
772 pitch = ft_face->glyph->bitmap.pitch;
773 if (! gstring->anti_alias)
778 if (gstring->anti_alias)
779 for (i = 0; i < ft_face->glyph->bitmap.rows;
780 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
782 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
783 for (j = 0; j < width; j++, xoff++)
785 intensity = bmp[j] >> 5;
788 ptable = point_table + intensity;
792 if (ptable->p - ptable->points == NUM_POINTS)
794 (*frame->driver->draw_points)
796 reverse ? 7 - intensity : intensity,
797 ptable->points, NUM_POINTS, region);
798 ptable->p = ptable->points;
804 for (i = 0; i < ft_face->glyph->bitmap.rows;
805 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
807 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
808 for (j = 0; j < width; j++, xoff++)
810 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
813 ptable = point_table;
817 if (ptable->p - ptable->points == NUM_POINTS)
819 (*frame->driver->draw_points) (frame, win, rface,
821 ptable->points, NUM_POINTS, region);
822 ptable->p = ptable->points;
829 if (gstring->anti_alias)
831 for (i = 1; i < 8; i++)
832 if (point_table[i].p != point_table[i].points)
833 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
834 point_table[i].points,
835 point_table[i].p - point_table[i].points, region);
839 if (point_table[0].p != point_table[0].points)
840 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
841 point_table[0].points,
842 point_table[0].p - point_table[0].points, region);
847 ft_list (MFrame *frame, MPlist *plist, MFont *font, MSymbol language)
850 MSymbol family = font ? FONT_PROPERTY (font, MFONT_FAMILY) : Mnil;
851 #ifdef HAVE_FONTCONFIG
852 FcChar8 *lang = (language != Mnil ? (FcChar8 *) MSYMBOL_NAME (language)
856 pl = ft_list_family (Mnil);
861 MPLIST_DO (p, MPLIST_PLIST (pl))
863 MFTInfo *ft_info = MPLIST_VAL (p);
865 #ifdef HAVE_FONTCONFIG
866 if (lang && ft_info->langset
867 && FcLangSetHasLang (ft_info->langset, lang) != FcLangEqual)
870 if (! mfont__match_p (&ft_info->font, font, MFONT_REGISTRY))
872 mplist_push (plist, MPLIST_KEY (pl), &ft_info->font);
880 MPLIST_DO (p, ft_family_list)
882 MFTInfo *ft_info = MPLIST_VAL (p);
884 #ifdef HAVE_FONTCONFIG
885 if (lang && ft_info->langset
886 && FcLangSetHasLang (ft_info->langset, lang) != FcLangEqual)
889 mplist_push (plist, MPLIST_KEY (p), &ft_info->font);
897 MFontDriver mfont__ft_driver =
898 { ft_select, ft_open, ft_find_metric, ft_encode_char, ft_render, ft_list };
905 if (FT_Init_FreeType (&ft_library) != 0)
906 MERROR (MERROR_FONT_FT, -1);
908 for (i = 0; i < ft_to_prop_size; i++)
909 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
911 Municode_bmp = msymbol ("unicode-bmp");
912 Municode_full = msymbol ("unicode-full");
913 Miso10646_1 = msymbol ("iso10646-1");
914 Miso8859_1 = msymbol ("iso8859-1");
916 Mserif = msymbol ("serif");
917 Msans_serif = msymbol ("sans-serif");
918 Mmonospace = msymbol ("monospace");
920 Mmedium = msymbol ("medium");
922 Mnull = msymbol ("");
924 #ifdef HAVE_FONTCONFIG
925 fc_generic_family_list = mplist ();
926 mplist_push (fc_generic_family_list, Mserif, Mserif);
927 mplist_push (fc_generic_family_list, Msans_serif, Msans_serif);
928 mplist_push (fc_generic_family_list, Mmonospace, Mmonospace);
929 /* These are (deprecated) aliases. */
930 mplist_push (fc_generic_family_list, msymbol ("sans"), Msans_serif);
931 mplist_push (fc_generic_family_list, msymbol ("sans serif"), Msans_serif);
932 mplist_push (fc_generic_family_list, msymbol ("mono"), Mmonospace);
945 MPLIST_DO (plist, ft_font_list)
947 MPLIST_DO (p, MPLIST_VAL (plist))
949 MFTInfo *ft_info = MPLIST_VAL (p);
951 M17N_OBJECT_UNREF (ft_info);
953 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
955 M17N_OBJECT_UNREF (ft_font_list);
958 M17N_OBJECT_UNREF (ft_family_list);
959 ft_family_list = NULL;
961 FT_Done_FreeType (ft_library);
962 all_fonts_scaned = 0;
964 #ifdef HAVE_FONTCONFIG
965 m17n_object_unref (fc_generic_family_list);
971 #ifdef HAVE_FONTCONFIG
976 } FC_vs_M17N_font_prop;
978 static FC_vs_M17N_font_prop fc_weight_table[] =
979 { { FC_WEIGHT_ULTRALIGHT, "extralight" },
980 { FC_WEIGHT_LIGHT, "light" },
981 { FC_WEIGHT_NORMAL, "normal" },
982 { FC_WEIGHT_MEDIUM, "medium" },
983 { FC_WEIGHT_DEMIBOLD, "demibold" },
984 { FC_WEIGHT_EXTRABOLD, "extrabold" },
985 { FC_WEIGHT_BLACK, "black" },
986 { FC_WEIGHT_MEDIUM, NULL } };
988 static FC_vs_M17N_font_prop fc_slant_table[] =
989 { { FC_SLANT_ROMAN, "r" },
990 { FC_SLANT_ITALIC, "i" },
991 { FC_SLANT_OBLIQUE, "o" },
992 { FC_SLANT_ROMAN, NULL } };
994 static FC_vs_M17N_font_prop fc_width_table[] =
995 { { FC_WIDTH_CONDENSED, "condensed" },
996 { FC_WIDTH_SEMIEXPANDED, "semicondensed" },
997 { FC_WIDTH_NORMAL, "normal" },
998 { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
999 { FC_WIDTH_EXPANDED, "expanded" },
1000 { FC_WIDTH_NORMAL, NULL } };
1004 fc_decode_prop (int val, FC_vs_M17N_font_prop *table)
1008 for (i = 0; table[i].m17n_value; i++)
1009 if (val <= table[i].fc_value)
1010 return msymbol ("table[i].m17n_value");
1011 return msymbol ("table[i - 1].m17n_value");
1015 fc_encode_prop (char *name, FC_vs_M17N_font_prop *table)
1019 for (i = 0; table[i].m17n_value && strcmp (name, table[i].m17n_value); i++);
1020 return table[i].fc_value;
1024 mfont__ft_parse_name (char *name, MFont *font)
1026 FcPattern *pat = FcNameParse ((FcChar8 *) name);
1033 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
1034 mfont__set_property (font, MFONT_FOUNDRY, msymbol ((char *) str));
1035 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1036 mfont__set_property (font, MFONT_FAMILY, msymbol ((char *) str));
1037 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
1038 mfont__set_property (font, MFONT_WEIGHT,
1039 fc_decode_prop (val, fc_weight_table));
1040 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
1041 mfont__set_property (font, MFONT_STYLE,
1042 fc_decode_prop (val, fc_slant_table));
1043 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
1044 mfont__set_property (font, MFONT_STRETCH,
1045 fc_decode_prop (val, fc_width_table));
1046 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
1047 font->property[MFONT_SIZE] = size * 10;
1048 FcPatternDestroy (pat);
1053 mfont__ft_unparse_name (MFont *font)
1055 FcPattern *pat = FcPatternCreate ();
1056 MSymbol sym, weight, style, stretch;
1059 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
1060 FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
1061 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
1062 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
1063 if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
1064 FcPatternAddInteger (pat, FC_WEIGHT, fc_encode_prop (MSYMBOL_NAME (weight),
1066 if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
1067 FcPatternAddInteger (pat, FC_SLANT, fc_encode_prop (MSYMBOL_NAME (style),
1069 if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
1070 FcPatternAddInteger (pat, FC_WIDTH, fc_encode_prop (MSYMBOL_NAME (stretch),
1072 name = (char *) FcNameUnparse (pat);
1073 FcPatternDestroy (pat);
1076 #endif /* HAVE_FONTCONFIG */
1081 #define DEVICE_DELTA(table, size) \
1082 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1083 ? (table).DeltaValue[(size) >= (table).StartSize] \
1087 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
1088 unsigned code, int size, int *x, int *y)
1090 if (anchor->AnchorFormat == 2)
1092 FT_Outline *outline;
1093 int ap = anchor->f.f1.AnchorPoint;
1095 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1096 outline = &ft_face->glyph->outline;
1097 if (ap < outline->n_points)
1099 *x = outline->points[ap].x;
1100 *y = outline->points[ap].y;
1103 else if (anchor->AnchorFormat == 3)
1105 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
1106 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
1111 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
1112 MSymbol script, MSymbol langsys,
1113 MSymbol gsub_features, MSymbol gpos_features)
1115 int len = to - from;
1116 MGlyph *g = MGLYPH (from);
1118 MRealizedFont *rfont;
1121 OTF_GlyphString otf_gstring;
1123 char *script_name, *language_name;
1124 char *gsub_feature_names, *gpos_feature_names;
1130 rfont = g->rface->rfont;
1131 ft_info = rfont->info;
1132 if (ft_info->otf_flag < 0)
1137 otf = OTF_open (ft_info->filename);
1138 if (otf && OTF_get_table (otf, "head") < 0)
1145 ft_info->otf_flag = -1;
1152 script_name = msymbol_name (script);
1155 if (langsys != Mnil)
1156 language_name = msymbol_name (langsys);
1158 language_name = NULL;
1160 = (gsub_features == Mt ? "*"
1161 : gsub_features == Mnil ? NULL
1162 : msymbol_name (gsub_features));
1163 if (gsub_feature_names && OTF_check_table (otf, "GSUB") < 0)
1164 gsub_feature_names = NULL;
1166 = (gpos_features == Mt ? "*"
1167 : gpos_features == Mnil ? NULL
1168 : msymbol_name (gpos_features));
1169 if (gpos_feature_names && OTF_check_table (otf, "GPOS") < 0)
1170 gpos_feature_names = NULL;
1172 otf_gstring.size = otf_gstring.used = len;
1173 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
1174 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1175 for (i = 0, need_cmap = 0; i < len; i++)
1177 if (gstring->glyphs[from + i].otf_encoded)
1179 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1180 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1184 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
1189 && OTF_drive_cmap (otf, &otf_gstring) < 0)
1192 OTF_drive_gdef (otf, &otf_gstring);
1193 gidx = gstring->used;
1195 if (gsub_feature_names)
1197 if (OTF_drive_gsub (otf, &otf_gstring, script_name, language_name,
1198 gsub_feature_names) < 0)
1200 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1202 MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
1205 temp.combining_code = 0;
1208 temp.code = otfg->glyph_id;
1209 temp.otf_encoded = 1;
1214 temp.otf_encoded = 0;
1216 temp.to = MGLYPH (from + otfg->f.index.to)->to;
1217 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1221 for (i = 0; i < len; i++)
1223 MGlyph temp = gstring->glyphs[from + i];
1225 if (otf_gstring.glyphs[i].glyph_id)
1227 temp.code = otf_gstring.glyphs[i].glyph_id;
1228 temp.otf_encoded = 1;
1230 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1233 ft_find_metric (rfont, gstring, gidx, gstring->used);
1235 if (gpos_feature_names)
1239 MGlyph *base = NULL, *mark = NULL;
1241 if (OTF_drive_gpos (otf, &otf_gstring, script_name, language_name,
1242 gpos_feature_names) < 0)
1245 u = otf->head->unitsPerEm;
1246 size10 = rfont->font.property[MFONT_SIZE];
1249 for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
1250 i < otf_gstring.used; i++, otfg++, g++)
1254 if (! otfg->glyph_id)
1256 switch (otfg->positioning_type)
1262 int format = otfg->f.f1.format;
1264 if (format & OTF_XPlacement)
1265 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
1266 if (format & OTF_XPlaDevice)
1267 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
1268 if (format & OTF_YPlacement)
1269 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
1270 if (format & OTF_YPlaDevice)
1271 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
1272 if (format & OTF_XAdvance)
1273 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
1274 if (format & OTF_XAdvDevice)
1275 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
1279 /* Not yet supported. */
1285 goto label_adjust_anchor;
1286 default: /* i.e. case 6 */
1291 label_adjust_anchor:
1293 int base_x, base_y, mark_x, mark_y;
1295 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
1296 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
1297 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
1298 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
1300 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
1301 adjust_anchor (otfg->f.f4.base_anchor, ft_info->ft_face,
1302 prev->code, size, &base_x, &base_y);
1303 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
1304 adjust_anchor (otfg->f.f4.mark_anchor, ft_info->ft_face,
1305 g->code, size, &mark_x, &mark_y);
1306 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
1307 g->yoff = prev->yoff + mark_y - base_y;
1308 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
1311 if (otfg->GlyphClass == OTF_GlyphClass0)
1313 else if (otfg->GlyphClass == OTF_GlyphClassMark)
1319 free (otf_gstring.glyphs);
1323 ft_find_metric (rfont, gstring, from, to);
1324 for (i = 0; i < len; i++)
1326 MGlyph temp = gstring->glyphs[from + i];
1327 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1329 free (otf_gstring.glyphs);
1335 mfont__ft_decode_otf (MGlyph *g)
1337 MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
1338 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
1340 return (c ? c : -1);
1343 #endif /* HAVE_OTF */
1345 #endif /* HAVE_FREETYPE */