Changeset - r18413:e892ae4942df
[Not reviewed]
master
0 4 0
rubidium - 13 years ago 2011-11-19 18:43:00
rubidium@openttd.org
(svn r23265) -Codechange: replace the setfallbackfont callback function with a class to call back
4 files changed with 96 insertions and 37 deletions:
0 comments (0 inline, 0 general)
src/fontcache.cpp
Show inline comments
 
@@ -10,12 +10,13 @@
 
/** @file fontcache.cpp Cache for characters from fonts. */
 

	
 
#include "stdafx.h"
 
#include "fontcache.h"
 
#include "blitter/factory.hpp"
 
#include "core/math_func.hpp"
 
#include "strings_func.h"
 

	
 
#include "table/sprites.h"
 
#include "table/control_codes.h"
 

	
 
static const int ASCII_LETTERSTART = 32; ///< First printable ASCII letter.
 

	
 
@@ -286,13 +287,13 @@ err1:
 
	return ret_font_name == NULL ? WIDE_TO_MB((const TCHAR*)logfont->elfFullName) : ret_font_name;
 
}
 

	
 
struct EFCParam {
 
	FreeTypeSettings *settings;
 
	LOCALESIGNATURE  locale;
 
	SetFallbackFontCallback *callback;
 
	MissingGlyphSearcher *callback;
 
};
 

	
 
static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXTMETRICEX *metric, DWORD type, LPARAM lParam)
 
{
 
	EFCParam *info = (EFCParam *)lParam;
 

	
 
@@ -346,18 +347,18 @@ static int CALLBACK EnumFontCallback(con
 

	
 
	if (!found) 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));
 
	if (info->callback(NULL)) return 1;
 
	if (info->callback->FindMissingGlyphs(NULL)) return 1;
 
	DEBUG(freetype, 1, "Fallback font: %s (%s)", font_name, english_name);
 
	return 0; // stop enumerating
 
}
 

	
 
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, SetFallbackFontCallback *callback)
 
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
 
{
 
	DEBUG(freetype, 1, "Trying fallback fonts");
 
	EFCParam langInfo;
 
	if (GetLocaleInfo(MAKELCID(winlangid, SORT_DEFAULT), LOCALE_FONTSIGNATURE, (LPTSTR)&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);
 
@@ -425,18 +426,18 @@ FT_Error GetFontByFaceName(const char *f
 
		}
 
	}
 

	
 
	return err;
 
}
 

	
 
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, SetFallbackFontCallback *callback)
 
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
 
{
 
	const char *str;
 
	bool result = false;
 

	
 
	callback(&str);
 
	callback->FindMissingGlyphs(&str);
 

	
 
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
 
	if (MacOSVersionIsAtLeast(10, 5, 0)) {
 
		/* Determine fallback font using CoreText. This uses the language isocode
 
		 * to find a suitable font. CoreText is available from 10.5 onwards. */
 
		char lang[16];
 
@@ -606,13 +607,13 @@ bool SetFallbackFont(FreeTypeSettings *s
 
			/* Uninit FreeType if we did the init. */
 
			FT_Done_FreeType(_library);
 
			_library = NULL;
 
		}
 
	 }
 

	
 
	callback(NULL);
 
	callback->FindMissingGlyphs(NULL);
 
	return result;
 
}
 

	
 
#elif defined(WITH_FONTCONFIG) /* end ifdef __APPLE__ */
 
/* ========================================================================================
 
 * FontConfig (unix) support
 
@@ -680,13 +681,13 @@ static FT_Error GetFontByFaceName(const 
 
		FcFini();
 
	}
 

	
 
	return err;
 
}
 

	
 
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, SetFallbackFontCallback *callback)
 
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
 
{
 
	if (!FcInit()) return false;
 

	
 
	bool ret = false;
 

	
 
	/* Fontconfig doesn't handle full language isocodes, only the part
 
@@ -719,13 +720,13 @@ bool SetFallbackFont(FreeTypeSettings *s
 
			}
 

	
 
			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);
 
			bool missing = callback->FindMissingGlyphs(NULL);
 
			DEBUG(freetype, 1, "Font \"%s\" misses%s glyphs", file, missing ? "" : " no");
 

	
 
			if (!missing) {
 
				ret = true;
 
				break;
 
			}
 
@@ -738,13 +739,13 @@ bool SetFallbackFont(FreeTypeSettings *s
 
	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, int winlangid, SetFallbackFontCallback *callback) { return false; }
 
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback) { return false; }
 
#endif /* WITH_FONTCONFIG */
 

	
 
static void SetFontGeometry(FT_Face face, FontSize size, int pixels)
 
{
 
	FT_Error err = FT_Set_Pixel_Sizes(face, 0, pixels);
 
	if (err == FT_Err_Invalid_Pixel_Size) {
src/fontcache.h
Show inline comments
 
@@ -44,24 +44,23 @@ extern FreeTypeSettings _freetype;
 
void InitFreeType();
 
void UninitFreeType();
 
const Sprite *GetGlyph(FontSize size, uint32 key);
 
uint GetGlyphWidth(FontSize size, uint32 key);
 
bool GetDrawGlyphShadow();
 

	
 
typedef bool (SetFallbackFontCallback)(const char **);
 
/**
 
 * 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.
 
 * @param callback The function to call to check for missing glyphs.
 
 * @return true if a font has been set, false otherwise.
 
 */
 
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, SetFallbackFontCallback *callback);
 
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, class MissingGlyphSearcher *callback);
 

	
 
#else
 

	
 
/* Stub for initializiation */
 
static inline void InitFreeType() { ResetFontSizes(); }
 
static inline void UninitFreeType() { ResetFontSizes(); }
src/strings.cpp
Show inline comments
 
@@ -1747,52 +1747,81 @@ const char *GetCurrentLanguageIsoCode()
 
/**
 
 * 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.
 
 * @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.
 
 */
 
static bool FindMissingGlyphs(const char **str)
 
bool MissingGlyphSearcher::FindMissingGlyphs(const char **str)
 
{
 
#ifdef WITH_FREETYPE
 
	UninitFreeType();
 
	InitFreeType();
 
#endif
 
	const Sprite *question_mark[FS_END];
 
	FontSize size;
 

	
 
	for (size = FS_BEGIN; size < FS_END; size++) {
 
	for (FontSize size = FS_BEGIN; size < FS_END; size++) {
 
		question_mark[size] = GetGlyph(size, '?');
 
	}
 

	
 
	for (uint i = 0; i != 32; i++) {
 
		for (uint j = 0; j < _langtab_num[i]; j++) {
 
			size = FS_NORMAL;
 
			const char *text = _langpack_offs[_langtab_start[i] + j];
 
			if (str != NULL) *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 (c == SCC_TINYFONT) {
 
					size = FS_SMALL;
 
				} else if (c == SCC_BIGFONT) {
 
					size = FS_LARGE;
 
				} else if (!IsInsideMM(c, SCC_SPRITE_START, SCC_SPRITE_END) && IsPrintable(c) && !IsTextDirectionChar(c) && c != '?' && GetGlyph(size, c) == question_mark[size]) {
 
					/* The character is printable, but not in the normal font. This is the case we were testing for. */
 
					return true;
 
				}
 
	this->Reset();
 
	for (const char *text = this->NextString(); text != NULL; text = this->NextString()) {
 
		FontSize size = this->DefaultSize();
 
		if (str != NULL) *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 (c == SCC_TINYFONT) {
 
				size = FS_SMALL;
 
			} else if (c == SCC_BIGFONT) {
 
				size = FS_LARGE;
 
			} else if (!IsInsideMM(c, SCC_SPRITE_START, SCC_SPRITE_END) && IsPrintable(c) && !IsTextDirectionChar(c) && c != '?' && GetGlyph(size, c) == question_mark[size]) {
 
				/* The character is printable, but not in the normal font. This is the case we were testing for. */
 
				return true;
 
			}
 
		}
 
	}
 
	return false;
 
}
 

	
 
/** Helper for searching through the language pack. */
 
class LanguagePackGlyphSearcher : public MissingGlyphSearcher {
 
	uint i; ///< Iterator for the primary language tables.
 
	uint j; ///< Iterator for the secondary language tables.
 

	
 
	/* virtual */ void Reset()
 
	{
 
		this->i = 0;
 
		this->j = 0;
 
	}
 

	
 
	FontSize DefaultSize()
 
	{
 
		return FS_NORMAL;
 
	}
 

	
 
	const char *NextString()
 
	{
 
		if (this->i >= 32) return NULL;
 

	
 
		const char *ret = _langpack_offs[_langtab_start[i] + j];
 

	
 
		this->j++;
 
		while (this->j >= _langtab_num[this->i] && this->i < 32) {
 
			i++;
 
			j = 0;
 
		}
 

	
 
		return ret;
 
	}
 
};
 

	
 
/**
 
 * Check whether the currently loaded language pack
 
 * uses characters that the currently loaded font
 
 * does not support. If this is the case an error
 
 * message will be shown in English. The error
 
 * message will not be localized because that would
 
@@ -1800,21 +1829,22 @@ static bool FindMissingGlyphs(const char
 
 * font, which is the whole reason this check has
 
 * been added.
 
 * @param base_font Whether to look at the base font as well.
 
 */
 
void CheckForMissingGlyphsInLoadedLanguagePack(bool base_font)
 
{
 
	bool bad_font = !base_font || FindMissingGlyphs(NULL);
 
	LanguagePackGlyphSearcher searcher;
 
	bool bad_font = !base_font || searcher.FindMissingGlyphs(NULL);
 
#ifdef WITH_FREETYPE
 
	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));
 

	
 
		bad_font = !SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, &FindMissingGlyphs);
 
		bad_font = !SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, &searcher);
 

	
 
		memcpy(&_freetype, &backup, sizeof(backup));
 

	
 
		if (bad_font && base_font) {
 
			/* Our fallback font does miss characters too, so keep the
 
			 * user chosen font as that is more likely to be any good than
src/strings_func.h
Show inline comments
 
@@ -11,12 +11,13 @@
 

	
 
#ifndef STRINGS_FUNC_H
 
#define STRINGS_FUNC_H
 

	
 
#include "strings_type.h"
 
#include "string_type.h"
 
#include "gfx_type.h"
 

	
 
class StringParameters {
 
	StringParameters *parent; ///< If not NULL, this instance references data from this parent instance.
 
	uint64 *data;             ///< Array with the actual data.
 
	WChar *type;              ///< Array with type information about the data. Can be NULL when no type information is needed. See #StringControlCode.
 

	
 
@@ -193,9 +194,37 @@ extern TextDirection _current_text_dir; 
 

	
 
void InitializeLanguagePacks();
 
const char *GetCurrentLanguageIsoCode();
 

	
 
int CDECL StringIDSorter(const StringID *a, const StringID *b);
 

	
 
/**
 
 * A searcher for missing glyphs.
 
 */
 
class MissingGlyphSearcher {
 
public:
 
	/** Make sure everything gets destructed right. */
 
	virtual ~MissingGlyphSearcher() {}
 

	
 
	/**
 
	 * Get the next string to search through.
 
	 * @return The next string or NULL if there is none.
 
	 */
 
	virtual const char *NextString() = 0;
 

	
 
	/**
 
	 * Get the default (font) size of the string.
 
	 * @return The font size.
 
	 */
 
	virtual FontSize DefaultSize() = 0;
 

	
 
	/**
 
	 * Reset the search, i.e. begin from the beginning again.
 
	 */
 
	virtual void Reset() = 0;
 

	
 
	bool FindMissingGlyphs(const char **str);
 
};
 

	
 
void CheckForMissingGlyphsInLoadedLanguagePack(bool base_font = true);
 

	
 
#endif /* STRINGS_FUNC_H */
0 comments (0 inline, 0 general)