Fix: Wayland crash on startup due to Pango also using FontConfig (#10916)

Basically, we haven't been a good neighbour. Turns out you shouldn't
actually call FcFini when you are done, as some library might still
want to use FontConfig. And they use a shared instance for their
administration.

The idea is that you call FcInit once, and use FcConfigReference
after that to get an instance, you can release. This entry is
ref-counted, and things happen automatically based on that.

At least, I think.
This commit is contained in:
Patric Stout 2023-06-03 21:09:02 +02:00 committed by Loïc Guilloux
parent 53709f0bdc
commit 57a6233754
1 changed files with 59 additions and 52 deletions

View File

@ -30,66 +30,70 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
FT_Error err = FT_Err_Cannot_Open_Resource; FT_Error err = FT_Err_Cannot_Open_Resource;
if (!FcInit()) { if (!FcInit()) {
ShowInfoF("Unable to load font configuration"); ShowInfo("Unable to load font configuration");
} else { return err;
FcPattern *match; }
FcPattern *pat;
FcFontSet *fs;
FcResult result;
char *font_style;
char *font_family;
/* Split & strip the font's style */ auto fc_instance = FcConfigReference(nullptr);
font_family = stredup(font_name); assert(fc_instance != nullptr);
font_style = strchr(font_family, ',');
if (font_style != nullptr) {
font_style[0] = '\0';
font_style++;
while (*font_style == ' ' || *font_style == '\t') font_style++;
}
/* Resolve the name and populate the information structure */ FcPattern *match;
pat = FcNameParse((FcChar8 *)font_family); FcPattern *pat;
if (font_style != nullptr) FcPatternAddString(pat, FC_STYLE, (FcChar8 *)font_style); FcFontSet *fs;
FcConfigSubstitute(nullptr, pat, FcMatchPattern); FcResult result;
FcDefaultSubstitute(pat); char *font_style;
fs = FcFontSetCreate(); char *font_family;
match = FcFontMatch(nullptr, pat, &result);
if (fs != nullptr && match != nullptr) { /* Split & strip the font's style */
int i; font_family = stredup(font_name);
FcChar8 *family; font_style = strchr(font_family, ',');
FcChar8 *style; if (font_style != nullptr) {
FcChar8 *file; font_style[0] = '\0';
int32_t index; font_style++;
FcFontSetAdd(fs, match); while (*font_style == ' ' || *font_style == '\t') font_style++;
}
for (i = 0; err != FT_Err_Ok && i < fs->nfont; i++) { /* Resolve the name and populate the information structure */
/* Try the new filename */ pat = FcNameParse((FcChar8 *)font_family);
if (FcPatternGetString(fs->fonts[i], FC_FILE, 0, &file) == FcResultMatch && if (font_style != nullptr) FcPatternAddString(pat, FC_STYLE, (FcChar8 *)font_style);
FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == FcResultMatch && FcConfigSubstitute(nullptr, pat, FcMatchPattern);
FcPatternGetString(fs->fonts[i], FC_STYLE, 0, &style) == FcResultMatch && FcDefaultSubstitute(pat);
FcPatternGetInteger(fs->fonts[i], FC_INDEX, 0, &index) == FcResultMatch) { fs = FcFontSetCreate();
match = FcFontMatch(nullptr, pat, &result);
/* The correct style? */ if (fs != nullptr && match != nullptr) {
if (font_style != nullptr && strcasecmp(font_style, (char *)style) != 0) continue; int i;
FcChar8 *family;
FcChar8 *style;
FcChar8 *file;
int32_t index;
FcFontSetAdd(fs, match);
/* Font config takes the best shot, which, if the family name is spelled for (i = 0; err != FT_Err_Ok && i < fs->nfont; i++) {
* wrongly a 'random' font, so check whether the family name is the /* Try the new filename */
* same as the supplied name */ if (FcPatternGetString(fs->fonts[i], FC_FILE, 0, &file) == FcResultMatch &&
if (strcasecmp(font_family, (char *)family) == 0) { FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == FcResultMatch &&
err = FT_New_Face(_library, (char *)file, index, face); FcPatternGetString(fs->fonts[i], FC_STYLE, 0, &style) == FcResultMatch &&
} FcPatternGetInteger(fs->fonts[i], FC_INDEX, 0, &index) == FcResultMatch) {
/* The correct style? */
if (font_style != nullptr && strcasecmp(font_style, (char *)style) != 0) continue;
/* Font config takes the best shot, which, if the family name is spelled
* wrongly a 'random' font, so check whether the family name is the
* same as the supplied name */
if (strcasecmp(font_family, (char *)family) == 0) {
err = FT_New_Face(_library, (char *)file, index, face);
} }
} }
} }
free(font_family);
FcPatternDestroy(pat);
FcFontSetDestroy(fs);
FcFini();
} }
free(font_family);
FcPatternDestroy(pat);
FcFontSetDestroy(fs);
FcConfigDestroy(fc_instance);
return err; return err;
} }
@ -98,10 +102,13 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
bool SetFallbackFont(FontCacheSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback) bool SetFallbackFont(FontCacheSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
{ {
if (!FcInit()) return false;
bool ret = false; bool ret = false;
if (!FcInit()) return ret;
auto fc_instance = FcConfigReference(nullptr);
assert(fc_instance != nullptr);
/* Fontconfig doesn't handle full language isocodes, only the part /* Fontconfig doesn't handle full language isocodes, only the part
* before the _ of e.g. en_GB is used, so "remove" everything after * before the _ of e.g. en_GB is used, so "remove" everything after
* the _. */ * the _. */
@ -168,6 +175,6 @@ bool SetFallbackFont(FontCacheSettings *settings, const char *language_isocode,
FcFontSetDestroy(fs); FcFontSetDestroy(fs);
} }
FcFini(); FcConfigDestroy(fc_instance);
return ret; return ret;
} }