(svn r14618) -Feature: when the chosen language isn't supported by the current font, try to find a font that does and use that instead. Thanks to glx/michi_cc for the Windows implementation.

This commit is contained in:
rubidium
2008-11-24 18:53:17 +00:00
parent 6878b181c7
commit fea78fbfbb
52 changed files with 342 additions and 47 deletions

View File

@@ -1358,9 +1358,13 @@ static bool GetLanguageFileHeader(const char *file, LanguagePack *hdr)
size_t read = fread(hdr, sizeof(*hdr), 1, f);
fclose(f);
return read == 1 &&
bool ret = read == 1 &&
hdr->ident == TO_LE32(LANGUAGE_PACK_IDENT) &&
hdr->version == TO_LE32(LANGUAGE_PACK_VERSION);
/* Convert endianness for the windows language ID */
if (ret) hdr->winlangid = FROM_LE16(hdr->winlangid);
return ret;
}
/**
@@ -1478,45 +1482,83 @@ void InitializeLanguagePacks()
*/
void CheckForMissingGlyphsInLoadedLanguagePack()
{
const Sprite *question_mark = GetGlyph(FS_NORMAL, '?');
#ifdef WITH_FREETYPE
/* Reset to the original state; switching languages might cause us to
* automatically choose another font. This resets that choice. */
UninitFreeType();
InitFreeType();
#endif
for (uint i = 0; i != 32; i++) {
for (uint j = 0; j < _langtab_num[i]; j++) {
const char *string = _langpack_offs[_langtab_start[i] + j];
WChar c;
while ((c = Utf8Consume(&string)) != '\0') {
if (c == SCC_SETX) {
/*
* SetX is, together with SetXY as special character that
* uses the next (two) characters as data points. We have
* to skip those, otherwise the UTF8 reading will go
* haywire.
*/
string++;
} else if (c == SCC_SETXY) {
string += 2;
} else if (IsPrintable(c) && c != '?' && GetGlyph(FS_NORMAL, c) == question_mark) {
/*
* The character is printable, but not in the normal font.
* This is the case we were testing for. In this case we
* have to show the error. As we do not want the string to
* be translated by the translators, we 'force' it into the
* binary and 'load' it via a BindCString. To do this
* properly we have to set the color of the string,
* otherwise we end up with a lot of artefacts. The color
* 'character' might change in the future, so for safety
* we just Utf8 Encode it into the string, which takes
* exactly three characters, so it replaces the "XXX" with
* the color marker.
*/
static char *err_str = strdup("XXXThe current font is missing some of the characters used in the texts for this language. Read the readme to see how to solve this.");
Utf8Encode(err_str, SCC_YELLOW);
SetDParamStr(0, err_str);
ShowErrorMessage(INVALID_STRING_ID, STR_JUST_RAW_STRING, 0, 0);
return;
bool retry = false;
for (;;) {
const Sprite *question_mark = GetGlyph(FS_NORMAL, '?');
for (uint i = 0; i != 32; i++) {
for (uint j = 0; j < _langtab_num[i]; j++) {
const char *string = _langpack_offs[_langtab_start[i] + j];
WChar c;
while ((c = Utf8Consume(&string)) != '\0') {
if (c == SCC_SETX) {
/*
* SetX is, together with SetXY as special character that
* uses the next (two) characters as data points. We have
* to skip those, otherwise the UTF8 reading will go
* haywire.
*/
string++;
} else if (c == SCC_SETXY) {
string += 2;
} else if (IsPrintable(c) && c != '?' && GetGlyph(FS_NORMAL, c) == question_mark) {
#ifdef WITH_FREETYPE
if (!retry) {
/* We found an unprintable character... lets try whether we can
* find a fallback font that can print the characters in the
* current language. */
retry = true;
FreeTypeSettings backup;
memcpy(&backup, &_freetype, sizeof(backup));
bool success = SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid);
if (success) {
UninitFreeType();
InitFreeType();
}
memcpy(&_freetype, &backup, sizeof(backup));
if (success) continue;
} else {
/* Our fallback font does miss characters too, so keep the
* user chosen font as that is more likely to be any good than
* the wild guess we made */
UninitFreeType();
InitFreeType();
}
#endif
/*
* The character is printable, but not in the normal font.
* This is the case we were testing for. In this case we
* have to show the error. As we do not want the string to
* be translated by the translators, we 'force' it into the
* binary and 'load' it via a BindCString. To do this
* properly we have to set the color of the string,
* otherwise we end up with a lot of artefacts. The color
* 'character' might change in the future, so for safety
* we just Utf8 Encode it into the string, which takes
* exactly three characters, so it replaces the "XXX" with
* the color marker.
*/
static char *err_str = strdup("XXXThe current font is missing some of the characters used in the texts for this language. Read the readme to see how to solve this.");
Utf8Encode(err_str, SCC_YELLOW);
SetDParamStr(0, err_str);
ShowErrorMessage(INVALID_STRING_ID, STR_JUST_RAW_STRING, 0, 0);
return;
}
}
}
}
break;
}
#if !defined(WITH_ICU)