--- rxvt-unicode/src/rxvtfont.C 2021/06/23 12:37:32 1.217 +++ rxvt-unicode/src/rxvtfont.C 2023/08/19 17:44:35 1.223 @@ -519,7 +519,8 @@ bool load (const rxvt_fontprop &prop, bool force_prop) { width = 1; height = 1; - ascent = 1; descent = 0; + ascent = 1; + descent = (*fs)[2]->descent; set_name (strdup ("built-in rendition overflow font")); @@ -1139,6 +1140,17 @@ struct rxvt_font_xft : rxvt_font { +#if XFT_CHAR_CACHE + // we cache the qascii range xoffsets in the name of speed, + // expecting terminals to deal mostly with these characters + // we also assume the xoff always fits into uint8_t, + // which is questionable, but let's see... + // also, it is uncomfortably big, due to the uints. + enum { char_cache_min = 0x20, char_cache_max = 0x7e }; + uint8_t xoff_cache [char_cache_max - char_cache_min + 1]; + FT_UInt glyph_cache [char_cache_max - char_cache_min + 1]; +#endif + rxvt_font_xft () { f = 0; @@ -1254,6 +1266,16 @@ FT_Face face = XftLockFace (f); + // fuck me plenty: XftLockFace can actually return 0. try not to crash. + // we also assume blindly that if the first lock succeeds, then subsequent + // locks will also succeed. + if (!face) + { + XftFontClose (disp, f); + success = false; + break; + } + ascent = (face->size->metrics.ascender + 63) >> 6; descent = (-face->size->metrics.descender + 63) >> 6; height = max (ascent + descent, (face->size->metrics.height + 63) >> 6); @@ -1332,6 +1354,19 @@ } #endif +#if XFT_CHAR_CACHE + // populate char cache + for (FcChar16 ch = char_cache_min; ch <= char_cache_max; ++ch) + { + FT_UInt glyph = XftCharIndex (disp, f, ch); + glyph_cache [ch - char_cache_min] = glyph; + + XGlyphInfo g; + XftGlyphExtents (disp, f, &glyph, 1, &g); + xoff_cache [ch - char_cache_min] = g.xOff; + } +#endif + return success; } @@ -1365,9 +1400,15 @@ XGlyphInfo g; XftTextExtents32 (term->dpy, f, &chr, 1, &g); + int cwidth = prop->width * wcw; + + // use same adjustments as in ->draw, see there + g.x += g.xOff ? cwidth - g.xOff >> 1 : 0; + g.x += g.xOff ? 0 : cwidth; + int w = g.width - g.x; - careful = g.x > 0 || w > prop->width * wcw; + careful = g.x > 0 || w > cwidth; if (careful && !OVERLAP_OK (w, wcw, prop)) return false; @@ -1435,9 +1476,23 @@ } #endif - FT_UInt glyph = XftCharIndex (disp, f, chr); - XGlyphInfo extents; - XftGlyphExtents (disp, f, &glyph, 1, &extents); + FT_UInt glyph; + int xOff; + + #if XFT_CHAR_CACHE + if (ecb_expect_true (IN_RANGE_INC (chr, char_cache_min, char_cache_max))) + { + glyph = glyph_cache [chr - char_cache_min]; + xOff = xoff_cache [chr - char_cache_min]; + } + else + #endif + { + glyph = XftCharIndex (disp, f, chr); + XGlyphInfo extents; + XftGlyphExtents (disp, f, &glyph, 1, &extents); + xOff = extents.xOff; + } ep->glyph = glyph; ep->x = x_; @@ -1445,7 +1500,7 @@ // the xft font cell might differ from the terminal font cell, // in which case we use the average between the two. - ep->x += extents.xOff ? cwidth - extents.xOff >> 1 : 0; + ep->x += xOff ? cwidth - xOff >> 1 : 0; // xft/freetype represent combining characters as characters with zero // width rendered over the previous character with some fonts, while @@ -1454,7 +1509,7 @@ // we handle the first two cases by keying off on xOff being 0 // for zero-width chars. normally, we would add extents.xOff // of the base character here, but we don't have that, so we use cwidth. - ep->x += extents.xOff ? 0 : cwidth; + ep->x += xOff ? 0 : cwidth; ++ep; }