diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2022-02-08 21:24:34 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2022-02-08 21:24:34 +0200 |
commit | 12a6fc81e8d11dc21db5938132818972df08e885 (patch) | |
tree | 530489e714a92aab4ff6375ba99c354cbb5e7e84 /src/ui/text.c | |
parent | bd83aca1b20e5583568faff0251e9d5a0c62df5b (diff) |
Fonts: Improved fallback glyph search
The fontpack documentation says that when a glyph isn't found, all available fonts are checked in priority order. However, the implementation didn't actually do this.
Now there is a separate priority mapping for loaded fonts so they can be quickly scanned for any missing glyphs in the right order.
"iosevka-body" was prioritized higher because it provides a number of UI icons.
Diffstat (limited to 'src/ui/text.c')
-rw-r--r-- | src/ui/text.c | 59 |
1 files changed, 38 insertions, 21 deletions
diff --git a/src/ui/text.c b/src/ui/text.c index 200108ed..e49034ca 100644 --- a/src/ui/text.c +++ b/src/ui/text.c | |||
@@ -246,12 +246,24 @@ struct Impl_CacheRow { | |||
246 | iInt2 pos; | 246 | iInt2 pos; |
247 | }; | 247 | }; |
248 | 248 | ||
249 | iDeclareType(PrioMapItem) | ||
250 | struct Impl_PrioMapItem { | ||
251 | int priority; | ||
252 | uint32_t fontIndex; | ||
253 | }; | ||
254 | |||
255 | static int cmp_PrioMapItem_(const void *a, const void *b) { | ||
256 | const iPrioMapItem *i = a, *j = b; | ||
257 | return -iCmp(i->priority, j->priority); | ||
258 | } | ||
259 | |||
249 | struct Impl_Text { | 260 | struct Impl_Text { |
250 | // enum iTextFont contentFont; | 261 | // enum iTextFont contentFont; |
251 | // enum iTextFont headingFont; | 262 | // enum iTextFont headingFont; |
252 | float contentFontSize; | 263 | float contentFontSize; |
253 | iArray fonts; /* fonts currently selected for use (incl. all styles/sizes) */ | 264 | iArray fonts; /* fonts currently selected for use (incl. all styles/sizes) */ |
254 | int overrideFontId; /* always checked for glyphs first, regardless of which font is used */ | 265 | int overrideFontId; /* always checked for glyphs first, regardless of which font is used */ |
266 | iArray fontPriorityOrder; | ||
255 | SDL_Renderer * render; | 267 | SDL_Renderer * render; |
256 | SDL_Texture * cache; | 268 | SDL_Texture * cache; |
257 | iInt2 cacheSize; | 269 | iInt2 cacheSize; |
@@ -284,8 +296,9 @@ static void setupFontVariants_Text_(iText *d, const iFontSpec *spec, int baseId) | |||
284 | /* This is the highest priority override font. */ | 296 | /* This is the highest priority override font. */ |
285 | d->overrideFontId = baseId; | 297 | d->overrideFontId = baseId; |
286 | } | 298 | } |
299 | pushBack_Array(&d->fontPriorityOrder, &(iPrioMapItem){ spec->priority, baseId }); | ||
287 | for (enum iFontStyle style = 0; style < max_FontStyle; style++) { | 300 | for (enum iFontStyle style = 0; style < max_FontStyle; style++) { |
288 | for (enum iFontSize sizeId = 0; sizeId < max_FontSize; sizeId++) { | 301 | for (enum iFontSize sizeId = 0; sizeId < max_FontSize; sizeId++) { |
289 | init_Font(font_Text_(FONT_ID(baseId, style, sizeId)), | 302 | init_Font(font_Text_(FONT_ID(baseId, style, sizeId)), |
290 | spec, | 303 | spec, |
291 | spec->styles[style], | 304 | spec->styles[style], |
@@ -322,6 +335,7 @@ static void initFonts_Text_(iText *d) { | |||
322 | and styles for each available font. Indices to `fonts` act as font runtime IDs. */ | 335 | and styles for each available font. Indices to `fonts` act as font runtime IDs. */ |
323 | /* First the mandatory fonts. */ | 336 | /* First the mandatory fonts. */ |
324 | d->overrideFontId = -1; | 337 | d->overrideFontId = -1; |
338 | clear_Array(&d->fontPriorityOrder); | ||
325 | resize_Array(&d->fonts, auxiliary_FontId); /* room for the built-ins */ | 339 | resize_Array(&d->fonts, auxiliary_FontId); /* room for the built-ins */ |
326 | setupFontVariants_Text_(d, tryFindSpec_(uiFont_PrefsString, "default"), default_FontId); | 340 | setupFontVariants_Text_(d, tryFindSpec_(uiFont_PrefsString, "default"), default_FontId); |
327 | setupFontVariants_Text_(d, tryFindSpec_(monospaceFont_PrefsString, "iosevka"), monospace_FontId); | 341 | setupFontVariants_Text_(d, tryFindSpec_(monospaceFont_PrefsString, "iosevka"), monospace_FontId); |
@@ -331,12 +345,14 @@ static void initFonts_Text_(iText *d) { | |||
331 | /* Check if there are auxiliary fonts available and set those up, too. */ | 345 | /* Check if there are auxiliary fonts available and set those up, too. */ |
332 | iConstForEach(PtrArray, s, listSpecsByPriority_Fonts()) { | 346 | iConstForEach(PtrArray, s, listSpecsByPriority_Fonts()) { |
333 | const iFontSpec *spec = s.ptr; | 347 | const iFontSpec *spec = s.ptr; |
348 | // printf("spec '%s': prio=%d\n", cstr_String(&spec->name), spec->priority); | ||
334 | if (spec->flags & (auxiliary_FontSpecFlag | user_FontSpecFlag)) { | 349 | if (spec->flags & (auxiliary_FontSpecFlag | user_FontSpecFlag)) { |
335 | const int fontId = size_Array(&d->fonts); | 350 | const int fontId = size_Array(&d->fonts); |
336 | resize_Array(&d->fonts, fontId + maxVariants_Fonts); | 351 | resize_Array(&d->fonts, fontId + maxVariants_Fonts); |
337 | setupFontVariants_Text_(d, spec, fontId); | 352 | setupFontVariants_Text_(d, spec, fontId); |
338 | } | 353 | } |
339 | } | 354 | } |
355 | sort_Array(&d->fontPriorityOrder, cmp_PrioMapItem_); | ||
340 | #if !defined (NDEBUG) | 356 | #if !defined (NDEBUG) |
341 | printf("[Text] %zu font variants ready\n", size_Array(&d->fonts)); | 357 | printf("[Text] %zu font variants ready\n", size_Array(&d->fonts)); |
342 | #endif | 358 | #endif |
@@ -402,6 +418,7 @@ void init_Text(iText *d, SDL_Renderer *render) { | |||
402 | iText *oldActive = activeText_; | 418 | iText *oldActive = activeText_; |
403 | activeText_ = d; | 419 | activeText_ = d; |
404 | init_Array(&d->fonts, sizeof(iFont)); | 420 | init_Array(&d->fonts, sizeof(iFont)); |
421 | init_Array(&d->fontPriorityOrder, sizeof(iPrioMapItem)); | ||
405 | d->contentFontSize = contentScale_Text_; | 422 | d->contentFontSize = contentScale_Text_; |
406 | d->ansiEscape = makeAnsiEscapePattern_Text(iFalse /* no ESC */); | 423 | d->ansiEscape = makeAnsiEscapePattern_Text(iFalse /* no ESC */); |
407 | d->baseFontId = -1; | 424 | d->baseFontId = -1; |
@@ -436,6 +453,7 @@ void deinit_Text(iText *d) { | |||
436 | deinitCache_Text_(d); | 453 | deinitCache_Text_(d); |
437 | d->render = NULL; | 454 | d->render = NULL; |
438 | iRelease(d->ansiEscape); | 455 | iRelease(d->ansiEscape); |
456 | deinit_Array(&d->fontPriorityOrder); | ||
439 | deinit_Array(&d->fonts); | 457 | deinit_Array(&d->fonts); |
440 | } | 458 | } |
441 | 459 | ||
@@ -571,25 +589,24 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) { | |||
571 | if ((*glyphIndex = glyphIndex_Font_(d, ch)) != 0) { | 589 | if ((*glyphIndex = glyphIndex_Font_(d, ch)) != 0) { |
572 | return d; | 590 | return d; |
573 | } | 591 | } |
574 | /* As a fallback, check all other available fonts of this size. */ | 592 | /* As a fallback, check all other available fonts of this size in priority order. */ |
575 | for (int aux = 0; aux < 2; aux++) { | 593 | iConstForEach(Array, i, &activeText_->fontPriorityOrder) { |
576 | for (iFont *font = font_Text_(FONT_ID(0, styleId, sizeId)); | 594 | iFont *font = font_Text_(FONT_ID(((const iPrioMapItem *) i.value)->fontIndex, |
577 | font < (iFont *) end_Array(&activeText_->fonts); | 595 | styleId, sizeId)); |
578 | font += maxVariants_Fonts) { | 596 | if (font == d || font == overrideFont) { |
579 | const iBool isAuxiliary = (font->fontSpec->flags & auxiliary_FontSpecFlag) ? 1 : 0; | 597 | continue; /* already checked this one */ |
580 | if (aux == isAuxiliary) { | 598 | } |
581 | /* First try auxiliary fonts, then other remaining fonts. */ | 599 | if ((*glyphIndex = glyphIndex_Font_(font, ch)) != 0) { |
582 | continue; | 600 | #if 0 |
583 | } | 601 | printf("using '%s' (pr:%d) for %lc (%x) => %d [missing in '%s']\n", |
584 | if (font == d || font == overrideFont) { | 602 | cstr_String(&font->fontSpec->id), |
585 | continue; /* already checked this one */ | 603 | font->fontSpec->priority, |
586 | } | 604 | (int) ch, |
587 | if ((*glyphIndex = glyphIndex_Font_(font, ch)) != 0) { | 605 | ch, |
588 | // printf("using %s[%f] for %lc (%x) => %d\n", | 606 | glyphIndex_Font_(font, ch), |
589 | // cstr_String(&font->fontSpec->name), font->fontSpec->scaling, | 607 | cstr_String(&d->fontSpec->id)); |
590 | // (int) ch, ch, glyphIndex_Font_(font, ch)); | 608 | #endif |
591 | return font; | 609 | return font; |
592 | } | ||
593 | } | 610 | } |
594 | } | 611 | } |
595 | if (!*glyphIndex) { | 612 | if (!*glyphIndex) { |