10 struct GHashTable *glyph_map = NULL;
12 #define FLOOR(x) ((x) & -64)
13 #define CEIL(x) (((x)+63) & -64)
14 #define TRUNC(x) ((x) >> 6)
15 #define ROUND(x) (((x)+32) & -64)
17 #define GLFT_SHADOW "shadow"
18 #define GLFT_SHADOW_OFFSET "shadowoffset"
19 #define GLFT_SHADOW_ALPHA "shadowalpha"
21 void dest_glyph_map_value(gpointer key, gpointer val, gpointer data)
23 struct GlftGlyph *g = val;
24 glDeleteTextures(1, &g->tnum);
28 static void GlftDefaultSubstitute(Display *d, int s, FcPattern *pat)
33 if (FcPatternGet(pat, FC_DPI, 0, &v) == FcResultNoMatch) {
34 dpi = DisplayHeight(d, s) * 25.4 / (double)DisplayHeightMM(d, s);
35 FcPatternAddDouble(pat, FC_DPI, dpi);
37 if (FcPatternGet(pat, FC_ANTIALIAS, 0, &v) == FcResultNoMatch) {
38 FcPatternAddBool(pat, FC_ANTIALIAS, FcFalse);
39 g_message("SETTING ANTIALIAS TRUE");
41 if (FcPatternGet(pat, FC_HINTING, 0, &v) == FcResultNoMatch)
42 FcPatternAddBool(pat, FC_HINTING, FcTrue);
43 if (FcPatternGet(pat, FC_AUTOHINT, 0, &v) == FcResultNoMatch)
44 FcPatternAddBool(pat, FC_AUTOHINT, FcFalse);
45 if (FcPatternGet(pat, FC_GLOBAL_ADVANCE, 0, &v) == FcResultNoMatch)
46 FcPatternAddBool(pat, FC_GLOBAL_ADVANCE, FcTrue);
47 if (FcPatternGet(pat, FC_SPACING, 0, &v) == FcResultNoMatch)
48 FcPatternAddInteger(pat, FC_SPACING, FC_PROPORTIONAL);
49 if (FcPatternGet(pat, FC_MINSPACE, 0, &v) == FcResultNoMatch)
50 FcPatternAddBool(pat, FC_MINSPACE, FcTrue);
51 if (FcPatternGet(pat, FC_CHAR_WIDTH, 0, &v) == FcResultNoMatch)
52 FcPatternAddInteger(pat, FC_CHAR_WIDTH, 0);
53 if (FcPatternGet(pat, GLFT_SHADOW, 0, &v) == FcResultNoMatch)
54 FcPatternAddBool(pat, GLFT_SHADOW, FcFalse);
55 if (FcPatternGet(pat, GLFT_SHADOW_OFFSET, 0, &v) == FcResultNoMatch)
56 FcPatternAddInteger(pat, GLFT_SHADOW_OFFSET, 2);
57 if (FcPatternGet(pat, GLFT_SHADOW_ALPHA, 0, &v) == FcResultNoMatch)
58 FcPatternAddDouble(pat, GLFT_SHADOW_ALPHA, 0.5);
60 FcDefaultSubstitute(pat);
63 struct GlftFont *GlftFontOpen(Display *d, int screen, const char *name)
65 struct GlftFont *font;
66 FcPattern *pat, *match;
69 FcBool hinting, autohint, advance;
73 pat = FcNameParse((const unsigned char*)name);
76 /* XXX read our extended attributes here? (if failing below..) */
78 FcConfigSubstitute(NULL, pat, FcMatchPattern);
79 GlftDefaultSubstitute(d, screen, pat);
81 match = FcFontMatch(NULL, pat, &res);
82 FcPatternDestroy(pat);
84 GlftDebug("failed to find matching font\n");
88 font = malloc(sizeof(struct GlftFont));
90 font->screen = screen;
92 font->ftflags = FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP;
94 if (FcPatternGetString(match, FC_FILE, 0, (FcChar8**) &font->filename) !=
96 GlftDebug("error getting FC_FILE from pattern\n");
100 switch (FcPatternGetInteger(match, FC_INDEX, 0, &font->index)) {
101 case FcResultNoMatch:
107 GlftDebug("error getting FC_INDEX from pattern\n");
111 switch (FcPatternGetBool(match, FC_ANTIALIAS, 0, &font->antialias)) {
112 case FcResultNoMatch:
113 font->antialias = FcTrue;
118 GlftDebug("error getting FC_ANTIALIAS from pattern\n");
122 switch (FcPatternGetBool(match, FC_HINTING, 0, &hinting)) {
123 case FcResultNoMatch:
129 GlftDebug("error getting FC_HINTING from pattern\n");
132 if (!hinting) font->ftflags |= FT_LOAD_NO_HINTING;
134 switch (FcPatternGetBool(match, FC_AUTOHINT, 0, &autohint)) {
135 case FcResultNoMatch:
141 GlftDebug("error getting FC_AUTOHINT from pattern\n");
144 if (autohint) font->ftflags |= FT_LOAD_FORCE_AUTOHINT;
146 switch (FcPatternGetBool(match, FC_GLOBAL_ADVANCE, 0, &advance)) {
147 case FcResultNoMatch:
153 GlftDebug("error getting FC_GLOBAL_ADVANCE from pattern\n");
156 if (!advance) font->ftflags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
158 switch (FcPatternGetInteger(match, FC_SPACING, 0, &font->spacing)) {
159 case FcResultNoMatch:
160 font->spacing = FC_PROPORTIONAL;
165 GlftDebug("error getting FC_SPACING from pattern\n");
169 switch (FcPatternGetBool(match, FC_MINSPACE, 0, &font->minspace)) {
170 case FcResultNoMatch:
171 font->minspace = FcTrue;
176 GlftDebug("error getting FC_MINSPACE from pattern\n");
180 switch (FcPatternGetInteger(match, FC_CHAR_WIDTH, 0, &font->char_width)) {
181 case FcResultNoMatch:
182 font->char_width = 0;
185 if (font->char_width)
186 font->spacing = FC_MONO;
189 GlftDebug("error getting FC_CHAR_WIDTH from pattern\n");
193 if (FcPatternGetDouble(match, FC_PIXEL_SIZE, 0, &psize) != FcResultMatch)
195 font->ftcharsize = (FT_F26Dot6) psize * 64;
197 if (FcPatternGetBool(match, GLFT_SHADOW, 0, &font->shadow) != FcResultMatch)
198 font->shadow = FcFalse;
200 if (FcPatternGetInteger(match,GLFT_SHADOW_OFFSET,0,&font->shadow_offset) !=
202 font->shadow_offset = 2;
204 if (FcPatternGetDouble(match, GLFT_SHADOW_ALPHA,0,&alpha) != FcResultMatch)
206 font->shadow_alpha = (float)alpha;
208 /* time to load the font! */
210 if (FT_New_Face(ft_lib, font->filename, font->index, &font->face)) {
211 GlftDebug("failed to open FT face\n");
214 assert(FT_IS_SCALABLE(font->face));
215 if (!FT_IS_SCALABLE(font->face)) {
216 GlftDebug("got a non-scalable face");
219 if (FT_Set_Char_Size(font->face, 0, font->ftcharsize, 0, 0)) {
220 GlftDebug("failed to set char size on FT face\n");
224 if (!FcPatternGetCharSet(match, FC_CHARSET, 0, &font->chars) !=
226 font->chars = FcFreeTypeCharSet(font->face, FcConfigGetBlanks(NULL));
228 GlftDebug("failed to get a valid CharSet\n");
232 if (font->char_width)
233 font->max_advance_width = font->char_width;
235 font->max_advance_width = font->face->size->metrics.max_advance >> 6;
236 font->descent = -(font->face->size->metrics.descender >> 6);
237 font->ascent = font->face->size->metrics.ascender >> 6;
238 if (font->minspace) font->height = font->ascent + font->descent;
239 else font->height = font->face->size->metrics.height >> 6;
241 font->kerning = FT_HAS_KERNING(font->face);
243 font->glyph_map = g_hash_table_new(g_int_hash, g_int_equal);
248 FT_Done_Face(font->face);
250 FcPatternDestroy(match);
255 void GlftFontClose(struct GlftFont *font)
258 FT_Done_Face(font->face);
259 FcPatternDestroy(font->pat);
260 FcCharSetDestroy(font->chars);
261 g_hash_table_foreach(font->glyph_map, dest_glyph_map_value, NULL);
262 g_hash_table_destroy(font->glyph_map);
267 struct GlftGlyph *GlftFontGlyph(struct GlftFont *font, const char *c)
269 const char *n = g_utf8_next_char(c);
274 FcUtf8ToUcs4((const FcChar8*) c, &w, b);
276 g = g_hash_table_lookup(font->glyph_map, &w);
278 if (FT_Load_Glyph(font->face, FcFreeTypeCharIndex(font->face, w),
280 if (FT_Load_Glyph(font->face, 0, font->ftflags))
283 g = g_hash_table_lookup(font->glyph_map, &w);
288 g = malloc(sizeof(struct GlftGlyph));
290 glGenTextures(1, &g->tnum);
292 GlftRenderGlyph(font->face, g);
294 if (!(font->spacing == FC_PROPORTIONAL)) {
295 g->width = font->max_advance_width;
297 g->width = TRUNC(ROUND(font->face->glyph->metrics.horiAdvance));
299 g->x = TRUNC(FLOOR(font->face->glyph->metrics.horiBearingX));
300 g->y = TRUNC(CEIL(font->face->glyph->metrics.horiBearingY));
301 g->height = TRUNC(ROUND(font->face->glyph->metrics.height));
303 g_hash_table_insert(font->glyph_map, &g->w, g);
309 int GlftFontAdvance(struct GlftFont *font,
310 struct GlftGlyph *left,
311 struct GlftGlyph *right)
316 if (left) k+= left->width;
321 FT_Get_Kerning(font->face, left->glyph, right->glyph,
322 FT_KERNING_UNFITTED, &v);
330 int GlftFontHeight(struct GlftFont *font)
335 int GlftFontMaxCharWidth(struct GlftFont *font)
337 return font->max_advance_width;