chiark / gitweb /
Don't emit counter hints for horizontal stems
authorBen Harris <bjh21@bjh21.me.uk>
Mon, 3 Mar 2025 22:57:37 +0000 (22:57 +0000)
committerBen Harris <bjh21@bjh21.me.uk>
Mon, 3 Mar 2025 22:57:37 +0000 (22:57 +0000)
Microsoft Windows 11 pays some attention to counter hints, and the
results are disastrous.  Specifically, at awkward ppem, characters
with counter hints end up one pixel smaller that characters without
them.  That makes the counters the same size, and puts every
horizontal stem squarely on a pixel, but means that cap height is all
wobbly, which looks horrible.  Additionally, some characters ('2' and
'3', at least) end up grossly distorted, with the top of the character
either stretched way above the character cell or squashed down to the
centre line.

Turning off the counter hints solves these problems.  Windows does
then draw the 'B' with its centre-line below the centre rather than
above it, but that's not a regression from 002.009.  As far as I can
tell, FreeType 2.12.1 ignores counter hints entirely.  At least, the
output of ftlint at 11 ppem is the same before and after this change.

Vertical counter hints survive.  They're also ignored by FreeType
2.12.1 (as are all vertical stem hints), but they seem to have a
broadly positive effect in Windows.

bedstead.c

index e0b12af9ad5352f2ec8c578b8639227bf96d7267..a875585d7a0d66932497578c41fe93da86d76abe 100644 (file)
@@ -4472,12 +4472,21 @@ emit_hints(int vstems[XSIZE], int ledges[XSIZE], int redges[XSIZE],
        enum hint_type vhints[XSIZE], hhints[YSIZE];
        bool printed, need_cntrmask = false;
 
+       /*
+        * We don't emit any counter hints for horizontal stems.  On
+        * Microsoft Windows 11, such counter hints are treated as
+        * more important than alignment zones, so when the cap height
+        * is an even number of pixels you end up with 'B' being one
+        * pixel smaller than 'C' to ensure that the two counters are
+        * the same size.  This is not actually what we want.
+        * FreeType 2.12.1 appears to entirely ignore those counter
+        * hints, so discarding them has no effect there.
+        */
        select_hints(YSIZE, hstems, tedges, bedges, hhints);
        cur = DESCENT * YPIX; printed = false;
        for (i = 0; i < YSIZE; i++) {
                switch (hhints[YSIZE - 1 - i]) {
                case hint_counter_stem:
-                       need_cntrmask = true;
                        if (middle_stem_tweak_wanted(hhints, YSIZE - 1 - i)) {
                                start = i * YPIX;
                                size = YPIX + 1;
@@ -4535,7 +4544,7 @@ emit_hints(int vstems[XSIZE], int ledges[XSIZE], int redges[XSIZE],
                printf(" cntrmask ");
                for (i = 0; i < YSIZE; i++)
                        if (hhints[i]) {
-                               printf("%c", "X0100"[hhints[i]]);
+                               printf("0");
                                nhints++;
                        }
                for (i = 0; i < XSIZE; i++)