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

Fontconfig: Make init and teardown more robust. #1793

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
161 changes: 78 additions & 83 deletions rts/Rendering/Fonts/CFontTexture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,56 +89,23 @@ class FtLibraryHandler {
: config(nullptr)
, lib(nullptr)
{
{
const FT_Error error = FT_Init_FreeType(&lib);
const FT_Error error = FT_Init_FreeType(&lib);

if (error != 0) {
FT_Int version[3];
FT_Library_Version(lib, &version[0], &version[1], &version[2]);

std::string msg = fmt::sprintf("%s::FreeTypeInit (version %d.%d.%d)", __func__, version[0], version[1], version[2]);
std::string err = fmt::sprintf("[%s] FT_Init_FreeType failure \"%s\"", __func__, GetFTError(error));

if (error != 0)
throw std::runtime_error(err);
}

#ifdef USE_FONTCONFIG
if (!UseFontConfig())
return;

{
std::string msg = fmt::sprintf("%s::FontConfigInit (version %d.%d.%d)", __func__, FC_MAJOR, FC_MINOR, FC_REVISION);
ScopedOnceTimer timer(msg);
ZoneScopedNC("FtLibraryHandler::FontConfigInit", tracy::Color::Purple);

try
{
FcInit();
} catch (const std::exception& e) {
LOG("FcInit() runtime error: \"%s\"", e.what());
config = nullptr;
return;
}

FcConfigEnableHome(FcFalse);
config = FcInitLoadConfigAndFonts();
if (!config)
return;

static constexpr const char* cacheDirFmt = R"(<fontconfig><cachedir>fontcache</cachedir></fontconfig>)";
if (!FcConfigParseAndLoadFromMemory(config, reinterpret_cast<const FcChar8*>(cacheDirFmt), FcTrue)) {
FcConfigDestroy(config);
config = nullptr;
}
std::string err = fmt::sprintf("[%s] FT_Init_FreeType failure (version %d.%d.%d) \"%s\"",
__func__, version[0], version[1], version[2], GetFTError(error));
throw std::runtime_error(err);
}
#endif
}

~FtLibraryHandler() {
FT_Done_FreeType(lib);

#ifdef USE_FONTCONFIG
if (!UseFontConfig())
if (!config)
return;

FcConfigDestroy(config);
Expand All @@ -147,22 +114,8 @@ class FtLibraryHandler {
#endif
}

// reduced set of fonts
// not called if FcInit() fails
static bool CheckGenFontConfigFast() {
FcConfigAppFontClear(GetFCConfig());
if (!FcConfigAppFontAddDir(GetFCConfig(), reinterpret_cast<const FcChar8*>("fonts")))
return false;

if (!FtLibraryHandler::CheckFontConfig()) {
return FcConfigBuildFonts(GetFCConfig());
}

return true;
}

static bool CheckGenFontConfigFull(bool console) {
#ifndef HEADLESS
bool InitFontconfig(bool console) {
#ifdef USE_FONTCONFIG
auto LOG_MSG = [console](const std::string& fmt, bool isError, auto&&... args) {
if (console) {
std::string fmtNL = fmt + "\n";
Expand All @@ -178,36 +131,88 @@ class FtLibraryHandler {
}
};

if (!FtLibraryHandler::CanUseFontConfig()) {
LOG_MSG("[%s] Fontconfig(version %d.%d.%d) failed to initialize", true, __func__, FC_MAJOR, FC_MINOR, FC_REVISION);
if (!UseFontConfig())
return false;
}

FcConfigAppFontClear(GetFCConfig());
FcConfigAppFontAddDir(GetFCConfig(), reinterpret_cast<const FcChar8*>("fonts"));

{
auto dirs = FcConfigGetCacheDirs(GetFCConfig());
std::string msg = fmt::sprintf("%s::FontConfigInit (version %d.%d.%d)", __func__, FC_MAJOR, FC_MINOR, FC_REVISION);
ScopedOnceTimer timer(msg);
ZoneScopedNC("FtLibraryHandler::FontConfigInit", tracy::Color::Purple);

FcBool res;
std::string errprefix = fmt::sprintf("[%s] Fontconfig(version %d.%d.%d) failed to initialize", __func__, FC_MAJOR, FC_MINOR, FC_REVISION);

// init configuration
FcConfigEnableHome(FcFalse);
config = FcConfigCreate();

static constexpr const char* cacheDirFmt = R"(<fontconfig><cachedir>fontcache</cachedir></fontconfig>)";

// Load system configuration.
// passing 0 here so fc will use the default os config file if possible.
res = FcConfigParseAndLoad(config, 0, true);
if (res) {
LOG_MSG("[%s] Using Fontconfig light init", false, __func__);

// add local cache in front
FcConfigParseAndLoadFromMemory(config, reinterpret_cast<const FcChar8*>(cacheDirFmt), FcTrue);

// build system fonts
res = FcConfigBuildFonts(config);
if (!res) {
LOG_MSG("%s fonts", true, errprefix.c_str());
InitFailed();
return false;
}
} else {
// Can't load step by step to use our cache, so retry with general
// fontconfig init method, that has a few extra fallbacks.
// this path is actually taken by windows.

// Init everything. Normally this would be enough, but the method before
// accounts for situations where system config is borked due to incompatible
// lib and system config files.
FcConfig *fcConfig = FcInitLoadConfigAndFonts();
if (fcConfig) {
FcConfigDestroy(config); // release previous config
config = fcConfig;

// add our cache at the back of the new config.
FcConfigParseAndLoadFromMemory(config, reinterpret_cast<const FcChar8*>(cacheDirFmt), FcTrue);
} else {
LOG_MSG("%s config and fonts. No system fallbacks will be available", false, errprefix.c_str());
}
}

// init app fonts dir
res = FcConfigAppFontAddDir(config, reinterpret_cast<const FcChar8*>("fonts"));
if (!res) {
LOG_MSG("%s font dir", true, errprefix.c_str());
InitFailed();
return false;
}

// print cache dirs
auto dirs = FcConfigGetCacheDirs(config);
FcStrListFirst(dirs);
for (FcChar8* dir = FcStrListNext(dirs); dir != nullptr; dir = FcStrListNext(dirs)) {
LOG_MSG("[%s] Using Fontconfig cache dir \"%s\"", false, __func__, dir);
}
FcStrListDone(dirs);
}

if (FtLibraryHandler::CheckFontConfig()) {
LOG_MSG("[%s] fontconfig up to date", false, __func__);
return true;
}

LOG_MSG("[%s] creating fontconfig", false, __func__);

return FcConfigBuildFonts(GetFCConfig());
#endif
#endif // USE_FONTCONFIG

return true;
}

void InitFailed() {
FcConfigDestroy(config);
FcFini();
config = nullptr;
}
static bool InitSingletonFontconfig(bool console) { return singleton->InitFontconfig(console); }

static bool UseFontConfig() { return (configHandler == nullptr || configHandler->GetBool("UseFontConfigLib")); }

#ifdef USE_FONTCONFIG
Expand Down Expand Up @@ -252,21 +257,11 @@ void FtLibraryHandlerProxy::InitFtLibrary()
#endif
}

bool FtLibraryHandlerProxy::CheckGenFontConfigFast()
{
RECOIL_DETAILED_TRACY_ZONE;
#ifndef HEADLESS
return FtLibraryHandler::CheckGenFontConfigFast();
#else
return false;
#endif
}

bool FtLibraryHandlerProxy::CheckGenFontConfigFull(bool console)
bool FtLibraryHandlerProxy::InitFontconfig(bool console)
{
RECOIL_DETAILED_TRACY_ZONE;
#ifndef HEADLESS
return FtLibraryHandler::CheckGenFontConfigFull(console);
return FtLibraryHandler::InitSingletonFontconfig(console);
#else
return false;
#endif
Expand Down
3 changes: 1 addition & 2 deletions rts/Rendering/Fonts/CFontTexture.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ class CBitmap;
class FtLibraryHandlerProxy {
public:
static void InitFtLibrary();
static bool CheckGenFontConfigFast();
static bool CheckGenFontConfigFull(bool console);
static bool InitFontconfig(bool console);
};


Expand Down
6 changes: 3 additions & 3 deletions rts/System/SpringApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,9 +329,9 @@ bool SpringApp::InitPlatformLibs()
bool SpringApp::InitFonts()
{
FtLibraryHandlerProxy::InitFtLibrary();
FtLibraryHandlerProxy::CheckGenFontConfigFast();
FtLibraryHandlerProxy::InitFontconfig(false);
CFontTexture::InitFonts();
return CglFont::LoadConfigFonts() && FtLibraryHandlerProxy::CheckGenFontConfigFull(false);
return CglFont::LoadConfigFonts();
/*
using namespace std::chrono_literals;
auto future = std::async(std::launch::async, []() {
Expand Down Expand Up @@ -478,7 +478,7 @@ void SpringApp::ParseCmdLine(int argc, char* argv[])
spring_time::setstarttime(spring_time::gettime(true));
}
FtLibraryHandlerProxy::InitFtLibrary();
if (FtLibraryHandlerProxy::CheckGenFontConfigFull(true)) {
if (FtLibraryHandlerProxy::InitFontconfig(true)) {
printf("[FtLibraryHandler::GenFontConfig] is succesfull\n");
exit(spring::EXIT_CODE_SUCCESS);
}
Expand Down