Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix linux fontconfig #1771

Merged
merged 8 commits into from
Nov 24, 2024
Merged

Conversation

saurtron
Copy link
Collaborator

@saurtron saurtron commented Nov 15, 2024

Work done

  • Fix linux fontconfig initialization and fallback mechanisms.
  • Initialize config with FcConfigEnableHome(false) and FcInitLoadConfigAndFonts. This way system configuration is automatically loaded both on linux and windows and we won't write in user folders out of the spring dir.
  • Don't load osFontsDir with FcConfigAppFontAddDir.
  • Remove foundry from search pattern since that confuses the search.
  • Filter out UKWN and ukwn foundries.

Remarks

  • The way to init config I believe should be more robust on windows too, but someone will have to test it to see if it actually works.
    • Loading system config can be done later on at CheckGenFontConfigFull, but that requires more changes like loading /etc/fonts/fonts.conf with FtConfigParseAndLoad and removing the CheckFontConfig there as otherwise FcConfigBuildFonts won't get called.
    • The proposed method works on windows too, and looks much cleaner.
  • Regarding the foundry filter, at least here, it's not finding requested glyphs (at least in first matches) when that is set. We could just filter out "UKWN" and "ukwn" and make it work but removing it was deemed better here. I know fontconfig should be returning matching fonts in order of priority filters, but somehow that's breaking it completely. Those foundries are defaults from some programs and totally not recommended to have inside font files.

Related issues

All these issues are somehow related, at least they are badly affecting linux since it's not loading system fonts at all atm, although just the fixes here may not fix them for everyone as that depends on system fonts. With the proposed changes now emojis and glyphs from 3925 work here (i had to install noto font in ubuntu 24 though).

Looks like on windows also #3925 is solved with this PR, otherwise fontconfig wouldn't find the glyphs even when present in the system. Not sure if this is because of the new initialization method or because of removing the foundry though, this would have to be checked by someone on windows.

The ZorinOS bug is a bit weird but might be related to trying to load /etc/fonts using FcConfigAppFontAddDir on an old distro, since that's not the intended way to use the method. Looks like the method is for loading actual font files from a directory, but /etc/fonts holds config files.

Imo fixing missing emojis can be fixed by distributing NotoEmoji-VariableFont_wght.ttf, glyphs, for beyond-all-reason/Beyond-All-Reason#3925 I found at NotoSansSymbols2-Regular.ttf (1f81a) and DejaVuSerif.ttf (1F525). All our provided fonts inside fonts/ should be loaded and used if the user misses glyphs. I know this is maybe more of a game issue and I can propose including and loading them there to bar. Then how to prioritize app provided fonts can be looked into but imo it should be feasible (there's some talks about this at #537).

@@ -461,7 +460,7 @@ static std::shared_ptr<FontFace> GetFontForCharacters(const std::vector<char32_t

if (family)
FcPatternAddString(pattern, FC_FAMILY, family);
if (foundry)
if (foundry && strcmp("UKWN", reinterpret_cast<char*>(foundry)) != 0 && strcmp("ukwn", reinterpret_cast<char*>(foundry)) != 0)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we put something like your comment from the PR description here, perhaps away in some sort of function?

Suggested change
if (foundry && strcmp("UKWN", reinterpret_cast<char*>(foundry)) != 0 && strcmp("ukwn", reinterpret_cast<char*>(foundry)) != 0)
if (foundry && isFoundryOkay(foundry))
static bool isFoundryOkay(const auto *foundry) {
  // guaranteed null-terminated because of blabla
  auto *const foundryString = reinterpret_cast <char*> (foundry);

  /* (FIXME wants better wording, i just copypasted from PR)
   * it's not finding requested glyphs (at least in first matches) when that is set.
   * Imo we could just not filter by foundry at all and would be cleaner but
   * trying to modify behaviour as little as possible. I know fontconfig should
   * be returning matching fonts in order of priority filters, but somehow
   * that's breaking it completely. Those foundries are defaults from some
   * programs and totally not recommended to have inside font files. */
  return strcmp("UKWN", foundryString) != 0 // fixme: consider string_view + starts_with, more idiomatic
      && strcmp("ukwn", foundryString) != 0; // fixme: case sensitivity (can a foundry be "Uknw"?)
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed that.

Regarding UKWN and ukwn case sensitivity, I found this seeming to imply just UKWN and ukwn are possible fonttools/fontbakery#713, also https://github.com/fonttools/fontbakery/blob/c9954809500b6a2fe4b03995594b917167315ecc/Lib/fontbakery/checks/vendorspecific/googlefonts/os2.py#L104 has some other bad codes but not sure we should filter by those too since we're not having any problems related to that and seems complicating the code for nothing atm.

string_view.starts_with instead of strcmp.
@saurtron
Copy link
Collaborator Author

saurtron commented Nov 15, 2024

Ok, I got the PR tested on windows by @rhys-vdw, discord logs here.

He could confirm:

  • Fallbacks still seem to work fine (by writing 🔥 and 的 into chat)
  • The gridmenu arrows show up, while they didn't before. I think that's the "foundry fix" thing doing a similar job on windows as linux, but it could be by fontconfig being better initialized with this PR's method.

@lhog
Copy link
Collaborator

lhog commented Nov 15, 2024

What if you remove the foundry check altogether? I don't think its use was taken from any best practices, but rather from some common sense.

@lhog
Copy link
Collaborator

lhog commented Nov 15, 2024

Don't load osFontsDir with FcConfigAppFontAddDir.

Because.... ?

@saurtron
Copy link
Collaborator Author

Don't load osFontsDir with FcConfigAppFontAddDir.

Because.... ?

Initializing the config object with FcInitLoadConfigAndFonts already loads system fonts and configuration, so loading manually becomes redundant.

@saurtron
Copy link
Collaborator Author

What if you remove the foundry check altogether? I don't think its use was taken from any best practices, but rather from some common sense.

I agree, didn't want to change more than needed but if you think it's ok I'll remove it.

@saurtron
Copy link
Collaborator Author

What if you remove the foundry check altogether? I don't think its use was taken from any best practices, but rather from some common sense.

removed it

@lhog
Copy link
Collaborator

lhog commented Nov 17, 2024

Initializing the config object with FcInitLoadConfigAndFonts already loads system fonts and configuration, so loading manually becomes redundant.

I see what you mean. Probably makes sense.
Remove

char osFontsDir[8192];
#ifdef _WIN32
ExpandEnvironmentStrings("%WINDIR%\\fonts", osFontsDir, sizeof(osFontsDir)); // expands %HOME% etc.
#else
strncpy(osFontsDir, "/etc/fonts/", sizeof(osFontsDir));
#endif
and further use of osFontsDir then too, otherwise it's confusing.

@saurtron
Copy link
Collaborator Author

saurtron commented Nov 17, 2024

Remove (...) and further use of osFontsDir then too, otherwise it's confusing.

Done, all uses of osFontsDir removed now.

Also, I noticed now fontconfig wasn't really using our defined cache folder, since fontconfig sets it's own general and user caches and it was preferring the user home cache.

For now I set FcConfigEnableHome(FcFalse) before loading config since this reverts back to previous behaviour of using fontconfig inside spring dir as cache directory for the engine fontconfig usage (at least on linux where the system one is not editable by the user, I'm guessing that must also be the case nowadays for windows but can't check myself). I also changed the loop that prints the cache dir(s) since it was printing just the first directory, but there can be many.

This (setting FcConfigEnableHome to false) might also skip other user folder fonts or font configuration, but I believe this is unlikely to be a problem. The alternative is just letting fontconfig use it's default cache dirs, probably not bad either, not totally sure why we use our own cache but for now just trying to maintain behaviour as much as possible while fixing issues. (other alternative is trying to fight it to use our cache first, but I didn't see a good way to prepend a cache dir ourselves, if not by convoluting initialization quite a bit)

@lhog lhog merged commit 07dd4bc into beyond-all-reason:master Nov 24, 2024
2 checks passed
@sprunk
Copy link
Collaborator

sprunk commented Nov 24, 2024

This way system configuration is automatically loaded both on linux and windows and we won't write in user folders out of the spring dir

Is this the C:\a\_temp\msys\msys64\var\cache\fontconfig thing? Does this mean it won't get created anymore?

@saurtron
Copy link
Collaborator Author

Is this the C:\a\_temp\msys\msys64\var\cache\fontconfig thing? Does this mean it won't get created anymore?

Hmm not sure maybe that's the system cache, that's a weird path. The user cache should go somewhere in the user folder and that's the one I disabled. If you run this you should see the cache dirs printed on engines infolog.txt. I'll try to get some log from windows as well to check.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants