From d8fd346e3320da3dc8d8b4a23737371a2ddbf676 Mon Sep 17 00:00:00 2001 From: Felipe Keller Braz Date: Wed, 20 May 2026 11:00:25 -0300 Subject: [PATCH] fix(fonts): add unicode fallback for cyrillic Improve AlternateUnicodeFont resolution on macOS/Linux by trying configured Unicode font first and then a deterministic fallback list of common system fonts. Also update the May 2026 dev diary before commit as required by project workflow. Fixes #144 --- .../W3DDevice/GameClient/GUI/W3DGameFont.cpp | 43 ++++++++++++++++++- .../W3DDevice/GameClient/GUI/W3DGameFont.cpp | 43 ++++++++++++++++++- docs/DEV_BLOG/2026-05-DIARY.md | 19 ++++++++ 3 files changed, 101 insertions(+), 4 deletions(-) diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/GUI/W3DGameFont.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/GUI/W3DGameFont.cpp index c90931db767..0e26a5836fc 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/GUI/W3DGameFont.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/GUI/W3DGameFont.cpp @@ -54,6 +54,46 @@ #include "WW3D2/render2dsentence.h" #include "GameClient/GlobalLanguage.h" +namespace +{ +// GeneralsX @bugfix GitHubCopilot 20/05/2026 Resolve a usable Unicode fallback font on macOS/Linux when localized font names are unavailable. +FontCharsClass *LoadUnicodeFallbackFont(Int size, Bool bold) +{ + const char *preferred_name = nullptr; + if (TheGlobalLanguageData && TheGlobalLanguageData->m_unicodeFontName.isNotEmpty()) { + preferred_name = TheGlobalLanguageData->m_unicodeFontName.str(); + } + + if (preferred_name != nullptr) { + FontCharsClass *font = WW3DAssetManager::Get_Instance()->Get_FontChars(preferred_name, size, bold); + if (font != nullptr) { + return font; + } + } + + static const char *kFallbackUnicodeFonts[] = { + "Arial Unicode MS", + "Arial Unicode", + "Arial", + "Helvetica Neue", + "Helvetica", + "Noto Sans", + "Noto Sans CJK SC", + "Noto Sans CJK JP", + "DejaVu Sans" + }; + + for (const char *font_name : kFallbackUnicodeFonts) { + FontCharsClass *font = WW3DAssetManager::Get_Instance()->Get_FontChars(font_name, size, bold); + if (font != nullptr) { + return font; + } + } + + return nullptr; +} +} + // DEFINES //////////////////////////////////////////////////////////////////// // PRIVATE TYPES ////////////////////////////////////////////////////////////// @@ -95,8 +135,7 @@ Bool W3DFontLibrary::loadFontData( GameFont *font ) font->height = fontChar->Get_Char_Height(); // load Unicode of same point size - name = TheGlobalLanguageData ? TheGlobalLanguageData->m_unicodeFontName.str() : "Arial Unicode MS"; - fontChar->AlternateUnicodeFont = WW3DAssetManager::Get_Instance()->Get_FontChars( name, size, bold ); + fontChar->AlternateUnicodeFont = LoadUnicodeFallbackFont(size, bold); return TRUE; } diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/GUI/W3DGameFont.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/GUI/W3DGameFont.cpp index b91335f4e89..d69b3e8a051 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/GUI/W3DGameFont.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/GUI/W3DGameFont.cpp @@ -54,6 +54,46 @@ #include "WW3D2/render2dsentence.h" #include "GameClient/GlobalLanguage.h" +namespace +{ +// GeneralsX @bugfix GitHubCopilot 20/05/2026 Resolve a usable Unicode fallback font on macOS/Linux when localized font names are unavailable. +FontCharsClass *LoadUnicodeFallbackFont(Int size, Bool bold) +{ + const char *preferred_name = nullptr; + if (TheGlobalLanguageData && TheGlobalLanguageData->m_unicodeFontName.isNotEmpty()) { + preferred_name = TheGlobalLanguageData->m_unicodeFontName.str(); + } + + if (preferred_name != nullptr) { + FontCharsClass *font = WW3DAssetManager::Get_Instance()->Get_FontChars(preferred_name, size, bold); + if (font != nullptr) { + return font; + } + } + + static const char *kFallbackUnicodeFonts[] = { + "Arial Unicode MS", + "Arial Unicode", + "Arial", + "Helvetica Neue", + "Helvetica", + "Noto Sans", + "Noto Sans CJK SC", + "Noto Sans CJK JP", + "DejaVu Sans" + }; + + for (const char *font_name : kFallbackUnicodeFonts) { + FontCharsClass *font = WW3DAssetManager::Get_Instance()->Get_FontChars(font_name, size, bold); + if (font != nullptr) { + return font; + } + } + + return nullptr; +} +} + // DEFINES //////////////////////////////////////////////////////////////////// // PRIVATE TYPES ////////////////////////////////////////////////////////////// @@ -95,8 +135,7 @@ Bool W3DFontLibrary::loadFontData( GameFont *font ) font->height = fontChar->Get_Char_Height(); // load Unicode of same point size - name = TheGlobalLanguageData ? TheGlobalLanguageData->m_unicodeFontName.str() : "Arial Unicode MS"; - fontChar->AlternateUnicodeFont = WW3DAssetManager::Get_Instance()->Get_FontChars( name, size, bold ); + fontChar->AlternateUnicodeFont = LoadUnicodeFallbackFont(size, bold); return TRUE; } diff --git a/docs/DEV_BLOG/2026-05-DIARY.md b/docs/DEV_BLOG/2026-05-DIARY.md index 8a024d42ae7..1178317981c 100644 --- a/docs/DEV_BLOG/2026-05-DIARY.md +++ b/docs/DEV_BLOG/2026-05-DIARY.md @@ -2,6 +2,25 @@ --- +## 2026-05-20: Start fix for macOS Cyrillic labels missing (Issue #144) + +Started implementation for Issue #144 after confirming reproduction details and +scope from the issue thread were sufficient to proceed without extra blockers. + +What was done: +- created branch `fix/issue-144-macos-cyrillic-text`. +- implemented robust Unicode fallback font resolution in both game targets: + - `GeneralsMD/.../W3DGameFont.cpp` + - `Generals/.../W3DGameFont.cpp` +- replaced direct single-font lookup for `AlternateUnicodeFont` with a fallback + chain that first tries localized configured Unicode font, then common system + fonts available on macOS/Linux (Arial/Helvetica/Noto/DejaVu families). +- kept behavior isolated to font loading path only; no gameplay logic touched. + +Validation: +- `[Platform] Build GeneralsXZH` completed successfully after the change. +- no diagnostics errors were reported in the edited font source files. + ## 2026-05-18: CI migration to macOS + Flatpak with Linux replay in Flatpak Migrated CI to keep only macOS and Linux Flatpak builds, and switched Linux