mirror of
https://github.com/JGRennison/OpenTTD-patches.git
synced 2024-11-11 13:10:45 +00:00
(svn r21298) -Fix [FS#4261]: fonts set in openttd.cfg were not properly checked for missing glyphs on language change
This commit is contained in:
parent
6625fd3073
commit
9904cb7372
@ -290,6 +290,7 @@ err1:
|
|||||||
struct EFCParam {
|
struct EFCParam {
|
||||||
FreeTypeSettings *settings;
|
FreeTypeSettings *settings;
|
||||||
LOCALESIGNATURE locale;
|
LOCALESIGNATURE locale;
|
||||||
|
SetFallbackFontCallback *callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXTMETRICEX *metric, DWORD type, LPARAM lParam)
|
static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXTMETRICEX *metric, DWORD type, LPARAM lParam)
|
||||||
@ -346,14 +347,15 @@ static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXT
|
|||||||
|
|
||||||
if (!found) return 1;
|
if (!found) return 1;
|
||||||
|
|
||||||
DEBUG(freetype, 1, "Fallback font: %s (%s)", font_name, english_name);
|
|
||||||
strecpy(info->settings->small_font, font_name, lastof(info->settings->small_font));
|
strecpy(info->settings->small_font, font_name, lastof(info->settings->small_font));
|
||||||
strecpy(info->settings->medium_font, font_name, lastof(info->settings->medium_font));
|
strecpy(info->settings->medium_font, font_name, lastof(info->settings->medium_font));
|
||||||
strecpy(info->settings->large_font, font_name, lastof(info->settings->large_font));
|
strecpy(info->settings->large_font, font_name, lastof(info->settings->large_font));
|
||||||
|
if (info->callback(NULL)) return 1;
|
||||||
|
DEBUG(freetype, 1, "Fallback font: %s (%s)", font_name, english_name);
|
||||||
return 0; // stop enumerating
|
return 0; // stop enumerating
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, const char *str)
|
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, SetFallbackFontCallback *callback)
|
||||||
{
|
{
|
||||||
DEBUG(freetype, 1, "Trying fallback fonts");
|
DEBUG(freetype, 1, "Trying fallback fonts");
|
||||||
EFCParam langInfo;
|
EFCParam langInfo;
|
||||||
@ -363,6 +365,7 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
langInfo.settings = settings;
|
langInfo.settings = settings;
|
||||||
|
langInfo.callback = callback;
|
||||||
|
|
||||||
LOGFONT font;
|
LOGFONT font;
|
||||||
/* Enumerate all fonts. */
|
/* Enumerate all fonts. */
|
||||||
@ -426,10 +429,13 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, const char *str)
|
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, SetFallbackFontCallback *callback)
|
||||||
{
|
{
|
||||||
|
const char *str;
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
|
callback(&str);
|
||||||
|
|
||||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
|
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
|
||||||
if (MacOSVersionIsAtLeast(10, 5, 0)) {
|
if (MacOSVersionIsAtLeast(10, 5, 0)) {
|
||||||
/* Determine fallback font using CoreText. This uses the language isocode
|
/* Determine fallback font using CoreText. This uses the language isocode
|
||||||
@ -604,6 +610,7 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callback(NULL);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -677,7 +684,7 @@ static FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, const char *str)
|
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, SetFallbackFontCallback *callback)
|
||||||
{
|
{
|
||||||
if (!FcInit()) return false;
|
if (!FcInit()) return false;
|
||||||
|
|
||||||
@ -687,63 +694,55 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i
|
|||||||
* 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 _. */
|
||||||
char lang[16];
|
char lang[16];
|
||||||
strecpy(lang, language_isocode, lastof(lang));
|
seprintf(lang, lastof(lang), ":lang=%s", language_isocode);
|
||||||
char *split = strchr(lang, '_');
|
char *split = strchr(lang, '_');
|
||||||
if (split != NULL) *split = '\0';
|
if (split != NULL) *split = '\0';
|
||||||
|
|
||||||
FcPattern *pat;
|
/* First create a pattern to match the wanted language. */
|
||||||
FcPattern *match;
|
FcPattern *pat = FcNameParse((FcChar8*)lang);
|
||||||
FcResult result;
|
/* We only want to know the filename. */
|
||||||
FcChar8 *file;
|
FcObjectSet *os = FcObjectSetBuild(FC_FILE, NULL);
|
||||||
FcFontSet *fs;
|
/* Get the list of filenames matching the wanted language. */
|
||||||
FcValue val;
|
FcFontSet *fs = FcFontList(NULL, pat, os);
|
||||||
val.type = FcTypeString;
|
|
||||||
val.u.s = (FcChar8*)lang;
|
|
||||||
|
|
||||||
/* First create a pattern to match the wanted language */
|
/* We don't need these anymore. */
|
||||||
pat = FcPatternCreate();
|
FcObjectSetDestroy(os);
|
||||||
/* And fill it with the language and other defaults */
|
FcPatternDestroy(pat);
|
||||||
if (pat == NULL ||
|
|
||||||
!FcPatternAdd(pat, "lang", val, false) ||
|
if (fs != NULL) {
|
||||||
!FcConfigSubstitute(0, pat, FcMatchPattern)) {
|
for (int i = 0; i < fs->nfont; i++) {
|
||||||
goto error_pattern;
|
FcPattern *font = fs->fonts[i];
|
||||||
|
|
||||||
|
FcChar8 *file = NULL;
|
||||||
|
FcResult res = FcPatternGetString(font, FC_FILE, 0, &file);
|
||||||
|
if (res != FcResultMatch || file == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
strecpy(settings->small_font, (const char*)file, lastof(settings->small_font));
|
||||||
|
strecpy(settings->medium_font, (const char*)file, lastof(settings->medium_font));
|
||||||
|
strecpy(settings->large_font, (const char*)file, lastof(settings->large_font));
|
||||||
|
|
||||||
|
bool missing = callback(NULL);
|
||||||
|
DEBUG(freetype, 1, "Font \"%s\" misses%s glyphs", file, missing ? "" : " no");
|
||||||
|
|
||||||
|
if (!missing) {
|
||||||
|
ret = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clean up the list of filenames. */
|
||||||
|
FcFontSetDestroy(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
FcDefaultSubstitute(pat);
|
|
||||||
|
|
||||||
/* Then create a font set and match that */
|
|
||||||
match = FcFontMatch(0, pat, &result);
|
|
||||||
|
|
||||||
if (match == NULL) {
|
|
||||||
goto error_pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find all fonts that do match */
|
|
||||||
fs = FcFontSetCreate();
|
|
||||||
FcFontSetAdd(fs, match);
|
|
||||||
|
|
||||||
/* And take the first, if it exists */
|
|
||||||
if (fs->nfont <= 0 || FcPatternGetString(fs->fonts[0], FC_FILE, 0, &file)) {
|
|
||||||
goto error_fontset;
|
|
||||||
}
|
|
||||||
|
|
||||||
strecpy(settings->small_font, (const char*)file, lastof(settings->small_font));
|
|
||||||
strecpy(settings->medium_font, (const char*)file, lastof(settings->medium_font));
|
|
||||||
strecpy(settings->large_font, (const char*)file, lastof(settings->large_font));
|
|
||||||
|
|
||||||
ret = true;
|
|
||||||
|
|
||||||
error_fontset:
|
|
||||||
FcFontSetDestroy(fs);
|
|
||||||
error_pattern:
|
|
||||||
if (pat != NULL) FcPatternDestroy(pat);
|
|
||||||
FcFini();
|
FcFini();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* without WITH_FONTCONFIG */
|
#else /* without WITH_FONTCONFIG */
|
||||||
FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) {return FT_Err_Cannot_Open_Resource;}
|
FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) {return FT_Err_Cannot_Open_Resource;}
|
||||||
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, const char *str) { return false; }
|
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, SetFallbackFontCallback *callback) { return false }
|
||||||
#endif /* WITH_FONTCONFIG */
|
#endif /* WITH_FONTCONFIG */
|
||||||
|
|
||||||
static void SetFontGeometry(FT_Face face, FontSize size, int pixels)
|
static void SetFontGeometry(FT_Face face, FontSize size, int pixels)
|
||||||
@ -891,6 +890,7 @@ static FT_Face GetFontFace(FontSize size)
|
|||||||
struct GlyphEntry {
|
struct GlyphEntry {
|
||||||
Sprite *sprite;
|
Sprite *sprite;
|
||||||
byte width;
|
byte width;
|
||||||
|
bool duplicate;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -918,6 +918,7 @@ static void ResetGlyphCache()
|
|||||||
if (_glyph_ptr[i][j] == NULL) continue;
|
if (_glyph_ptr[i][j] == NULL) continue;
|
||||||
|
|
||||||
for (int k = 0; k < 256; k++) {
|
for (int k = 0; k < 256; k++) {
|
||||||
|
if (_glyph_ptr[i][j][k].duplicate) continue;
|
||||||
free(_glyph_ptr[i][j][k].sprite);
|
free(_glyph_ptr[i][j][k].sprite);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -937,7 +938,7 @@ static GlyphEntry *GetGlyphPtr(FontSize size, WChar key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void SetGlyphPtr(FontSize size, WChar key, const GlyphEntry *glyph)
|
static void SetGlyphPtr(FontSize size, WChar key, const GlyphEntry *glyph, bool duplicate = false)
|
||||||
{
|
{
|
||||||
if (_glyph_ptr[size] == NULL) {
|
if (_glyph_ptr[size] == NULL) {
|
||||||
DEBUG(freetype, 3, "Allocating root glyph cache for size %u", size);
|
DEBUG(freetype, 3, "Allocating root glyph cache for size %u", size);
|
||||||
@ -950,8 +951,9 @@ static void SetGlyphPtr(FontSize size, WChar key, const GlyphEntry *glyph)
|
|||||||
}
|
}
|
||||||
|
|
||||||
DEBUG(freetype, 4, "Set glyph for unicode character 0x%04X, size %u", key, size);
|
DEBUG(freetype, 4, "Set glyph for unicode character 0x%04X, size %u", key, size);
|
||||||
_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)].sprite = glyph->sprite;
|
_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)].sprite = glyph->sprite;
|
||||||
_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)].width = glyph->width;
|
_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)].width = glyph->width;
|
||||||
|
_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)].duplicate = duplicate;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *AllocateFont(size_t size)
|
static void *AllocateFont(size_t size)
|
||||||
@ -1004,7 +1006,14 @@ const Sprite *GetGlyph(FontSize size, WChar key)
|
|||||||
|
|
||||||
bool aa = GetFontAAState(size);
|
bool aa = GetFontAAState(size);
|
||||||
|
|
||||||
FT_Load_Char(face, key, FT_LOAD_DEFAULT);
|
FT_UInt glyph_index = FT_Get_Char_Index(face, key);
|
||||||
|
if (glyph_index == 0) {
|
||||||
|
GetGlyph(size, '?');
|
||||||
|
glyph = GetGlyphPtr(size, '?');
|
||||||
|
SetGlyphPtr(size, key, glyph, true);
|
||||||
|
return glyph->sprite;
|
||||||
|
}
|
||||||
|
FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
|
||||||
FT_Render_Glyph(face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
|
FT_Render_Glyph(face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
|
||||||
|
|
||||||
/* Despite requesting a normal glyph, FreeType may have returned a bitmap */
|
/* Despite requesting a normal glyph, FreeType may have returned a bitmap */
|
||||||
|
@ -46,6 +46,7 @@ void UninitFreeType();
|
|||||||
const Sprite *GetGlyph(FontSize size, uint32 key);
|
const Sprite *GetGlyph(FontSize size, uint32 key);
|
||||||
uint GetGlyphWidth(FontSize size, uint32 key);
|
uint GetGlyphWidth(FontSize size, uint32 key);
|
||||||
|
|
||||||
|
typedef bool (SetFallbackFontCallback)(const char **);
|
||||||
/**
|
/**
|
||||||
* We would like to have a fallback font as the current one
|
* We would like to have a fallback font as the current one
|
||||||
* doesn't contain all characters we need.
|
* doesn't contain all characters we need.
|
||||||
@ -53,10 +54,10 @@ uint GetGlyphWidth(FontSize size, uint32 key);
|
|||||||
* @param settings the settings to overwrite the fontname of.
|
* @param settings the settings to overwrite the fontname of.
|
||||||
* @param language_isocode the language, e.g. en_GB.
|
* @param language_isocode the language, e.g. en_GB.
|
||||||
* @param winlangid the language ID windows style.
|
* @param winlangid the language ID windows style.
|
||||||
* @param str Sample string.
|
* @param callback The function to call to check for missing glyphs.
|
||||||
* @return true if a font has been set, false otherwise.
|
* @return true if a font has been set, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, const char *str);
|
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, SetFallbackFontCallback *callback);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
@ -1568,16 +1568,19 @@ const char *GetCurrentLanguageIsoCode()
|
|||||||
* Check whether there are glyphs missing in the current language.
|
* Check whether there are glyphs missing in the current language.
|
||||||
* @param Pointer to an address for storing the text pointer.
|
* @param Pointer to an address for storing the text pointer.
|
||||||
* @return If glyphs are missing, return \c true, else return \false.
|
* @return If glyphs are missing, return \c true, else return \false.
|
||||||
* @pre *str must not be \c NULL.
|
* @post If \c true is returned and str is not NULL, *str points to a string that is found to contain at least one missing glyph.
|
||||||
* @post If \c true is returned, *str points to a string that is found to contain at least one missing glyph.
|
|
||||||
*/
|
*/
|
||||||
static bool FindMissingGlyphs(const char **str)
|
static bool FindMissingGlyphs(const char **str)
|
||||||
{
|
{
|
||||||
|
#ifdef WITH_FREETYPE
|
||||||
|
UninitFreeType();
|
||||||
|
InitFreeType();
|
||||||
|
#endif
|
||||||
const Sprite *question_mark = GetGlyph(FS_NORMAL, '?');
|
const Sprite *question_mark = GetGlyph(FS_NORMAL, '?');
|
||||||
for (uint i = 0; i != 32; i++) {
|
for (uint i = 0; i != 32; i++) {
|
||||||
for (uint j = 0; j < _langtab_num[i]; j++) {
|
for (uint j = 0; j < _langtab_num[i]; j++) {
|
||||||
const char *text = _langpack_offs[_langtab_start[i] + j];
|
const char *text = _langpack_offs[_langtab_start[i] + j];
|
||||||
*str = text;
|
if (str != NULL) *str = text;
|
||||||
for (WChar c = Utf8Consume(&text); c != '\0'; c = Utf8Consume(&text)) {
|
for (WChar c = Utf8Consume(&text); c != '\0'; c = Utf8Consume(&text)) {
|
||||||
if (c == SCC_SETX) {
|
if (c == SCC_SETX) {
|
||||||
/* SetX is, together with SetXY as special character that
|
/* SetX is, together with SetXY as special character that
|
||||||
@ -1608,15 +1611,7 @@ static bool FindMissingGlyphs(const char **str)
|
|||||||
*/
|
*/
|
||||||
void CheckForMissingGlyphsInLoadedLanguagePack()
|
void CheckForMissingGlyphsInLoadedLanguagePack()
|
||||||
{
|
{
|
||||||
#ifdef WITH_FREETYPE
|
bool bad_font = FindMissingGlyphs(NULL);
|
||||||
/* Reset to the original state; switching languages might cause us to
|
|
||||||
* automatically choose another font. This resets that choice. */
|
|
||||||
UninitFreeType();
|
|
||||||
InitFreeType();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const char *str;
|
|
||||||
bool bad_font = FindMissingGlyphs(&str);
|
|
||||||
#ifdef WITH_FREETYPE
|
#ifdef WITH_FREETYPE
|
||||||
if (bad_font) {
|
if (bad_font) {
|
||||||
/* We found an unprintable character... lets try whether we can find
|
/* We found an unprintable character... lets try whether we can find
|
||||||
@ -1624,23 +1619,16 @@ void CheckForMissingGlyphsInLoadedLanguagePack()
|
|||||||
FreeTypeSettings backup;
|
FreeTypeSettings backup;
|
||||||
memcpy(&backup, &_freetype, sizeof(backup));
|
memcpy(&backup, &_freetype, sizeof(backup));
|
||||||
|
|
||||||
bool success = SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, str);
|
bad_font = !SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, &FindMissingGlyphs);
|
||||||
if (success) {
|
|
||||||
UninitFreeType();
|
|
||||||
InitFreeType();
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&_freetype, &backup, sizeof(backup));
|
memcpy(&_freetype, &backup, sizeof(backup));
|
||||||
|
|
||||||
if (success) {
|
if (bad_font) {
|
||||||
bad_font = FindMissingGlyphs(&str);
|
/* Our fallback font does miss characters too, so keep the
|
||||||
if (bad_font) {
|
* user chosen font as that is more likely to be any good than
|
||||||
/* Our fallback font does miss characters too, so keep the
|
* the wild guess we made */
|
||||||
* user chosen font as that is more likely to be any good than
|
UninitFreeType();
|
||||||
* the wild guess we made */
|
InitFreeType();
|
||||||
UninitFreeType();
|
|
||||||
InitFreeType();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user