From 39d7e7fbdcd9a332f5268931e477110ddcdafe78 Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Wed, 20 Nov 2024 14:25:46 +0000 Subject: [PATCH] Slightly ugly hack to bias middle stems upwards By default, FreeType 2.12.1 prefers to move the middle stems of characters like 'B' and 'e' downwards, which is ugly. By applying a tiny tweak to the "hstem" commands for such stems we can persuade FreeType to move them upwards instead. This wasn't a problem when we were using FontForge because FontForge didn't use proper stem hints on the baseline. --- bedstead.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/bedstead.c b/bedstead.c index b5d3b68..193e02f 100644 --- a/bedstead.c +++ b/bedstead.c @@ -3863,6 +3863,47 @@ counters_done: printf(" -->"); } +/* + * The purpose of this function is to adjust a few hints to improve + * FreeType's rendering of certain characters at awkward sizes. The + * letters 'B' and 'e' at 11 pixels per em under FreeType 2.12.1 are a + * good test case. + * + * It appears that when rendering these characters, FreeType fixes the + * top and bottom strokes to the top and bottom alignment zones. If + * those are an even number of pixels apart, this means that the + * middle stroke falls precisely on a pixel boundary. FreeType then + * has three choices: move the stem up to the pixel row above the + * centre, move it down to the row below, or anti-alias it across the + * two rows. FreeType chooses to move the stem down, which makes the + * characters look top-heavy. We'd much prefer FreeType to move the + * stem upwards. + * + * It turns out that this can be achieved just by making the middle + * stem hint slightly closer to the stem above that to the stem below. + * This just requires adjusting the width of the stem hint by one + * design unit. As far as I can see, this is allowed by the Type 1 + * font specification. A stem hint must encompass the stem outline, + * but it's allowed to be larger than the stem. And it practice it + * seems to work fine. + * + * To avoid surprising effects on other characters, this tweak is + * applied only to two rows and only if the character looks like it + * might benefit. In particular, it's not applied to any stem hint + * that might be captured by an alignment zone. + */ +static bool +middle_stem_tweak_wanted(enum hint_type hhints[YSIZE], int row) +{ + if (row == 4 && + hhints[1] == hint_counter_stem && + hhints[7] == hint_counter_stem) return true; + if (row == 5 && + hhints[3] == hint_counter_stem && + hhints[7] == hint_counter_stem) return true; + return false; +} + static void emit_hints(int vstems[XSIZE], int ledges[XSIZE], int redges[XSIZE], int hstems[YSIZE], int tedges[YSIZE], int bedges[YSIZE]) @@ -3877,7 +3918,12 @@ emit_hints(int vstems[XSIZE], int ledges[XSIZE], int redges[XSIZE], for (i = 0; i < YSIZE; i++) { switch (hhints[YSIZE - 1 - i]) { case hint_counter_stem: - need_cntrmask = true; /* FALLTHROUGH */ + need_cntrmask = true; + if (middle_stem_tweak_wanted(hhints, YSIZE - 1 - i)) { + start = i * YPIX; + size = YPIX + 1; + break; + } /* FALLTHROUGH */ case hint_stem: start = i * YPIX; size = YPIX; -- 2.30.2