Download: Stable · Snapshot | Docs | Changes | Wishlist
A user reported that the 'Inconsolata' font by Raph Levien works badly
in Windows PuTTY, because the Windows terminal front end sets the
terminal's character-cell height based on the obvious font metrics
provided by the Windows text rendering API (
usWinDescent). Those metrics are based on the ink
extent of the font rather than on the typographically ideal line
spacing. And Inconsolata recently gained support for Vietnamese text,
with multiple diacritics which increase the font's ink extent, so the
lines are now more widely spaced than is desirable.
Apparently there's a separate set of metrics called the 'typographical metrics', and a flag in the font header to request they be used.
Our correspondent forwarded on some useful implementation notes from Raph Levien:
The first step is to use
GetFontDatato read the relevant tables. One is the OS/2 table, which has tag 0x322F534F, and the other is head (tag 0x64616568). A good reference for bit-bashing these tables btw is
sfntly; here's the code for OS/2 and head. Both are quite small, OS/2 is typically 96 bytes and head is 54 bytes, so the buffers can be stack allocated. I recommend first calling with out a buffer to get a size, then calling a second time with
min(sizeof(stack buffer),size reported
). If the size reported from head is below 54 or the size of OS/2 is below 74, then bail (the sizes can vary somewhat based on table version).
From the head table you'll need
uint16at offset 18), and from OS/2 you'll need
int16at 68, 70, and 72). The logic goes like this. If bit 7 is set (
fsSelection & 0x80 != 0), then compute ascent and descent from the typo metrics instead. I'd recommend combining line gap and ascender, as this will minimize clipping of accented characters. The math goes like this:round_up(units, font_height, unitsPerEm) = floor((units * font_height + units - 1) / unitsPerEm) new_ascent = round_up(sTypoAscender + sTypoLineGap, font_height, unitsPerEm) new_descent = round_up(-sTypoDescender, font_height, unitsPerEm)
The sum of the two is your new height, to be used in place of
tm.tmHeight. You will also need to subtract
tm.tmAscent - new_ascentfrom your y coordinate when drawing text (
ExtTextOut) to avoid the baseline being too low, as these drawing commands use the "top" as a reference point, and the GDI understanding of that point is the point above the Vietnamese accented characters, which is quite high.
Some thoughts from our own side:
Existing worked example: commit 34d7602954d4483b3bc9db700e7df2c15348947a in LibreOffice seems to be doing something relevant to this.