1 /* $Id: fontcache.cpp 26389 2014-03-03 21:34:36Z fonsinchen $ */
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"
21 #include "zoom_func.h"
23 #include "table/sprites.h"
24 #include "table/control_codes.h"
25 #include "table/unicode.h"
27 #include "safeguards.h"
29 static const int ASCII_LETTERSTART
= 32; ///< First printable ASCII letter.
30 static const int MAX_FONT_SIZE
= 72; ///< Maximum font size.
32 /** Default heights for the different sizes of fonts. */
33 static const int _default_font_height
[FS_END
] = {10, 6, 18, 10};
34 static const int _default_font_ascender
[FS_END
] = { 8, 5, 15, 8};
37 * Create a new font cache.
38 * @param fs The size of the font.
40 FontCache::FontCache(FontSize fs
) : parent(FontCache::Get(fs
)), fs(fs
), height(_default_font_height
[fs
]),
41 ascender(_default_font_ascender
[fs
]), descender(_default_font_ascender
[fs
] - _default_font_height
[fs
]),
44 assert(this->parent
== nullptr || this->fs
== this->parent
->fs
);
45 FontCache::caches
[this->fs
] = this;
46 font_height_cache
[this->fs
] = this->height
;
47 Layouter::ResetFontCache(this->fs
);
50 /** Clean everything up. */
51 FontCache::~FontCache()
53 assert(this->fs
== this->parent
->fs
);
54 FontCache::caches
[this->fs
] = this->parent
;
55 Layouter::ResetFontCache(this->fs
);
59 /** Font cache for fonts that are based on a freetype font. */
60 class SpriteFontCache
: public FontCache
{
62 SpriteID
**glyph_to_spriteid_map
; ///< Mapping of glyphs to sprite IDs.
64 void ClearGlyphToSpriteMap();
66 SpriteFontCache(FontSize fs
);
68 virtual SpriteID
GetUnicodeGlyph(WChar key
);
69 virtual void SetUnicodeGlyph(WChar key
, SpriteID sprite
);
70 virtual void InitializeUnicodeGlyphMap();
71 virtual void ClearFontCache();
72 virtual const Sprite
*GetGlyph(GlyphID key
);
73 virtual uint
GetGlyphWidth(GlyphID key
);
74 virtual int GetHeight() const;
75 virtual bool GetDrawGlyphShadow();
76 virtual GlyphID
MapCharToGlyph(WChar key
) { assert(IsPrintable(key
)); return SPRITE_GLYPH
| key
; }
77 virtual const void *GetFontTable(uint32 tag
, size_t &length
) { length
= 0; return nullptr; }
78 virtual const char *GetFontName() { return "sprite"; }
82 * Create a new sprite font cache.
83 * @param fs The font size to create the cache for.
85 SpriteFontCache::SpriteFontCache(FontSize fs
) : FontCache(fs
), glyph_to_spriteid_map(nullptr)
87 this->InitializeUnicodeGlyphMap();
91 * Free everything we allocated.
93 SpriteFontCache::~SpriteFontCache()
95 this->ClearGlyphToSpriteMap();
98 SpriteID
SpriteFontCache::GetUnicodeGlyph(GlyphID key
)
100 if (this->glyph_to_spriteid_map
[GB(key
, 8, 8)] == nullptr) return 0;
101 return this->glyph_to_spriteid_map
[GB(key
, 8, 8)][GB(key
, 0, 8)];
104 void SpriteFontCache::SetUnicodeGlyph(GlyphID key
, SpriteID sprite
)
106 if (this->glyph_to_spriteid_map
== nullptr) this->glyph_to_spriteid_map
= CallocT
<SpriteID
*>(256);
107 if (this->glyph_to_spriteid_map
[GB(key
, 8, 8)] == nullptr) this->glyph_to_spriteid_map
[GB(key
, 8, 8)] = CallocT
<SpriteID
>(256);
108 this->glyph_to_spriteid_map
[GB(key
, 8, 8)][GB(key
, 0, 8)] = sprite
;
111 void SpriteFontCache::InitializeUnicodeGlyphMap()
113 /* Clear out existing glyph map if it exists */
114 this->ClearGlyphToSpriteMap();
118 default: NOT_REACHED();
119 case FS_MONO
: // Use normal as default for mono spaced font
120 case FS_NORMAL
: base
= SPR_ASCII_SPACE
; break;
121 case FS_SMALL
: base
= SPR_ASCII_SPACE_SMALL
; break;
122 case FS_LARGE
: base
= SPR_ASCII_SPACE_BIG
; break;
125 for (uint i
= ASCII_LETTERSTART
; i
< 256; i
++) {
126 SpriteID sprite
= base
+ i
- ASCII_LETTERSTART
;
127 if (!SpriteExists(sprite
)) continue;
128 this->SetUnicodeGlyph(i
, sprite
);
129 this->SetUnicodeGlyph(i
+ SCC_SPRITE_START
, sprite
);
132 for (uint i
= 0; i
< lengthof(_default_unicode_map
); i
++) {
133 byte key
= _default_unicode_map
[i
].key
;
135 /* Clear the glyph. This happens if the glyph at this code point
136 * is non-standard and should be accessed by an SCC_xxx enum
138 this->SetUnicodeGlyph(_default_unicode_map
[i
].code
, 0);
140 SpriteID sprite
= base
+ key
- ASCII_LETTERSTART
;
141 this->SetUnicodeGlyph(_default_unicode_map
[i
].code
, sprite
);
145 font_height_cache
[this->fs
] = this->GetHeight();
149 * Clear the glyph to sprite mapping.
151 void SpriteFontCache::ClearGlyphToSpriteMap()
153 if (this->glyph_to_spriteid_map
== nullptr) return;
155 for (uint i
= 0; i
< 256; i
++) {
156 free(this->glyph_to_spriteid_map
[i
]);
158 free(this->glyph_to_spriteid_map
);
159 this->glyph_to_spriteid_map
= nullptr;
162 void SpriteFontCache::ClearFontCache()
164 Layouter::ResetFontCache(this->fs
);
167 const Sprite
*SpriteFontCache::GetGlyph(GlyphID key
)
169 SpriteID sprite
= this->GetUnicodeGlyph(key
);
170 if (sprite
== 0) sprite
= this->GetUnicodeGlyph('?');
171 return GetSprite(sprite
, ST_FONT
);
174 uint
SpriteFontCache::GetGlyphWidth(GlyphID key
)
176 SpriteID sprite
= this->GetUnicodeGlyph(key
);
177 if (sprite
== 0) sprite
= this->GetUnicodeGlyph('?');
178 return SpriteExists(sprite
) ? GetSprite(sprite
, ST_FONT
)->width
+ ScaleGUITrad(this->fs
!= FS_NORMAL
? 1 : 0) : 0;
181 int SpriteFontCache::GetHeight() const
183 return ScaleGUITrad(this->height
);
186 bool SpriteFontCache::GetDrawGlyphShadow()
191 /* static */ FontCache
*FontCache::caches
[FS_END
] = { new SpriteFontCache(FS_NORMAL
), new SpriteFontCache(FS_SMALL
), new SpriteFontCache(FS_LARGE
), new SpriteFontCache(FS_MONO
) };
192 int font_height_cache
[FS_END
];
194 void UpdateFontHeightCache()
196 for (int i
= 0; i
< FS_END
; i
++) {
197 font_height_cache
[i
] = FontCache::Get((FontSize
) i
)->GetHeight();
202 #include <ft2build.h>
203 #include FT_FREETYPE_H
205 #include FT_TRUETYPE_TABLES_H
207 /** Font cache for fonts that are based on a freetype font. */
208 class FreeTypeFontCache
: public FontCache
{
210 FT_Face face
; ///< The font face associated with this font.
212 typedef SmallMap
<uint32
, SmallPair
<size_t, const void*> > FontTable
; ///< Table with font table cache
213 FontTable font_tables
; ///< Cached font tables.
215 /** Container for information about a glyph. */
217 Sprite
*sprite
; ///< The loaded sprite.
218 byte width
; ///< The width of the glyph.
219 bool duplicate
; ///< Whether this glyph entry is a duplicate, i.e. may this be freed?
223 * The glyph cache. This is structured to reduce memory consumption.
224 * 1) There is a 'segment' table for each font size.
225 * 2) Each segment table is a discrete block of characters.
226 * 3) Each block contains 256 (aligned) characters sequential characters.
228 * The cache is accessed in the following way:
229 * For character 0x0041 ('A'): glyph_to_sprite[0x00][0x41]
230 * For character 0x20AC (Euro): glyph_to_sprite[0x20][0xAC]
232 * Currently only 256 segments are allocated, "limiting" us to 65536 characters.
233 * This can be simply changed in the two functions Get & SetGlyphPtr.
235 GlyphEntry
**glyph_to_sprite
;
237 GlyphEntry
*GetGlyphPtr(GlyphID key
);
238 void SetGlyphPtr(GlyphID key
, const GlyphEntry
*glyph
, bool duplicate
= false);
241 FreeTypeFontCache(FontSize fs
, FT_Face face
, int pixels
);
242 ~FreeTypeFontCache();
243 virtual SpriteID
GetUnicodeGlyph(WChar key
) { return this->parent
->GetUnicodeGlyph(key
); }
244 virtual void SetUnicodeGlyph(WChar key
, SpriteID sprite
) { this->parent
->SetUnicodeGlyph(key
, sprite
); }
246 virtual void InitializeUnicodeGlyphMap()
248 this->parent
->InitializeUnicodeGlyphMap();
249 font_height_cache
[this->fs
] = this->GetHeight();
252 virtual void ClearFontCache();
253 virtual const Sprite
*GetGlyph(GlyphID key
);
254 virtual uint
GetGlyphWidth(GlyphID key
);
255 virtual bool GetDrawGlyphShadow();
256 virtual GlyphID
MapCharToGlyph(WChar key
);
257 virtual const void *GetFontTable(uint32 tag
, size_t &length
);
258 virtual const char *GetFontName() { return face
->family_name
; }
261 FT_Library _library
= nullptr;
263 FreeTypeSettings _freetype
;
265 static const byte FACE_COLOUR
= 1;
266 static const byte SHADOW_COLOUR
= 2;
269 * Create a new FreeTypeFontCache.
270 * @param fs The font size that is going to be cached.
271 * @param face The font that has to be loaded.
272 * @param pixels The number of pixels this font should be high.
274 FreeTypeFontCache::FreeTypeFontCache(FontSize fs
, FT_Face face
, int pixels
) : FontCache(fs
), face(face
), glyph_to_sprite(nullptr)
276 assert(face
!= nullptr);
279 /* Try to determine a good height based on the minimal height recommended by the font. */
280 pixels
= _default_font_height
[this->fs
];
282 TT_Header
*head
= (TT_Header
*)FT_Get_Sfnt_Table(this->face
, ft_sfnt_head
);
283 if (head
!= nullptr) {
284 /* Font height is minimum height plus the difference between the default
285 * height for this font size and the small size. */
286 int diff
= _default_font_height
[this->fs
] - _default_font_height
[FS_SMALL
];
287 pixels
= Clamp(min(head
->Lowest_Rec_PPEM
, 20) + diff
, _default_font_height
[this->fs
], MAX_FONT_SIZE
);
291 FT_Error err
= FT_Set_Pixel_Sizes(this->face
, 0, pixels
);
292 if (err
!= FT_Err_Ok
) {
294 /* Find nearest size to that requested */
295 FT_Bitmap_Size
*bs
= this->face
->available_sizes
;
296 int i
= this->face
->num_fixed_sizes
;
297 if (i
> 0) { // In pathetic cases one might get no fixed sizes at all.
301 if (abs(pixels
- bs
->height
) >= abs(pixels
- n
)) continue;
303 chosen
= this->face
->num_fixed_sizes
- i
;
306 /* Don't use FT_Set_Pixel_Sizes here - it might give us another
307 * error, even though the size is available (FS#5885). */
308 err
= FT_Select_Size(this->face
, chosen
);
312 if (err
== FT_Err_Ok
) {
313 this->units_per_em
= this->face
->units_per_EM
;
314 this->ascender
= this->face
->size
->metrics
.ascender
>> 6;
315 this->descender
= this->face
->size
->metrics
.descender
>> 6;
316 this->height
= this->ascender
- this->descender
;
318 /* Both FT_Set_Pixel_Sizes and FT_Select_Size failed. */
319 DEBUG(freetype
, 0, "Font size selection failed. Using FontCache defaults.");
322 font_height_cache
[this->fs
] = this->GetHeight();
326 * Loads the freetype font.
327 * First type to load the fontname as if it were a path. If that fails,
328 * try to resolve the filename of the font using fontconfig, where the
329 * format is 'font family name' or 'font family name, font style'.
330 * @param fs The font size to load.
332 static void LoadFreeTypeFont(FontSize fs
)
334 FreeTypeSubSetting
*settings
= nullptr;
336 default: NOT_REACHED();
337 case FS_SMALL
: settings
= &_freetype
.small
; break;
338 case FS_NORMAL
: settings
= &_freetype
.medium
; break;
339 case FS_LARGE
: settings
= &_freetype
.large
; break;
340 case FS_MONO
: settings
= &_freetype
.mono
; break;
343 if (StrEmpty(settings
->font
)) return;
345 if (_library
== nullptr) {
346 if (FT_Init_FreeType(&_library
) != FT_Err_Ok
) {
347 ShowInfoF("Unable to initialize FreeType, using sprite fonts instead");
351 DEBUG(freetype
, 2, "Initialized");
354 FT_Face face
= nullptr;
355 FT_Error error
= FT_New_Face(_library
, settings
->font
, 0, &face
);
357 if (error
!= FT_Err_Ok
) error
= GetFontByFaceName(settings
->font
, &face
);
359 if (error
== FT_Err_Ok
) {
360 DEBUG(freetype
, 2, "Requested '%s', using '%s %s'", settings
->font
, face
->family_name
, face
->style_name
);
362 /* Attempt to select the unicode character map */
363 error
= FT_Select_Charmap(face
, ft_encoding_unicode
);
364 if (error
== FT_Err_Ok
) goto found_face
; // Success
366 if (error
== FT_Err_Invalid_CharMap_Handle
) {
367 /* Try to pick a different character map instead. We default to
368 * the first map, but platform_id 0 encoding_id 0 should also
369 * be unicode (strange system...) */
370 FT_CharMap found
= face
->charmaps
[0];
373 for (i
= 0; i
< face
->num_charmaps
; i
++) {
374 FT_CharMap charmap
= face
->charmaps
[i
];
375 if (charmap
->platform_id
== 0 && charmap
->encoding_id
== 0) {
380 if (found
!= nullptr) {
381 error
= FT_Set_Charmap(face
, found
);
382 if (error
== FT_Err_Ok
) goto found_face
;
389 static const char *SIZE_TO_NAME
[] = { "medium", "small", "large", "mono" };
390 ShowInfoF("Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", settings
->font
, SIZE_TO_NAME
[fs
], error
);
394 new FreeTypeFontCache(fs
, face
, settings
->size
);
399 * Free everything that was allocated for this font cache.
401 FreeTypeFontCache::~FreeTypeFontCache()
403 FT_Done_Face(this->face
);
404 this->ClearFontCache();
406 for (FontTable::iterator iter
= this->font_tables
.Begin(); iter
!= this->font_tables
.End(); iter
++) {
407 free(iter
->second
.second
);
412 * Reset cached glyphs.
414 void FreeTypeFontCache::ClearFontCache()
416 if (this->glyph_to_sprite
== nullptr) return;
418 for (int i
= 0; i
< 256; i
++) {
419 if (this->glyph_to_sprite
[i
] == nullptr) continue;
421 for (int j
= 0; j
< 256; j
++) {
422 if (this->glyph_to_sprite
[i
][j
].duplicate
) continue;
423 free(this->glyph_to_sprite
[i
][j
].sprite
);
426 free(this->glyph_to_sprite
[i
]);
429 free(this->glyph_to_sprite
);
430 this->glyph_to_sprite
= nullptr;
432 Layouter::ResetFontCache(this->fs
);
435 FreeTypeFontCache::GlyphEntry
*FreeTypeFontCache::GetGlyphPtr(GlyphID key
)
437 if (this->glyph_to_sprite
== nullptr) return nullptr;
438 if (this->glyph_to_sprite
[GB(key
, 8, 8)] == nullptr) return nullptr;
439 return &this->glyph_to_sprite
[GB(key
, 8, 8)][GB(key
, 0, 8)];
443 void FreeTypeFontCache::SetGlyphPtr(GlyphID key
, const GlyphEntry
*glyph
, bool duplicate
)
445 if (this->glyph_to_sprite
== nullptr) {
446 DEBUG(freetype
, 3, "Allocating root glyph cache for size %u", this->fs
);
447 this->glyph_to_sprite
= CallocT
<GlyphEntry
*>(256);
450 if (this->glyph_to_sprite
[GB(key
, 8, 8)] == nullptr) {
451 DEBUG(freetype
, 3, "Allocating glyph cache for range 0x%02X00, size %u", GB(key
, 8, 8), this->fs
);
452 this->glyph_to_sprite
[GB(key
, 8, 8)] = CallocT
<GlyphEntry
>(256);
455 DEBUG(freetype
, 4, "Set glyph for unicode character 0x%04X, size %u", key
, this->fs
);
456 this->glyph_to_sprite
[GB(key
, 8, 8)][GB(key
, 0, 8)].sprite
= glyph
->sprite
;
457 this->glyph_to_sprite
[GB(key
, 8, 8)][GB(key
, 0, 8)].width
= glyph
->width
;
458 this->glyph_to_sprite
[GB(key
, 8, 8)][GB(key
, 0, 8)].duplicate
= duplicate
;
461 static void *AllocateFont(size_t size
)
463 return MallocT
<byte
>(size
);
467 /* Check if a glyph should be rendered with antialiasing */
468 static bool GetFontAAState(FontSize size
)
470 /* AA is only supported for 32 bpp */
471 if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 32) return false;
474 default: NOT_REACHED();
475 case FS_NORMAL
: return _freetype
.medium
.aa
;
476 case FS_SMALL
: return _freetype
.small
.aa
;
477 case FS_LARGE
: return _freetype
.large
.aa
;
478 case FS_MONO
: return _freetype
.mono
.aa
;
483 const Sprite
*FreeTypeFontCache::GetGlyph(GlyphID key
)
485 if ((key
& SPRITE_GLYPH
) != 0) return this->parent
->GetGlyph(key
);
487 /* Check for the glyph in our cache */
488 GlyphEntry
*glyph
= this->GetGlyphPtr(key
);
489 if (glyph
!= nullptr && glyph
->sprite
!= nullptr) return glyph
->sprite
;
491 FT_GlyphSlot slot
= this->face
->glyph
;
493 bool aa
= GetFontAAState(this->fs
);
495 GlyphEntry new_glyph
;
497 GlyphID question_glyph
= this->MapCharToGlyph('?');
498 if (question_glyph
== 0) {
499 /* The font misses the '?' character. Use built-in sprite.
500 * Note: We cannot use the baseset as this also has to work in the bootstrap GUI. */
501 #define CPSET { 0, 0, 0, 0, 1 }
502 #define CP___ { 0, 0, 0, 0, 0 }
503 static SpriteLoader::CommonPixel builtin_questionmark_data
[10 * 8] = {
504 CP___
, CP___
, CPSET
, CPSET
, CPSET
, CPSET
, CP___
, CP___
,
505 CP___
, CPSET
, CPSET
, CP___
, CP___
, CPSET
, CPSET
, CP___
,
506 CP___
, CP___
, CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
,
507 CP___
, CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
,
508 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
509 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
510 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
511 CP___
, CP___
, CP___
, CP___
, CP___
, CP___
, CP___
, CP___
,
512 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
513 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
517 static const SpriteLoader::Sprite builtin_questionmark
= {
523 builtin_questionmark_data
526 Sprite
*spr
= BlitterFactory::GetCurrentBlitter()->Encode(&builtin_questionmark
, AllocateFont
);
527 assert(spr
!= nullptr);
528 new_glyph
.sprite
= spr
;
529 new_glyph
.width
= spr
->width
+ (this->fs
!= FS_NORMAL
);
530 this->SetGlyphPtr(key
, &new_glyph
, false);
531 return new_glyph
.sprite
;
533 /* Use '?' for missing characters. */
534 this->GetGlyph(question_glyph
);
535 glyph
= this->GetGlyphPtr(question_glyph
);
536 this->SetGlyphPtr(key
, glyph
, true);
537 return glyph
->sprite
;
540 FT_Load_Glyph(this->face
, key
, FT_LOAD_DEFAULT
);
541 FT_Render_Glyph(this->face
->glyph
, aa
? FT_RENDER_MODE_NORMAL
: FT_RENDER_MODE_MONO
);
543 /* Despite requesting a normal glyph, FreeType may have returned a bitmap */
544 aa
= (slot
->bitmap
.pixel_mode
== FT_PIXEL_MODE_GRAY
);
546 /* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */
547 uint width
= max(1U, (uint
)slot
->bitmap
.width
+ (this->fs
== FS_NORMAL
));
548 uint height
= max(1U, (uint
)slot
->bitmap
.rows
+ (this->fs
== FS_NORMAL
));
550 /* Limit glyph size to prevent overflows later on. */
551 if (width
> 256 || height
> 256) usererror("Font glyph is too large");
553 /* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */
554 SpriteLoader::Sprite sprite
;
555 sprite
.AllocateData(ZOOM_LVL_NORMAL
, width
* height
);
556 sprite
.type
= ST_FONT
;
557 sprite
.width
= width
;
558 sprite
.height
= height
;
559 sprite
.x_offs
= slot
->bitmap_left
;
560 sprite
.y_offs
= this->ascender
- slot
->bitmap_top
;
562 /* Draw shadow for medium size */
563 if (this->fs
== FS_NORMAL
&& !aa
) {
564 for (uint y
= 0; y
< (uint
)slot
->bitmap
.rows
; y
++) {
565 for (uint x
= 0; x
< (uint
)slot
->bitmap
.width
; x
++) {
566 if (aa
? (slot
->bitmap
.buffer
[x
+ y
* slot
->bitmap
.pitch
] > 0) : HasBit(slot
->bitmap
.buffer
[(x
/ 8) + y
* slot
->bitmap
.pitch
], 7 - (x
% 8))) {
567 sprite
.data
[1 + x
+ (1 + y
) * sprite
.width
].m
= SHADOW_COLOUR
;
568 sprite
.data
[1 + x
+ (1 + y
) * sprite
.width
].a
= aa
? slot
->bitmap
.buffer
[x
+ y
* slot
->bitmap
.pitch
] : 0xFF;
574 for (uint y
= 0; y
< (uint
)slot
->bitmap
.rows
; y
++) {
575 for (uint x
= 0; x
< (uint
)slot
->bitmap
.width
; x
++) {
576 if (aa
? (slot
->bitmap
.buffer
[x
+ y
* slot
->bitmap
.pitch
] > 0) : HasBit(slot
->bitmap
.buffer
[(x
/ 8) + y
* slot
->bitmap
.pitch
], 7 - (x
% 8))) {
577 sprite
.data
[x
+ y
* sprite
.width
].m
= FACE_COLOUR
;
578 sprite
.data
[x
+ y
* sprite
.width
].a
= aa
? slot
->bitmap
.buffer
[x
+ y
* slot
->bitmap
.pitch
] : 0xFF;
583 new_glyph
.sprite
= BlitterFactory::GetCurrentBlitter()->Encode(&sprite
, AllocateFont
);
584 new_glyph
.width
= slot
->advance
.x
>> 6;
586 this->SetGlyphPtr(key
, &new_glyph
);
588 return new_glyph
.sprite
;
592 bool FreeTypeFontCache::GetDrawGlyphShadow()
594 return this->fs
== FS_NORMAL
&& GetFontAAState(FS_NORMAL
);
598 uint
FreeTypeFontCache::GetGlyphWidth(GlyphID key
)
600 if ((key
& SPRITE_GLYPH
) != 0) return this->parent
->GetGlyphWidth(key
);
602 GlyphEntry
*glyph
= this->GetGlyphPtr(key
);
603 if (glyph
== nullptr || glyph
->sprite
== nullptr) {
605 glyph
= this->GetGlyphPtr(key
);
611 GlyphID
FreeTypeFontCache::MapCharToGlyph(WChar key
)
613 assert(IsPrintable(key
));
615 if (key
>= SCC_SPRITE_START
&& key
<= SCC_SPRITE_END
) {
616 return this->parent
->MapCharToGlyph(key
);
619 return FT_Get_Char_Index(this->face
, key
);
622 const void *FreeTypeFontCache::GetFontTable(uint32 tag
, size_t &length
)
624 const FontTable::iterator iter
= this->font_tables
.Find(tag
);
625 if (iter
!= this->font_tables
.End()) {
626 length
= iter
->second
.first
;
627 return iter
->second
.second
;
631 FT_Byte
*result
= nullptr;
633 FT_Load_Sfnt_Table(this->face
, tag
, 0, nullptr, &len
);
636 result
= MallocT
<FT_Byte
>(len
);
637 FT_Load_Sfnt_Table(this->face
, tag
, 0, result
, &len
);
641 this->font_tables
.Insert(tag
, SmallPair
<size_t, const void *>(length
, result
));
645 #endif /* WITH_FREETYPE */
648 * (Re)initialize the freetype related things, i.e. load the non-sprite fonts.
649 * @param monospace Whether to initialise the monospace or regular fonts.
651 void InitFreeType(bool monospace
)
653 for (FontSize fs
= FS_BEGIN
; fs
< FS_END
; fs
++) {
654 if (monospace
!= (fs
== FS_MONO
)) continue;
656 FontCache
*fc
= FontCache::Get(fs
);
657 if (fc
->HasParent()) delete fc
;
660 LoadFreeTypeFont(fs
);
666 * Free everything allocated w.r.t. fonts.
668 void UninitFreeType()
670 for (FontSize fs
= FS_BEGIN
; fs
< FS_END
; fs
++) {
671 FontCache
*fc
= FontCache::Get(fs
);
672 if (fc
->HasParent()) delete fc
;
676 FT_Done_FreeType(_library
);
678 #endif /* WITH_FREETYPE */