summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-08-09 11:37:33 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-08-09 11:37:33 +0300
commit3530d4127b840c63e1a15b38844bf13483cf9490 (patch)
tree8fcc44af5fbe11468c86a9c43e47ca813cc776e1 /src/ui
parent4c277ce0e6efe5d372b399bd37eaef07d6ea8c1a (diff)
Text: Enforce spacing on monospaced fonts
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/text.c16
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
84static void deinit_Font(iFont *d) { 84static 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);