diff options
Diffstat (limited to 'src/ui/text.c')
-rw-r--r-- | src/ui/text.c | 180 |
1 files changed, 71 insertions, 109 deletions
diff --git a/src/ui/text.c b/src/ui/text.c index ac879af4..1af7bb5d 100644 --- a/src/ui/text.c +++ b/src/ui/text.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* Copyright 2020 Jaakko Keränen <jaakko.keranen@iki.fi> | 1 | /* Copyright 2020 Jaakko Keränen <jaakko.keranen@iki.fi> |
2 | 2 | ||
3 | Redistribution and use in source and binary forms, with or without | 3 | Redistribution and use in source and binary forms, with or without |
4 | modification, are permitted provided that the following conditions are met: | 4 | modification, are permitted provided that the following conditions are met: |
@@ -113,16 +113,18 @@ struct Impl_Font { | |||
113 | iHash glyphs; | 113 | iHash glyphs; |
114 | iBool isMonospaced; | 114 | iBool isMonospaced; |
115 | iBool manualKernOnly; | 115 | iBool manualKernOnly; |
116 | enum iFontId symbolsFont; /* font to use for symbols */ | 116 | enum iFontSize sizeId; /* used to look up different fonts of matching size */ |
117 | enum iFontId japaneseFont; /* font to use for Japanese glyphs */ | 117 | // enum iFontId |
118 | enum iFontId koreanFont; /* font to use for Korean glyphs */ | 118 | // enum iFontId japaneseFont; /* font to use for Japanese glyphs */ |
119 | uint32_t indexTable[128 - 32]; | 119 | // enum iFontId chineseFont; /* font to use for Simplified Chinese glyphs */ |
120 | // enum iFontId koreanFont; /* font to use for Korean glyphs */ | ||
121 | uint32_t indexTable[128 - 32]; /* quick ASCII lookup */ | ||
120 | }; | 122 | }; |
121 | 123 | ||
122 | static iFont *font_Text_(enum iFontId id); | 124 | static iFont *font_Text_(enum iFontId id); |
123 | 125 | ||
124 | static void init_Font(iFont *d, const iBlock *data, int height, float scale, | 126 | static void init_Font(iFont *d, const iBlock *data, int height, float scale, |
125 | enum iFontId symbolsFont, iBool isMonospaced) { | 127 | enum iFontSize sizeId, iBool isMonospaced) { |
126 | init_Hash(&d->glyphs); | 128 | init_Hash(&d->glyphs); |
127 | d->data = NULL; | 129 | d->data = NULL; |
128 | d->isMonospaced = isMonospaced; | 130 | d->isMonospaced = isMonospaced; |
@@ -145,9 +147,11 @@ static void init_Font(iFont *d, const iBlock *data, int height, float scale, | |||
145 | } | 147 | } |
146 | d->vertOffset = height * (1.0f - scale) / 2; | 148 | d->vertOffset = height * (1.0f - scale) / 2; |
147 | d->baseline = ascent * d->yScale; | 149 | d->baseline = ascent * d->yScale; |
148 | d->symbolsFont = symbolsFont; | 150 | d->sizeId = sizeId; |
149 | d->japaneseFont = regularJapanese_FontId; | 151 | // d->symbolsFont = symbolsFont; |
150 | d->koreanFont = regularKorean_FontId; | 152 | // d->japaneseFont = regularJapanese_FontId; |
153 | // d->chineseFont = regularChinese_FontId; | ||
154 | // d->koreanFont = regularKorean_FontId; | ||
151 | memset(d->indexTable, 0xff, sizeof(d->indexTable)); | 155 | memset(d->indexTable, 0xff, sizeof(d->indexTable)); |
152 | } | 156 | } |
153 | 157 | ||
@@ -281,73 +285,52 @@ static void initFonts_Text_(iText *d) { | |||
281 | const iBlock *ttf; | 285 | const iBlock *ttf; |
282 | int size; | 286 | int size; |
283 | float scaling; | 287 | float scaling; |
284 | int symbolsFont; | 288 | enum iFontSize sizeId; |
289 | /* UI sizes: 1.0, 1.125, 1.333, 1.666 */ | ||
290 | /* Content sizes: smallmono, mono, 1.0, 1.2, 1.333, 1.666, 2.0 */ | ||
285 | } fontData[max_FontId] = { | 291 | } fontData[max_FontId] = { |
286 | { &fontSourceSansProRegular_Embedded, uiSize, 1.0f, defaultSymbols_FontId }, | 292 | /* UI fonts: normal weight */ |
287 | { &fontSourceSansProBold_Embedded, uiSize, 1.0f, defaultSymbols_FontId }, | 293 | { &fontSourceSansProRegular_Embedded, uiSize, 1.0f, uiNormal_FontSize }, |
288 | { &fontSourceSansProRegular_Embedded, uiSize * 1.125f, 1.0f, defaultMediumSymbols_FontId }, | 294 | { &fontSourceSansProRegular_Embedded, uiSize * 1.125f, 1.0f, uiMedium_FontSize }, |
289 | { &fontSourceSansProBold_Embedded, uiSize * 1.125f, 1.0f, defaultMediumSymbols_FontId }, | 295 | { &fontSourceSansProRegular_Embedded, uiSize * 1.333f, 1.0f, uiBig_FontSize }, |
290 | { &fontSourceSansProRegular_Embedded, uiSize * 1.333f, 1.0f, defaultBigSymbols_FontId }, | 296 | { &fontSourceSansProRegular_Embedded, uiSize * 1.666f, 1.0f, uiLarge_FontSize }, |
291 | { &fontSourceSansProBold_Embedded, uiSize * 1.333f, 1.0f, defaultBigSymbols_FontId }, | 297 | /* UI fonts: bold weight */ |
292 | { &fontSourceSansProRegular_Embedded, uiSize * 1.666f, 1.0f, defaultLargeSymbols_FontId }, | 298 | { &fontSourceSansProBold_Embedded, uiSize, 1.0f, uiNormal_FontSize }, |
293 | { &fontSourceSansProBold_Embedded, uiSize * 1.666f, 1.0f, defaultLargeSymbols_FontId }, | 299 | { &fontSourceSansProBold_Embedded, uiSize * 1.125f, 1.0f, uiMedium_FontSize }, |
294 | { &fontIosevkaTermExtended_Embedded, uiSize * 0.866f, 1.0f, defaultSymbols_FontId }, | 300 | { &fontSourceSansProBold_Embedded, uiSize * 1.333f, 1.0f, uiBig_FontSize }, |
295 | { &fontSourceSansProRegular_Embedded, textSize, scaling, symbols_FontId }, | 301 | { &fontSourceSansProBold_Embedded, uiSize * 1.666f, 1.0f, uiLarge_FontSize }, |
296 | /* content fonts */ | 302 | /* content fonts */ |
297 | { regularFont, textSize, scaling, symbols_FontId }, | 303 | { regularFont, textSize, scaling, contentRegular_FontSize }, |
298 | { boldFont, textSize, scaling, symbols_FontId }, | 304 | { boldFont, textSize, scaling, contentRegular_FontSize }, |
299 | { &fontIosevkaTermExtended_Embedded, monoSize, 1.0f, monospaceSymbols_FontId }, | 305 | { italicFont, textSize, italicScaling,contentRegular_FontSize }, |
300 | { &fontIosevkaTermExtended_Embedded, smallMonoSize, 1.0f, monospaceSmallSymbols_FontId }, | 306 | { regularFont, textSize * 1.200f, scaling, contentMedium_FontSize }, |
301 | { regularFont, textSize * 1.200f, scaling, mediumSymbols_FontId }, | 307 | { h3Font, textSize * 1.333f, h123Scaling, contentBig_FontSize }, |
302 | { h3Font, textSize * 1.333f, h123Scaling, bigSymbols_FontId }, | 308 | { h12Font, textSize * 1.666f, h123Scaling, contentLarge_FontSize }, |
303 | { italicFont, textSize, italicScaling,symbols_FontId }, | 309 | { lightFont, textSize * 1.666f, lightScaling, contentLarge_FontSize }, |
304 | { h12Font, textSize * 1.666f, h123Scaling, largeSymbols_FontId }, | 310 | { h12Font, textSize * 2.000f, h123Scaling, contentHuge_FontSize }, |
305 | { h12Font, textSize * 2.000f, h123Scaling, hugeSymbols_FontId }, | 311 | { &fontIosevkaTermExtended_Embedded, smallMonoSize, 1.0f, contentMonoSmall_FontSize }, |
306 | { lightFont, textSize * 1.666f, lightScaling, largeSymbols_FontId }, | 312 | { &fontIosevkaTermExtended_Embedded, monoSize, 1.0f, contentMono_FontSize }, |
307 | /* monospace content fonts */ | 313 | /* extra content fonts */ |
308 | { &fontIosevkaTermExtended_Embedded, textSize, 0.866f, symbols_FontId }, | 314 | { &fontSourceSansProRegular_Embedded, textSize, scaling, contentRegular_FontSize }, |
309 | /* symbol fonts */ | 315 | { &fontIosevkaTermExtended_Embedded, textSize, 0.866f, contentRegular_FontSize }, |
310 | { &fontSymbola_Embedded, uiSize, 1.0f, defaultSymbols_FontId }, | 316 | /* symbols and scripts */ |
311 | { &fontSymbola_Embedded, uiSize * 1.125f, 1.0f, defaultMediumSymbols_FontId }, | 317 | #define DEFINE_FONT_SET(data) \ |
312 | { &fontSymbola_Embedded, uiSize * 1.333f, 1.0f, defaultBigSymbols_FontId }, | 318 | { &data, uiSize, 1.0f, uiNormal_FontSize }, \ |
313 | { &fontSymbola_Embedded, uiSize * 1.666f, 1.0f, defaultLargeSymbols_FontId }, | 319 | { &data, uiSize * 1.125f, 1.0f, uiMedium_FontSize }, \ |
314 | { &fontSymbola_Embedded, textSize, 1.0f, symbols_FontId }, | 320 | { &data, uiSize * 1.333f, 1.0f, uiBig_FontSize }, \ |
315 | { &fontSymbola_Embedded, textSize * 1.200f, 1.0f, mediumSymbols_FontId }, | 321 | { &data, uiSize * 1.666f, 1.0f, uiLarge_FontSize }, \ |
316 | { &fontSymbola_Embedded, textSize * 1.333f, 1.0f, bigSymbols_FontId }, | 322 | { &data, textSize, 1.0f, contentRegular_FontSize }, \ |
317 | { &fontSymbola_Embedded, textSize * 1.666f, 1.0f, largeSymbols_FontId }, | 323 | { &data, textSize * 1.200f, 1.0f, contentMedium_FontSize }, \ |
318 | { &fontSymbola_Embedded, textSize * 2.000f, 1.0f, hugeSymbols_FontId }, | 324 | { &data, textSize * 1.333f, 1.0f, contentBig_FontSize }, \ |
319 | { &fontSymbola_Embedded, monoSize, 1.0f, monospaceSymbols_FontId }, | 325 | { &data, textSize * 1.666f, 1.0f, contentLarge_FontSize }, \ |
320 | { &fontSymbola_Embedded, smallMonoSize, 1.0f, monospaceSmallSymbols_FontId }, | 326 | { &data, textSize * 2.000f, 1.0f, contentHuge_FontSize }, \ |
321 | /* emoji fonts */ | 327 | { &data, smallMonoSize, 1.0f, contentMonoSmall_FontSize }, \ |
322 | { &fontNotoEmojiRegular_Embedded, uiSize, 1.0f, defaultSymbols_FontId }, | 328 | { &data, monoSize, 1.0f, contentMono_FontSize } |
323 | { &fontNotoEmojiRegular_Embedded, uiSize * 1.125f, 1.0f, defaultMediumSymbols_FontId }, | 329 | DEFINE_FONT_SET(fontSymbola_Embedded), |
324 | { &fontNotoEmojiRegular_Embedded, uiSize * 1.333f, 1.0f, defaultBigSymbols_FontId }, | 330 | DEFINE_FONT_SET(fontNotoEmojiRegular_Embedded), |
325 | { &fontNotoEmojiRegular_Embedded, uiSize * 1.666f, 1.0f, defaultLargeSymbols_FontId }, | 331 | DEFINE_FONT_SET(fontNotoSansJPRegular_Embedded), |
326 | { &fontNotoEmojiRegular_Embedded, textSize, 1.0f, symbols_FontId }, | 332 | DEFINE_FONT_SET(fontNotoSansSCRegular_Embedded), |
327 | { &fontNotoEmojiRegular_Embedded, textSize * 1.200f, 1.0f, mediumSymbols_FontId }, | 333 | DEFINE_FONT_SET(fontNanumGothicRegular_Embedded), /* TODO: should use Noto Sans here, too */ |
328 | { &fontNotoEmojiRegular_Embedded, textSize * 1.333f, 1.0f, bigSymbols_FontId }, | ||
329 | { &fontNotoEmojiRegular_Embedded, textSize * 1.666f, 1.0f, largeSymbols_FontId }, | ||
330 | { &fontNotoEmojiRegular_Embedded, textSize * 2.000f, 1.0f, hugeSymbols_FontId }, | ||
331 | { &fontNotoEmojiRegular_Embedded, monoSize, 1.0f, monospaceSymbols_FontId }, | ||
332 | { &fontNotoEmojiRegular_Embedded, smallMonoSize, 1.0f, monospaceSmallSymbols_FontId }, | ||
333 | /* japanese fonts */ | ||
334 | { &fontNotoSansJPRegular_Embedded, uiSize, 1.0f, defaultSymbols_FontId }, | ||
335 | { &fontNotoSansJPRegular_Embedded, smallMonoSize, 1.0f, monospaceSmallSymbols_FontId }, | ||
336 | { &fontNotoSansJPRegular_Embedded, monoSize, 1.0f, monospaceSymbols_FontId }, | ||
337 | { &fontNotoSansJPRegular_Embedded, textSize, 1.0f, symbols_FontId }, | ||
338 | { &fontNotoSansJPRegular_Embedded, textSize * 1.200f, 1.0f, mediumSymbols_FontId }, | ||
339 | { &fontNotoSansJPRegular_Embedded, textSize * 1.333f, 1.0f, bigSymbols_FontId }, | ||
340 | { &fontNotoSansJPRegular_Embedded, textSize * 1.666f, 1.0f, largeSymbols_FontId }, | ||
341 | { &fontNotoSansJPRegular_Embedded, textSize * 2.000f, 1.0f, hugeSymbols_FontId }, | ||
342 | /* korean fonts */ | ||
343 | { &fontNanumGothicRegular_Embedded, uiSize, 1.0f, defaultSymbols_FontId }, | ||
344 | { &fontNanumGothicRegular_Embedded, smallMonoSize, 1.0f, monospaceSmallSymbols_FontId }, | ||
345 | { &fontNanumGothicRegular_Embedded, monoSize, 1.0f, monospaceSymbols_FontId }, | ||
346 | { &fontNanumGothicRegular_Embedded, textSize, 1.0f, symbols_FontId }, | ||
347 | { &fontNanumGothicRegular_Embedded, textSize * 1.200f, 1.0f, mediumSymbols_FontId }, | ||
348 | { &fontNanumGothicRegular_Embedded, textSize * 1.333f, 1.0f, bigSymbols_FontId }, | ||
349 | { &fontNanumGothicRegular_Embedded, textSize * 1.666f, 1.0f, largeSymbols_FontId }, | ||
350 | { &fontNanumGothicRegular_Embedded, textSize * 2.000f, 1.0f, hugeSymbols_FontId }, | ||
351 | }; | 334 | }; |
352 | iForIndices(i, fontData) { | 335 | iForIndices(i, fontData) { |
353 | iFont *font = &d->fonts[i]; | 336 | iFont *font = &d->fonts[i]; |
@@ -355,42 +338,12 @@ static void initFonts_Text_(iText *d) { | |||
355 | fontData[i].ttf, | 338 | fontData[i].ttf, |
356 | fontData[i].size, | 339 | fontData[i].size, |
357 | fontData[i].scaling, | 340 | fontData[i].scaling, |
358 | fontData[i].symbolsFont, | 341 | fontData[i].sizeId, |
359 | fontData[i].ttf == &fontIosevkaTermExtended_Embedded); | 342 | fontData[i].ttf == &fontIosevkaTermExtended_Embedded); |
360 | if (i == default_FontId || i == defaultMedium_FontId) { | 343 | if (i == default_FontId || i == defaultMedium_FontId) { |
361 | font->manualKernOnly = iTrue; | 344 | font->manualKernOnly = iTrue; |
362 | } | 345 | } |
363 | } | 346 | } |
364 | /* Japanese script. */ { | ||
365 | /* Everything defaults to the regular sized japanese font, so these are just | ||
366 | the other sizes. */ | ||
367 | font_Text_(default_FontId)->japaneseFont = defaultJapanese_FontId; | ||
368 | font_Text_(defaultMedium_FontId)->japaneseFont = defaultJapanese_FontId; | ||
369 | font_Text_(defaultBig_FontId)->japaneseFont = defaultJapanese_FontId; | ||
370 | font_Text_(defaultLarge_FontId)->japaneseFont = defaultJapanese_FontId; | ||
371 | font_Text_(defaultMonospace_FontId)->japaneseFont = defaultJapanese_FontId; | ||
372 | font_Text_(monospaceSmall_FontId)->japaneseFont = monospaceSmallJapanese_FontId; | ||
373 | font_Text_(monospace_FontId)->japaneseFont = monospaceJapanese_FontId; | ||
374 | font_Text_(medium_FontId)->japaneseFont = mediumJapanese_FontId; | ||
375 | font_Text_(big_FontId)->japaneseFont = bigJapanese_FontId; | ||
376 | font_Text_(largeBold_FontId)->japaneseFont = largeJapanese_FontId; | ||
377 | font_Text_(largeLight_FontId)->japaneseFont = largeJapanese_FontId; | ||
378 | font_Text_(hugeBold_FontId)->japaneseFont = hugeJapanese_FontId; | ||
379 | } | ||
380 | /* Korean script. */ { | ||
381 | font_Text_(default_FontId)->koreanFont = defaultKorean_FontId; | ||
382 | font_Text_(defaultMedium_FontId)->koreanFont = defaultKorean_FontId; | ||
383 | font_Text_(defaultBig_FontId)->koreanFont = defaultKorean_FontId; | ||
384 | font_Text_(defaultLarge_FontId)->koreanFont = defaultKorean_FontId; | ||
385 | font_Text_(defaultMonospace_FontId)->koreanFont = defaultKorean_FontId; | ||
386 | font_Text_(monospaceSmall_FontId)->koreanFont = monospaceSmallKorean_FontId; | ||
387 | font_Text_(monospace_FontId)->koreanFont = monospaceKorean_FontId; | ||
388 | font_Text_(medium_FontId)->koreanFont = mediumKorean_FontId; | ||
389 | font_Text_(big_FontId)->koreanFont = bigKorean_FontId; | ||
390 | font_Text_(largeBold_FontId)->koreanFont = largeKorean_FontId; | ||
391 | font_Text_(largeLight_FontId)->koreanFont = largeKorean_FontId; | ||
392 | font_Text_(hugeBold_FontId)->koreanFont = hugeKorean_FontId; | ||
393 | } | ||
394 | gap_Text = iRound(gap_UI * d->contentFontSize); | 347 | gap_Text = iRound(gap_UI * d->contentFontSize); |
395 | } | 348 | } |
396 | 349 | ||
@@ -522,9 +475,11 @@ static SDL_Surface *rasterizeGlyph_Font_(const iFont *d, uint32_t glyphIndex, fl | |||
522 | return surface8; | 475 | return surface8; |
523 | } | 476 | } |
524 | 477 | ||
478 | #if 0 | ||
525 | iLocalDef SDL_Rect sdlRect_(const iRect rect) { | 479 | iLocalDef SDL_Rect sdlRect_(const iRect rect) { |
526 | return (SDL_Rect){ rect.pos.x, rect.pos.y, rect.size.x, rect.size.y }; | 480 | return (SDL_Rect){ rect.pos.x, rect.pos.y, rect.size.x, rect.size.y }; |
527 | } | 481 | } |
482 | #endif | ||
528 | 483 | ||
529 | iLocalDef iCacheRow *cacheRow_Text_(iText *d, int height) { | 484 | iLocalDef iCacheRow *cacheRow_Text_(iText *d, int height) { |
530 | return at_Array(&d->cacheRows, (height - 1) / d->cacheRowAllocStep); | 485 | return at_Array(&d->cacheRows, (height - 1) / d->cacheRowAllocStep); |
@@ -603,21 +558,28 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) { | |||
603 | } | 558 | } |
604 | /* Not defined in current font, try Noto Emoji (for selected characters). */ | 559 | /* Not defined in current font, try Noto Emoji (for selected characters). */ |
605 | if ((ch >= 0x1f300 && ch < 0x1f600) || (ch >= 0x1f680 && ch <= 0x1f6c5)) { | 560 | if ((ch >= 0x1f300 && ch < 0x1f600) || (ch >= 0x1f680 && ch <= 0x1f6c5)) { |
606 | iFont *emoji = font_Text_(d->symbolsFont + fromSymbolsToEmojiOffset_FontId); | 561 | iFont *emoji = font_Text_(emoji_FontId + d->sizeId); |
607 | if (emoji != d && (*glyphIndex = glyphIndex_Font_(emoji, ch)) != 0) { | 562 | if (emoji != d && (*glyphIndex = glyphIndex_Font_(emoji, ch)) != 0) { |
608 | return emoji; | 563 | return emoji; |
609 | } | 564 | } |
610 | } | 565 | } |
566 | /* Try Simplified Chinese. */ | ||
567 | if (ch >= 0x2e80) { | ||
568 | iFont *sc = font_Text_(chineseSimplified_FontId + d->sizeId); | ||
569 | if (sc != d && (*glyphIndex = glyphIndex_Font_(sc, ch)) != 0) { | ||
570 | return sc; | ||
571 | } | ||
572 | } | ||
611 | /* Could be Korean. */ | 573 | /* Could be Korean. */ |
612 | if (ch >= 0x3000) { | 574 | if (ch >= 0x3000) { |
613 | iFont *korean = font_Text_(d->koreanFont); | 575 | iFont *korean = font_Text_(korean_FontId + d->sizeId); |
614 | if (korean != d && (*glyphIndex = glyphIndex_Font_(korean, ch)) != 0) { | 576 | if (korean != d && (*glyphIndex = glyphIndex_Font_(korean, ch)) != 0) { |
615 | return korean; | 577 | return korean; |
616 | } | 578 | } |
617 | } | 579 | } |
618 | /* Japanese perhaps? */ | 580 | /* Japanese perhaps? */ |
619 | if (ch > 0x3040) { | 581 | if (ch > 0x3040) { |
620 | iFont *japanese = font_Text_(d->japaneseFont); | 582 | iFont *japanese = font_Text_(japanese_FontId + d->sizeId); |
621 | if (japanese != d && (*glyphIndex = glyphIndex_Font_(japanese, ch)) != 0) { | 583 | if (japanese != d && (*glyphIndex = glyphIndex_Font_(japanese, ch)) != 0) { |
622 | return japanese; | 584 | return japanese; |
623 | } | 585 | } |
@@ -631,7 +593,7 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) { | |||
631 | } | 593 | } |
632 | #endif | 594 | #endif |
633 | /* Fall back to Symbola for anything else. */ | 595 | /* Fall back to Symbola for anything else. */ |
634 | iFont *font = font_Text_(d->symbolsFont); | 596 | iFont *font = font_Text_(symbols_FontId + d->sizeId); |
635 | *glyphIndex = glyphIndex_Font_(font, ch); | 597 | *glyphIndex = glyphIndex_Font_(font, ch); |
636 | // if (!*glyphIndex) { | 598 | // if (!*glyphIndex) { |
637 | // fprintf(stderr, "failed to find %08x (%lc)\n", ch, ch); fflush(stderr); | 599 | // fprintf(stderr, "failed to find %08x (%lc)\n", ch, ch); fflush(stderr); |