summaryrefslogtreecommitdiff
path: root/src/ui/text.c
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2022-02-08 21:24:34 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2022-02-08 21:24:34 +0200
commit12a6fc81e8d11dc21db5938132818972df08e885 (patch)
tree530489e714a92aab4ff6375ba99c354cbb5e7e84 /src/ui/text.c
parentbd83aca1b20e5583568faff0251e9d5a0c62df5b (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.c59
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
249iDeclareType(PrioMapItem)
250struct Impl_PrioMapItem {
251 int priority;
252 uint32_t fontIndex;
253};
254
255static 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
249struct Impl_Text { 260struct 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) {