Re: [hackers] [dwm][PATCH] drw: use cap height for optical text centering
On 19/5/26 2:56 pm, aartoni wrote:
> The current formula centers the font em box (ascent + descent)
> within the drawing area. This assumes visible ink is symmetric
> inside that box. Fonts whose ascent includes significant internal
> leading above the cap line (e.g. Fira Code: ascent 894, capHeight
> 1377, upm 1950) cause text to ride above optical center.
>
> Read the cap height by measuring a capital H via XftTextExtents8,
> which is already linked. Center the cap height span instead of the
> em box. For fonts where the measurement fails (ext.y <= 0), fall
> back to 2*ascent - h, which is algebraically equivalent to the old
> formula and produces pixel-identical output.
>
> No new dependencies. No change for fonts with symmetric metrics.
> ---
> drw.c | 7 ++++++-
> drw.h | 1 +
> 2 files changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/drw.c b/drw.c
> index 9fdd1a4..2fbdbab 100644
> --- a/drw.c
> +++ b/drw.c
> _AT_@ -94,6 +94,7 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
> Fnt *font;
> XftFont *xfont = NULL;
> FcPattern *pattern = NULL;
> + XGlyphInfo ext;
>
> if (fontname) {
> /* Using the pattern found at font->xfont->pattern does not yield the
> _AT_@ -123,6 +124,10 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
> font->xfont = xfont;
> font->pattern = pattern;
> font->h = xfont->ascent + xfont->descent;
> + font->cap = xfont->ascent > xfont->descent ? xfont->ascent - xfont->descent : 0;
> + XftTextExtents8(drw->dpy, xfont, (FcChar8 *)"H", 1, &ext);
> + if (ext.y > 0)
> + font->cap = ext.y;
> font->dpy = drw->dpy;
>
> return font;
> _AT_@ -330,7 +335,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
>
> if (utf8strlen) {
> if (render) {
> - ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
> + ty = y + (h + usedfont->cap) / 2;
> XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
> usedfont->xfont, x, ty, (XftChar8 *)utf8str, utf8strlen);
> }
> diff --git a/drw.h b/drw.h
> index bda06f9..eea46ce 100644
> --- a/drw.h
> +++ b/drw.h
> _AT_@ -6,6 +6,7 @@ typedef struct {
>
> typedef struct Fnt {
> Display *dpy;
> + unsigned int cap;
> unsigned int h;
> XftFont *xfont;
> FcPattern *pattern;
This patch looks good. I only have a tiny nitpick: I think we can change
from
the ternary to using util.h's MAX function and it makes intent much clearer
and is a bit more concise:
- font->cap = xfont->ascent > xfont->descent ? xfont->ascent -
xfont->descent : 0;
+ font->cap = MAX(xfont->ascent - xfont->descent, 0);
Other than that, LGTM!
Received on Tue May 19 2026 - 15:27:54 CEST
This archive was generated by hypermail 2.3.0
: Tue May 19 2026 - 15:36:38 CEST