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.
This commit is contained in:
Ben Harris 2024-11-20 14:25:46 +00:00
parent 9a1a2e4966
commit 39d7e7fbdc

View File

@ -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;