diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-08-09 11:37:33 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-08-09 11:37:33 +0300 |
commit | 3530d4127b840c63e1a15b38844bf13483cf9490 (patch) | |
tree | 8fcc44af5fbe11468c86a9c43e47ca813cc776e1 /src/ui | |
parent | 4c277ce0e6efe5d372b399bd37eaef07d6ea8c1a (diff) |
Text: Enforce spacing on monospaced fonts
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/text.c | 16 |
1 files changed, 11 insertions, 5 deletions
diff --git a/src/ui/text.c b/src/ui/text.c index 9468ea65..d57c77ee 100644 --- a/src/ui/text.c +++ b/src/ui/text.c | |||
@@ -61,7 +61,7 @@ struct Impl_Font { | |||
61 | int height; | 61 | int height; |
62 | int baseline; | 62 | int baseline; |
63 | iHash glyphs; | 63 | iHash glyphs; |
64 | iBool enableKerning; | 64 | iBool isMonospaced; |
65 | enum iFontId symbolsFont; /* font to use for symbols */ | 65 | enum iFontId symbolsFont; /* font to use for symbols */ |
66 | }; | 66 | }; |
67 | 67 | ||
@@ -78,7 +78,7 @@ static void init_Font(iFont *d, const iBlock *data, int height, enum iFontId sym | |||
78 | stbtt_GetFontVMetrics(&d->font, &ascent, NULL, NULL); | 78 | stbtt_GetFontVMetrics(&d->font, &ascent, NULL, NULL); |
79 | d->baseline = (int) ascent * d->scale; | 79 | d->baseline = (int) ascent * d->scale; |
80 | d->symbolsFont = symbolsFont; | 80 | d->symbolsFont = symbolsFont; |
81 | d->enableKerning = iTrue; | 81 | d->isMonospaced = iFalse; |
82 | } | 82 | } |
83 | 83 | ||
84 | static void deinit_Font(iFont *d) { | 84 | static void deinit_Font(iFont *d) { |
@@ -148,7 +148,7 @@ static void initFonts_Text_(iText *d) { | |||
148 | iFont *font = &d->fonts[i]; | 148 | iFont *font = &d->fonts[i]; |
149 | init_Font(font, fontData[i].ttf, fontData[i].size, fontData[i].symbolsFont); | 149 | init_Font(font, fontData[i].ttf, fontData[i].size, fontData[i].symbolsFont); |
150 | if (fontData[i].ttf == &fontFiraMonoRegular_Embedded) { | 150 | if (fontData[i].ttf == &fontFiraMonoRegular_Embedded) { |
151 | font->enableKerning = iFalse; | 151 | font->isMonospaced = iTrue; |
152 | } | 152 | } |
153 | } | 153 | } |
154 | gap_Text = iRound(gap_UI * d->contentFontSize); | 154 | gap_Text = iRound(gap_UI * d->contentFontSize); |
@@ -385,12 +385,16 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe | |||
385 | const iInt2 orig = pos; | 385 | const iInt2 orig = pos; |
386 | float xpos = pos.x; | 386 | float xpos = pos.x; |
387 | float xposMax = xpos; | 387 | float xposMax = xpos; |
388 | float monoAdvance = 0; | ||
388 | iAssert(xposLimit == 0 || isMeasuring_(mode)); | 389 | iAssert(xposLimit == 0 || isMeasuring_(mode)); |
389 | const char *lastWordEnd = text.start; | 390 | const char *lastWordEnd = text.start; |
390 | if (continueFrom_out) { | 391 | if (continueFrom_out) { |
391 | *continueFrom_out = text.end; | 392 | *continueFrom_out = text.end; |
392 | } | 393 | } |
393 | iChar prevCh = 0; | 394 | iChar prevCh = 0; |
395 | if (d->isMonospaced) { | ||
396 | monoAdvance = glyph_Font_(d, 'M')->advance; | ||
397 | } | ||
394 | for (const char *chPos = text.start; chPos != text.end; ) { | 398 | for (const char *chPos = text.start; chPos != text.end; ) { |
395 | iAssert(chPos < text.end); | 399 | iAssert(chPos < text.end); |
396 | const char *currentPos = chPos; | 400 | const char *currentPos = chPos; |
@@ -460,13 +464,15 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe | |||
460 | if (!isMeasuring_(mode)) { | 464 | if (!isMeasuring_(mode)) { |
461 | SDL_RenderCopy(text_.render, text_.cache, (const SDL_Rect *) &glyph->rect[hoff], &dst); | 465 | SDL_RenderCopy(text_.render, text_.cache, (const SDL_Rect *) &glyph->rect[hoff], &dst); |
462 | } | 466 | } |
463 | xpos += glyph->advance; | 467 | /* Symbols and emojis are NOT monospaced, so must conform when the primary font |
468 | is monospaced. */ | ||
469 | xpos += (d->isMonospaced && glyph->font != d ? monoAdvance : glyph->advance); | ||
464 | xposMax = iMax(xposMax, xpos); | 470 | xposMax = iMax(xposMax, xpos); |
465 | if (mode == measureNoWrap_RunMode || isWrapBoundary_(prevCh, ch)) { | 471 | if (mode == measureNoWrap_RunMode || isWrapBoundary_(prevCh, ch)) { |
466 | lastWordEnd = chPos; | 472 | lastWordEnd = chPos; |
467 | } | 473 | } |
468 | /* Check the next character. */ | 474 | /* Check the next character. */ |
469 | if (d->enableKerning && glyph->font == d) { | 475 | if (!d->isMonospaced && glyph->font == d) { |
470 | /* TODO: No need to decode the next char twice; check this on the next iteration. */ | 476 | /* TODO: No need to decode the next char twice; check this on the next iteration. */ |
471 | const char *peek = chPos; | 477 | const char *peek = chPos; |
472 | const iChar next = nextChar_(&peek, text.end); | 478 | const iChar next = nextChar_(&peek, text.end); |