From 73c96402a21872dba8999caba8f4374a91f0d8e4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= jaakko.keranen@iki.fi
Date: Mon, 7 Dec 2020 20:44:46 +0200
Subject: [PATCH 1/1] Text: Align monospace glyph sizing to pixel grid
This is a better solution than a magic 0.25 pixel offset.
To eliminate partially occupied glyph edge pixels, scale the glyphs slightly so they align with full pixels. Scaling is only done horizontally so it doesn't affect line height.
IssueID #86
src/ui/text.c | 49 +++++++++++++++++++++++++++++--------------------
1 file changed, 29 insertions(+), 20 deletions(-)
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;
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->height = height;
iZap(d->font);
stbtt_InitFont(&d->font, constData_Block(data), 0);
/* 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->symbolsFont = symbolsFont;
d->japaneseFont = regularJapanese_FontId;
d->koreanFont = regularKorean_FontId;
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
--
2.25.1
text/plain
This content has been proxied by September (ba2dc).