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);
548 unsigned short family_id;
550 if (! mplist_find_by_key (ft_info->charmap_list, registry))
552 /* Always ignore FOUNDRY. */
553 ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY];
554 /* Ignore FAMILY too. */
555 family_id = ft_info->font.property[MFONT_FAMILY];
556 ft_info->font.property[MFONT_FAMILY] = spec->property[MFONT_FAMILY];
557 score = mfont__score (&ft_info->font, spec, request, limited_size);
558 ft_info->font.property[MFONT_FAMILY] = family_id;
562 || best_score > score))
570 if (best_score == 0 || family != Mnil)
576 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
577 rfont->frame = frame;
579 rfont->request = *request;
580 rfont->font = best_font->font;
581 rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
582 rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
583 rfont->score = best_score;
584 rfont->info = best_font;
585 M17N_OBJECT_REF (best_font);
590 /* The FreeType font driver function OPEN. */
593 ft_open (MRealizedFont *rfont)
595 MFTInfo *base = rfont->info, *ft_info;
596 MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
597 int mdebug_mask = MDEBUG_FONT;
600 M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
601 ft_info->font = base->font;
602 ft_info->filename = strdup (base->filename);
603 ft_info->otf_flag = base->otf_flag;
604 ft_info->charmap_list = base->charmap_list;
605 M17N_OBJECT_REF (ft_info->charmap_list);
606 M17N_OBJECT_UNREF (base);
607 rfont->info = ft_info;
610 ft_info->ft_face = NULL;
611 if (FT_New_Face (ft_library, ft_info->filename, 0, &ft_info->ft_face))
613 if (registry == Mnil)
615 ft_info->charmap_index
616 = (int) mplist_get (((MFTInfo *) rfont->info)->charmap_list, registry);
617 if (ft_info->charmap_index >= 0
618 && FT_Set_Charmap (ft_info->ft_face,
619 ft_info->ft_face->charmaps[ft_info->charmap_index]))
621 size = rfont->font.property[MFONT_SIZE] / 10;
622 if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0, size))
625 MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename);
627 rfont->ascent = ft_info->ft_face->ascender >> 6;
628 rfont->descent = - (ft_info->ft_face->descender >> 6);
629 rfont->type = Mfreetype;
630 rfont->fontp = ft_info->ft_face;
634 MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename);
635 if (ft_info->ft_face)
636 FT_Done_Face (ft_info->ft_face);
637 M17N_OBJECT_UNREF (ft_info->charmap_list);
638 free (ft_info->filename);
644 /* The FreeType font driver function FIND_METRIC. */
647 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
650 MFTInfo *ft_info = (MFTInfo *) rfont->info;
651 FT_Face ft_face = ft_info->ft_face;
652 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
654 for (; g != gend; g++)
656 if (g->code == MCHAR_INVALID_CODE)
658 if (FT_IS_SCALABLE (ft_face))
660 unsigned unitsPerEm = ft_face->units_per_EM;
661 int size = rfont->font.property[MFONT_SIZE] / 10;
664 g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
665 g->width = ft_face->max_advance_width * size / unitsPerEm;
666 g->ascent = ft_face->ascender * size / unitsPerEm;
667 g->descent = (- ft_face->descender) * size / unitsPerEm;
671 BDF_PropertyRec prop;
674 g->rbearing = g->width = ft_face->available_sizes->width;
675 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
677 g->ascent = prop.u.integer;
678 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
679 g->descent = prop.u.integer;
683 g->ascent = ft_face->available_sizes->height;
690 FT_Glyph_Metrics *metrics;
692 FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
693 metrics = &ft_face->glyph->metrics;
694 g->lbearing = (metrics->horiBearingX >> 6);
695 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
696 g->width = metrics->horiAdvance >> 6;
697 g->ascent = metrics->horiBearingY >> 6;
698 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
703 /* The FreeType font driver function ENCODE_CHAR. */
706 ft_encode_char (MRealizedFont *rfont, unsigned code)
710 if (rfont->status == 0)
712 if ((rfont->driver->open) (rfont) < 0)
715 ft_info = (MFTInfo *) rfont->info;
716 code = (unsigned) FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) code);
718 return MCHAR_INVALID_CODE;
723 /* The FreeType font driver function RENDER. */
725 #define NUM_POINTS 0x1000
728 MDrawPoint points[NUM_POINTS];
733 ft_render (MDrawWindow win, int x, int y,
734 MGlyphString *gstring, MGlyph *from, MGlyph *to,
735 int reverse, MDrawRegion region)
739 MRealizedFace *rface = from->rface;
740 MFrame *frame = rface->frame;
741 FT_Int32 load_flags = FT_LOAD_RENDER;
744 MPointTable point_table[8];
749 /* It is assured that the all glyphs in the current range use the
750 same realized face. */
751 ft_info = (MFTInfo *) rface->rfont->info;
752 ft_face = ft_info->ft_face;
754 if (! gstring->anti_alias)
756 #ifdef FT_LOAD_TARGET_MONO
757 load_flags |= FT_LOAD_TARGET_MONO;
759 load_flags |= FT_LOAD_MONOCHROME;
763 for (i = 0; i < 8; i++)
764 point_table[i].p = point_table[i].points;
766 for (g = from; g < to; x += g++->width)
774 FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
775 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
776 bmp = ft_face->glyph->bitmap.buffer;
777 width = ft_face->glyph->bitmap.width;
778 pitch = ft_face->glyph->bitmap.pitch;
779 if (! gstring->anti_alias)
784 if (gstring->anti_alias)
785 for (i = 0; i < ft_face->glyph->bitmap.rows;
786 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
788 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
789 for (j = 0; j < width; j++, xoff++)
791 intensity = bmp[j] >> 5;
794 ptable = point_table + intensity;
798 if (ptable->p - ptable->points == NUM_POINTS)
800 (*frame->driver->draw_points)
802 reverse ? 7 - intensity : intensity,
803 ptable->points, NUM_POINTS, region);
804 ptable->p = ptable->points;
810 for (i = 0; i < ft_face->glyph->bitmap.rows;
811 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
813 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
814 for (j = 0; j < width; j++, xoff++)
816 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
819 ptable = point_table;
823 if (ptable->p - ptable->points == NUM_POINTS)
825 (*frame->driver->draw_points) (frame, win, rface,
827 ptable->points, NUM_POINTS, region);
828 ptable->p = ptable->points;
835 if (gstring->anti_alias)
837 for (i = 1; i < 8; i++)
838 if (point_table[i].p != point_table[i].points)
839 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
840 point_table[i].points,
841 point_table[i].p - point_table[i].points, region);
845 if (point_table[0].p != point_table[0].points)
846 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
847 point_table[0].points,
848 point_table[0].p - point_table[0].points, region);
853 ft_list (MFrame *frame, MPlist *plist, MFont *font, MSymbol language)
856 MSymbol family = font ? FONT_PROPERTY (font, MFONT_FAMILY) : Mnil;
857 #ifdef HAVE_FONTCONFIG
858 FcChar8 *lang = (language != Mnil ? (FcChar8 *) MSYMBOL_NAME (language)
862 pl = ft_list_family (Mnil);
867 MPLIST_DO (p, MPLIST_PLIST (pl))
869 MFTInfo *ft_info = MPLIST_VAL (p);
871 #ifdef HAVE_FONTCONFIG
872 if (lang && ft_info->langset
873 && FcLangSetHasLang (ft_info->langset, lang) != FcLangEqual)
876 if (! mfont__match_p (&ft_info->font, font, MFONT_REGISTRY))
878 mplist_push (plist, MPLIST_KEY (pl), &ft_info->font);
886 MPLIST_DO (p, ft_family_list)
888 MFTInfo *ft_info = MPLIST_VAL (p);
890 #ifdef HAVE_FONTCONFIG
891 if (lang && ft_info->langset
892 && FcLangSetHasLang (ft_info->langset, lang) != FcLangEqual)
895 mplist_push (plist, MPLIST_KEY (p), &ft_info->font);
903 MFontDriver mfont__ft_driver =
904 { ft_select, ft_open, ft_find_metric, ft_encode_char, ft_render, ft_list };
911 if (FT_Init_FreeType (&ft_library) != 0)
912 MERROR (MERROR_FONT_FT, -1);
914 for (i = 0; i < ft_to_prop_size; i++)
915 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
917 Municode_bmp = msymbol ("unicode-bmp");
918 Municode_full = msymbol ("unicode-full");
919 Miso10646_1 = msymbol ("iso10646-1");
920 Miso8859_1 = msymbol ("iso8859-1");
922 Mserif = msymbol ("serif");
923 Msans_serif = msymbol ("sans-serif");
924 Mmonospace = msymbol ("monospace");
926 Mmedium = msymbol ("medium");
928 Mnull = msymbol ("");
930 #ifdef HAVE_FONTCONFIG
931 fc_generic_family_list = mplist ();
932 mplist_push (fc_generic_family_list, Mserif, Mserif);
933 mplist_push (fc_generic_family_list, Msans_serif, Msans_serif);
934 mplist_push (fc_generic_family_list, Mmonospace, Mmonospace);
935 /* These are (deprecated) aliases. */
936 mplist_push (fc_generic_family_list, msymbol ("sans"), Msans_serif);
937 mplist_push (fc_generic_family_list, msymbol ("sans serif"), Msans_serif);
938 mplist_push (fc_generic_family_list, msymbol ("mono"), Mmonospace);
951 MPLIST_DO (plist, ft_font_list)
953 MPLIST_DO (p, MPLIST_VAL (plist))
955 MFTInfo *ft_info = MPLIST_VAL (p);
957 M17N_OBJECT_UNREF (ft_info);
959 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
961 M17N_OBJECT_UNREF (ft_font_list);
964 M17N_OBJECT_UNREF (ft_family_list);
965 ft_family_list = NULL;
967 FT_Done_FreeType (ft_library);
968 all_fonts_scaned = 0;
970 #ifdef HAVE_FONTCONFIG
971 m17n_object_unref (fc_generic_family_list);
977 #ifdef HAVE_FONTCONFIG
982 } FC_vs_M17N_font_prop;
984 static FC_vs_M17N_font_prop fc_weight_table[] =
985 { { FC_WEIGHT_ULTRALIGHT, "extralight" },
986 { FC_WEIGHT_LIGHT, "light" },
987 { FC_WEIGHT_NORMAL, "normal" },
988 { FC_WEIGHT_MEDIUM, "medium" },
989 { FC_WEIGHT_DEMIBOLD, "demibold" },
990 { FC_WEIGHT_EXTRABOLD, "extrabold" },
991 { FC_WEIGHT_BLACK, "black" },
992 { FC_WEIGHT_MEDIUM, NULL } };
994 static FC_vs_M17N_font_prop fc_slant_table[] =
995 { { FC_SLANT_ROMAN, "r" },
996 { FC_SLANT_ITALIC, "i" },
997 { FC_SLANT_OBLIQUE, "o" },
998 { FC_SLANT_ROMAN, NULL } };
1000 static FC_vs_M17N_font_prop fc_width_table[] =
1001 { { FC_WIDTH_CONDENSED, "condensed" },
1002 { FC_WIDTH_SEMIEXPANDED, "semicondensed" },
1003 { FC_WIDTH_NORMAL, "normal" },
1004 { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
1005 { FC_WIDTH_EXPANDED, "expanded" },
1006 { FC_WIDTH_NORMAL, NULL } };
1010 fc_decode_prop (int val, FC_vs_M17N_font_prop *table)
1014 for (i = 0; table[i].m17n_value; i++)
1015 if (val <= table[i].fc_value)
1016 return msymbol ("table[i].m17n_value");
1017 return msymbol ("table[i - 1].m17n_value");
1021 fc_encode_prop (char *name, FC_vs_M17N_font_prop *table)
1025 for (i = 0; table[i].m17n_value && strcmp (name, table[i].m17n_value); i++);
1026 return table[i].fc_value;
1030 mfont__ft_parse_name (char *name, MFont *font)
1032 FcPattern *pat = FcNameParse ((FcChar8 *) name);
1039 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
1040 mfont__set_property (font, MFONT_FOUNDRY, msymbol ((char *) str));
1041 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1042 mfont__set_property (font, MFONT_FAMILY, msymbol ((char *) str));
1043 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
1044 mfont__set_property (font, MFONT_WEIGHT,
1045 fc_decode_prop (val, fc_weight_table));
1046 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
1047 mfont__set_property (font, MFONT_STYLE,
1048 fc_decode_prop (val, fc_slant_table));
1049 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
1050 mfont__set_property (font, MFONT_STRETCH,
1051 fc_decode_prop (val, fc_width_table));
1052 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
1053 font->property[MFONT_SIZE] = size * 10;
1054 FcPatternDestroy (pat);
1059 mfont__ft_unparse_name (MFont *font)
1061 FcPattern *pat = FcPatternCreate ();
1062 MSymbol sym, weight, style, stretch;
1065 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
1066 FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
1067 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
1068 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
1069 if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
1070 FcPatternAddInteger (pat, FC_WEIGHT, fc_encode_prop (MSYMBOL_NAME (weight),
1072 if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
1073 FcPatternAddInteger (pat, FC_SLANT, fc_encode_prop (MSYMBOL_NAME (style),
1075 if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
1076 FcPatternAddInteger (pat, FC_WIDTH, fc_encode_prop (MSYMBOL_NAME (stretch),
1078 name = (char *) FcNameUnparse (pat);
1079 FcPatternDestroy (pat);
1082 #endif /* HAVE_FONTCONFIG */
1087 #define DEVICE_DELTA(table, size) \
1088 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1089 ? (table).DeltaValue[(size) >= (table).StartSize] \
1093 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
1094 unsigned code, int size, int *x, int *y)
1096 if (anchor->AnchorFormat == 2)
1098 FT_Outline *outline;
1099 int ap = anchor->f.f1.AnchorPoint;
1101 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1102 outline = &ft_face->glyph->outline;
1103 if (ap < outline->n_points)
1105 *x = outline->points[ap].x;
1106 *y = outline->points[ap].y;
1109 else if (anchor->AnchorFormat == 3)
1111 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
1112 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
1117 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
1118 MSymbol script, MSymbol langsys,
1119 MSymbol gsub_features, MSymbol gpos_features)
1121 int len = to - from;
1122 MGlyph *g = MGLYPH (from);
1124 MRealizedFont *rfont;
1127 OTF_GlyphString otf_gstring;
1129 char *script_name, *language_name;
1130 char *gsub_feature_names, *gpos_feature_names;
1136 rfont = g->rface->rfont;
1137 ft_info = rfont->info;
1138 if (ft_info->otf_flag < 0)
1143 otf = OTF_open (ft_info->filename);
1144 if (otf && OTF_get_table (otf, "head") < 0)
1151 ft_info->otf_flag = -1;
1158 script_name = msymbol_name (script);
1161 if (langsys != Mnil)
1162 language_name = msymbol_name (langsys);
1164 language_name = NULL;
1166 = (gsub_features == Mt ? "*"
1167 : gsub_features == Mnil ? NULL
1168 : msymbol_name (gsub_features));
1169 if (gsub_feature_names && OTF_check_table (otf, "GSUB") < 0)
1170 gsub_feature_names = NULL;
1172 = (gpos_features == Mt ? "*"
1173 : gpos_features == Mnil ? NULL
1174 : msymbol_name (gpos_features));
1175 if (gpos_feature_names && OTF_check_table (otf, "GPOS") < 0)
1176 gpos_feature_names = NULL;
1178 otf_gstring.size = otf_gstring.used = len;
1179 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
1180 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1181 for (i = 0, need_cmap = 0; i < len; i++)
1183 if (gstring->glyphs[from + i].otf_encoded)
1185 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1186 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1190 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
1195 && OTF_drive_cmap (otf, &otf_gstring) < 0)
1198 OTF_drive_gdef (otf, &otf_gstring);
1199 gidx = gstring->used;
1201 if (gsub_feature_names)
1203 if (OTF_drive_gsub (otf, &otf_gstring, script_name, language_name,
1204 gsub_feature_names) < 0)
1206 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1208 MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
1211 temp.combining_code = 0;
1214 temp.code = otfg->glyph_id;
1215 temp.otf_encoded = 1;
1220 temp.otf_encoded = 0;
1222 temp.to = MGLYPH (from + otfg->f.index.to)->to;
1223 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1227 for (i = 0; i < len; i++)
1229 MGlyph temp = gstring->glyphs[from + i];
1231 if (otf_gstring.glyphs[i].glyph_id)
1233 temp.code = otf_gstring.glyphs[i].glyph_id;
1234 temp.otf_encoded = 1;
1236 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1239 ft_find_metric (rfont, gstring, gidx, gstring->used);
1241 if (gpos_feature_names)
1245 MGlyph *base = NULL, *mark = NULL;
1247 if (OTF_drive_gpos (otf, &otf_gstring, script_name, language_name,
1248 gpos_feature_names) < 0)
1251 u = otf->head->unitsPerEm;
1252 size10 = rfont->font.property[MFONT_SIZE];
1255 for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
1256 i < otf_gstring.used; i++, otfg++, g++)
1260 if (! otfg->glyph_id)
1262 switch (otfg->positioning_type)
1268 int format = otfg->f.f1.format;
1270 if (format & OTF_XPlacement)
1271 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
1272 if (format & OTF_XPlaDevice)
1273 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
1274 if (format & OTF_YPlacement)
1275 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
1276 if (format & OTF_YPlaDevice)
1277 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
1278 if (format & OTF_XAdvance)
1279 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
1280 if (format & OTF_XAdvDevice)
1281 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
1285 /* Not yet supported. */
1291 goto label_adjust_anchor;
1292 default: /* i.e. case 6 */
1297 label_adjust_anchor:
1299 int base_x, base_y, mark_x, mark_y;
1301 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
1302 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
1303 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
1304 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
1306 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
1307 adjust_anchor (otfg->f.f4.base_anchor, ft_info->ft_face,
1308 prev->code, size, &base_x, &base_y);
1309 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
1310 adjust_anchor (otfg->f.f4.mark_anchor, ft_info->ft_face,
1311 g->code, size, &mark_x, &mark_y);
1312 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
1313 g->yoff = prev->yoff + mark_y - base_y;
1314 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
1317 if (otfg->GlyphClass == OTF_GlyphClass0)
1319 else if (otfg->GlyphClass == OTF_GlyphClassMark)
1325 free (otf_gstring.glyphs);
1329 ft_find_metric (rfont, gstring, from, to);
1330 for (i = 0; i < len; i++)
1332 MGlyph temp = gstring->glyphs[from + i];
1333 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1335 free (otf_gstring.glyphs);
1341 mfont__ft_decode_otf (MGlyph *g)
1343 MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
1344 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
1346 return (c ? c : -1);
1349 #endif /* HAVE_OTF */
1351 #endif /* HAVE_FREETYPE */