diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-24 09:51:50 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:14 -0300 |
| commit | d32452950262b4ec2b50b0e0af66f7870c8e5d5d (patch) | |
| tree | d2122f2dd6cd5d415a4986619ad47d30506c78d8 /src/gui/font.c | |
| parent | f6738c7edfff2249e0b13f2a76962f45d02c86bb (diff) | |
| download | pardes-d32452950262b4ec2b50b0e0af66f7870c8e5d5d.tar.gz pardes-d32452950262b4ec2b50b0e0af66f7870c8e5d5d.zip | |
Embolden bold text's outline before it is rasterized, and drop the old stb_truetype sources
Bold in the SDL shell was a smear of the finished glyph: every pixel took
the larger of itself and three quarters of its left neighbour. That added a
grey fringe on the right of each stem instead of a thicker stem, so bold read
as blurred regular text, and at large sizes it barely read as bold at all.
The rasterizer now does what Ghostty's FreeType face does: it loads the
hinted glyph, thickens the outline with FT_Outline_Embolden, and renders
that. The stems widen as one shape with hinted edges, and the advance is
untouched, so the cell grid, caret and selection do not move. The strength
is Ghostty's heuristic, 1/32 of the line height rounded up (one pixel at a
32 px line). A bitmap strike has no outline; it is widened by one whole
pixel with FT_Bitmap_Embolden, the classic overstrike. Underline and
strikethrough are still drawn into the cached cell mask (decorateLine).
vendor/stb (stb_truetype.h and its implementation unit) was left over from
the rasterizer FreeType replaced; nothing built or referenced it.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Diffstat (limited to 'src/gui/font.c')
| -rw-r--r-- | src/gui/font.c | 30 |
1 files changed, 24 insertions, 6 deletions
diff --git a/src/gui/font.c b/src/gui/font.c index 5989dd4e..5ea595f9 100644 --- a/src/gui/font.c +++ b/src/gui/font.c @@ -3,6 +3,7 @@ // fallback, and the light target for shape-preserving grayscale text. #include "font.h" #include <freetype-zig.h> +#include <freetype/ftbitmap.h> #include <stdlib.h> #include <string.h> @@ -126,7 +127,7 @@ void ui_font_cell_metrics(UIFont *f, float px, int32_t *cell_w, int32_t *cell_h, *ascent = asc > 0 ? asc : 1; } -static int raster(UIFont *f, float px, int32_t cp, uint8_t *out, +static int raster(UIFont *f, float px, int32_t cp, int bold, uint8_t *out, int32_t stride, int32_t cell_w, int32_t cell_h, int32_t ascent, int centered) { if (!f || !out || stride < cell_w || cell_w <= 0 || cell_h <= 0) @@ -140,6 +141,22 @@ static int raster(UIFont *f, float px, int32_t cp, uint8_t *out, FT_Get_Char_Index(f->face, (FT_ULong)(uint32_t)cp); if (FT_Load_Glyph(f->face, glyph_index, load_flags()) != 0) return 0; + if (bold) { + // Synthetic bold thickens the hinted outline before it is rendered, so + // the wider stems are rasterized as one shape and keep hinted edges; the + // advance is untouched, as the cell grid requires. Strength is Ghostty's + // heuristic: 1/32 of the line height in 26.6, rounded up (one pixel at a + // 32 px line). A bitmap strike has no outline: widen it by one whole pixel, + // the classic overstrike, which keeps its pixels sharp. + FT_GlyphSlot slot = f->face->glyph; + if (slot->format == FT_GLYPH_FORMAT_OUTLINE) { + const FT_Pos height = f->face->size->metrics.height; + FT_Outline_Embolden(&slot->outline, (height + 31) / 32); + } else if (slot->format == FT_GLYPH_FORMAT_BITMAP && + FT_GlyphSlot_Own_Bitmap(slot) == 0) { + FT_Bitmap_Embolden(f->library, &slot->bitmap, 64, 0); + } + } if (FT_Render_Glyph(f->face->glyph, FT_RENDER_MODE_NORMAL) != 0) return 0; @@ -187,13 +204,14 @@ static int raster(UIFont *f, float px, int32_t cp, uint8_t *out, return 1; } -int ui_font_raster(UIFont *f, float px, int32_t cp, uint8_t *out, +int ui_font_raster(UIFont *f, float px, int32_t cp, int bold, uint8_t *out, int32_t stride, int32_t cell_w, int32_t cell_h, int32_t ascent) { - return raster(f, px, cp, out, stride, cell_w, cell_h, ascent, 0); + return raster(f, px, cp, bold, out, stride, cell_w, cell_h, ascent, 0); } -int ui_font_raster_centered(UIFont *f, float px, int32_t cp, uint8_t *out, - int32_t stride, int32_t width, int32_t height) { - return raster(f, px, cp, out, stride, width, height, 0, 1); +int ui_font_raster_centered(UIFont *f, float px, int32_t cp, int bold, + uint8_t *out, int32_t stride, int32_t width, + int32_t height) { + return raster(f, px, cp, bold, out, stride, width, height, 0, 1); } |
