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_add (plist, fam, ft_info);
325 mplist_put (ft_family_list, fam, ft_info);
326 else if (! mplist_get (ft_family_list, fam))
327 mplist_add (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
366 FcPattern *pattern, *pat;
372 MSymbol generic = Mnil;
381 fc_config = FcConfigGetCurrent ();
382 MPLIST_DO (plist, mfont_freetype_path)
383 if (MPLIST_STRING_P (plist)
384 && (pathname = MPLIST_STRING (plist))
385 && stat (pathname, &buf) == 0)
387 FcStrList *strlist = FcConfigGetFontDirs (fc_config);
390 while ((dir = FcStrListNext (strlist)))
391 if (strcmp ((char *) dir, pathname) == 0)
394 FcConfigAppFontAddDir (fc_config, (FcChar8 *) pathname);
395 FcStrListDone (strlist);
399 pattern = FcPatternCreate ();
402 generic = mplist_get (fc_generic_family_list, family);
406 plist = mplist_find_by_key (ft_font_list, family);
411 mplist_push (ft_font_list, family, plist);
413 FcPatternAddString (pattern, FC_FAMILY,
414 (FcChar8 *) (msymbol_name (family)));
416 && FcConfigSubstitute (fc_config, pattern, FcMatchPattern)
419 FcPatternDestroy (pattern);
424 os = FcObjectSetBuild (FC_FILE, FC_FAMILY, FC_LANG, NULL);
425 pat = FcPatternCreate ();
432 if (FcPatternGetString (pattern, FC_FAMILY, j, &fname)
435 FcPatternAddString (pat, FC_FAMILY, fname);
436 fs = FcFontList (fc_config, pat, os);
439 fs = FcFontList (fc_config, pattern, os);
441 for (i = 0; i < fs->nfont; i++)
446 if (FcPatternGetString (fs->fonts[i], FC_FILE, 0, &filename)
449 if (FcPatternGetLangSet (fs->fonts[i], FC_LANG, 0, &langset)
456 FcPatternGetString (fs->fonts[i], FC_FAMILY, 0, &fname);
457 STRDUP_LOWER (buf, bufsize, fname);
458 fam = msymbol ((char *) buf);
459 plist = mplist_get (ft_font_list, fam);
463 mplist_push (ft_font_list, fam, plist);
464 add_font_info ((char *) filename, fam, langset, plist);
468 add_font_info ((char *) filename, family, langset, plist);
472 FcPatternDel (pat, FC_FAMILY);
477 FcFontSetDestroy (fs);
478 FcObjectSetDestroy (os);
479 FcPatternDestroy (pattern);
480 FcPatternDestroy (pat);
484 MPLIST_DO (plist, fc_generic_family_list)
485 if (MPLIST_KEY (plist) == MPLIST_SYMBOL (plist)
486 && ! mplist_get (ft_font_list, MPLIST_KEY (plist)))
487 ft_list_family (MPLIST_KEY (plist));
488 all_fonts_scaned = 1;
492 #else /* not HAVE_FONTCONFIG */
498 MPLIST_DO (plist, mfont_freetype_path)
499 if (MPLIST_STRING_P (plist)
500 && (pathname = MPLIST_STRING (plist))
501 && stat (pathname, &buf) == 0)
503 if (S_ISREG (buf.st_mode))
504 add_font_info (pathname, Mnil, NULL, NULL);
505 else if (S_ISDIR (buf.st_mode))
507 int len = strlen (pathname);
509 DIR *dir = opendir (pathname);
514 strcpy (path, pathname);
515 strcpy (path + len, "/");
517 while ((dp = readdir (dir)) != NULL)
519 strcpy (path + len, dp->d_name);
520 add_font_info (path, Mnil, NULL, NULL);
529 plist = mplist_find_by_key (ft_font_list, family);
533 mplist_push (ft_font_list, family, plist);
537 #endif /* not HAVE_FONTCONFIG */
543 /* The FreeType font driver function SELECT. */
545 static MRealizedFont *
546 ft_select (MFrame *frame, MFont *spec, MFont *request, int limited_size)
548 MPlist *plist, *pl, *p;
551 MRealizedFont *rfont;
552 MSymbol family, registry;
554 family = FONT_PROPERTY (spec, MFONT_FAMILY);
556 family = FONT_PROPERTY (request, MFONT_FAMILY);
557 registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
558 if (registry == Mnil)
561 plist = ft_list_family (family);
564 MPLIST_DO (pl, plist)
566 MPLIST_DO (p, MPLIST_VAL (pl))
568 MFTInfo *ft_info = MPLIST_VAL (p);
570 unsigned short family_id;
572 if (! mplist_find_by_key (ft_info->charmap_list, registry))
574 /* Always ignore FOUNDRY. */
575 ft_info->font.property[MFONT_FOUNDRY] = spec->property[MFONT_FOUNDRY];
576 /* Ignore FAMILY too. */
577 family_id = ft_info->font.property[MFONT_FAMILY];
578 ft_info->font.property[MFONT_FAMILY] = spec->property[MFONT_FAMILY];
579 score = mfont__score (&ft_info->font, spec, request, limited_size);
580 ft_info->font.property[MFONT_FAMILY] = family_id;
584 || best_score > score))
592 if (best_score == 0 || family != Mnil)
598 MSTRUCT_CALLOC (rfont, MERROR_FONT_FT);
599 rfont->frame = frame;
601 rfont->request = *request;
602 rfont->font = best_font->font;
603 rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
604 rfont->font.property[MFONT_REGISTRY] = spec->property[MFONT_REGISTRY];
605 rfont->score = best_score;
606 rfont->info = best_font;
607 M17N_OBJECT_REF (best_font);
612 /* The FreeType font driver function OPEN. */
615 ft_open (MRealizedFont *rfont)
617 MFTInfo *base = rfont->info, *ft_info;
618 MSymbol registry = FONT_PROPERTY (&rfont->font, MFONT_REGISTRY);
619 int mdebug_mask = MDEBUG_FONT;
622 M17N_OBJECT (ft_info, close_ft, MERROR_FONT_FT);
623 ft_info->font = base->font;
624 ft_info->filename = strdup (base->filename);
625 ft_info->otf_flag = base->otf_flag;
626 ft_info->charmap_list = base->charmap_list;
627 M17N_OBJECT_REF (ft_info->charmap_list);
628 M17N_OBJECT_UNREF (base);
629 rfont->info = ft_info;
632 ft_info->ft_face = NULL;
633 if (FT_New_Face (ft_library, ft_info->filename, 0, &ft_info->ft_face))
635 if (registry == Mnil)
637 ft_info->charmap_index
638 = (int) mplist_get (((MFTInfo *) rfont->info)->charmap_list, registry);
639 if (ft_info->charmap_index >= 0
640 && FT_Set_Charmap (ft_info->ft_face,
641 ft_info->ft_face->charmaps[ft_info->charmap_index]))
643 size = rfont->font.property[MFONT_SIZE] / 10;
644 if (FT_Set_Pixel_Sizes (ft_info->ft_face, 0, size))
647 MDEBUG_PRINT1 (" [FT-FONT] o %s\n", ft_info->filename);
649 rfont->ascent = ft_info->ft_face->ascender >> 6;
650 rfont->descent = - (ft_info->ft_face->descender >> 6);
651 rfont->type = Mfreetype;
652 rfont->fontp = ft_info->ft_face;
656 MDEBUG_PRINT1 (" [FT-FONT] x %s\n", ft_info->filename);
657 if (ft_info->ft_face)
658 FT_Done_Face (ft_info->ft_face);
659 M17N_OBJECT_UNREF (ft_info->charmap_list);
660 free (ft_info->filename);
666 /* The FreeType font driver function FIND_METRIC. */
669 ft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
672 MFTInfo *ft_info = (MFTInfo *) rfont->info;
673 FT_Face ft_face = ft_info->ft_face;
674 MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
676 for (; g != gend; g++)
678 if (g->code == MCHAR_INVALID_CODE)
680 if (FT_IS_SCALABLE (ft_face))
682 unsigned unitsPerEm = ft_face->units_per_EM;
683 int size = rfont->font.property[MFONT_SIZE] / 10;
686 g->rbearing = ft_face->max_advance_width * size / unitsPerEm;
687 g->width = ft_face->max_advance_width * size / unitsPerEm;
688 g->ascent = ft_face->ascender * size / unitsPerEm;
689 g->descent = (- ft_face->descender) * size / unitsPerEm;
693 BDF_PropertyRec prop;
696 g->rbearing = g->width = ft_face->available_sizes->width;
697 if (FT_Get_BDF_Property (ft_face, "ASCENT", &prop) == 0)
699 g->ascent = prop.u.integer;
700 FT_Get_BDF_Property (ft_face, "DESCENT", &prop);
701 g->descent = prop.u.integer;
705 g->ascent = ft_face->available_sizes->height;
712 FT_Glyph_Metrics *metrics;
714 FT_Load_Glyph (ft_face, (FT_UInt) g->code, FT_LOAD_DEFAULT);
715 metrics = &ft_face->glyph->metrics;
716 g->lbearing = (metrics->horiBearingX >> 6);
717 g->rbearing = (metrics->horiBearingX + metrics->width) >> 6;
718 g->width = metrics->horiAdvance >> 6;
719 g->ascent = metrics->horiBearingY >> 6;
720 g->descent = (metrics->height - metrics->horiBearingY) >> 6;
725 /* The FreeType font driver function ENCODE_CHAR. */
728 ft_encode_char (MRealizedFont *rfont, unsigned code)
732 if (rfont->status == 0)
734 if ((rfont->driver->open) (rfont) < 0)
737 ft_info = (MFTInfo *) rfont->info;
738 code = (unsigned) FT_Get_Char_Index (ft_info->ft_face, (FT_ULong) code);
740 return MCHAR_INVALID_CODE;
745 /* The FreeType font driver function RENDER. */
747 #define NUM_POINTS 0x1000
750 MDrawPoint points[NUM_POINTS];
755 ft_render (MDrawWindow win, int x, int y,
756 MGlyphString *gstring, MGlyph *from, MGlyph *to,
757 int reverse, MDrawRegion region)
761 MRealizedFace *rface = from->rface;
762 MFrame *frame = rface->frame;
763 FT_Int32 load_flags = FT_LOAD_RENDER;
766 MPointTable point_table[8];
771 /* It is assured that the all glyphs in the current range use the
772 same realized face. */
773 ft_info = (MFTInfo *) rface->rfont->info;
774 ft_face = ft_info->ft_face;
776 if (! gstring->anti_alias)
778 #ifdef FT_LOAD_TARGET_MONO
779 load_flags |= FT_LOAD_TARGET_MONO;
781 load_flags |= FT_LOAD_MONOCHROME;
785 for (i = 0; i < 8; i++)
786 point_table[i].p = point_table[i].points;
788 for (g = from; g < to; x += g++->width)
796 FT_Load_Glyph (ft_face, (FT_UInt) g->code, load_flags);
797 yoff = y - ft_face->glyph->bitmap_top + g->yoff;
798 bmp = ft_face->glyph->bitmap.buffer;
799 width = ft_face->glyph->bitmap.width;
800 pitch = ft_face->glyph->bitmap.pitch;
801 if (! gstring->anti_alias)
806 if (gstring->anti_alias)
807 for (i = 0; i < ft_face->glyph->bitmap.rows;
808 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
810 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
811 for (j = 0; j < width; j++, xoff++)
813 intensity = bmp[j] >> 5;
816 ptable = point_table + intensity;
820 if (ptable->p - ptable->points == NUM_POINTS)
822 (*frame->driver->draw_points)
824 reverse ? 7 - intensity : intensity,
825 ptable->points, NUM_POINTS, region);
826 ptable->p = ptable->points;
832 for (i = 0; i < ft_face->glyph->bitmap.rows;
833 i++, bmp += ft_face->glyph->bitmap.pitch, yoff++)
835 xoff = x + ft_face->glyph->bitmap_left + g->xoff;
836 for (j = 0; j < width; j++, xoff++)
838 intensity = bmp[j / 8] & (1 << (7 - (j % 8)));
841 ptable = point_table;
845 if (ptable->p - ptable->points == NUM_POINTS)
847 (*frame->driver->draw_points) (frame, win, rface,
849 ptable->points, NUM_POINTS, region);
850 ptable->p = ptable->points;
857 if (gstring->anti_alias)
859 for (i = 1; i < 8; i++)
860 if (point_table[i].p != point_table[i].points)
861 (*frame->driver->draw_points) (frame, win, rface, reverse ? 7 - i : i,
862 point_table[i].points,
863 point_table[i].p - point_table[i].points, region);
867 if (point_table[0].p != point_table[0].points)
868 (*frame->driver->draw_points) (frame, win, rface, reverse ? 0 : 7,
869 point_table[0].points,
870 point_table[0].p - point_table[0].points, region);
875 ft_list (MFrame *frame, MPlist *plist, MFont *font, MSymbol language)
878 MSymbol family = font ? FONT_PROPERTY (font, MFONT_FAMILY) : Mnil;
879 #ifdef HAVE_FONTCONFIG
880 FcChar8 *lang = (language != Mnil ? (FcChar8 *) MSYMBOL_NAME (language)
884 pl = ft_list_family (Mnil);
889 MPLIST_DO (p, MPLIST_PLIST (pl))
891 MFTInfo *ft_info = MPLIST_VAL (p);
893 #ifdef HAVE_FONTCONFIG
894 if (lang && ft_info->langset
895 && FcLangSetHasLang (ft_info->langset, lang) != FcLangEqual)
898 if (! mfont__match_p (&ft_info->font, font, MFONT_REGISTRY))
900 mplist_push (plist, MPLIST_KEY (pl), &ft_info->font);
908 MPLIST_DO (p, ft_family_list)
910 MFTInfo *ft_info = MPLIST_VAL (p);
912 #ifdef HAVE_FONTCONFIG
913 if (lang && ft_info->langset
914 && FcLangSetHasLang (ft_info->langset, lang) != FcLangEqual)
917 mplist_push (plist, MPLIST_KEY (p), &ft_info->font);
925 MFontDriver mfont__ft_driver =
926 { ft_select, ft_open, ft_find_metric, ft_encode_char, ft_render, ft_list };
933 if (FT_Init_FreeType (&ft_library) != 0)
934 MERROR (MERROR_FONT_FT, -1);
936 for (i = 0; i < ft_to_prop_size; i++)
937 ft_to_prop[i].len = strlen (ft_to_prop[i].ft_style);
939 Municode_bmp = msymbol ("unicode-bmp");
940 Municode_full = msymbol ("unicode-full");
941 Miso10646_1 = msymbol ("iso10646-1");
942 Miso8859_1 = msymbol ("iso8859-1");
944 Mserif = msymbol ("serif");
945 Msans_serif = msymbol ("sans-serif");
946 Mmonospace = msymbol ("monospace");
948 Mmedium = msymbol ("medium");
950 Mnull = msymbol ("");
952 #ifdef HAVE_FONTCONFIG
953 fc_generic_family_list = mplist ();
954 mplist_push (fc_generic_family_list, Mserif, Mserif);
955 mplist_push (fc_generic_family_list, Msans_serif, Msans_serif);
956 mplist_push (fc_generic_family_list, Mmonospace, Mmonospace);
957 /* These are (deprecated) aliases. */
958 mplist_push (fc_generic_family_list, msymbol ("sans"), Msans_serif);
959 mplist_push (fc_generic_family_list, msymbol ("sans serif"), Msans_serif);
960 mplist_push (fc_generic_family_list, msymbol ("mono"), Mmonospace);
973 MPLIST_DO (plist, ft_font_list)
975 MPLIST_DO (p, MPLIST_VAL (plist))
977 MFTInfo *ft_info = MPLIST_VAL (p);
979 M17N_OBJECT_UNREF (ft_info);
981 M17N_OBJECT_UNREF (MPLIST_VAL (plist));
983 M17N_OBJECT_UNREF (ft_font_list);
986 M17N_OBJECT_UNREF (ft_family_list);
987 ft_family_list = NULL;
989 FT_Done_FreeType (ft_library);
990 all_fonts_scaned = 0;
992 #ifdef HAVE_FONTCONFIG
993 m17n_object_unref (fc_generic_family_list);
999 #ifdef HAVE_FONTCONFIG
1004 } FC_vs_M17N_font_prop;
1006 static FC_vs_M17N_font_prop fc_weight_table[] =
1007 { { FC_WEIGHT_ULTRALIGHT, "extralight" },
1008 { FC_WEIGHT_LIGHT, "light" },
1009 { FC_WEIGHT_NORMAL, "normal" },
1010 { FC_WEIGHT_MEDIUM, "medium" },
1011 { FC_WEIGHT_DEMIBOLD, "demibold" },
1012 { FC_WEIGHT_EXTRABOLD, "extrabold" },
1013 { FC_WEIGHT_BLACK, "black" },
1014 { FC_WEIGHT_MEDIUM, NULL } };
1016 static FC_vs_M17N_font_prop fc_slant_table[] =
1017 { { FC_SLANT_ROMAN, "r" },
1018 { FC_SLANT_ITALIC, "i" },
1019 { FC_SLANT_OBLIQUE, "o" },
1020 { FC_SLANT_ROMAN, NULL } };
1022 static FC_vs_M17N_font_prop fc_width_table[] =
1023 { { FC_WIDTH_CONDENSED, "condensed" },
1024 { FC_WIDTH_SEMIEXPANDED, "semicondensed" },
1025 { FC_WIDTH_NORMAL, "normal" },
1026 { FC_WIDTH_SEMIEXPANDED, "semiexpanded" },
1027 { FC_WIDTH_EXPANDED, "expanded" },
1028 { FC_WIDTH_NORMAL, NULL } };
1032 fc_decode_prop (int val, FC_vs_M17N_font_prop *table)
1036 for (i = 0; table[i].m17n_value; i++)
1037 if (val <= table[i].fc_value)
1038 return msymbol ("table[i].m17n_value");
1039 return msymbol ("table[i - 1].m17n_value");
1043 fc_encode_prop (char *name, FC_vs_M17N_font_prop *table)
1047 for (i = 0; table[i].m17n_value && strcmp (name, table[i].m17n_value); i++);
1048 return table[i].fc_value;
1052 mfont__ft_parse_name (char *name, MFont *font)
1054 FcPattern *pat = FcNameParse ((FcChar8 *) name);
1061 if (FcPatternGetString (pat, FC_FOUNDRY, 0, &str) == FcResultMatch)
1062 mfont__set_property (font, MFONT_FOUNDRY, msymbol ((char *) str));
1063 if (FcPatternGetString (pat, FC_FAMILY, 0, &str) == FcResultMatch)
1064 mfont__set_property (font, MFONT_FAMILY, msymbol ((char *) str));
1065 if (FcPatternGetInteger (pat, FC_WEIGHT, 0, &val) == FcResultMatch)
1066 mfont__set_property (font, MFONT_WEIGHT,
1067 fc_decode_prop (val, fc_weight_table));
1068 if (FcPatternGetInteger (pat, FC_SLANT, 0, &val) == FcResultMatch)
1069 mfont__set_property (font, MFONT_STYLE,
1070 fc_decode_prop (val, fc_slant_table));
1071 if (FcPatternGetInteger (pat, FC_WIDTH, 0, &val) == FcResultMatch)
1072 mfont__set_property (font, MFONT_STRETCH,
1073 fc_decode_prop (val, fc_width_table));
1074 if (FcPatternGetDouble (pat, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
1075 font->property[MFONT_SIZE] = size * 10;
1076 FcPatternDestroy (pat);
1081 mfont__ft_unparse_name (MFont *font)
1083 FcPattern *pat = FcPatternCreate ();
1084 MSymbol sym, weight, style, stretch;
1087 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FOUNDRY)) != Mnil)
1088 FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) MSYMBOL_NAME (sym));
1089 if ((sym = (MSymbol) FONT_PROPERTY (font, MFONT_FAMILY)) != Mnil)
1090 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) MSYMBOL_NAME (sym));
1091 if ((weight = (MSymbol) FONT_PROPERTY (font, MFONT_WEIGHT)) != Mnil)
1092 FcPatternAddInteger (pat, FC_WEIGHT, fc_encode_prop (MSYMBOL_NAME (weight),
1094 if ((style = (MSymbol) FONT_PROPERTY (font, MFONT_STYLE)) != Mnil)
1095 FcPatternAddInteger (pat, FC_SLANT, fc_encode_prop (MSYMBOL_NAME (style),
1097 if ((stretch = (MSymbol) FONT_PROPERTY (font, MFONT_STRETCH)) != Mnil)
1098 FcPatternAddInteger (pat, FC_WIDTH, fc_encode_prop (MSYMBOL_NAME (stretch),
1100 name = (char *) FcNameUnparse (pat);
1101 FcPatternDestroy (pat);
1104 #endif /* HAVE_FONTCONFIG */
1109 #define DEVICE_DELTA(table, size) \
1110 (((size) >= (table).StartSize && (size) <= (table).EndSize) \
1111 ? (table).DeltaValue[(size) >= (table).StartSize] \
1115 adjust_anchor (OTF_Anchor *anchor, FT_Face ft_face,
1116 unsigned code, int size, int *x, int *y)
1118 if (anchor->AnchorFormat == 2)
1120 FT_Outline *outline;
1121 int ap = anchor->f.f1.AnchorPoint;
1123 FT_Load_Glyph (ft_face, (FT_UInt) code, FT_LOAD_MONOCHROME);
1124 outline = &ft_face->glyph->outline;
1125 if (ap < outline->n_points)
1127 *x = outline->points[ap].x;
1128 *y = outline->points[ap].y;
1131 else if (anchor->AnchorFormat == 3)
1133 *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, size);
1134 *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, size);
1139 mfont__ft_drive_otf (MGlyphString *gstring, int from, int to,
1140 MSymbol script, MSymbol langsys,
1141 MSymbol gsub_features, MSymbol gpos_features)
1143 int len = to - from;
1144 MGlyph *g = MGLYPH (from);
1146 MRealizedFont *rfont;
1149 OTF_GlyphString otf_gstring;
1151 char *script_name, *language_name;
1152 char *gsub_feature_names, *gpos_feature_names;
1158 rfont = g->rface->rfont;
1159 ft_info = rfont->info;
1160 if (ft_info->otf_flag < 0)
1165 otf = OTF_open (ft_info->filename);
1166 if (otf && OTF_get_table (otf, "head") < 0)
1173 ft_info->otf_flag = -1;
1180 script_name = msymbol_name (script);
1183 if (langsys != Mnil)
1184 language_name = msymbol_name (langsys);
1186 language_name = NULL;
1188 = (gsub_features == Mt ? "*"
1189 : gsub_features == Mnil ? NULL
1190 : msymbol_name (gsub_features));
1191 if (gsub_feature_names && OTF_check_table (otf, "GSUB") < 0)
1192 gsub_feature_names = NULL;
1194 = (gpos_features == Mt ? "*"
1195 : gpos_features == Mnil ? NULL
1196 : msymbol_name (gpos_features));
1197 if (gpos_feature_names && OTF_check_table (otf, "GPOS") < 0)
1198 gpos_feature_names = NULL;
1200 otf_gstring.size = otf_gstring.used = len;
1201 otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
1202 memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
1203 for (i = 0, need_cmap = 0; i < len; i++)
1205 if (gstring->glyphs[from + i].otf_encoded)
1207 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].c;
1208 otf_gstring.glyphs[i].glyph_id = gstring->glyphs[from + i].code;
1212 otf_gstring.glyphs[i].c = gstring->glyphs[from + i].code;
1217 && OTF_drive_cmap (otf, &otf_gstring) < 0)
1220 OTF_drive_gdef (otf, &otf_gstring);
1221 gidx = gstring->used;
1223 if (gsub_feature_names)
1225 if (OTF_drive_gsub (otf, &otf_gstring, script_name, language_name,
1226 gsub_feature_names) < 0)
1228 for (i = 0, otfg = otf_gstring.glyphs; i < otf_gstring.used; i++, otfg++)
1230 MGlyph temp = *(MGLYPH (from + otfg->f.index.from));
1233 temp.combining_code = 0;
1236 temp.code = otfg->glyph_id;
1237 temp.otf_encoded = 1;
1242 temp.otf_encoded = 0;
1244 temp.to = MGLYPH (from + otfg->f.index.to)->to;
1245 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1249 for (i = 0; i < len; i++)
1251 MGlyph temp = gstring->glyphs[from + i];
1253 if (otf_gstring.glyphs[i].glyph_id)
1255 temp.code = otf_gstring.glyphs[i].glyph_id;
1256 temp.otf_encoded = 1;
1258 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1261 ft_find_metric (rfont, gstring, gidx, gstring->used);
1263 if (gpos_feature_names)
1267 MGlyph *base = NULL, *mark = NULL;
1269 if (OTF_drive_gpos (otf, &otf_gstring, script_name, language_name,
1270 gpos_feature_names) < 0)
1273 u = otf->head->unitsPerEm;
1274 size10 = rfont->font.property[MFONT_SIZE];
1277 for (i = 0, otfg = otf_gstring.glyphs, g = MGLYPH (gidx);
1278 i < otf_gstring.used; i++, otfg++, g++)
1282 if (! otfg->glyph_id)
1284 switch (otfg->positioning_type)
1290 int format = otfg->f.f1.format;
1292 if (format & OTF_XPlacement)
1293 g->xoff = otfg->f.f1.value->XPlacement * size10 / u / 10;
1294 if (format & OTF_XPlaDevice)
1295 g->xoff += DEVICE_DELTA (otfg->f.f1.value->XPlaDevice, size);
1296 if (format & OTF_YPlacement)
1297 g->yoff = - (otfg->f.f1.value->YPlacement * size10 / u / 10);
1298 if (format & OTF_YPlaDevice)
1299 g->yoff -= DEVICE_DELTA (otfg->f.f1.value->YPlaDevice, size);
1300 if (format & OTF_XAdvance)
1301 g->width += otfg->f.f1.value->XAdvance * size10 / u / 10;
1302 if (format & OTF_XAdvDevice)
1303 g->width += DEVICE_DELTA (otfg->f.f1.value->XAdvDevice, size);
1307 /* Not yet supported. */
1313 goto label_adjust_anchor;
1314 default: /* i.e. case 6 */
1319 label_adjust_anchor:
1321 int base_x, base_y, mark_x, mark_y;
1323 base_x = otfg->f.f4.base_anchor->XCoordinate * size10 / u / 10;
1324 base_y = otfg->f.f4.base_anchor->YCoordinate * size10 / u / 10;
1325 mark_x = otfg->f.f4.mark_anchor->XCoordinate * size10 / u / 10;
1326 mark_y = otfg->f.f4.mark_anchor->YCoordinate * size10 / u / 10;
1328 if (otfg->f.f4.base_anchor->AnchorFormat != 1)
1329 adjust_anchor (otfg->f.f4.base_anchor, ft_info->ft_face,
1330 prev->code, size, &base_x, &base_y);
1331 if (otfg->f.f4.mark_anchor->AnchorFormat != 1)
1332 adjust_anchor (otfg->f.f4.mark_anchor, ft_info->ft_face,
1333 g->code, size, &mark_x, &mark_y);
1334 g->xoff = prev->xoff + (base_x - prev->width) - mark_x;
1335 g->yoff = prev->yoff + mark_y - base_y;
1336 g->combining_code = MAKE_PRECOMPUTED_COMBINDING_CODE ();
1339 if (otfg->GlyphClass == OTF_GlyphClass0)
1341 else if (otfg->GlyphClass == OTF_GlyphClassMark)
1347 free (otf_gstring.glyphs);
1351 ft_find_metric (rfont, gstring, from, to);
1352 for (i = 0; i < len; i++)
1354 MGlyph temp = gstring->glyphs[from + i];
1355 MLIST_APPEND1 (gstring, glyphs, temp, MERROR_FONT_OTF);
1357 free (otf_gstring.glyphs);
1363 mfont__ft_decode_otf (MGlyph *g)
1365 MFTInfo *ft_info = (MFTInfo *) g->rface->rfont->info;
1366 int c = OTF_get_unicode (ft_info->otf, (OTF_GlyphID) g->code);
1368 return (c ? c : -1);
1371 #endif /* HAVE_OTF */
1373 #endif /* HAVE_FREETYPE */