mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-12 19:18:20 +00:00
Merge pull request #9185 from Robyt3/Client-Font-Error
Improve error handling on invalid fonts and font index
This commit is contained in:
commit
0f91b1287d
|
@ -615,37 +615,65 @@ public:
|
|||
void AddFace(FT_Face Face)
|
||||
{
|
||||
m_vFtFaces.push_back(Face);
|
||||
if(!m_DefaultFace)
|
||||
m_DefaultFace = Face;
|
||||
}
|
||||
|
||||
void SetDefaultFaceByName(const char *pFamilyName)
|
||||
bool SetDefaultFaceByName(const char *pFamilyName)
|
||||
{
|
||||
m_DefaultFace = GetFaceByName(pFamilyName);
|
||||
if(!m_DefaultFace)
|
||||
{
|
||||
if(!m_vFtFaces.empty())
|
||||
{
|
||||
m_DefaultFace = m_vFtFaces.front();
|
||||
}
|
||||
log_error("textrender", "The default font face '%s' could not be found", pFamilyName);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetIconFaceByName(const char *pFamilyName)
|
||||
bool SetIconFaceByName(const char *pFamilyName)
|
||||
{
|
||||
m_IconFace = GetFaceByName(pFamilyName);
|
||||
if(!m_IconFace)
|
||||
{
|
||||
log_error("textrender", "The icon font face '%s' could not be found", pFamilyName);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AddFallbackFaceByName(const char *pFamilyName)
|
||||
bool AddFallbackFaceByName(const char *pFamilyName)
|
||||
{
|
||||
FT_Face Face = GetFaceByName(pFamilyName);
|
||||
if(Face != nullptr && std::find(m_vFallbackFaces.begin(), m_vFallbackFaces.end(), Face) == m_vFallbackFaces.end())
|
||||
if(!Face)
|
||||
{
|
||||
m_vFallbackFaces.push_back(Face);
|
||||
log_error("textrender", "The fallback font face '%s' could not be found", pFamilyName);
|
||||
return false;
|
||||
}
|
||||
if(std::find(m_vFallbackFaces.begin(), m_vFallbackFaces.end(), Face) != m_vFallbackFaces.end())
|
||||
{
|
||||
log_warn("textrender", "The fallback font face '%s' was specified multiple times", pFamilyName);
|
||||
return true;
|
||||
}
|
||||
m_vFallbackFaces.push_back(Face);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetVariantFaceByName(const char *pFamilyName)
|
||||
bool SetVariantFaceByName(const char *pFamilyName)
|
||||
{
|
||||
FT_Face Face = GetFaceByName(pFamilyName);
|
||||
if(m_VariantFace != Face)
|
||||
{
|
||||
m_VariantFace = Face;
|
||||
Clear(); // rebuild atlas after changing variant font
|
||||
if(!Face && pFamilyName != nullptr)
|
||||
{
|
||||
log_error("textrender", "The variant font face '%s' could not be found", pFamilyName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetFontPreset(EFontPreset FontPreset)
|
||||
|
@ -1002,9 +1030,7 @@ class CTextRender : public IEngineTextRender
|
|||
FT_Error CollectionLoadError = FT_New_Memory_Face(m_FTLibrary, pFontData, FontDataSize, -1, &FtFace);
|
||||
if(CollectionLoadError)
|
||||
{
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "Failed to load font file '%s': %s", pFontName, FT_Error_String(CollectionLoadError));
|
||||
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "textrender", aBuf);
|
||||
log_error("textrender", "Failed to load font file '%s': %s", pFontName, FT_Error_String(CollectionLoadError));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1017,26 +1043,20 @@ class CTextRender : public IEngineTextRender
|
|||
FT_Error FaceLoadError = FT_New_Memory_Face(m_FTLibrary, pFontData, FontDataSize, FaceIndex, &FtFace);
|
||||
if(FaceLoadError)
|
||||
{
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "Failed to load font face %ld from font file '%s': %s", FaceIndex, pFontName, FT_Error_String(FaceLoadError));
|
||||
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "textrender", aBuf);
|
||||
log_error("textrender", "Failed to load font face %ld from font file '%s': %s", FaceIndex, pFontName, FT_Error_String(FaceLoadError));
|
||||
FT_Done_Face(FtFace);
|
||||
continue;
|
||||
}
|
||||
|
||||
m_pGlyphMap->AddFace(FtFace);
|
||||
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "Loaded font face %ld '%s %s' from font file '%s'", FaceIndex, FtFace->family_name, FtFace->style_name, pFontName);
|
||||
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "textrender", aBuf);
|
||||
log_debug("textrender", "Loaded font face %ld '%s %s' from font file '%s'", FaceIndex, FtFace->family_name, FtFace->style_name, pFontName);
|
||||
LoadedAny = true;
|
||||
}
|
||||
|
||||
if(!LoadedAny)
|
||||
{
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "Failed to load font file '%s': no font faces could be loaded", pFontName);
|
||||
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "textrender", aBuf);
|
||||
log_error("textrender", "Failed to load font file '%s': no font faces could be loaded", pFontName);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1083,9 +1103,7 @@ public:
|
|||
{
|
||||
int LMajor, LMinor, LPatch;
|
||||
FT_Library_Version(m_FTLibrary, &LMajor, &LMinor, &LPatch);
|
||||
char aFreetypeVersion[128];
|
||||
str_format(aFreetypeVersion, sizeof(aFreetypeVersion), "Freetype version %d.%d.%d (compiled = %d.%d.%d)", LMajor, LMinor, LPatch, FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH);
|
||||
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "textrender", aFreetypeVersion);
|
||||
log_info("textrender", "Freetype version %d.%d.%d (compiled = %d.%d.%d)", LMajor, LMinor, LPatch, FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH);
|
||||
}
|
||||
|
||||
m_FirstFreeTextContainerIndex = -1;
|
||||
|
@ -1142,7 +1160,7 @@ public:
|
|||
m_pStorage = nullptr;
|
||||
}
|
||||
|
||||
void LoadFonts() override
|
||||
bool LoadFonts() override
|
||||
{
|
||||
// read file data into buffer
|
||||
const char *pFilename = "fonts/index.json";
|
||||
|
@ -1150,10 +1168,8 @@ public:
|
|||
unsigned JsonFileSize;
|
||||
if(!Storage()->ReadFile(pFilename, IStorage::TYPE_ALL, &pFileData, &JsonFileSize))
|
||||
{
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "Failed to open/read font index file '%s'", pFilename);
|
||||
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "textrender", aBuf);
|
||||
return;
|
||||
log_error("textrender", "Failed to open/read font index file '%s'", pFilename);
|
||||
return false;
|
||||
}
|
||||
|
||||
// parse json data
|
||||
|
@ -1163,11 +1179,16 @@ public:
|
|||
free(pFileData);
|
||||
if(pJsonData == nullptr)
|
||||
{
|
||||
char aBuf[512];
|
||||
str_format(aBuf, sizeof(aBuf), "Failed to parse font index file '%s': %s", pFilename, aError);
|
||||
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "textrender", aBuf);
|
||||
return;
|
||||
log_error("textrender", "Failed to parse font index file '%s': %s", pFilename, aError);
|
||||
return false;
|
||||
}
|
||||
if(pJsonData->type != json_object)
|
||||
{
|
||||
log_error("textrender", "Font index malformed: root must be an object", pFilename, aError);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Success = true;
|
||||
|
||||
// extract font file definitions
|
||||
const json_value &FontFiles = (*pJsonData)["font files"];
|
||||
|
@ -1176,7 +1197,11 @@ public:
|
|||
for(unsigned FontFileIndex = 0; FontFileIndex < FontFiles.u.array.length; ++FontFileIndex)
|
||||
{
|
||||
if(FontFiles[FontFileIndex].type != json_string)
|
||||
{
|
||||
log_error("textrender", "Font index malformed: 'font files' must be an array of strings (error at index %d)", FontFileIndex);
|
||||
Success = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
char aFontName[IO_MAX_PATH_LENGTH];
|
||||
str_format(aFontName, sizeof(aFontName), "fonts/%s", FontFiles[FontFileIndex].u.string.ptr);
|
||||
|
@ -1193,32 +1218,60 @@ public:
|
|||
free(pFontData);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error("textrender", "Failed to open/read font file '%s'", aFontName);
|
||||
Success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error("textrender", "Font index malformed: 'font files' must be an array");
|
||||
Success = false;
|
||||
}
|
||||
|
||||
// extract default family name
|
||||
const json_value &DefaultFace = (*pJsonData)["default"];
|
||||
if(DefaultFace.type == json_string)
|
||||
{
|
||||
m_pGlyphMap->SetDefaultFaceByName(DefaultFace.u.string.ptr);
|
||||
if(!m_pGlyphMap->SetDefaultFaceByName(DefaultFace.u.string.ptr))
|
||||
{
|
||||
Success = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error("textrender", "Font index malformed: 'default' must be a string");
|
||||
Success = false;
|
||||
}
|
||||
|
||||
// extract language variant family names
|
||||
const json_value &Variants = (*pJsonData)["language variants"];
|
||||
if(Variants.type == json_object)
|
||||
{
|
||||
m_vVariants.resize(Variants.u.object.length);
|
||||
m_vVariants.reserve(Variants.u.object.length);
|
||||
for(size_t i = 0; i < Variants.u.object.length; ++i)
|
||||
{
|
||||
str_format(m_vVariants[i].m_aLanguageFile, sizeof(m_vVariants[i].m_aLanguageFile), "languages/%s.txt", Variants.u.object.values[i].name);
|
||||
|
||||
const json_value *pFamilyName = Variants.u.object.values[i].value;
|
||||
if(pFamilyName->type == json_string)
|
||||
str_copy(m_vVariants[i].m_aFamilyName, pFamilyName->u.string.ptr);
|
||||
else
|
||||
m_vVariants[i].m_aFamilyName[0] = '\0';
|
||||
if(pFamilyName->type != json_string)
|
||||
{
|
||||
log_error("textrender", "Font index malformed: 'language variants' entries must have string values (error on entry '%s')", Variants.u.object.values[i].name);
|
||||
Success = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
SFontLanguageVariant Variant;
|
||||
str_format(Variant.m_aLanguageFile, sizeof(Variant.m_aLanguageFile), "languages/%s.txt", Variants.u.object.values[i].name);
|
||||
str_copy(Variant.m_aFamilyName, pFamilyName->u.string.ptr);
|
||||
m_vVariants.emplace_back(Variant);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error("textrender", "Font index malformed: 'language variants' must be an array");
|
||||
Success = false;
|
||||
}
|
||||
|
||||
// extract fallback family names
|
||||
const json_value &FallbackFaces = (*pJsonData)["fallbacks"];
|
||||
|
@ -1226,21 +1279,41 @@ public:
|
|||
{
|
||||
for(unsigned i = 0; i < FallbackFaces.u.array.length; ++i)
|
||||
{
|
||||
if(FallbackFaces[i].type == json_string)
|
||||
if(FallbackFaces[i].type != json_string)
|
||||
{
|
||||
m_pGlyphMap->AddFallbackFaceByName(FallbackFaces[i].u.string.ptr);
|
||||
log_error("textrender", "Font index malformed: 'fallbacks' must be an array of strings (error at index %d)", i);
|
||||
Success = false;
|
||||
continue;
|
||||
}
|
||||
if(!m_pGlyphMap->AddFallbackFaceByName(FallbackFaces[i].u.string.ptr))
|
||||
{
|
||||
Success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error("textrender", "Font index malformed: 'fallbacks' must be an array");
|
||||
Success = false;
|
||||
}
|
||||
|
||||
// extract icon font family name
|
||||
const json_value &IconFace = (*pJsonData)["icon"];
|
||||
if(IconFace.type == json_string)
|
||||
{
|
||||
m_pGlyphMap->SetIconFaceByName(IconFace.u.string.ptr);
|
||||
if(!m_pGlyphMap->SetIconFaceByName(IconFace.u.string.ptr))
|
||||
{
|
||||
Success = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error("textrender", "Font index malformed: 'icon' must be a string");
|
||||
Success = false;
|
||||
}
|
||||
|
||||
json_value_free(pJsonData);
|
||||
return Success;
|
||||
}
|
||||
|
||||
void SetFontPreset(EFontPreset FontPreset) override
|
||||
|
|
|
@ -316,7 +316,7 @@ public:
|
|||
virtual void MoveCursor(CTextCursor *pCursor, float x, float y) const = 0;
|
||||
virtual void SetCursorPosition(CTextCursor *pCursor, float x, float y) const = 0;
|
||||
|
||||
virtual void LoadFonts() = 0;
|
||||
virtual bool LoadFonts() = 0;
|
||||
virtual void SetFontPreset(EFontPreset FontPreset) = 0;
|
||||
virtual void SetFontLanguageVariant(const char *pLanguageFile) = 0;
|
||||
|
||||
|
|
|
@ -328,7 +328,10 @@ void CGameClient::OnInit()
|
|||
for(int i = 0; i < OLD_NUM_NETOBJTYPES; i++)
|
||||
Client()->SnapSetStaticsize7(i, m_NetObjHandler7.GetObjSize(i));
|
||||
|
||||
TextRender()->LoadFonts();
|
||||
if(!TextRender()->LoadFonts())
|
||||
{
|
||||
Client()->AddWarning(SWarning(Localize("Some fonts could not be loaded. Check the local console for details.")));
|
||||
}
|
||||
TextRender()->SetFontLanguageVariant(g_Config.m_ClLanguagefile);
|
||||
|
||||
// update and swap after font loading, they are quite huge
|
||||
|
|
Loading…
Reference in a new issue