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])
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;