From f0ebe530ad8de855d2be4e6e3f7c20fb736d56d6 Mon Sep 17 00:00:00 2001 From: alberth Date: Mon, 2 Aug 2010 12:10:48 +0000 Subject: (svn r20296) -Fix: Fallback font selection due to missing glyphs did not work as intended. --- src/fontcache.h | 1 + src/strings.cpp | 139 +++++++++++++++++++++++++++++--------------------------- 2 files changed, 72 insertions(+), 68 deletions(-) (limited to 'src') diff --git a/src/fontcache.h b/src/fontcache.h index affc2606c..b4bdc7a99 100644 --- a/src/fontcache.h +++ b/src/fontcache.h @@ -53,6 +53,7 @@ uint GetGlyphWidth(FontSize size, uint32 key); * @param settings the settings to overwrite the fontname of. * @param language_isocode the language, e.g. en_GB. * @param winlangid the language ID windows style. + * @param str Sample string. * @return true if a font has been set, false otherwise. */ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, const char *str); diff --git a/src/strings.cpp b/src/strings.cpp index 9b2581b42..5b5664f00 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -1572,6 +1572,38 @@ const char *GetCurrentLanguageIsoCode() return _langpack->isocode; } +/** + * Check whether there are glyphs missing in the current language. + * @param Pointer to an address for storing the text pointer. + * @return If glyphs are missing, return \c true, else return \false. + * @pre *str must not be \c NULL. + * @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) +{ + 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 *text = _langpack_offs[_langtab_start[i] + j]; + *str = text; + for (WChar c = Utf8Consume(&text); c != '\0'; c = Utf8Consume(&text)) { + 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. */ + text++; + } else if (c == SCC_SETXY) { + text += 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. */ + return true; + } + } + } + } + return false; +} + /** * Check whether the currently loaded language pack * uses characters that the currently loaded font @@ -1589,81 +1621,52 @@ void CheckForMissingGlyphsInLoadedLanguagePack() * automatically choose another font. This resets that choice. */ UninitFreeType(); InitFreeType(); - bool retry = false; #endif - 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) { + const char *str; + bool bad_font = FindMissingGlyphs(&str); #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, string); - if (success) { - UninitFreeType(); - InitFreeType(); - } + if (bad_font) { + /* We found an unprintable character... lets try whether we can find + * a fallback font that can print the characters in the current language. */ + FreeTypeSettings backup; + memcpy(&backup, &_freetype, sizeof(backup)); + + bool success = SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, str); + if (success) { + UninitFreeType(); + InitFreeType(); + } - memcpy(&_freetype, &backup, sizeof(backup)); + 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 colour of the string, - * otherwise we end up with a lot of artefacts. The colour - * '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 colour 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(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_WARNING); - - /* Reset the font width */ - LoadStringWidthTable(); - return; - } - } + if (success) { + bad_font = FindMissingGlyphs(&str); + if (bad_font) { + /* 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(); } } - break; + } +#endif + + if (bad_font) { + /* All attempts have failed. Display an 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 colour of the string, otherwise we end up with a lot of artefacts. + * The colour '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 colour 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(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_WARNING); + + /* Reset the font width */ + LoadStringWidthTable(); + return; } /* Update the font with cache */ -- cgit v1.2.3-70-g09d2