From fea78fbfbb2bfe5c6ddf90adb811eb60f4ecfc50 Mon Sep 17 00:00:00 2001 From: rubidium Date: Mon, 24 Nov 2008 18:53:17 +0000 Subject: (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. --- src/fontcache.cpp | 186 +++++++++++++++++++++++++++++++++++-- src/fontcache.h | 19 +++- src/lang/afrikaans.txt | 1 + src/lang/brazilian_portuguese.txt | 1 + src/lang/bulgarian.txt | 1 + src/lang/catalan.txt | 1 + src/lang/croatian.txt | 1 + src/lang/czech.txt | 1 + src/lang/danish.txt | 1 + src/lang/dutch.txt | 1 + src/lang/english.txt | 1 + src/lang/english_US.txt | 1 + src/lang/esperanto.txt | 1 + src/lang/estonian.txt | 1 + src/lang/finnish.txt | 1 + src/lang/french.txt | 1 + src/lang/galician.txt | 1 + src/lang/german.txt | 1 + src/lang/hungarian.txt | 1 + src/lang/icelandic.txt | 1 + src/lang/italian.txt | 1 + src/lang/japanese.txt | 1 + src/lang/korean.txt | 1 + src/lang/lithuanian.txt | 1 + src/lang/norwegian_bokmal.txt | 1 + src/lang/norwegian_nynorsk.txt | 1 + src/lang/origveh.txt | 3 +- src/lang/piglatin.txt | 1 + src/lang/polish.txt | 1 + src/lang/portuguese.txt | 1 + src/lang/romanian.txt | 1 + src/lang/russian.txt | 1 + src/lang/simplified_chinese.txt | 1 + src/lang/slovak.txt | 1 + src/lang/slovenian.txt | 1 + src/lang/spanish.txt | 1 + src/lang/swedish.txt | 1 + src/lang/traditional_chinese.txt | 1 + src/lang/turkish.txt | 1 + src/lang/ukrainian.txt | 1 + src/lang/unfinished/frisian.txt | 1 + src/lang/unfinished/greek.txt | 1 + src/lang/unfinished/ido.txt | 1 + src/lang/unfinished/indonesian.txt | 1 + src/lang/unfinished/latvian.txt | 1 + src/lang/unfinished/macedonian.txt | 1 + src/lang/unfinished/persian.txt | 1 + src/lang/unfinished/serbian.txt | 1 + src/lang/welsh.txt | 1 + src/strgen/strgen.cpp | 10 ++ src/strgen/strgen.h | 11 ++- src/strings.cpp | 116 +++++++++++++++-------- 52 files changed, 343 insertions(+), 48 deletions(-) diff --git a/src/fontcache.cpp b/src/fontcache.cpp index 28924885d..b35458046 100644 --- a/src/fontcache.cpp +++ b/src/fontcache.cpp @@ -154,8 +154,68 @@ registry_no_font_found: RegCloseKey(hKey); return err; } -#else -# ifdef WITH_FONTCONFIG + + +struct EFCParam { + FreeTypeSettings *settings; + LOCALESIGNATURE locale; +}; + +static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXTMETRICEX *metric, DWORD type, LPARAM lParam) +{ + EFCParam *info = (EFCParam *)lParam; + + /* Only use TrueType fonts */ + if (!(type & TRUETYPE_FONTTYPE)) return 1; + /* Don't use SYMBOL fonts */ + if (logfont->elfLogFont.lfCharSet == SYMBOL_CHARSET) return 1; + + /* The font has to have at least one of the supported locales to be usable. */ + if ((metric->ntmFontSig.fsCsb[0] & info->locale.lsCsbSupported[0]) == 0 && (metric->ntmFontSig.fsCsb[1] & info->locale.lsCsbSupported[1]) == 0) { + /* On win9x metric->ntmFontSig seems to contain garbage. */ + FONTSIGNATURE fs; + memset(&fs, 0, sizeof(fs)); + HFONT font = CreateFontIndirect(&logfont->elfLogFont); + if (font != NULL) { + HDC dc = GetDC(NULL); + HGDIOBJ oldfont = SelectObject(dc, font); + GetTextCharsetInfo(dc, &fs, 0); + SelectObject(dc, oldfont); + ReleaseDC(NULL, dc); + DeleteObject(font); + } + if ((fs.fsCsb[0] & info->locale.lsCsbSupported[0]) == 0 && (fs.fsCsb[1] & info->locale.lsCsbSupported[1]) == 0) return 1; + } + + 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->large_font, font_name, lastof(info->settings->large_font)); + return 0; // stop enumerating +} + +bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid) +{ + EFCParam langInfo; + if (GetLocaleInfo(MAKELCID(winlangid, SORT_DEFAULT), LOCALE_FONTSIGNATURE, (LPWSTR)&langInfo.locale, sizeof(langInfo.locale) / sizeof(TCHAR)) == 0) { + /* Invalid langid or some other mysterious error, can't determine fallback font. */ + DEBUG(freetype, 1, "Can't get locale info for fallback font (langid=0x%x)", winlangid); + return false; + } + langInfo.settings = settings; + + LOGFONT font; + /* Enumerate all fonts. */ + font.lfCharSet = DEFAULT_CHARSET; + font.lfFaceName[0] = '\0'; + font.lfPitchAndFamily = 0; + + HDC dc = GetDC(NULL); + int ret = EnumFontFamiliesEx(dc, &font, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&langInfo, 0); + ReleaseDC(NULL, dc); + return ret == 0; +} + +#elif defined(WITH_FONTCONFIG) static FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) { FT_Error err = FT_Err_Cannot_Open_Resource; @@ -221,11 +281,75 @@ static FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) return err; } -# else -FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) {return FT_Err_Cannot_Open_Resource;} -# endif /* WITH_FONTCONFIG */ -#endif +bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid) +{ + if (!FcInit()) return false; + + bool ret = false; + + /* Fontconfig doesn't handle full language isocodes, only the part + * before the _ of e.g. en_GB is used, so "remove" everything after + * the _. */ + char lang[16]; + strecpy(lang, language_isocode, lastof(lang)); + char *split = strchr(lang, '_'); + if (split != NULL) *split = '\0'; + + FcPattern *pat; + FcPattern *match; + FcResult result; + FcChar8 *file; + FcFontSet *fs; + FcValue val; + val.type = FcTypeString; + val.u.s = (FcChar8*)lang; + + /* First create a pattern to match the wanted language */ + pat = FcPatternCreate(); + /* And fill it with the language and other defaults */ + if (pat == NULL || + !FcPatternAdd(pat, "lang", val, false) || + !FcConfigSubstitute(0, pat, FcMatchPattern)) { + goto error_pattern; + } + + FcDefaultSubstitute(pat); + + /* The 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(); + return ret; +} + +#else /* without WITH_FONTCONFIG */ +FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) {return FT_Err_Cannot_Open_Resource;} +bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode) { return false; } +#endif /* WITH_FONTCONFIG */ /** * Loads the freetype font. @@ -303,6 +427,35 @@ void InitFreeType() if (_face_large != NULL) FT_Set_Pixel_Sizes(_face_large, 0, _freetype.large_size); } +static void ResetGlyphCache(); + +/** + * Unload a face and set it to NULL. + * @param face the face to unload + */ +static void UnloadFace(FT_Face *face) +{ + if (*face == NULL) return; + + FT_Done_Face(*face); + *face = NULL; +} + +/** + * Free everything allocated w.r.t. fonts. + */ +void UninitFreeType() +{ + ResetGlyphCache(); + + UnloadFace(&_face_small); + UnloadFace(&_face_medium); + UnloadFace(&_face_large); + + FT_Done_FreeType(_library); + _library = NULL; +} + static FT_Face GetFontFace(FontSize size) { @@ -335,6 +488,27 @@ struct GlyphEntry { */ static GlyphEntry **_glyph_ptr[FS_END]; +/** Clear the complete cache */ +static void ResetGlyphCache() +{ + for (int i = 0; i < FS_END; i++) { + if (_glyph_ptr[i] == NULL) continue; + + for (int j = 0; j < 256; j++) { + if (_glyph_ptr[i][j] == NULL) continue; + + for (int k = 0; k < 256; k++) { + if (_glyph_ptr[i][j][k].sprite == NULL) continue; + free(_glyph_ptr[i][j][k].sprite); + } + + free(_glyph_ptr[i][j]); + } + + free(_glyph_ptr[i]); + _glyph_ptr[i] = NULL; + } +} static GlyphEntry *GetGlyphPtr(FontSize size, WChar key) { diff --git a/src/fontcache.h b/src/fontcache.h index bf32c2927..e72fc8225 100644 --- a/src/fontcache.h +++ b/src/fontcache.h @@ -19,9 +19,9 @@ void InitializeUnicodeGlyphMap(); #ifdef WITH_FREETYPE struct FreeTypeSettings { - char small_font[260]; - char medium_font[260]; - char large_font[260]; + char small_font[MAX_PATH]; + char medium_font[MAX_PATH]; + char large_font[MAX_PATH]; uint small_size; uint medium_size; uint large_size; @@ -33,13 +33,26 @@ struct FreeTypeSettings { extern FreeTypeSettings _freetype; void InitFreeType(); +void UninitFreeType(); const struct Sprite *GetGlyph(FontSize size, uint32 key); uint GetGlyphWidth(FontSize size, uint32 key); +/** + * We would like to have a fallback font as the current one + * doesn't contain all characters we need. + * This function must set all fonts of settings. + * @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. + * @return true if a font has been set, false otherwise. + */ +bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid); + #else /* Stub for initializiation */ static inline void InitFreeType() {} +static inline void UninitFreeType() {} /** Get the Sprite for a glyph */ static inline const Sprite *GetGlyph(FontSize size, uint32 key) diff --git a/src/lang/afrikaans.txt b/src/lang/afrikaans.txt index 1fe44e6c6..359c50c55 100644 --- a/src/lang/afrikaans.txt +++ b/src/lang/afrikaans.txt @@ -1,6 +1,7 @@ ##name Afrikaans ##ownname Jaybee ##isocode af_ZA +##winlangid 0x0436 ##plural 0 ##gender male diff --git a/src/lang/brazilian_portuguese.txt b/src/lang/brazilian_portuguese.txt index a2bbd593b..bcd1d6bd0 100644 --- a/src/lang/brazilian_portuguese.txt +++ b/src/lang/brazilian_portuguese.txt @@ -1,6 +1,7 @@ ##name Brazilian_Portuguese ##ownname Português (BR) ##isocode pt_BR +##winlangid 0x0416 ##plural 2 ##gender m f diff --git a/src/lang/bulgarian.txt b/src/lang/bulgarian.txt index a1704fd14..66acc6044 100644 --- a/src/lang/bulgarian.txt +++ b/src/lang/bulgarian.txt @@ -1,6 +1,7 @@ ##name Bulgarian ##ownname Български ##isocode bg_BG +##winlangid 0x0402 ##plural 0 ##case m f n p ##gender m f n p diff --git a/src/lang/catalan.txt b/src/lang/catalan.txt index 4d5ffd392..ea0d0bf06 100644 --- a/src/lang/catalan.txt +++ b/src/lang/catalan.txt @@ -1,6 +1,7 @@ ##name Catalan ##ownname Català ##isocode ca_ES +##winlangid 0x0403 ##plural 0 # diff --git a/src/lang/croatian.txt b/src/lang/croatian.txt index 9a70432e8..9a27ca102 100644 --- a/src/lang/croatian.txt +++ b/src/lang/croatian.txt @@ -1,6 +1,7 @@ ##name Croatian ##ownname Hrvatski ##isocode hr_HR +##winlangid 0x041a ##plural 6 ##case nom gen dat aku vok lok ins ##gender male female middle diff --git a/src/lang/czech.txt b/src/lang/czech.txt index 73f807b52..f2da56ab1 100644 --- a/src/lang/czech.txt +++ b/src/lang/czech.txt @@ -1,6 +1,7 @@ ##name Czech ##ownname Čeština ##isocode cs_CZ +##winlangid 0x0405 ##plural 6 ##case nom gen dat acc voc loc ins big small ##gender m f n diff --git a/src/lang/danish.txt b/src/lang/danish.txt index 931de2a82..d048c261a 100644 --- a/src/lang/danish.txt +++ b/src/lang/danish.txt @@ -1,6 +1,7 @@ ##name Danish ##ownname Dansk ##isocode da_DA +##winlangid 0x0406 ##plural 0 # diff --git a/src/lang/dutch.txt b/src/lang/dutch.txt index 73908f23c..113ea0cb0 100644 --- a/src/lang/dutch.txt +++ b/src/lang/dutch.txt @@ -1,6 +1,7 @@ ##name Dutch ##ownname Nederlands ##isocode nl_NL +##winlangid 0x0413 ##plural 0 # diff --git a/src/lang/english.txt b/src/lang/english.txt index 4a8f8f243..d77741b02 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1,6 +1,7 @@ ##name English (UK) ##ownname English (UK) ##isocode en_GB +##winlangid 0x0809 ##plural 0 # diff --git a/src/lang/english_US.txt b/src/lang/english_US.txt index 68efdf1ea..60404b192 100644 --- a/src/lang/english_US.txt +++ b/src/lang/english_US.txt @@ -1,6 +1,7 @@ ##name English (US) ##ownname English (US) ##isocode en_US +##winlangid 0x0409 ##plural 0 # diff --git a/src/lang/esperanto.txt b/src/lang/esperanto.txt index 1ed900995..8d55e779c 100644 --- a/src/lang/esperanto.txt +++ b/src/lang/esperanto.txt @@ -1,6 +1,7 @@ ##name Esperanto ##ownname Esperanto ##isocode eo_EO +##winlangid 0x0000 ##plural 0 ##case n diff --git a/src/lang/estonian.txt b/src/lang/estonian.txt index 425e6f71d..e592c57f0 100644 --- a/src/lang/estonian.txt +++ b/src/lang/estonian.txt @@ -1,6 +1,7 @@ ##name Estonian ##ownname Eesti keel ##isocode et_ET +##winlangid 0x0425 ##plural 0 ##case g in diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt index 0bee74f9c..120f247c0 100644 --- a/src/lang/finnish.txt +++ b/src/lang/finnish.txt @@ -1,6 +1,7 @@ ##name Finnish ##ownname Suomi ##isocode fi_FI +##winlangid 0x040b ##plural 0 # diff --git a/src/lang/french.txt b/src/lang/french.txt index 6371c432d..8770cf9f2 100644 --- a/src/lang/french.txt +++ b/src/lang/french.txt @@ -1,6 +1,7 @@ ##name French ##ownname Français ##isocode fr_FR +##winlangid 0x040c ##plural 2 ##gender m m2 f diff --git a/src/lang/galician.txt b/src/lang/galician.txt index 6c2db27c8..b1c4b8ea5 100644 --- a/src/lang/galician.txt +++ b/src/lang/galician.txt @@ -1,6 +1,7 @@ ##name Galician ##ownname Galego ##isocode gl_ES +##winlangid 0x0456 ##plural 0 ##gender m f n diff --git a/src/lang/german.txt b/src/lang/german.txt index e823b5ebb..108377fe5 100644 --- a/src/lang/german.txt +++ b/src/lang/german.txt @@ -1,6 +1,7 @@ ##name German ##ownname Deutsch ##isocode de_DE +##winlangid 0x0407 ##plural 0 ##gender m w n p diff --git a/src/lang/hungarian.txt b/src/lang/hungarian.txt index 683ac78d1..bef7d66dc 100644 --- a/src/lang/hungarian.txt +++ b/src/lang/hungarian.txt @@ -1,6 +1,7 @@ ##name Hungarian ##ownname Magyar ##isocode hu_HU +##winlangid 0x040e ##plural 1 ##case t ba diff --git a/src/lang/icelandic.txt b/src/lang/icelandic.txt index 9791b24d8..cba7f8cc0 100644 --- a/src/lang/icelandic.txt +++ b/src/lang/icelandic.txt @@ -1,6 +1,7 @@ ##name Icelandic ##ownname Íslenska ##isocode is_IS +##winlangid 0x040f ##plural 0 ##gender karlkyn kvenkyn hvorugkyn diff --git a/src/lang/italian.txt b/src/lang/italian.txt index d09ef4f1b..c7ed03c97 100644 --- a/src/lang/italian.txt +++ b/src/lang/italian.txt @@ -1,6 +1,7 @@ ##name Italian ##ownname Italiano ##isocode it_IT +##winlangid 0x0410 ##plural 0 ##case ms mp fs fp ##gender m f diff --git a/src/lang/japanese.txt b/src/lang/japanese.txt index 0c5752468..413ec8209 100644 --- a/src/lang/japanese.txt +++ b/src/lang/japanese.txt @@ -1,6 +1,7 @@ ##name Japanese ##ownname 日本語 ##isocode ja_JP +##winlangid 0x0411 ##plural 1 # diff --git a/src/lang/korean.txt b/src/lang/korean.txt index d3f3c0a41..9f337a889 100644 --- a/src/lang/korean.txt +++ b/src/lang/korean.txt @@ -1,6 +1,7 @@ ##name Korean ##ownname 한국어 ##isocode ko_KR +##winlangid 0x0412 ##plural 1 # diff --git a/src/lang/lithuanian.txt b/src/lang/lithuanian.txt index 24f154b27..d212b535c 100644 --- a/src/lang/lithuanian.txt +++ b/src/lang/lithuanian.txt @@ -1,6 +1,7 @@ ##name Lithuanian ##ownname Lietuvių ##isocode lt_LT +##winlangid 0x0427 ##plural 5 ##case kas ko kam ka kuo kur kreip ##gender vyr mot diff --git a/src/lang/norwegian_bokmal.txt b/src/lang/norwegian_bokmal.txt index e8665f076..703e7a327 100644 --- a/src/lang/norwegian_bokmal.txt +++ b/src/lang/norwegian_bokmal.txt @@ -1,6 +1,7 @@ ##name Norwegian ##ownname Norsk (bokmål) ##isocode nb_NO +##winlangid 0x0414 ##plural 0 # diff --git a/src/lang/norwegian_nynorsk.txt b/src/lang/norwegian_nynorsk.txt index c68a1c237..87e829ceb 100644 --- a/src/lang/norwegian_nynorsk.txt +++ b/src/lang/norwegian_nynorsk.txt @@ -1,6 +1,7 @@ ##name Norwegian new ##ownname Norsk, Nynorsk ##isocode nn_NO +##winlangid 0x0814 ##plural 0 ##gender masculine feminine neuter diff --git a/src/lang/origveh.txt b/src/lang/origveh.txt index 17b9a665b..d1cc58ee3 100644 --- a/src/lang/origveh.txt +++ b/src/lang/origveh.txt @@ -1,6 +1,7 @@ ##name Original vehicle names (ENG) ##ownname Original vehicle names (ENG) -##isocode xx +##isocode xx_OV +##winlangid 0x0000 ##id 0x8000 STR_8000_KIRBY_PAUL_TANK_STEAM :Collett Pannier Tank (Steam) diff --git a/src/lang/piglatin.txt b/src/lang/piglatin.txt index 5acac3cbd..9ce6bbbd6 100644 --- a/src/lang/piglatin.txt +++ b/src/lang/piglatin.txt @@ -1,6 +1,7 @@ ##name Pig latin ##ownname Igpay atinlay ##isocode xx_PL +##winlangid 0x0000 ##plural 0 # diff --git a/src/lang/polish.txt b/src/lang/polish.txt index 1db3d8d0b..0b3eb2825 100644 --- a/src/lang/polish.txt +++ b/src/lang/polish.txt @@ -1,6 +1,7 @@ ##name Polish ##ownname Polski ##isocode pl_PL +##winlangid 0x0415 ##plural 7 ##case d c b n m w ##gender m f n diff --git a/src/lang/portuguese.txt b/src/lang/portuguese.txt index c0a8f5f71..6258acae8 100644 --- a/src/lang/portuguese.txt +++ b/src/lang/portuguese.txt @@ -1,6 +1,7 @@ ##name Portuguese ##ownname Português ##isocode pt_PT +##winlangid 0x0816 ##plural 0 # diff --git a/src/lang/romanian.txt b/src/lang/romanian.txt index d8078ae71..def0a12d6 100644 --- a/src/lang/romanian.txt +++ b/src/lang/romanian.txt @@ -1,6 +1,7 @@ ##name Romanian ##ownname Românã ##isocode ro_RO +##winlangid 0x0418 ##plural 0 # diff --git a/src/lang/russian.txt b/src/lang/russian.txt index a1d7fc5e3..2812e4372 100644 --- a/src/lang/russian.txt +++ b/src/lang/russian.txt @@ -1,6 +1,7 @@ ##name Russian ##ownname Русский ##isocode ru_RU +##winlangid 0x0419 ##plural 6 ##case m f n p ##gender m f n p diff --git a/src/lang/simplified_chinese.txt b/src/lang/simplified_chinese.txt index b04c67abe..1922d964c 100644 --- a/src/lang/simplified_chinese.txt +++ b/src/lang/simplified_chinese.txt @@ -1,6 +1,7 @@ ##name Chinese (Simplified) ##ownname 简体中文 ##isocode zh_CN +##winlangid 0x0804 ##plural 1 # diff --git a/src/lang/slovak.txt b/src/lang/slovak.txt index ce19cafe7..a7cb3f2b3 100644 --- a/src/lang/slovak.txt +++ b/src/lang/slovak.txt @@ -1,6 +1,7 @@ ##name Slovak ##ownname Slovensky ##isocode sk_SK +##winlangid 0x041b ##plural 6 ##case g ##gender m z s diff --git a/src/lang/slovenian.txt b/src/lang/slovenian.txt index e15a6c0a7..cf145a995 100644 --- a/src/lang/slovenian.txt +++ b/src/lang/slovenian.txt @@ -1,6 +1,7 @@ ##name Slovenian ##ownname Slovenščina ##isocode sl_SL +##winlangid 0x0424 ##plural 8 ##case r d t diff --git a/src/lang/spanish.txt b/src/lang/spanish.txt index eff25caa9..6070bce7f 100644 --- a/src/lang/spanish.txt +++ b/src/lang/spanish.txt @@ -1,6 +1,7 @@ ##name Spanish ##ownname Español (ES) ##isocode es_ES +##winlangid 0x0c0a ##plural 0 ##gender masculino femenino diff --git a/src/lang/swedish.txt b/src/lang/swedish.txt index 4cc81c4d8..0d5b6bf02 100644 --- a/src/lang/swedish.txt +++ b/src/lang/swedish.txt @@ -1,6 +1,7 @@ ##name Swedish ##ownname Svenska ##isocode sv_SE +##winlangid 0x081d ##plural 0 # diff --git a/src/lang/traditional_chinese.txt b/src/lang/traditional_chinese.txt index ee85486f6..5c8dbd13f 100644 --- a/src/lang/traditional_chinese.txt +++ b/src/lang/traditional_chinese.txt @@ -1,6 +1,7 @@ ##name Chinese (Traditional) ##ownname 中文 ##isocode zh_TW +##winlangid 0x0404 ##plural 1 # diff --git a/src/lang/turkish.txt b/src/lang/turkish.txt index 92d5fe48f..c57979c0a 100644 --- a/src/lang/turkish.txt +++ b/src/lang/turkish.txt @@ -1,6 +1,7 @@ ##name Turkish ##ownname Türkçe ##isocode tr_TR +##winlangid 0x041f ##plural 1 # diff --git a/src/lang/ukrainian.txt b/src/lang/ukrainian.txt index db7b53bbc..393bfbef1 100644 --- a/src/lang/ukrainian.txt +++ b/src/lang/ukrainian.txt @@ -1,6 +1,7 @@ ##name Ukrainian ##ownname Українська ##isocode uk_UA +##winlangid 0x0422 ##plural 6 ##gender m f s mn ##case r d z diff --git a/src/lang/unfinished/frisian.txt b/src/lang/unfinished/frisian.txt index ff09635c6..39d316f35 100644 --- a/src/lang/unfinished/frisian.txt +++ b/src/lang/unfinished/frisian.txt @@ -1,6 +1,7 @@ ##name Frisian ##ownname Frysk ##isocode fy_NL +##winlangid 0x0462 ##id 0x0000 STR_NULL : diff --git a/src/lang/unfinished/greek.txt b/src/lang/unfinished/greek.txt index 81eb57011..0f7a1220d 100644 --- a/src/lang/unfinished/greek.txt +++ b/src/lang/unfinished/greek.txt @@ -1,6 +1,7 @@ ##name Greek ##ownname Ελληνικά ##isocode el_GR +##winlangid 0x0408 ##plural 0 ##gender m f n diff --git a/src/lang/unfinished/ido.txt b/src/lang/unfinished/ido.txt index 67c22b2b2..8d6b7ddc9 100644 --- a/src/lang/unfinished/ido.txt +++ b/src/lang/unfinished/ido.txt @@ -1,6 +1,7 @@ ##name Ido ##ownname Ido ##isocode io_XX +##winlangid 0x0000 ##plural 0 # diff --git a/src/lang/unfinished/indonesian.txt b/src/lang/unfinished/indonesian.txt index 143172e10..9f6f1ab55 100644 --- a/src/lang/unfinished/indonesian.txt +++ b/src/lang/unfinished/indonesian.txt @@ -1,6 +1,7 @@ ##name Indonesian ##ownname Indonesian ##isocode id_ID +##winlangid 0x0421 ##plural 0 # diff --git a/src/lang/unfinished/latvian.txt b/src/lang/unfinished/latvian.txt index 6dbc62d9f..da260bfae 100644 --- a/src/lang/unfinished/latvian.txt +++ b/src/lang/unfinished/latvian.txt @@ -1,6 +1,7 @@ ##name Latvian ##ownname Latviešu ##isocode lv_LV +##winlangid 0x0426 ##plural 3 ##case kas ##gender m f diff --git a/src/lang/unfinished/macedonian.txt b/src/lang/unfinished/macedonian.txt index 3b03e516a..a5b022467 100644 --- a/src/lang/unfinished/macedonian.txt +++ b/src/lang/unfinished/macedonian.txt @@ -1,6 +1,7 @@ ##name Macedonian ##ownname Македонски ##isocode mk_MK +##winlangid 0x042f ##plural 0 # diff --git a/src/lang/unfinished/persian.txt b/src/lang/unfinished/persian.txt index 82ed1c99b..4f797ffbe 100644 --- a/src/lang/unfinished/persian.txt +++ b/src/lang/unfinished/persian.txt @@ -1,6 +1,7 @@ ##name Persian ##ownname Farsi ##isocode fa_IR +##winlangid 0x0429 ##plural 0 ##textdir rtl diff --git a/src/lang/unfinished/serbian.txt b/src/lang/unfinished/serbian.txt index 389e3b96e..94c43d4a8 100644 --- a/src/lang/unfinished/serbian.txt +++ b/src/lang/unfinished/serbian.txt @@ -1,6 +1,7 @@ ##name Serbian ##ownname Srpski ##isocode sr_YU +##winlangid 0x7c1a ##plural 0 ##case ih a ova ca ci ka ća va ao u om im e ke on ona to ##gender muški ženski srednji diff --git a/src/lang/welsh.txt b/src/lang/welsh.txt index daef80993..4b65b5223 100644 --- a/src/lang/welsh.txt +++ b/src/lang/welsh.txt @@ -1,6 +1,7 @@ ##name Welsh ##ownname Cymraeg ##isocode cy_GB +##winlangid 0x0452 ##plural 0 # diff --git a/src/strgen/strgen.cpp b/src/strgen/strgen.cpp index 298597311..ba6a9bb40 100644 --- a/src/strgen/strgen.cpp +++ b/src/strgen/strgen.cpp @@ -87,6 +87,7 @@ static uint32 _hash; static char _lang_name[32], _lang_ownname[32], _lang_isocode[16]; static byte _lang_pluralform; static byte _lang_textdir; +static uint16 _lang_winlangid; #define MAX_NUM_GENDER 8 static char _genders[MAX_NUM_GENDER][16]; static int _numgenders; @@ -649,6 +650,13 @@ static void HandlePragma(char *str) } else { error("Invalid textdir %s", str + 8); } + } else if (!memcmp(str, "winlangid ", 10)) { + char *buf = str + 10; + long langid = strtol(buf, NULL, 16); + if (langid > UINT16_MAX || langid < 0) { + error("Invalid winlangid %s", buf); + } + _lang_winlangid = (uint16)langid; } else if (!memcmp(str, "gender ", 7)) { char* buf = str + 7; @@ -912,6 +920,7 @@ static void ParseFile(const char *file, bool english) _numgenders = 0; _lang_name[0] = _lang_ownname[0] = _lang_isocode[0] = '\0'; _lang_textdir = TD_LTR; + _lang_winlangid = 0x0000; // neutral language code // TODO:!! We can't reset the cases. In case the translated strings // derive some strings from english.... @@ -1161,6 +1170,7 @@ static void WriteLangfile(const char *filename) hdr.version = TO_LE32(_hash); hdr.plural_form = _lang_pluralform; hdr.text_dir = _lang_textdir; + hdr.winlangid = TO_LE16(_lang_winlangid); strcpy(hdr.name, _lang_name); strcpy(hdr.own_name, _lang_ownname); strcpy(hdr.isocode, _lang_isocode); diff --git a/src/strgen/strgen.h b/src/strgen/strgen.h index a38b1760d..93253259f 100644 --- a/src/strgen/strgen.h +++ b/src/strgen/strgen.h @@ -14,7 +14,16 @@ struct LanguagePackHeader { uint16 offsets[32]; // the offsets byte plural_form; // plural form index byte text_dir; // default direction of the text - byte pad[2]; // pad header to be a multiple of 4 + /** + * Windows language ID: + * Windows cannot and will not convert isocodes to something it can use to + * determine whether a font can be used for the language or not. As a result + * of that we need to pass the language id via strgen to OpenTTD to tell + * what language it is in "Windows". The ID is the 'locale identifier' on: + * http://msdn.microsoft.com/en-us/library/ms776294.aspx + */ + uint16 winlangid; // windows language id + /* byte pad[0]; // pad header to be a multiple of 4 */ }; assert_compile(sizeof(LanguagePackHeader) % 4 == 0); diff --git a/src/strings.cpp b/src/strings.cpp index 2fb3a7854..a93645341 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -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, '?'); - - 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; +#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 + + 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) -- cgit v1.2.3-54-g00ecf