4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
10 /** @file fontcache.cpp Cache for characters from fonts. */
13 #include "fontcache.h"
14 #include "fontdetection.h"
15 #include "blitter/factory.hpp"
16 #include "core/math_func.hpp"
17 #include "core/smallmap_type.hpp"
18 #include "strings_func.h"
19 #include "zoom_type.h"
20 #include "gfx_layout.h"
22 #include "table/sprites.h"
23 #include "table/control_codes.h"
24 #include "table/unicode.h"
26 static const int ASCII_LETTERSTART
= 32; ///< First printable ASCII letter.
27 static const int MAX_FONT_SIZE
= 72; ///< Maximum font size.
29 /** Default heights for the different sizes of fonts. */
30 static const int _default_font_height
[FS_END
] = {10, 6, 18, 10};
31 static const int _default_font_ascender
[FS_END
] = { 8, 5, 15, 8};
34 * Create a new font cache.
35 * @param fs The size of the font.
37 FontCache::FontCache(FontSize fs
) : parent(FontCache::Get(fs
)), fs(fs
), height(_default_font_height
[fs
]),
38 ascender(_default_font_ascender
[fs
]), descender(_default_font_ascender
[fs
] - _default_font_height
[fs
]),
41 assert(parent
== NULL
|| this->fs
== parent
->fs
);
42 FontCache::caches
[this->fs
] = this;
43 Layouter::ResetFontCache(this->fs
);
46 /** Clean everything up. */
47 FontCache::~FontCache()
49 assert(this->fs
== parent
->fs
);
50 FontCache::caches
[this->fs
] = this->parent
;
51 Layouter::ResetFontCache(this->fs
);
56 * Get height of a character for a given font size.
57 * @param size Font size to get height of
58 * @return Height of characters in the given font (pixels)
60 int GetCharacterHeight(FontSize size
)
62 return FontCache::Get(size
)->GetHeight();
66 /** Font cache for fonts that are based on a freetype font. */
67 class SpriteFontCache
: public FontCache
{
69 SpriteID
**glyph_to_spriteid_map
; ///< Mapping of glyphs to sprite IDs.
71 void ClearGlyphToSpriteMap();
73 SpriteFontCache(FontSize fs
);
75 virtual SpriteID
GetUnicodeGlyph(WChar key
);
76 virtual void SetUnicodeGlyph(WChar key
, SpriteID sprite
);
77 virtual void InitializeUnicodeGlyphMap();
78 virtual void ClearFontCache();
79 virtual const Sprite
*GetGlyph(GlyphID key
);
80 virtual uint
GetGlyphWidth(GlyphID key
);
81 virtual bool GetDrawGlyphShadow();
82 virtual GlyphID
MapCharToGlyph(WChar key
) { assert(IsPrintable(key
)); return SPRITE_GLYPH
| key
; }
83 virtual const void *GetFontTable(uint32 tag
, size_t &length
) { length
= 0; return NULL
; }
84 virtual const char *GetFontName() { return "sprite"; }
88 * Create a new sprite font cache.
89 * @param fs The font size to create the cache for.
91 SpriteFontCache::SpriteFontCache(FontSize fs
) : FontCache(fs
), glyph_to_spriteid_map(NULL
)
93 this->InitializeUnicodeGlyphMap();
97 * Free everything we allocated.
99 SpriteFontCache::~SpriteFontCache()
101 this->ClearGlyphToSpriteMap();
104 SpriteID
SpriteFontCache::GetUnicodeGlyph(GlyphID key
)
106 if (this->glyph_to_spriteid_map
[GB(key
, 8, 8)] == NULL
) return 0;
107 return this->glyph_to_spriteid_map
[GB(key
, 8, 8)][GB(key
, 0, 8)];
110 void SpriteFontCache::SetUnicodeGlyph(GlyphID key
, SpriteID sprite
)
112 if (this->glyph_to_spriteid_map
== NULL
) this->glyph_to_spriteid_map
= CallocT
<SpriteID
*>(256);
113 if (this->glyph_to_spriteid_map
[GB(key
, 8, 8)] == NULL
) this->glyph_to_spriteid_map
[GB(key
, 8, 8)] = CallocT
<SpriteID
>(256);
114 this->glyph_to_spriteid_map
[GB(key
, 8, 8)][GB(key
, 0, 8)] = sprite
;
117 void SpriteFontCache::InitializeUnicodeGlyphMap()
119 /* Clear out existing glyph map if it exists */
120 this->ClearGlyphToSpriteMap();
124 default: NOT_REACHED();
125 case FS_MONO
: // Use normal as default for mono spaced font, i.e. FALL THROUGH
126 case FS_NORMAL
: base
= SPR_ASCII_SPACE
; break;
127 case FS_SMALL
: base
= SPR_ASCII_SPACE_SMALL
; break;
128 case FS_LARGE
: base
= SPR_ASCII_SPACE_BIG
; break;
131 for (uint i
= ASCII_LETTERSTART
; i
< 256; i
++) {
132 SpriteID sprite
= base
+ i
- ASCII_LETTERSTART
;
133 if (!SpriteExists(sprite
)) continue;
134 this->SetUnicodeGlyph(i
, sprite
);
135 this->SetUnicodeGlyph(i
+ SCC_SPRITE_START
, sprite
);
138 for (uint i
= 0; i
< lengthof(_default_unicode_map
); i
++) {
139 byte key
= _default_unicode_map
[i
].key
;
141 /* Clear the glyph. This happens if the glyph at this code point
142 * is non-standard and should be accessed by an SCC_xxx enum
144 this->SetUnicodeGlyph(_default_unicode_map
[i
].code
, 0);
146 SpriteID sprite
= base
+ key
- ASCII_LETTERSTART
;
147 this->SetUnicodeGlyph(_default_unicode_map
[i
].code
, sprite
);
153 * Clear the glyph to sprite mapping.
155 void SpriteFontCache::ClearGlyphToSpriteMap()
157 if (this->glyph_to_spriteid_map
== NULL
) return;
159 for (uint i
= 0; i
< 256; i
++) {
160 free(this->glyph_to_spriteid_map
[i
]);
162 free(this->glyph_to_spriteid_map
);
163 this->glyph_to_spriteid_map
= NULL
;
166 void SpriteFontCache::ClearFontCache()
168 Layouter::ResetFontCache(this->fs
);
171 const Sprite
*SpriteFontCache::GetGlyph(GlyphID key
)
173 SpriteID sprite
= this->GetUnicodeGlyph(key
);
174 if (sprite
== 0) sprite
= this->GetUnicodeGlyph('?');
175 return GetSprite(sprite
, ST_FONT
);
178 uint
SpriteFontCache::GetGlyphWidth(GlyphID key
)
180 SpriteID sprite
= this->GetUnicodeGlyph(key
);
181 if (sprite
== 0) sprite
= this->GetUnicodeGlyph('?');
182 return SpriteExists(sprite
) ? GetSprite(sprite
, ST_FONT
)->width
+ (this->fs
!= FS_NORMAL
) : 0;
185 bool SpriteFontCache::GetDrawGlyphShadow()
190 /*static */ FontCache
*FontCache::caches
[FS_END
] = { new SpriteFontCache(FS_NORMAL
), new SpriteFontCache(FS_SMALL
), new SpriteFontCache(FS_LARGE
), new SpriteFontCache(FS_MONO
) };
193 #include <ft2build.h>
194 #include FT_FREETYPE_H
196 #include FT_TRUETYPE_TABLES_H
198 /** Font cache for fonts that are based on a freetype font. */
199 class FreeTypeFontCache
: public FontCache
{
201 FT_Face face
; ///< The font face associated with this font.
203 typedef SmallMap
<uint32
, SmallPair
<size_t, const void*> > FontTable
; ///< Table with font table cache
204 FontTable font_tables
; ///< Cached font tables.
206 /** Container for information about a glyph. */
208 Sprite
*sprite
; ///< The loaded sprite.
209 byte width
; ///< The width of the glyph.
210 bool duplicate
; ///< Whether this glyph entry is a duplicate, i.e. may this be freed?
214 * The glyph cache. This is structured to reduce memory consumption.
215 * 1) There is a 'segment' table for each font size.
216 * 2) Each segment table is a discrete block of characters.
217 * 3) Each block contains 256 (aligned) characters sequential characters.
219 * The cache is accessed in the following way:
220 * For character 0x0041 ('A'): glyph_to_sprite[0x00][0x41]
221 * For character 0x20AC (Euro): glyph_to_sprite[0x20][0xAC]
223 * Currently only 256 segments are allocated, "limiting" us to 65536 characters.
224 * This can be simply changed in the two functions Get & SetGlyphPtr.
226 GlyphEntry
**glyph_to_sprite
;
228 GlyphEntry
*GetGlyphPtr(GlyphID key
);
229 void SetGlyphPtr(GlyphID key
, const GlyphEntry
*glyph
, bool duplicate
= false);
232 FreeTypeFontCache(FontSize fs
, FT_Face face
, int pixels
);
233 ~FreeTypeFontCache();
234 virtual SpriteID
GetUnicodeGlyph(WChar key
) { return this->parent
->GetUnicodeGlyph(key
); }
235 virtual void SetUnicodeGlyph(WChar key
, SpriteID sprite
) { this->parent
->SetUnicodeGlyph(key
, sprite
); }
236 virtual void InitializeUnicodeGlyphMap() { this->parent
->InitializeUnicodeGlyphMap(); }
237 virtual void ClearFontCache();
238 virtual const Sprite
*GetGlyph(GlyphID key
);
239 virtual uint
GetGlyphWidth(GlyphID key
);
240 virtual bool GetDrawGlyphShadow();
241 virtual GlyphID
MapCharToGlyph(WChar key
);
242 virtual const void *GetFontTable(uint32 tag
, size_t &length
);
243 virtual const char *GetFontName() { return face
->family_name
; }
246 FT_Library _library
= NULL
;
248 FreeTypeSettings _freetype
;
250 static const byte FACE_COLOUR
= 1;
251 static const byte SHADOW_COLOUR
= 2;
254 * Create a new FreeTypeFontCache.
255 * @param fs The font size that is going to be cached.
256 * @param face The font that has to be loaded.
257 * @param pixels The number of pixels this font should be high.
259 FreeTypeFontCache::FreeTypeFontCache(FontSize fs
, FT_Face face
, int pixels
) : FontCache(fs
), face(face
), glyph_to_sprite(NULL
)
261 assert(face
!= NULL
);
264 /* Try to determine a good height based on the minimal height recommended by the font. */
265 pixels
= _default_font_height
[this->fs
];
267 TT_Header
*head
= (TT_Header
*)FT_Get_Sfnt_Table(this->face
, ft_sfnt_head
);
269 /* Font height is minimum height plus the difference between the default
270 * height for this font size and the small size. */
271 int diff
= _default_font_height
[this->fs
] - _default_font_height
[FS_SMALL
];
272 pixels
= Clamp(min(head
->Lowest_Rec_PPEM
, 20) + diff
, _default_font_height
[this->fs
], MAX_FONT_SIZE
);
276 FT_Error err
= FT_Set_Pixel_Sizes(this->face
, 0, pixels
);
277 if (err
== FT_Err_Invalid_Pixel_Size
) {
279 /* Find nearest size to that requested */
280 FT_Bitmap_Size
*bs
= this->face
->available_sizes
;
281 int i
= this->face
->num_fixed_sizes
;
284 if (abs(pixels
- bs
->height
) < abs(pixels
- n
)) n
= bs
->height
;
287 FT_Set_Pixel_Sizes(this->face
, 0, n
);
290 this->units_per_em
= this->face
->units_per_EM
;
291 this->ascender
= this->face
->size
->metrics
.ascender
>> 6;
292 this->descender
= this->face
->size
->metrics
.descender
>> 6;
293 this->height
= this->ascender
- this->descender
;
297 * Loads the freetype font.
298 * First type to load the fontname as if it were a path. If that fails,
299 * try to resolve the filename of the font using fontconfig, where the
300 * format is 'font family name' or 'font family name, font style'.
301 * @param fs The font size to load.
303 static void LoadFreeTypeFont(FontSize fs
)
305 FreeTypeSubSetting
*settings
= NULL
;
307 default: NOT_REACHED();
308 case FS_SMALL
: settings
= &_freetype
.small
; break;
309 case FS_NORMAL
: settings
= &_freetype
.medium
; break;
310 case FS_LARGE
: settings
= &_freetype
.large
; break;
311 case FS_MONO
: settings
= &_freetype
.mono
; break;
314 if (StrEmpty(settings
->font
)) return;
316 if (_library
== NULL
) {
317 if (FT_Init_FreeType(&_library
) != FT_Err_Ok
) {
318 ShowInfoF("Unable to initialize FreeType, using sprite fonts instead");
322 DEBUG(freetype
, 2, "Initialized");
326 FT_Error error
= FT_New_Face(_library
, settings
->font
, 0, &face
);
328 if (error
!= FT_Err_Ok
) error
= GetFontByFaceName(settings
->font
, &face
);
330 if (error
== FT_Err_Ok
) {
331 DEBUG(freetype
, 2, "Requested '%s', using '%s %s'", settings
->font
, face
->family_name
, face
->style_name
);
333 /* Attempt to select the unicode character map */
334 error
= FT_Select_Charmap(face
, ft_encoding_unicode
);
335 if (error
== FT_Err_Ok
) goto found_face
; // Success
337 if (error
== FT_Err_Invalid_CharMap_Handle
) {
338 /* Try to pick a different character map instead. We default to
339 * the first map, but platform_id 0 encoding_id 0 should also
340 * be unicode (strange system...) */
341 FT_CharMap found
= face
->charmaps
[0];
344 for (i
= 0; i
< face
->num_charmaps
; i
++) {
345 FT_CharMap charmap
= face
->charmaps
[i
];
346 if (charmap
->platform_id
== 0 && charmap
->encoding_id
== 0) {
352 error
= FT_Set_Charmap(face
, found
);
353 if (error
== FT_Err_Ok
) goto found_face
;
360 static const char *SIZE_TO_NAME
[] = { "medium", "small", "large", "mono" };
361 ShowInfoF("Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", settings
->font
, SIZE_TO_NAME
[fs
], error
);
365 new FreeTypeFontCache(fs
, face
, settings
->size
);
370 * Free everything that was allocated for this font cache.
372 FreeTypeFontCache::~FreeTypeFontCache()
374 FT_Done_Face(this->face
);
375 this->ClearFontCache();
377 for (FontTable::iterator iter
= this->font_tables
.Begin(); iter
!= this->font_tables
.End(); iter
++) {
378 free(iter
->second
.second
);
383 * Reset cached glyphs.
385 void FreeTypeFontCache::ClearFontCache()
387 if (this->glyph_to_sprite
== NULL
) return;
389 for (int i
= 0; i
< 256; i
++) {
390 if (this->glyph_to_sprite
[i
] == NULL
) continue;
392 for (int j
= 0; j
< 256; j
++) {
393 if (this->glyph_to_sprite
[i
][j
].duplicate
) continue;
394 free(this->glyph_to_sprite
[i
][j
].sprite
);
397 free(this->glyph_to_sprite
[i
]);
400 free(this->glyph_to_sprite
);
401 this->glyph_to_sprite
= NULL
;
403 Layouter::ResetFontCache(this->fs
);
406 FreeTypeFontCache::GlyphEntry
*FreeTypeFontCache::GetGlyphPtr(GlyphID key
)
408 if (this->glyph_to_sprite
== NULL
) return NULL
;
409 if (this->glyph_to_sprite
[GB(key
, 8, 8)] == NULL
) return NULL
;
410 return &this->glyph_to_sprite
[GB(key
, 8, 8)][GB(key
, 0, 8)];
414 void FreeTypeFontCache::SetGlyphPtr(GlyphID key
, const GlyphEntry
*glyph
, bool duplicate
)
416 if (this->glyph_to_sprite
== NULL
) {
417 DEBUG(freetype
, 3, "Allocating root glyph cache for size %u", this->fs
);
418 this->glyph_to_sprite
= CallocT
<GlyphEntry
*>(256);
421 if (this->glyph_to_sprite
[GB(key
, 8, 8)] == NULL
) {
422 DEBUG(freetype
, 3, "Allocating glyph cache for range 0x%02X00, size %u", GB(key
, 8, 8), this->fs
);
423 this->glyph_to_sprite
[GB(key
, 8, 8)] = CallocT
<GlyphEntry
>(256);
426 DEBUG(freetype
, 4, "Set glyph for unicode character 0x%04X, size %u", key
, this->fs
);
427 this->glyph_to_sprite
[GB(key
, 8, 8)][GB(key
, 0, 8)].sprite
= glyph
->sprite
;
428 this->glyph_to_sprite
[GB(key
, 8, 8)][GB(key
, 0, 8)].width
= glyph
->width
;
429 this->glyph_to_sprite
[GB(key
, 8, 8)][GB(key
, 0, 8)].duplicate
= duplicate
;
432 static void *AllocateFont(size_t size
)
434 return MallocT
<byte
>(size
);
438 /* Check if a glyph should be rendered with antialiasing */
439 static bool GetFontAAState(FontSize size
)
441 /* AA is only supported for 32 bpp */
442 if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 32) return false;
445 default: NOT_REACHED();
446 case FS_NORMAL
: return _freetype
.medium
.aa
;
447 case FS_SMALL
: return _freetype
.small
.aa
;
448 case FS_LARGE
: return _freetype
.large
.aa
;
449 case FS_MONO
: return _freetype
.mono
.aa
;
454 const Sprite
*FreeTypeFontCache::GetGlyph(GlyphID key
)
456 if ((key
& SPRITE_GLYPH
) != 0) return parent
->GetGlyph(key
);
458 /* Check for the glyph in our cache */
459 GlyphEntry
*glyph
= this->GetGlyphPtr(key
);
460 if (glyph
!= NULL
&& glyph
->sprite
!= NULL
) return glyph
->sprite
;
462 FT_GlyphSlot slot
= this->face
->glyph
;
464 bool aa
= GetFontAAState(this->fs
);
466 GlyphEntry new_glyph
;
468 GlyphID question_glyph
= this->MapCharToGlyph('?');
469 if (question_glyph
== 0) {
470 /* The font misses the '?' character. Use built-in sprite.
471 * Note: We cannot use the baseset as this also has to work in the bootstrap GUI. */
472 #define CPSET { 0, 0, 0, 0, 1 }
473 #define CP___ { 0, 0, 0, 0, 0 }
474 static SpriteLoader::CommonPixel builtin_questionmark_data
[10 * 8] = {
475 CP___
, CP___
, CPSET
, CPSET
, CPSET
, CPSET
, CP___
, CP___
,
476 CP___
, CPSET
, CPSET
, CP___
, CP___
, CPSET
, CPSET
, CP___
,
477 CP___
, CP___
, CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
,
478 CP___
, CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
,
479 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
480 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
481 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
482 CP___
, CP___
, CP___
, CP___
, CP___
, CP___
, CP___
, CP___
,
483 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
484 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
488 static const SpriteLoader::Sprite builtin_questionmark
= {
494 builtin_questionmark_data
497 Sprite
*spr
= BlitterFactory::GetCurrentBlitter()->Encode(&builtin_questionmark
, AllocateFont
);
499 new_glyph
.sprite
= spr
;
500 new_glyph
.width
= spr
->width
+ (this->fs
!= FS_NORMAL
);
501 this->SetGlyphPtr(key
, &new_glyph
, false);
502 return new_glyph
.sprite
;
504 /* Use '?' for missing characters. */
505 this->GetGlyph(question_glyph
);
506 glyph
= this->GetGlyphPtr(question_glyph
);
507 this->SetGlyphPtr(key
, glyph
, true);
508 return glyph
->sprite
;
511 FT_Load_Glyph(this->face
, key
, FT_LOAD_DEFAULT
);
512 FT_Render_Glyph(this->face
->glyph
, aa
? FT_RENDER_MODE_NORMAL
: FT_RENDER_MODE_MONO
);
514 /* Despite requesting a normal glyph, FreeType may have returned a bitmap */
515 aa
= (slot
->bitmap
.pixel_mode
== FT_PIXEL_MODE_GRAY
);
517 /* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */
518 int width
= max(1, slot
->bitmap
.width
+ (this->fs
== FS_NORMAL
));
519 int height
= max(1, slot
->bitmap
.rows
+ (this->fs
== FS_NORMAL
));
521 /* Limit glyph size to prevent overflows later on. */
522 if (width
> 256 || height
> 256) usererror("Font glyph is too large");
524 /* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */
525 SpriteLoader::Sprite sprite
;
526 sprite
.AllocateData(ZOOM_LVL_NORMAL
, width
* height
);
527 sprite
.type
= ST_FONT
;
528 sprite
.width
= width
;
529 sprite
.height
= height
;
530 sprite
.x_offs
= slot
->bitmap_left
;
531 sprite
.y_offs
= this->ascender
- slot
->bitmap_top
;
533 /* Draw shadow for medium size */
534 if (this->fs
== FS_NORMAL
&& !aa
) {
535 for (int y
= 0; y
< slot
->bitmap
.rows
; y
++) {
536 for (int x
= 0; x
< slot
->bitmap
.width
; x
++) {
537 if (aa
? (slot
->bitmap
.buffer
[x
+ y
* slot
->bitmap
.pitch
] > 0) : HasBit(slot
->bitmap
.buffer
[(x
/ 8) + y
* slot
->bitmap
.pitch
], 7 - (x
% 8))) {
538 sprite
.data
[1 + x
+ (1 + y
) * sprite
.width
].m
= SHADOW_COLOUR
;
539 sprite
.data
[1 + x
+ (1 + y
) * sprite
.width
].a
= aa
? slot
->bitmap
.buffer
[x
+ y
* slot
->bitmap
.pitch
] : 0xFF;
545 for (int y
= 0; y
< slot
->bitmap
.rows
; y
++) {
546 for (int x
= 0; x
< slot
->bitmap
.width
; x
++) {
547 if (aa
? (slot
->bitmap
.buffer
[x
+ y
* slot
->bitmap
.pitch
] > 0) : HasBit(slot
->bitmap
.buffer
[(x
/ 8) + y
* slot
->bitmap
.pitch
], 7 - (x
% 8))) {
548 sprite
.data
[x
+ y
* sprite
.width
].m
= FACE_COLOUR
;
549 sprite
.data
[x
+ y
* sprite
.width
].a
= aa
? slot
->bitmap
.buffer
[x
+ y
* slot
->bitmap
.pitch
] : 0xFF;
554 new_glyph
.sprite
= BlitterFactory::GetCurrentBlitter()->Encode(&sprite
, AllocateFont
);
555 new_glyph
.width
= slot
->advance
.x
>> 6;
557 this->SetGlyphPtr(key
, &new_glyph
);
559 return new_glyph
.sprite
;
563 bool FreeTypeFontCache::GetDrawGlyphShadow()
565 return this->fs
== FS_NORMAL
&& GetFontAAState(FS_NORMAL
);
569 uint
FreeTypeFontCache::GetGlyphWidth(GlyphID key
)
571 if ((key
& SPRITE_GLYPH
) != 0) return this->parent
->GetGlyphWidth(key
);
573 GlyphEntry
*glyph
= this->GetGlyphPtr(key
);
574 if (glyph
== NULL
|| glyph
->sprite
== NULL
) {
576 glyph
= this->GetGlyphPtr(key
);
582 GlyphID
FreeTypeFontCache::MapCharToGlyph(WChar key
)
584 assert(IsPrintable(key
));
586 if (key
>= SCC_SPRITE_START
&& key
<= SCC_SPRITE_END
) {
587 return this->parent
->MapCharToGlyph(key
);
590 return FT_Get_Char_Index(this->face
, key
);
593 const void *FreeTypeFontCache::GetFontTable(uint32 tag
, size_t &length
)
595 const FontTable::iterator iter
= this->font_tables
.Find(tag
);
596 if (iter
!= this->font_tables
.End()) {
597 length
= iter
->second
.first
;
598 return iter
->second
.second
;
602 FT_Byte
*result
= NULL
;
604 FT_Load_Sfnt_Table(this->face
, tag
, 0, NULL
, &len
);
607 result
= MallocT
<FT_Byte
>(len
);
608 FT_Load_Sfnt_Table(this->face
, tag
, 0, result
, &len
);
612 this->font_tables
.Insert(tag
, SmallPair
<size_t, const void *>(length
, result
));
616 #endif /* WITH_FREETYPE */
619 * (Re)initialize the freetype related things, i.e. load the non-sprite fonts.
620 * @param monospace Whether to initialise the monospace or regular fonts.
622 void InitFreeType(bool monospace
)
624 for (FontSize fs
= FS_BEGIN
; fs
< FS_END
; fs
++) {
625 if (monospace
!= (fs
== FS_MONO
)) continue;
627 FontCache
*fc
= FontCache::Get(fs
);
628 if (fc
->HasParent()) delete fc
;
631 LoadFreeTypeFont(fs
);
637 * Free everything allocated w.r.t. fonts.
639 void UninitFreeType()
641 for (FontSize fs
= FS_BEGIN
; fs
< FS_END
; fs
++) {
642 FontCache
*fc
= FontCache::Get(fs
);
643 if (fc
->HasParent()) delete fc
;
647 FT_Done_FreeType(_library
);
649 #endif /* WITH_FREETYPE */