From 1420a2218d5f65c4bf76a0390be58fe9ec89a6aa Mon Sep 17 00:00:00 2001 From: Sergei Grechanik Date: Mon, 10 Jun 2024 20:16:58 -0700 Subject: [PATCH] Check if the fallback font actually contains the char For some reason FcFontSetMatch may return a font that doesn't contain the character specified via the charset. This commit works around this by calling FcFontSort instead and then trying the fonts one by one until we find a font that actually contains the character. --- x.c | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/x.c b/x.c index bd23686..84cc0ae 100644 --- a/x.c +++ b/x.c @@ -128,7 +128,6 @@ typedef struct { short lbearing; short rbearing; XftFont *match; - FcFontSet *set; FcPattern *pattern; } Font; @@ -966,7 +965,6 @@ xloadfont(Font *f, FcPattern *pattern) (const FcChar8 *) ascii_printable, strlen(ascii_printable), &extents); - f->set = NULL; f->pattern = configured; f->ascent = f->match->ascent; @@ -1055,8 +1053,6 @@ xunloadfont(Font *f) { XftFontClose(xw.dpy, f->match); FcPatternDestroy(f->pattern); - if (f->set) - FcFontSetDestroy(f->set); } void @@ -1251,9 +1247,9 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x FT_UInt glyphidx; FcResult fcres; FcPattern *fcpattern, *fontpattern; - FcFontSet *fcsets[] = { NULL }; FcCharSet *fccharset; - int i, f, numspecs = 0; + FcFontSet *candidatefonts; + int i, j, f, numspecs = 0; for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { /* Fetch rune and mode for current glyph. */ @@ -1310,11 +1306,6 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x /* Nothing was found. Use fontconfig to find matching font. */ if (f >= frclen) { - if (!font->set) - font->set = FcFontSort(0, font->pattern, - 1, 0, &fcres); - fcsets[0] = font->set; - /* * Nothing was found in the cache. Now use * some dozen of Fontconfig calls to get the @@ -1334,8 +1325,32 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x FcMatchPattern); FcDefaultSubstitute(fcpattern); - fontpattern = FcFontSetMatch(0, fcsets, 1, - fcpattern, &fcres); + /* FcFontSetMatch may return a font that doesn't contain + * the character we are looking for. Sort the font set + * instead and use the first one that contains the + * character or the first font if none contains it. + */ + candidatefonts = + FcFontSort(0, fcpattern, 1, 0, &fcres); + fontpattern = NULL; + for (j = 0; j < candidatefonts->nfont; j++) { + FcCharSet *charset = NULL; + fontpattern = candidatefonts->fonts[j]; + char contains_rune = + FcPatternGetCharSet( + fontpattern, FC_CHARSET, 0, + &charset) == FcResultMatch && + charset && + FcCharSetHasChar(charset, rune); + if (contains_rune) + break; + fontpattern = NULL; + } + if (!fontpattern) + fontpattern = candidatefonts->fonts[0]; + fontpattern = + FcFontRenderPrepare(0, fcpattern, fontpattern); + FcFontSetDestroy(candidatefonts); /* Allocate memory for the new cache entry. */ if (frclen >= frccap) { -- 2.43.0