Changeset - r20426:c68b26c88f35
[Not reviewed]
master
0 1 0
rubidium - 11 years ago 2013-06-23 15:29:20
rubidium@openttd.org
(svn r25441) -Codechange: move the freetype font allocation into the FreeTypeFontCache
1 file changed with 49 insertions and 81 deletions:
0 comments (0 inline, 0 general)
src/fontcache.cpp
Show inline comments
 
@@ -140,8 +140,11 @@ bool SpriteFontCache::GetDrawGlyphShadow
 

	
 
/** Font cache for fonts that are based on a freetype font. */
 
class FreeTypeFontCache : public FontCache {
 
private:
 
	FT_Face face;  ///< The font face associated with this font.
 
public:
 
	FreeTypeFontCache(FontSize fs) : FontCache(fs) {}
 
	FreeTypeFontCache(FontSize fs, FT_Face face, int pixels);
 
	~FreeTypeFontCache();
 
	virtual SpriteID GetUnicodeGlyph(uint32 key) { return this->parent->GetUnicodeGlyph(key); }
 
	virtual void SetUnicodeGlyph(uint32 key, SpriteID sprite) { this->parent->SetUnicodeGlyph(key, sprite); }
 
	virtual void InitializeUnicodeGlyphMap() { this->parent->InitializeUnicodeGlyphMap(); }
 
@@ -152,10 +155,6 @@ public:
 
};
 

	
 
FT_Library _library = NULL;
 
static FT_Face _face_small = NULL;
 
static FT_Face _face_medium = NULL;
 
static FT_Face _face_large = NULL;
 
static FT_Face _face_mono = NULL;
 
static int _ascender[FS_END];
 

	
 
FreeTypeSettings _freetype;
 
@@ -163,40 +162,46 @@ FreeTypeSettings _freetype;
 
static const byte FACE_COLOUR   = 1;
 
static const byte SHADOW_COLOUR = 2;
 

	
 
static void SetFontGeometry(FT_Face face, FontSize size, int pixels)
 
/**
 
 * Create a new FreeTypeFontCache.
 
 * @param fs     The font size that is going to be cached.
 
 * @param face   The font that has to be loaded.
 
 * @param pixels The number of pixels this font should be high.
 
 */
 
FreeTypeFontCache::FreeTypeFontCache(FontSize fs, FT_Face face, int pixels) : FontCache(fs), face(face)
 
{
 
	if (pixels == 0) {
 
		/* Try to determine a good height based on the minimal height recommended by the font. */
 
		pixels = _default_font_height[size];
 
		pixels = _default_font_height[this->fs];
 

	
 
		TT_Header *head = (TT_Header *)FT_Get_Sfnt_Table(face, ft_sfnt_head);
 
		TT_Header *head = (TT_Header *)FT_Get_Sfnt_Table(this->face, ft_sfnt_head);
 
		if (head != NULL) {
 
			/* Font height is minimum height plus the difference between the default
 
			 * height for this font size and the small size. */
 
			int diff = _default_font_height[size] - _default_font_height[FS_SMALL];
 
			pixels = Clamp(min(head->Lowest_Rec_PPEM, 20) + diff, _default_font_height[size], MAX_FONT_SIZE);
 
			int diff = _default_font_height[this->fs] - _default_font_height[FS_SMALL];
 
			pixels = Clamp(min(head->Lowest_Rec_PPEM, 20) + diff, _default_font_height[this->fs], MAX_FONT_SIZE);
 
		}
 
	}
 

	
 
	FT_Error err = FT_Set_Pixel_Sizes(face, 0, pixels);
 
	FT_Error err = FT_Set_Pixel_Sizes(this->face, 0, pixels);
 
	if (err == FT_Err_Invalid_Pixel_Size) {
 

	
 
		/* Find nearest size to that requested */
 
		FT_Bitmap_Size *bs = face->available_sizes;
 
		int i = face->num_fixed_sizes;
 
		FT_Bitmap_Size *bs = this->face->available_sizes;
 
		int i = this->face->num_fixed_sizes;
 
		int n = bs->height;
 
		for (; --i; bs++) {
 
			if (abs(pixels - bs->height) < abs(pixels - n)) n = bs->height;
 
		}
 

	
 
		FT_Set_Pixel_Sizes(face, 0, n);
 
		FT_Set_Pixel_Sizes(this->face, 0, n);
 
	}
 

	
 
	int asc = face->size->metrics.ascender >> 6;
 
	int dec = face->size->metrics.descender >> 6;
 
	int asc = this->face->size->metrics.ascender >> 6;
 
	int dec = this->face->size->metrics.descender >> 6;
 

	
 
	_ascender[size] = asc;
 
	_font_height[size] = asc - dec;
 
	_ascender[this->fs] = asc;
 
	_font_height[this->fs] = asc - dec;
 
}
 

	
 
/**
 
@@ -253,15 +258,11 @@ static void LoadFreeTypeFont(const char 
 
static void ResetGlyphCache(bool monospace);
 

	
 
/**
 
 * Unload a face and set it to NULL.
 
 * @param face the face to unload
 
 * Unload the face
 
 */
 
static void UnloadFace(FT_Face *face)
 
FreeTypeFontCache::~FreeTypeFontCache()
 
{
 
	if (*face == NULL) return;
 

	
 
	FT_Done_Face(*face);
 
	*face = NULL;
 
	if (this->face != NULL) FT_Done_Face(this->face);
 
}
 

	
 
/**
 
@@ -273,14 +274,6 @@ void InitFreeType(bool monospace)
 
	ResetFontSizes(monospace);
 
	ResetGlyphCache(monospace);
 

	
 
	if (monospace) {
 
		UnloadFace(&_face_mono);
 
	} else {
 
		UnloadFace(&_face_small);
 
		UnloadFace(&_face_medium);
 
		UnloadFace(&_face_large);
 
	}
 

	
 
	if (StrEmpty(_freetype.small.font) && StrEmpty(_freetype.medium.font) && StrEmpty(_freetype.large.font) && StrEmpty(_freetype.mono.font)) {
 
		DEBUG(freetype, 1, "No font faces specified, using sprite fonts instead");
 
		return;
 
@@ -297,30 +290,23 @@ void InitFreeType(bool monospace)
 

	
 
	/* Load each font */
 
	if (monospace) {
 
		LoadFreeTypeFont(_freetype.mono.font ,  &_face_mono,   "mono");
 
		FT_Face mono = NULL;
 
		LoadFreeTypeFont(_freetype.mono.font ,  &mono,   "mono");
 

	
 
		if (_face_mono != NULL) {
 
			new FreeTypeFontCache(FS_MONO);
 
			SetFontGeometry(_face_mono, FS_MONO, _freetype.mono.size);
 
		}
 
		if (mono != NULL) new FreeTypeFontCache(FS_MONO, mono, _freetype.mono.size);
 
	} else {
 
		LoadFreeTypeFont(_freetype.small.font,  &_face_small,  "small");
 
		LoadFreeTypeFont(_freetype.medium.font, &_face_medium, "medium");
 
		LoadFreeTypeFont(_freetype.large.font,  &_face_large,  "large");
 
		FT_Face small  = NULL;
 
		FT_Face medium = NULL;
 
		FT_Face large  = NULL;
 

	
 
		LoadFreeTypeFont(_freetype.small.font,  &small,  "small");
 
		LoadFreeTypeFont(_freetype.medium.font, &medium, "medium");
 
		LoadFreeTypeFont(_freetype.large.font,  &large,  "large");
 

	
 
		/* Set each font size */
 
		if (_face_small != NULL) {
 
			new FreeTypeFontCache(FS_SMALL);
 
			SetFontGeometry(_face_small, FS_SMALL, _freetype.small.size);
 
		}
 
		if (_face_medium != NULL) {
 
			new FreeTypeFontCache(FS_NORMAL);
 
			SetFontGeometry(_face_medium, FS_NORMAL, _freetype.medium.size);
 
		}
 
		if (_face_large != NULL) {
 
			new FreeTypeFontCache(FS_LARGE);
 
			SetFontGeometry(_face_large, FS_LARGE, _freetype.large.size);
 
		}
 
		if (small != NULL)  new FreeTypeFontCache(FS_SMALL,  small,  _freetype.small.size);
 
		if (medium != NULL) new FreeTypeFontCache(FS_NORMAL, medium, _freetype.medium.size);
 
		if (large != NULL)  new FreeTypeFontCache(FS_LARGE,  large,  _freetype.large.size);
 
	}
 
}
 

	
 
@@ -329,13 +315,9 @@ void InitFreeType(bool monospace)
 
 */
 
void UninitFreeType()
 
{
 
	ResetGlyphCache(true);
 
	ResetGlyphCache(false);
 

	
 
	UnloadFace(&_face_small);
 
	UnloadFace(&_face_medium);
 
	UnloadFace(&_face_large);
 
	UnloadFace(&_face_mono);
 
	ResetFontSizes(true);
 
	ResetFontSizes(false);
 
	ClearFontCache();
 

	
 
	for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
 
		FontCache *fc = FontCache::Get(fs);
 
@@ -355,18 +337,6 @@ void FreeTypeFontCache::ClearFontCache()
 
	ResetGlyphCache(false);
 
}
 

	
 
static FT_Face GetFontFace(FontSize size)
 
{
 
	switch (size) {
 
		default: NOT_REACHED();
 
		case FS_NORMAL: return _face_medium;
 
		case FS_SMALL:  return _face_small;
 
		case FS_LARGE:  return _face_large;
 
		case FS_MONO:   return _face_mono;
 
	}
 
}
 

	
 

	
 
struct GlyphEntry {
 
	Sprite *sprite;
 
	byte width;
 
@@ -464,7 +434,6 @@ static bool GetFontAAState(FontSize size
 

	
 
const Sprite *FreeTypeFontCache::GetGlyph(WChar key)
 
{
 
	FT_Face face = GetFontFace(this->fs);
 
	FT_GlyphSlot slot;
 
	GlyphEntry new_glyph;
 
	GlyphEntry *glyph;
 
@@ -477,7 +446,7 @@ const Sprite *FreeTypeFontCache::GetGlyp
 
	assert(IsPrintable(key));
 

	
 
	/* Bail out if no face loaded, or for our special characters */
 
	if (face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) {
 
	if (this->face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) {
 
		SpriteID sprite = this->GetUnicodeGlyph(key);
 
		if (sprite == 0) sprite = this->GetUnicodeGlyph('?');
 

	
 
@@ -485,7 +454,7 @@ const Sprite *FreeTypeFontCache::GetGlyp
 
		if (sprite != 0) return GetSprite(sprite, ST_FONT);
 

	
 
		/* For the 'rare' case there is no font available at all. */
 
		if (face == NULL) error("No sprite font and no real font either... bailing!");
 
		if (this->face == NULL) error("No sprite font and no real font either... bailing!");
 

	
 
		/* Use the '?' from the freetype font. */
 
		key = '?';
 
@@ -495,11 +464,11 @@ const Sprite *FreeTypeFontCache::GetGlyp
 
	glyph = GetGlyphPtr(this->fs, key);
 
	if (glyph != NULL && glyph->sprite != NULL) return glyph->sprite;
 

	
 
	slot = face->glyph;
 
	slot = this->face->glyph;
 

	
 
	bool aa = GetFontAAState(this->fs);
 

	
 
	FT_UInt glyph_index = FT_Get_Char_Index(face, key);
 
	FT_UInt glyph_index = FT_Get_Char_Index(this->face, key);
 
	if (glyph_index == 0) {
 
		if (key == '?') {
 
			/* The font misses the '?' character. Use sprite font. */
 
@@ -518,8 +487,8 @@ const Sprite *FreeTypeFontCache::GetGlyp
 
			return glyph->sprite;
 
		}
 
	}
 
	FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
 
	FT_Render_Glyph(face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
 
	FT_Load_Glyph(this->face, glyph_index, FT_LOAD_DEFAULT);
 
	FT_Render_Glyph(this->face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
 

	
 
	/* Despite requesting a normal glyph, FreeType may have returned a bitmap */
 
	aa = (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
 
@@ -577,10 +546,9 @@ bool FreeTypeFontCache::GetDrawGlyphShad
 

	
 
uint FreeTypeFontCache::GetGlyphWidth(WChar key)
 
{
 
	FT_Face face = GetFontFace(this->fs);
 
	GlyphEntry *glyph;
 

	
 
	if (face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) {
 
	if (this->face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) {
 
		SpriteID sprite = this->GetUnicodeGlyph(key);
 
		if (sprite == 0) sprite = this->GetUnicodeGlyph('?');
 
		return SpriteExists(sprite) ? GetSprite(sprite, ST_FONT)->width + (this->fs != FS_NORMAL && this->fs != FS_MONO) : 0;
0 comments (0 inline, 0 general)