diff --git a/src/ui/text.c b/src/ui/text.c

index 1761a87c..a8be33b6 100644

--- a/src/ui/text.c

+++ b/src/ui/text.c

@@ -85,7 +85,7 @@ iDefineTypeConstructionArgs(Glyph, (iChar ch), ch)

struct Impl_Font {

 iBlock *       data;

 stbtt_fontinfo font;

- float scale;

+ float xScale, yScale;

 int            vertOffset; /* offset due to scaling */

 int            height;

 int            baseline;

@@ -100,21 +100,33 @@ struct Impl_Font {



static iFont *font_Text_(enum iFontId id);



-static void init_Font(iFont *d, const iBlock *data, int height, float scale, enum iFontId symbolsFont) {

+static void init_Font(iFont *d, const iBlock *data, int height, float scale,

+ enum iFontId symbolsFont, iBool isMonospaced) {

 init_Hash(&d->glyphs);

 d->data = NULL;

+ d->isMonospaced = isMonospaced;

 d->height = height;

 iZap(d->font);

 stbtt_InitFont(&d->font, constData_Block(data), 0);

- d->scale = stbtt_ScaleForPixelHeight(&d->font, height) * scale;

+ d->xScale = d->yScale = stbtt_ScaleForPixelHeight(&d->font, height) * scale;

+ if (d->isMonospaced) {

+ /* It is important that monospaced fonts align 1:1 with the pixel grid so that

+ box-drawing characters don't have partially occupied edge pixels, leading to seams

+ between adjacent glyphs. */

+ int adv;

+ stbtt_GetCodepointHMetrics(&d->font, 'M', &adv, NULL);

+ const float advance = (float) adv * d->xScale;

+ if (advance > 4) { /* not too tiny */

+ d->xScale *= floorf(advance) / advance;

+ }

+ }

 d->vertOffset = height * (1.0f - scale) / 2;

 int ascent;

 stbtt_GetFontVMetrics(&d->font, &ascent, NULL, NULL);

- d->baseline = ceil(ascent * d->scale);

+ d->baseline = ceil(ascent * d->yScale);

 d->symbolsFont  = symbolsFont;

 d->japaneseFont = regularJapanese_FontId;

 d->koreanFont   = regularKorean_FontId;

- d->isMonospaced = iFalse;

 memset(d->indexTable, 0xff, sizeof(d->indexTable));

}



@@ -271,11 +283,12 @@ static void initFonts_Text_(iText *d) {

 };

 iForIndices(i, fontData) {

     iFont *font = &d->fonts[i];

- init_Font(

- font, fontData[i].ttf, fontData[i].size, fontData[i].scaling, fontData[i].symbolsFont);

- if (fontData[i].ttf == &fontFiraMonoRegular_Embedded) {

- font->isMonospaced = iTrue;

- }

+ init_Font(font,

+ fontData[i].ttf,

+ fontData[i].size,

+ fontData[i].scaling,

+ fontData[i].symbolsFont,

+ fontData[i].ttf == &fontFiraMonoRegular_Embedded);

     if (i == default_FontId || i == defaultMedium_FontId) {

         font->manualKernOnly = iTrue;

     }

@@ -423,7 +436,7 @@ static void freeBmp_(void *ptr) {

static SDL_Surface *rasterizeGlyph_Font_(const iFont *d, uint32_t glyphIndex, float xShift) {

 int w, h;

 uint8_t *bmp = stbtt_GetGlyphBitmapSubpixel(

- &d->font, d->scale, d->scale, xShift, 0.0f, glyphIndex, &w, &h, 0, 0);

+ &d->font, d->xScale, d->yScale, xShift, 0.0f, glyphIndex, &w, &h, 0, 0);

 collect_Garbage(bmp, freeBmp_); /* `bmp` must be freed afterwards. */

 SDL_Surface *surface8 =

     SDL_CreateRGBSurfaceWithFormatFrom(bmp, w, h, 8, w, SDL_PIXELFORMAT_INDEX8);

@@ -478,12 +491,12 @@ static void cache_Font_(iFont *d, iGlyph *glyph, int hoff) {

         int adv;

         const uint32_t gIndex = glyph->glyphIndex;

         stbtt_GetGlyphHMetrics(&d->font, gIndex, &adv, NULL);

- glyph->advance = d->scale * adv;

+ glyph->advance = d->xScale * adv;

     }

     stbtt_GetGlyphBitmapBoxSubpixel(&d->font,

                                     glyph->glyphIndex,

- d->scale,

- d->scale,

+ d->xScale,

+ d->yScale,

                                     hoff * 0.5f,

                                     0.0f,

                                     &glyph->d[hoff].x,

@@ -734,11 +747,7 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe

     }

     const iBool useMonoAdvance =

         monoAdvance > 0 && !isJapanese_FontId(fontId_Text_(glyph->font));

- /* The -0.25f is to mitigate issues with box-drawing characters sometimes rounding

- up to leave a hairline gap with the previous character. The purpose is to overlap

- the glyphs slightly, since they are rendered antialiased and unhinted, which means

- the right edge pixels may end up partially non-opaque. */

- const float advance = (useMonoAdvance ? monoAdvance - 0.25f : glyph->advance);

+ const float advance = (useMonoAdvance ? monoAdvance : glyph->advance);

     if (!isMeasuring_(mode)) {

         if (useMonoAdvance && dst.w > advance && glyph->font != d) {

             /* Glyphs from a different font may need recentering to look better. */

@@ -769,7 +778,7 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe

         const char *peek = chPos;

         const iChar next = nextChar_(&peek, text.end);

         if (enableKerning_Text && !d->manualKernOnly && next) {

- xpos += d->scale * stbtt_GetGlyphKernAdvance(&d->font, glyph->glyphIndex, next);

+ xpos += d->xScale * stbtt_GetGlyphKernAdvance(&d->font, glyph->glyphIndex, next);

         }

     }

#endif

Proxy Information
Original URL
gemini://git.skyjake.fi/lagrange/work%2Fv1.7/pcdiff/73c96402a21872dba8999caba8f4374a91f0d8e4
Status Code
Success (20)
Meta
text/plain
Capsule Response Time
223.180727 milliseconds
Gemini-to-HTML Time
1.674815 milliseconds

This content has been proxied by September (ba2dc).