diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-09-13 09:39:01 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-09-13 09:43:08 +0300 |
commit | b505a32d5e3dc6f8405cf48a5f854b1c09534038 (patch) | |
tree | d1a6b14a930116c4d184bd23ab61c6fa6b7ac211 /src | |
parent | a7806a4cd61e8125b9ce095515418e84f34256c1 (diff) |
Added Kosugi Maru for Japanese text
Kosugi Maru is from Google Fonts and licensed used Apache License 2.0.
Diffstat (limited to 'src')
-rw-r--r-- | src/ui/text.c | 55 | ||||
-rw-r--r-- | src/ui/text.h | 13 |
2 files changed, 55 insertions, 13 deletions
diff --git a/src/ui/text.c b/src/ui/text.c index 3de1c83b..a48d0e0e 100644 --- a/src/ui/text.c +++ b/src/ui/text.c | |||
@@ -92,6 +92,7 @@ struct Impl_Font { | |||
92 | iBool isMonospaced; | 92 | iBool isMonospaced; |
93 | iBool manualKernOnly; | 93 | iBool manualKernOnly; |
94 | enum iFontId symbolsFont; /* font to use for symbols */ | 94 | enum iFontId symbolsFont; /* font to use for symbols */ |
95 | enum iFontId japaneseFont; /* font to use for Japanese glyphs */ | ||
95 | uint32_t indexTable[128 - 32]; | 96 | uint32_t indexTable[128 - 32]; |
96 | }; | 97 | }; |
97 | 98 | ||
@@ -108,6 +109,7 @@ static void init_Font(iFont *d, const iBlock *data, int height, enum iFontId sym | |||
108 | stbtt_GetFontVMetrics(&d->font, &ascent, NULL, NULL); | 109 | stbtt_GetFontVMetrics(&d->font, &ascent, NULL, NULL); |
109 | d->baseline = (int) ascent * d->scale; | 110 | d->baseline = (int) ascent * d->scale; |
110 | d->symbolsFont = symbolsFont; | 111 | d->symbolsFont = symbolsFont; |
112 | d->japaneseFont = regularJapanese_FontId; | ||
111 | d->isMonospaced = iFalse; | 113 | d->isMonospaced = iFalse; |
112 | memset(d->indexTable, 0xff, sizeof(d->indexTable)); | 114 | memset(d->indexTable, 0xff, sizeof(d->indexTable)); |
113 | } | 115 | } |
@@ -189,6 +191,11 @@ static void initFonts_Text_(iText *d) { | |||
189 | { &fontNotoEmojiRegular_Embedded, textSize * 1.666f, largeSymbols_FontId }, | 191 | { &fontNotoEmojiRegular_Embedded, textSize * 1.666f, largeSymbols_FontId }, |
190 | { &fontNotoEmojiRegular_Embedded, textSize * 2.000f, hugeSymbols_FontId }, | 192 | { &fontNotoEmojiRegular_Embedded, textSize * 2.000f, hugeSymbols_FontId }, |
191 | { &fontNotoEmojiRegular_Embedded, textSize * 0.866f, smallSymbols_FontId }, | 193 | { &fontNotoEmojiRegular_Embedded, textSize * 0.866f, smallSymbols_FontId }, |
194 | { &fontKosugiMaruRegular_Embedded, textSize * 0.666f, smallSymbols_FontId }, | ||
195 | { &fontKosugiMaruRegular_Embedded, textSize, symbols_FontId }, | ||
196 | { &fontKosugiMaruRegular_Embedded, textSize * 1.333f, mediumSymbols_FontId }, | ||
197 | { &fontKosugiMaruRegular_Embedded, textSize * 1.666f, largeSymbols_FontId }, | ||
198 | { &fontKosugiMaruRegular_Embedded, textSize * 2.000f, hugeSymbols_FontId }, | ||
192 | }; | 199 | }; |
193 | iForIndices(i, fontData) { | 200 | iForIndices(i, fontData) { |
194 | iFont *font = &d->fonts[i]; | 201 | iFont *font = &d->fonts[i]; |
@@ -200,6 +207,18 @@ static void initFonts_Text_(iText *d) { | |||
200 | font->manualKernOnly = iTrue; | 207 | font->manualKernOnly = iTrue; |
201 | } | 208 | } |
202 | } | 209 | } |
210 | /* Japanese script. */ { | ||
211 | /* Everything defaults to the regular sized japanese font, so these are just | ||
212 | the other sizes. */ | ||
213 | /* TODO: Add these to the table above... */ | ||
214 | font_Text_(monospace_FontId)->japaneseFont = smallJapanese_FontId; | ||
215 | font_Text_(monospaceSmall_FontId)->japaneseFont = smallJapanese_FontId; | ||
216 | font_Text_(medium_FontId)->japaneseFont = mediumJapanese_FontId; | ||
217 | font_Text_(mediumBold_FontId)->japaneseFont = mediumJapanese_FontId; | ||
218 | font_Text_(largeBold_FontId)->japaneseFont = largeJapanese_FontId; | ||
219 | font_Text_(largeLight_FontId)->japaneseFont = largeJapanese_FontId; | ||
220 | font_Text_(hugeBold_FontId)->japaneseFont = hugeJapanese_FontId; | ||
221 | } | ||
203 | gap_Text = iRound(gap_UI * d->contentFontSize); | 222 | gap_Text = iRound(gap_UI * d->contentFontSize); |
204 | } | 223 | } |
205 | 224 | ||
@@ -344,13 +363,19 @@ static void cache_Font_(iFont *d, iGlyph *glyph, int hoff) { | |||
344 | SDL_Renderer *render = txt->render; | 363 | SDL_Renderer *render = txt->render; |
345 | SDL_Texture *tex = NULL; | 364 | SDL_Texture *tex = NULL; |
346 | SDL_Surface *surface = NULL; | 365 | SDL_Surface *surface = NULL; |
347 | const iChar ch = char_Glyph(glyph); | ||
348 | iRect *glRect = &glyph->rect[hoff]; | 366 | iRect *glRect = &glyph->rect[hoff]; |
349 | /* Rasterize the glyph using stbtt. */ { | 367 | /* Rasterize the glyph using stbtt. */ { |
350 | surface = rasterizeGlyph_Font_(d, glyph->glyphIndex, hoff * 0.5f); | 368 | surface = rasterizeGlyph_Font_(d, glyph->glyphIndex, hoff * 0.5f); |
351 | if (hoff == 0) { | 369 | if (hoff == 0) { |
352 | int adv; | 370 | int adv; |
353 | stbtt_GetGlyphHMetrics(&d->font, glyph->glyphIndex, &adv, NULL); | 371 | const uint32_t gIndex = glyph->glyphIndex; |
372 | // float advScale = d->scale; | ||
373 | // if (isJapanese_FontId(d - text_.fonts)) { | ||
374 | /* Treat as monospace. */ | ||
375 | // gIndex = stbtt_FindGlyphIndex(&d->font, 0x5712); | ||
376 | // advScale *= 2.0f; | ||
377 | // } | ||
378 | stbtt_GetGlyphHMetrics(&d->font, gIndex, &adv, NULL); | ||
354 | glyph->advance = d->scale * adv; | 379 | glyph->advance = d->scale * adv; |
355 | } | 380 | } |
356 | stbtt_GetGlyphBitmapBoxSubpixel(&d->font, | 381 | stbtt_GetGlyphBitmapBoxSubpixel(&d->font, |
@@ -389,6 +414,13 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) { | |||
389 | return emoji; | 414 | return emoji; |
390 | } | 415 | } |
391 | } | 416 | } |
417 | /* Japanese perhaps? */ | ||
418 | if (ch > 0x3040) { | ||
419 | iFont *japanese = font_Text_(d->japaneseFont); | ||
420 | if (japanese != d && (*glyphIndex = glyphIndex_Font_(japanese, ch)) != 0) { | ||
421 | return japanese; | ||
422 | } | ||
423 | } | ||
392 | /* Fall back to Symbola for anything else. */ | 424 | /* Fall back to Symbola for anything else. */ |
393 | iFont *font = font_Text_(d->symbolsFont); | 425 | iFont *font = font_Text_(d->symbolsFont); |
394 | *glyphIndex = glyphIndex_Font_(font, ch); | 426 | *glyphIndex = glyphIndex_Font_(font, ch); |
@@ -437,6 +469,10 @@ static iChar nextChar_(const char **chPos, const char *end) { | |||
437 | return ch; | 469 | return ch; |
438 | } | 470 | } |
439 | 471 | ||
472 | static enum iFontId fontId_Text_(const iFont *font) { | ||
473 | return font - text_.fonts; | ||
474 | } | ||
475 | |||
440 | iLocalDef iBool isWrapBoundary_(iChar a, iChar b) { | 476 | iLocalDef iBool isWrapBoundary_(iChar a, iChar b) { |
441 | if (b == '/' || b == '-' || b == ',' || b == ';' || b == ':') { | 477 | if (b == '/' || b == '-' || b == ',' || b == ';' || b == ':') { |
442 | return iTrue; | 478 | return iTrue; |
@@ -540,29 +576,24 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe | |||
540 | SDL_RenderCopy(text_.render, text_.cache, (const SDL_Rect *) &glyph->rect[hoff], &dst); | 576 | SDL_RenderCopy(text_.render, text_.cache, (const SDL_Rect *) &glyph->rect[hoff], &dst); |
541 | } | 577 | } |
542 | /* Symbols and emojis are NOT monospaced, so must conform when the primary font | 578 | /* Symbols and emojis are NOT monospaced, so must conform when the primary font |
543 | is monospaced. */ | 579 | is monospaced. Except with Japanese script, that's larger than the normal monospace. */ |
544 | xpos += (d->isMonospaced && glyph->font != d ? monoAdvance : glyph->advance); | 580 | xpos += (monoAdvance > 0 && !isJapanese_FontId(fontId_Text_(glyph->font)) ? monoAdvance |
581 | : glyph->advance); | ||
545 | xposMax = iMax(xposMax, xpos); | 582 | xposMax = iMax(xposMax, xpos); |
546 | if (continueFrom_out && (mode == measureNoWrap_RunMode || isWrapBoundary_(prevCh, ch))) { | 583 | if (continueFrom_out && (mode == measureNoWrap_RunMode || isWrapBoundary_(prevCh, ch))) { |
547 | lastWordEnd = chPos; | 584 | lastWordEnd = chPos; |
548 | } | 585 | } |
586 | #if defined (LAGRANGE_ENABLE_KERNING) | ||
549 | /* Check the next character. */ | 587 | /* Check the next character. */ |
550 | if (!d->isMonospaced && glyph->font == d) { | 588 | if (!d->isMonospaced && glyph->font == d) { |
551 | /* TODO: No need to decode the next char twice; check this on the next iteration. */ | 589 | /* TODO: No need to decode the next char twice; check this on the next iteration. */ |
552 | const char *peek = chPos; | 590 | const char *peek = chPos; |
553 | const iChar next = nextChar_(&peek, text.end); | 591 | const iChar next = nextChar_(&peek, text.end); |
554 | #if 0 | ||
555 | if (ch == '/' && next == '/') { | ||
556 | /* Manual kerning for double-slash. */ | ||
557 | xpos -= glyph->rect[hoff].size.x * 0.5f; | ||
558 | } else | ||
559 | #endif | ||
560 | #if defined (LAGRANGE_ENABLE_KERNING) | ||
561 | if (enableKerning_Text && !d->manualKernOnly && next) { | 592 | if (enableKerning_Text && !d->manualKernOnly && next) { |
562 | xpos += d->scale * stbtt_GetGlyphKernAdvance(&d->font, glyph->glyphIndex, next); | 593 | xpos += d->scale * stbtt_GetGlyphKernAdvance(&d->font, glyph->glyphIndex, next); |
563 | } | 594 | } |
564 | #endif | ||
565 | } | 595 | } |
596 | #endif | ||
566 | prevCh = ch; | 597 | prevCh = ch; |
567 | if (--maxLen == 0) { | 598 | if (--maxLen == 0) { |
568 | break; | 599 | break; |
diff --git a/src/ui/text.h b/src/ui/text.h index 2b4ec5c3..9a22620f 100644 --- a/src/ui/text.h +++ b/src/ui/text.h | |||
@@ -40,7 +40,7 @@ enum iFontId { | |||
40 | mediumBold_FontId, | 40 | mediumBold_FontId, |
41 | largeBold_FontId, | 41 | largeBold_FontId, |
42 | hugeBold_FontId, | 42 | hugeBold_FontId, |
43 | largeLight_FontId, | 43 | largeLight_FontId, |
44 | /* symbol fonts */ | 44 | /* symbol fonts */ |
45 | defaultSymbols_FontId, | 45 | defaultSymbols_FontId, |
46 | defaultMediumSymbols_FontId, | 46 | defaultMediumSymbols_FontId, |
@@ -57,10 +57,17 @@ enum iFontId { | |||
57 | largeEmoji_FontId, | 57 | largeEmoji_FontId, |
58 | hugeEmoji_FontId, | 58 | hugeEmoji_FontId, |
59 | smallEmoji_FontId, | 59 | smallEmoji_FontId, |
60 | /* japanese script */ | ||
61 | smallJapanese_FontId, | ||
62 | regularJapanese_FontId, | ||
63 | mediumJapanese_FontId, | ||
64 | largeJapanese_FontId, | ||
65 | hugeJapanese_FontId, | ||
60 | max_FontId, | 66 | max_FontId, |
61 | 67 | ||
62 | /* Meta: */ | 68 | /* Meta: */ |
63 | fromSymbolsToEmojiOffset_FontId = 7, | 69 | fromSymbolsToEmojiOffset_FontId = 7, |
70 | |||
64 | /* UI fonts: */ | 71 | /* UI fonts: */ |
65 | uiLabel_FontId = default_FontId, | 72 | uiLabel_FontId = default_FontId, |
66 | uiShortcuts_FontId = default_FontId, | 73 | uiShortcuts_FontId = default_FontId, |
@@ -78,6 +85,10 @@ enum iFontId { | |||
78 | banner_FontId = largeLight_FontId, | 85 | banner_FontId = largeLight_FontId, |
79 | }; | 86 | }; |
80 | 87 | ||
88 | iLocalDef iBool isJapanese_FontId(enum iFontId id) { | ||
89 | return id >= smallJapanese_FontId && id <= hugeJapanese_FontId; | ||
90 | } | ||
91 | |||
81 | #define variationSelectorEmoji_Char ((iChar) 0xfe0f) | 92 | #define variationSelectorEmoji_Char ((iChar) 0xfe0f) |
82 | 93 | ||
83 | extern int gap_Text; /* affected by content font size */ | 94 | extern int gap_Text; /* affected by content font size */ |