changeset 15632:508c27998f99 draft

(svn r20296) -Fix: Fallback font selection due to missing glyphs did not work as intended.
author alberth <alberth@openttd.org>
date Mon, 02 Aug 2010 12:10:48 +0000
parents 5194651ab37d
children b0568a7ded47
files src/fontcache.h src/strings.cpp
diffstat 2 files changed, 72 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- a/src/fontcache.h
+++ b/src/fontcache.h
@@ -53,6 +53,7 @@
  * @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);
--- a/src/strings.cpp
+++ b/src/strings.cpp
@@ -1573,6 +1573,38 @@
 }
 
 /**
+ * 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
  * does not support. If this is the case an error
@@ -1589,81 +1621,52 @@
 	 * 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));
 
-							memcpy(&_freetype, &backup, sizeof(backup));
+		bool success = SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, str);
+		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 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 */