From 7fe46cb90c77522d29e975ad69b226473949f25c Mon Sep 17 00:00:00 2001 From: phall Date: Mon, 10 Aug 2026 22:17:44 -0400 Subject: [PATCH] fix(macos): enable font smoothing so glyphs render at full weight Every glyph the AppKit host draws lands in a CGBitmapContext, and font smoothing - macOS's stem darkening for text - is off by default on the transparent backing all three of those contexts use. The result is that ALL text renders systematically thin, which is what the faint-text report was about. Measured with phux-cockpit's scripts/measure-glyph-smoothing.m against the bundled JetBrains Mono NL, 13pt: scale 2 solid stem pixels 2341 -> 3164 (+35.2%) scale 1 solid stem pixels 635 -> 940 (+48.0%) Filling an opaque ground under the cells was also considered and is NOT included: measured on the same harness it moves solid stem pixels by -0.3% (2341 -> 2334), so it buys no weight while adding a full-screen fill to every frame. The CPU reference renderer never touches CoreText and blends coverage itself, so it does not share the defect and no reference screenshot can catch a regression here. Re-measure rather than eyeball. Co-Authored-By: Claude Opus 5 (1M context) --- src/platform/macos/appkit_host.m | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/platform/macos/appkit_host.m b/src/platform/macos/appkit_host.m index 3225c78dc..31506581d 100644 --- a/src/platform/macos/appkit_host.m +++ b/src/platform/macos/appkit_host.m @@ -4501,6 +4501,17 @@ - (BOOL)ensureCanvasCompositor { if (!bitmap) return nil; CGContextSetAllowsAntialiasing(bitmap, true); CGContextSetShouldAntialias(bitmap, true); + /* Font smoothing is macOS's stem darkening for text, and it is OFF by + * default on a transparent backing. Every glyph this host draws lands in + * a CGBitmapContext like this one, so leaving it off renders ALL text + * systematically thin - measured at 35% fewer fully-solid stem pixels + * (2341 vs 3164 at 13pt/scale 2) with the bundled JetBrains Mono NL. + * Measure with phux-cockpit's scripts/measure-glyph-smoothing.m before + * changing this; the deficit is invisible in the CPU reference renderer, + * which never touches CoreText, so no reference screenshot can catch a + * regression here. Allows- must precede Should-: the former gates it. */ + CGContextSetAllowsFontSmoothing(bitmap, true); + CGContextSetShouldSmoothFonts(bitmap, true); CGContextTranslateCTM(bitmap, 0, (CGFloat)rasterHeight); CGContextScaleCTM(bitmap, scale, -scale); CGContextTranslateCTM(bitmap, -minX / scale, -minY / scale); @@ -5177,6 +5188,11 @@ - (NativeSdkPacketCommandRaster *)rasterCacheBuildEntryForCommand:(NSDictionary if (!bitmap) return nil; CGContextSetAllowsAntialiasing(bitmap, true); CGContextSetShouldAntialias(bitmap, true); + /* Stem darkening for text; see the raster path above for why and for how + * to measure it. This is the CACHED command raster, so a glyph rasterized + * thin here stays thin for the life of the cache entry. */ + CGContextSetAllowsFontSmoothing(bitmap, true); + CGContextSetShouldSmoothFonts(bitmap, true); CGContextTranslateCTM(bitmap, 0, (CGFloat)rasterHeight); CGContextScaleCTM(bitmap, scale, -scale); CGContextTranslateCTM(bitmap, -minX / scale, -minY / scale); @@ -5390,6 +5406,12 @@ - (NSInteger)drawPacketCommands:(NSArray *)commands keys:(NSArray *)keys pixels: CGContextSetAllowsAntialiasing(context, true); CGContextSetShouldAntialias(context, true); + /* Stem darkening for text; see the raster path above for why and for how + * to measure it. This is the MAIN per-present surface pass - the one that + * draws the terminal cell grid - so it is the site the faint-text report + * was actually about. */ + CGContextSetAllowsFontSmoothing(context, true); + CGContextSetShouldSmoothFonts(context, true); CGContextTranslateCTM(context, 0, (CGFloat)pixelHeight); CGContextScaleCTM(context, scale, -scale);