sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

commit 0c6a1c7823c6ff0b616142bc58719f19013e97b1
parent d893c7ab3871c86248f97d8bb4b8ae3c42a5fa2f
Author: Paul Storkman <storkman@storkman.nl>
Date:   Wed, 21 Jan 2026 13:50:02 +0100

[st][patches][fontmetrics] Add new patch

An alternative way to retrieve vertical font metrics.

Diffstat:
Ast.suckless.org/patches/fontmetrics/index.md | 26++++++++++++++++++++++++++
Ast.suckless.org/patches/fontmetrics/st-fontmetrics-0.9.3.diff | 148+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 174 insertions(+), 0 deletions(-)

diff --git a/st.suckless.org/patches/fontmetrics/index.md b/st.suckless.org/patches/fontmetrics/index.md @@ -0,0 +1,26 @@ +fontmetrics +=========== + +Description +----------- +This patch uses the font metrics provided in a TrueType font's `OS/2` table +(see [Microsoft](https://learn.microsoft.com/en-us/typography/opentype/spec/os2) +or [Apple](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6OS2.html) documentation), +if available, to determine the character cell height and underline/strike-through thickness and position. +This may or may not make the font rendering, particularly block and box-drawing elements, better or worse. + +`st` normally uses the descent and ascent heights provided by FreeType, +which seems to derive them from `hhea` table values. + +There is no standard for how monotype font files are supposed to communicate correct metrics to terminal emulators, +and actual usage is inconsistent between fonts. + +Download +-------- + +- [st-fontmetrics-0.9.3.diff](st-fontmetrics-0.9.3.diff) (0.9.3) + +Authors +------- + +- Paul Storkman - <storkman@storkman.nl> diff --git a/st.suckless.org/patches/fontmetrics/st-fontmetrics-0.9.3.diff b/st.suckless.org/patches/fontmetrics/st-fontmetrics-0.9.3.diff @@ -0,0 +1,148 @@ +From d0d9715e5197a5b8af810508f48db001f54817c3 Mon Sep 17 00:00:00 2001 +From: Paul Storkman <storkman@storkman.nl> +Date: Tue, 4 Nov 2025 17:41:50 +0100 +Subject: [PATCH] Use vertical font metrics from the "OS/2" table, if possible. + +--- + config.def.h | 10 +++++++ + x.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++----- + 2 files changed, 77 insertions(+), 6 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 2cd740a..e959638 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -8,6 +8,16 @@ + static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; + static int borderpx = 2; + ++/* "OS/2" OpenType tables give more accurate typographic metrics for some fonts, ++ * which may or may not improve rendering of box-drawing elements. ++ */ ++static int ignoreOS2metrics = 0; ++ ++/* Multiplier applied to the distance between baselines. ++ * Increasing this value can misalign block or line-drawing characters. ++ */ ++static float linespacing = 1.0; ++ + /* + * What program is execed by st depends of these precedence rules: + * 1: program passed with -e +diff --git a/x.c b/x.c +index d73152b..ae07d57 100644 +--- a/x.c ++++ b/x.c +@@ -15,6 +15,8 @@ + #include <X11/Xft/Xft.h> + #include <X11/XKBlib.h> + ++#include <freetype/tttables.h> ++ + char *argv0; + #include "arg.h" + #include "st.h" +@@ -123,6 +125,10 @@ typedef struct { + int width; + int ascent; + int descent; ++ int strike_y; ++ int strike_h; ++ int underline_y; ++ int underline_h; + int badslant; + int badweight; + short lbearing; +@@ -969,14 +975,67 @@ xloadfont(Font *f, FcPattern *pattern) + f->set = NULL; + f->pattern = configured; + +- f->ascent = f->match->ascent; +- f->descent = f->match->descent; ++ f->ascent = f->match->ascent * linespacing; ++ f->descent = f->match->descent * linespacing; + f->lbearing = 0; + f->rbearing = f->match->max_advance_width; + + f->height = f->ascent + f->descent; + f->width = DIVCEIL(extents.xOff, strlen(ascii_printable)); + ++ f->strike_y = -2 * f->match->ascent / 3; ++ f->strike_h = 1; ++ f->underline_y = 1; ++ f->underline_h = 1; ++ ++ /* Extract proper typographic metrics if available. */ ++ do { ++ TT_OS2 *os2; ++ TT_Postscript *post; ++ FT_Face face; ++ double px, uppx, asc, desc, lgap; ++ if (ignoreOS2metrics) ++ break; ++ if (FcPatternGetDouble(f->match->pattern, ++ FC_PIXEL_SIZE, 0, &px) != FcResultMatch) ++ break; ++ ++ face = XftLockFace(f->match); ++ /* Rerturn value may be NULL. This is not documented. */ ++ if (!face) ++ break; ++ os2 = FT_Get_Sfnt_Table(face, FT_SFNT_OS2); ++ if (!os2) { ++ XftUnlockFace(f->match); ++ break; ++ } ++ uppx = face->units_per_EM / px; ++ asc = os2->sTypoAscender / uppx; ++ desc = os2->sTypoDescender / uppx; ++ lgap = os2->sTypoLineGap / uppx; ++ lgap = (asc + desc + lgap) * linespacing - asc - desc; ++ post = FT_Get_Sfnt_Table(face, FT_SFNT_POST); ++ if (!post) { ++ f->strike_y = -2 * asc / 3; ++ } else { ++ f->strike_y = -os2->yStrikeoutPosition / uppx; ++ f->strike_h = os2->yStrikeoutSize / uppx; ++ if (f->strike_h == 0) ++ f->strike_h = 1; ++ f->underline_y = post->underlinePosition / uppx; ++ f->underline_h = post->underlineThickness / uppx; ++ if (f->underline_y == 0) ++ f->underline_y = 1; ++ if (f->underline_h == 0) ++ f->underline_h = f->strike_h; ++ } ++ XftUnlockFace(f->match); ++ ++ f->ascent = asc + lgap/2; ++ f->descent = -desc + lgap/2 + asc - f->ascent; ++ f->height = f->ascent + f->descent; ++ } while (0); ++ + return 0; + } + +@@ -1496,13 +1555,15 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i + + /* Render underline and strikethrough. */ + if (base.mode & ATTR_UNDERLINE) { +- XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1, +- width, 1); ++ XftDrawRect(xw.draw, fg, winx, ++ winy + (dc.font.ascent + dc.font.underline_y) * chscale, ++ width, dc.font.underline_h); + } + + if (base.mode & ATTR_STRUCK) { +- XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3, +- width, 1); ++ XftDrawRect(xw.draw, fg, winx, ++ winy + (dc.font.ascent + dc.font.strike_y) * chscale - dc.font.strike_h/2, ++ width, dc.font.strike_h); + } + + /* Reset clip to none. */ +-- +2.49.1 +