st-fontmetrics-0.9.3.diff (4173B)
1 From d0d9715e5197a5b8af810508f48db001f54817c3 Mon Sep 17 00:00:00 2001 2 From: Paul Storkman <storkman@storkman.nl> 3 Date: Tue, 4 Nov 2025 17:41:50 +0100 4 Subject: [PATCH] Use vertical font metrics from the "OS/2" table, if possible. 5 6 --- 7 config.def.h | 10 +++++++ 8 x.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++----- 9 2 files changed, 77 insertions(+), 6 deletions(-) 10 11 diff --git a/config.def.h b/config.def.h 12 index 2cd740a..e959638 100644 13 --- a/config.def.h 14 +++ b/config.def.h 15 @@ -8,6 +8,16 @@ 16 static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; 17 static int borderpx = 2; 18 19 +/* "OS/2" OpenType tables give more accurate typographic metrics for some fonts, 20 + * which may or may not improve rendering of box-drawing elements. 21 + */ 22 +static int ignoreOS2metrics = 0; 23 + 24 +/* Multiplier applied to the distance between baselines. 25 + * Increasing this value can misalign block or line-drawing characters. 26 + */ 27 +static float linespacing = 1.0; 28 + 29 /* 30 * What program is execed by st depends of these precedence rules: 31 * 1: program passed with -e 32 diff --git a/x.c b/x.c 33 index d73152b..ae07d57 100644 34 --- a/x.c 35 +++ b/x.c 36 @@ -15,6 +15,8 @@ 37 #include <X11/Xft/Xft.h> 38 #include <X11/XKBlib.h> 39 40 +#include <freetype/tttables.h> 41 + 42 char *argv0; 43 #include "arg.h" 44 #include "st.h" 45 @@ -123,6 +125,10 @@ typedef struct { 46 int width; 47 int ascent; 48 int descent; 49 + int strike_y; 50 + int strike_h; 51 + int underline_y; 52 + int underline_h; 53 int badslant; 54 int badweight; 55 short lbearing; 56 @@ -969,14 +975,67 @@ xloadfont(Font *f, FcPattern *pattern) 57 f->set = NULL; 58 f->pattern = configured; 59 60 - f->ascent = f->match->ascent; 61 - f->descent = f->match->descent; 62 + f->ascent = f->match->ascent * linespacing; 63 + f->descent = f->match->descent * linespacing; 64 f->lbearing = 0; 65 f->rbearing = f->match->max_advance_width; 66 67 f->height = f->ascent + f->descent; 68 f->width = DIVCEIL(extents.xOff, strlen(ascii_printable)); 69 70 + f->strike_y = -2 * f->match->ascent / 3; 71 + f->strike_h = 1; 72 + f->underline_y = 1; 73 + f->underline_h = 1; 74 + 75 + /* Extract proper typographic metrics if available. */ 76 + do { 77 + TT_OS2 *os2; 78 + TT_Postscript *post; 79 + FT_Face face; 80 + double px, uppx, asc, desc, lgap; 81 + if (ignoreOS2metrics) 82 + break; 83 + if (FcPatternGetDouble(f->match->pattern, 84 + FC_PIXEL_SIZE, 0, &px) != FcResultMatch) 85 + break; 86 + 87 + face = XftLockFace(f->match); 88 + /* Rerturn value may be NULL. This is not documented. */ 89 + if (!face) 90 + break; 91 + os2 = FT_Get_Sfnt_Table(face, FT_SFNT_OS2); 92 + if (!os2) { 93 + XftUnlockFace(f->match); 94 + break; 95 + } 96 + uppx = face->units_per_EM / px; 97 + asc = os2->sTypoAscender / uppx; 98 + desc = os2->sTypoDescender / uppx; 99 + lgap = os2->sTypoLineGap / uppx; 100 + lgap = (asc + desc + lgap) * linespacing - asc - desc; 101 + post = FT_Get_Sfnt_Table(face, FT_SFNT_POST); 102 + if (!post) { 103 + f->strike_y = -2 * asc / 3; 104 + } else { 105 + f->strike_y = -os2->yStrikeoutPosition / uppx; 106 + f->strike_h = os2->yStrikeoutSize / uppx; 107 + if (f->strike_h == 0) 108 + f->strike_h = 1; 109 + f->underline_y = post->underlinePosition / uppx; 110 + f->underline_h = post->underlineThickness / uppx; 111 + if (f->underline_y == 0) 112 + f->underline_y = 1; 113 + if (f->underline_h == 0) 114 + f->underline_h = f->strike_h; 115 + } 116 + XftUnlockFace(f->match); 117 + 118 + f->ascent = asc + lgap/2; 119 + f->descent = -desc + lgap/2 + asc - f->ascent; 120 + f->height = f->ascent + f->descent; 121 + } while (0); 122 + 123 return 0; 124 } 125 126 @@ -1496,13 +1555,15 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i 127 128 /* Render underline and strikethrough. */ 129 if (base.mode & ATTR_UNDERLINE) { 130 - XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1, 131 - width, 1); 132 + XftDrawRect(xw.draw, fg, winx, 133 + winy + (dc.font.ascent + dc.font.underline_y) * chscale, 134 + width, dc.font.underline_h); 135 } 136 137 if (base.mode & ATTR_STRUCK) { 138 - XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3, 139 - width, 1); 140 + XftDrawRect(xw.draw, fg, winx, 141 + winy + (dc.font.ascent + dc.font.strike_y) * chscale - dc.font.strike_h/2, 142 + width, dc.font.strike_h); 143 } 144 145 /* Reset clip to none. */ 146 -- 147 2.49.1 148