2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
8 /** @file fontcache.cpp Cache for characters from fonts. */
11 #include "fontcache.h"
12 #include "fontcache_internal.h"
13 #include "fontdetection.h"
14 #include "blitter/factory.hpp"
15 #include "core/math_func.hpp"
16 #include "core/smallmap_type.hpp"
17 #include "strings_func.h"
18 #include "zoom_type.h"
19 #include "gfx_layout.h"
20 #include "zoom_func.h"
21 #include "fileio_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.
31 /** Default heights for the different sizes of fonts. */
32 static const int _default_font_height
[FS_END
] = {10, 6, 18, 10};
33 static const int _default_font_ascender
[FS_END
] = { 8, 5, 15, 8};
35 FreeTypeSettings _freetype
;
38 * Create a new font cache.
39 * @param fs The size of the font.
41 FontCache::FontCache(FontSize fs
) : parent(FontCache::Get(fs
)), fs(fs
), height(_default_font_height
[fs
]),
42 ascender(_default_font_ascender
[fs
]), descender(_default_font_ascender
[fs
] - _default_font_height
[fs
]),
45 assert(this->parent
== nullptr || this->fs
== this->parent
->fs
);
46 FontCache::caches
[this->fs
] = this;
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
);
58 int FontCache::GetDefaultFontHeight(FontSize fs
)
60 return _default_font_height
[fs
];
65 * Get height of a character for a given font size.
66 * @param size Font size to get height of
67 * @return Height of characters in the given font (pixels)
69 int GetCharacterHeight(FontSize size
)
71 return FontCache::Get(size
)->GetHeight();
75 /** Font cache for fonts that are based on a freetype font. */
76 class SpriteFontCache
: public FontCache
{
78 SpriteID
**glyph_to_spriteid_map
; ///< Mapping of glyphs to sprite IDs.
80 void ClearGlyphToSpriteMap();
82 SpriteFontCache(FontSize fs
);
84 virtual SpriteID
GetUnicodeGlyph(WChar key
);
85 virtual void SetUnicodeGlyph(WChar key
, SpriteID sprite
);
86 virtual void InitializeUnicodeGlyphMap();
87 virtual void ClearFontCache();
88 virtual const Sprite
*GetGlyph(GlyphID key
);
89 virtual uint
GetGlyphWidth(GlyphID key
);
90 virtual int GetHeight() const;
91 virtual bool GetDrawGlyphShadow();
92 virtual GlyphID
MapCharToGlyph(WChar key
) { assert(IsPrintable(key
)); return SPRITE_GLYPH
| key
; }
93 virtual const void *GetFontTable(uint32 tag
, size_t &length
) { length
= 0; return nullptr; }
94 virtual const char *GetFontName() { return "sprite"; }
95 virtual bool IsBuiltInFont() { return true; }
99 * Create a new sprite font cache.
100 * @param fs The font size to create the cache for.
102 SpriteFontCache::SpriteFontCache(FontSize fs
) : FontCache(fs
), glyph_to_spriteid_map(nullptr)
104 this->InitializeUnicodeGlyphMap();
108 * Free everything we allocated.
110 SpriteFontCache::~SpriteFontCache()
112 this->ClearGlyphToSpriteMap();
115 SpriteID
SpriteFontCache::GetUnicodeGlyph(WChar key
)
117 if (this->glyph_to_spriteid_map
[GB(key
, 8, 8)] == nullptr) return 0;
118 return this->glyph_to_spriteid_map
[GB(key
, 8, 8)][GB(key
, 0, 8)];
121 void SpriteFontCache::SetUnicodeGlyph(WChar key
, SpriteID sprite
)
123 if (this->glyph_to_spriteid_map
== nullptr) this->glyph_to_spriteid_map
= CallocT
<SpriteID
*>(256);
124 if (this->glyph_to_spriteid_map
[GB(key
, 8, 8)] == nullptr) this->glyph_to_spriteid_map
[GB(key
, 8, 8)] = CallocT
<SpriteID
>(256);
125 this->glyph_to_spriteid_map
[GB(key
, 8, 8)][GB(key
, 0, 8)] = sprite
;
128 void SpriteFontCache::InitializeUnicodeGlyphMap()
130 /* Clear out existing glyph map if it exists */
131 this->ClearGlyphToSpriteMap();
135 default: NOT_REACHED();
136 case FS_MONO
: // Use normal as default for mono spaced font
137 case FS_NORMAL
: base
= SPR_ASCII_SPACE
; break;
138 case FS_SMALL
: base
= SPR_ASCII_SPACE_SMALL
; break;
139 case FS_LARGE
: base
= SPR_ASCII_SPACE_BIG
; break;
142 for (uint i
= ASCII_LETTERSTART
; i
< 256; i
++) {
143 SpriteID sprite
= base
+ i
- ASCII_LETTERSTART
;
144 if (!SpriteExists(sprite
)) continue;
145 this->SetUnicodeGlyph(i
, sprite
);
146 this->SetUnicodeGlyph(i
+ SCC_SPRITE_START
, sprite
);
149 for (uint i
= 0; i
< lengthof(_default_unicode_map
); i
++) {
150 byte key
= _default_unicode_map
[i
].key
;
152 /* Clear the glyph. This happens if the glyph at this code point
153 * is non-standard and should be accessed by an SCC_xxx enum
155 this->SetUnicodeGlyph(_default_unicode_map
[i
].code
, 0);
157 SpriteID sprite
= base
+ key
- ASCII_LETTERSTART
;
158 this->SetUnicodeGlyph(_default_unicode_map
[i
].code
, sprite
);
164 * Clear the glyph to sprite mapping.
166 void SpriteFontCache::ClearGlyphToSpriteMap()
168 if (this->glyph_to_spriteid_map
== nullptr) return;
170 for (uint i
= 0; i
< 256; i
++) {
171 free(this->glyph_to_spriteid_map
[i
]);
173 free(this->glyph_to_spriteid_map
);
174 this->glyph_to_spriteid_map
= nullptr;
177 void SpriteFontCache::ClearFontCache()
179 Layouter::ResetFontCache(this->fs
);
182 const Sprite
*SpriteFontCache::GetGlyph(GlyphID key
)
184 SpriteID sprite
= this->GetUnicodeGlyph(key
);
185 if (sprite
== 0) sprite
= this->GetUnicodeGlyph('?');
186 return GetSprite(sprite
, ST_FONT
);
189 uint
SpriteFontCache::GetGlyphWidth(GlyphID key
)
191 SpriteID sprite
= this->GetUnicodeGlyph(key
);
192 if (sprite
== 0) sprite
= this->GetUnicodeGlyph('?');
193 return SpriteExists(sprite
) ? GetSprite(sprite
, ST_FONT
)->width
+ ScaleFontTrad(this->fs
!= FS_NORMAL
? 1 : 0) : 0;
196 int SpriteFontCache::GetHeight() const
198 return ScaleFontTrad(this->height
);
201 bool SpriteFontCache::GetDrawGlyphShadow()
206 /* static */ FontCache
*FontCache::caches
[FS_END
] = { new SpriteFontCache(FS_NORMAL
), new SpriteFontCache(FS_SMALL
), new SpriteFontCache(FS_LARGE
), new SpriteFontCache(FS_MONO
) };
210 * Create a new TrueTypeFontCache.
211 * @param fs The font size that is going to be cached.
212 * @param pixels The number of pixels this font should be high.
214 TrueTypeFontCache::TrueTypeFontCache(FontSize fs
, int pixels
) : FontCache(fs
), req_size(pixels
), glyph_to_sprite(nullptr)
219 * Free everything that was allocated for this font cache.
221 TrueTypeFontCache::~TrueTypeFontCache()
223 this->ClearFontCache();
225 for (auto &iter
: this->font_tables
) {
226 free(iter
.second
.second
);
231 * Reset cached glyphs.
233 void TrueTypeFontCache::ClearFontCache()
235 if (this->glyph_to_sprite
== nullptr) return;
237 for (int i
= 0; i
< 256; i
++) {
238 if (this->glyph_to_sprite
[i
] == nullptr) continue;
240 for (int j
= 0; j
< 256; j
++) {
241 if (this->glyph_to_sprite
[i
][j
].duplicate
) continue;
242 free(this->glyph_to_sprite
[i
][j
].sprite
);
245 free(this->glyph_to_sprite
[i
]);
248 free(this->glyph_to_sprite
);
249 this->glyph_to_sprite
= nullptr;
251 Layouter::ResetFontCache(this->fs
);
255 TrueTypeFontCache::GlyphEntry
*TrueTypeFontCache::GetGlyphPtr(GlyphID key
)
257 if (this->glyph_to_sprite
== nullptr) return nullptr;
258 if (this->glyph_to_sprite
[GB(key
, 8, 8)] == nullptr) return nullptr;
259 return &this->glyph_to_sprite
[GB(key
, 8, 8)][GB(key
, 0, 8)];
262 void TrueTypeFontCache::SetGlyphPtr(GlyphID key
, const GlyphEntry
*glyph
, bool duplicate
)
264 if (this->glyph_to_sprite
== nullptr) {
265 DEBUG(freetype
, 3, "Allocating root glyph cache for size %u", this->fs
);
266 this->glyph_to_sprite
= CallocT
<GlyphEntry
*>(256);
269 if (this->glyph_to_sprite
[GB(key
, 8, 8)] == nullptr) {
270 DEBUG(freetype
, 3, "Allocating glyph cache for range 0x%02X00, size %u", GB(key
, 8, 8), this->fs
);
271 this->glyph_to_sprite
[GB(key
, 8, 8)] = CallocT
<GlyphEntry
>(256);
274 DEBUG(freetype
, 4, "Set glyph for unicode character 0x%04X, size %u", key
, this->fs
);
275 this->glyph_to_sprite
[GB(key
, 8, 8)][GB(key
, 0, 8)].sprite
= glyph
->sprite
;
276 this->glyph_to_sprite
[GB(key
, 8, 8)][GB(key
, 0, 8)].width
= glyph
->width
;
277 this->glyph_to_sprite
[GB(key
, 8, 8)][GB(key
, 0, 8)].duplicate
= duplicate
;
280 void *AllocateFont(size_t size
)
282 return MallocT
<byte
>(size
);
286 /* Check if a glyph should be rendered with anti-aliasing. */
287 static bool GetFontAAState(FontSize size
)
289 /* AA is only supported for 32 bpp */
290 if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 32) return false;
293 default: NOT_REACHED();
294 case FS_NORMAL
: return _freetype
.medium
.aa
;
295 case FS_SMALL
: return _freetype
.small
.aa
;
296 case FS_LARGE
: return _freetype
.large
.aa
;
297 case FS_MONO
: return _freetype
.mono
.aa
;
301 bool TrueTypeFontCache::GetDrawGlyphShadow()
303 return this->fs
== FS_NORMAL
&& GetFontAAState(FS_NORMAL
);
306 uint
TrueTypeFontCache::GetGlyphWidth(GlyphID key
)
308 if ((key
& SPRITE_GLYPH
) != 0) return this->parent
->GetGlyphWidth(key
);
310 GlyphEntry
*glyph
= this->GetGlyphPtr(key
);
311 if (glyph
== nullptr || glyph
->sprite
== nullptr) {
313 glyph
= this->GetGlyphPtr(key
);
319 const Sprite
*TrueTypeFontCache::GetGlyph(GlyphID key
)
321 if ((key
& SPRITE_GLYPH
) != 0) return this->parent
->GetGlyph(key
);
323 /* Check for the glyph in our cache */
324 GlyphEntry
*glyph
= this->GetGlyphPtr(key
);
325 if (glyph
!= nullptr && glyph
->sprite
!= nullptr) return glyph
->sprite
;
328 GlyphID question_glyph
= this->MapCharToGlyph('?');
329 if (question_glyph
== 0) {
330 /* The font misses the '?' character. Use built-in sprite.
331 * Note: We cannot use the baseset as this also has to work in the bootstrap GUI. */
332 #define CPSET { 0, 0, 0, 0, 1 }
333 #define CP___ { 0, 0, 0, 0, 0 }
334 static SpriteLoader::CommonPixel builtin_questionmark_data
[10 * 8] = {
335 CP___
, CP___
, CPSET
, CPSET
, CPSET
, CPSET
, CP___
, CP___
,
336 CP___
, CPSET
, CPSET
, CP___
, CP___
, CPSET
, CPSET
, CP___
,
337 CP___
, CP___
, CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
,
338 CP___
, CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
,
339 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
340 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
341 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
342 CP___
, CP___
, CP___
, CP___
, CP___
, CP___
, CP___
, CP___
,
343 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
344 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
348 static const SpriteLoader::Sprite builtin_questionmark
= {
354 builtin_questionmark_data
357 Sprite
*spr
= BlitterFactory::GetCurrentBlitter()->Encode(&builtin_questionmark
, AllocateFont
);
358 assert(spr
!= nullptr);
359 GlyphEntry new_glyph
;
360 new_glyph
.sprite
= spr
;
361 new_glyph
.width
= spr
->width
+ (this->fs
!= FS_NORMAL
);
362 this->SetGlyphPtr(key
, &new_glyph
, false);
363 return new_glyph
.sprite
;
365 /* Use '?' for missing characters. */
366 this->GetGlyph(question_glyph
);
367 glyph
= this->GetGlyphPtr(question_glyph
);
368 this->SetGlyphPtr(key
, glyph
, true);
369 return glyph
->sprite
;
373 return this->InternalGetGlyph(key
, GetFontAAState(this->fs
));
376 const void *TrueTypeFontCache::GetFontTable(uint32 tag
, size_t &length
)
378 const FontTable::iterator iter
= this->font_tables
.Find(tag
);
379 if (iter
!= this->font_tables
.data() + this->font_tables
.size()) {
380 length
= iter
->second
.first
;
381 return iter
->second
.second
;
384 const void *result
= this->InternalGetFontTable(tag
, length
);
386 this->font_tables
.Insert(tag
, std::pair
<size_t, const void *>(length
, result
));
392 #include <ft2build.h>
393 #include FT_FREETYPE_H
395 #include FT_TRUETYPE_TABLES_H
397 /** Font cache for fonts that are based on a freetype font. */
398 class FreeTypeFontCache
: public TrueTypeFontCache
{
400 FT_Face face
; ///< The font face associated with this font.
402 void SetFontSize(FontSize fs
, FT_Face face
, int pixels
);
403 virtual const void *InternalGetFontTable(uint32 tag
, size_t &length
);
404 virtual const Sprite
*InternalGetGlyph(GlyphID key
, bool aa
);
407 FreeTypeFontCache(FontSize fs
, FT_Face face
, int pixels
);
408 ~FreeTypeFontCache();
409 virtual void ClearFontCache();
410 virtual GlyphID
MapCharToGlyph(WChar key
);
411 virtual const char *GetFontName() { return face
->family_name
; }
412 virtual bool IsBuiltInFont() { return false; }
415 FT_Library _library
= nullptr;
419 * Create a new FreeTypeFontCache.
420 * @param fs The font size that is going to be cached.
421 * @param face The font that has to be loaded.
422 * @param pixels The number of pixels this font should be high.
424 FreeTypeFontCache::FreeTypeFontCache(FontSize fs
, FT_Face face
, int pixels
) : TrueTypeFontCache(fs
, pixels
), face(face
)
426 assert(face
!= nullptr);
428 this->SetFontSize(fs
, face
, pixels
);
431 void FreeTypeFontCache::SetFontSize(FontSize fs
, FT_Face face
, int pixels
)
434 /* Try to determine a good height based on the minimal height recommended by the font. */
435 int scaled_height
= ScaleFontTrad(_default_font_height
[this->fs
]);
436 pixels
= scaled_height
;
438 TT_Header
*head
= (TT_Header
*)FT_Get_Sfnt_Table(this->face
, ft_sfnt_head
);
439 if (head
!= nullptr) {
440 /* Font height is minimum height plus the difference between the default
441 * height for this font size and the small size. */
442 int diff
= scaled_height
- ScaleFontTrad(_default_font_height
[FS_SMALL
]);
443 pixels
= Clamp(std::min
<uint
>(head
->Lowest_Rec_PPEM
, MAX_FONT_MIN_REC_SIZE
) + diff
, scaled_height
, MAX_FONT_SIZE
);
446 pixels
= ScaleFontTrad(pixels
);
448 this->used_size
= pixels
;
450 FT_Error err
= FT_Set_Pixel_Sizes(this->face
, 0, pixels
);
451 if (err
!= FT_Err_Ok
) {
453 /* Find nearest size to that requested */
454 FT_Bitmap_Size
*bs
= this->face
->available_sizes
;
455 int i
= this->face
->num_fixed_sizes
;
456 if (i
> 0) { // In pathetic cases one might get no fixed sizes at all.
460 if (abs(pixels
- bs
->height
) >= abs(pixels
- n
)) continue;
462 chosen
= this->face
->num_fixed_sizes
- i
;
465 /* Don't use FT_Set_Pixel_Sizes here - it might give us another
466 * error, even though the size is available (FS#5885). */
467 err
= FT_Select_Size(this->face
, chosen
);
471 if (err
== FT_Err_Ok
) {
472 this->units_per_em
= this->face
->units_per_EM
;
473 this->ascender
= this->face
->size
->metrics
.ascender
>> 6;
474 this->descender
= this->face
->size
->metrics
.descender
>> 6;
475 this->height
= this->ascender
- this->descender
;
477 /* Both FT_Set_Pixel_Sizes and FT_Select_Size failed. */
478 DEBUG(freetype
, 0, "Font size selection failed. Using FontCache defaults.");
483 * Loads the freetype font.
484 * First type to load the fontname as if it were a path. If that fails,
485 * try to resolve the filename of the font using fontconfig, where the
486 * format is 'font family name' or 'font family name, font style'.
487 * @param fs The font size to load.
489 static void LoadFreeTypeFont(FontSize fs
)
491 FreeTypeSubSetting
*settings
= nullptr;
493 default: NOT_REACHED();
494 case FS_SMALL
: settings
= &_freetype
.small
; break;
495 case FS_NORMAL
: settings
= &_freetype
.medium
; break;
496 case FS_LARGE
: settings
= &_freetype
.large
; break;
497 case FS_MONO
: settings
= &_freetype
.mono
; break;
500 if (StrEmpty(settings
->font
)) return;
502 if (_library
== nullptr) {
503 if (FT_Init_FreeType(&_library
) != FT_Err_Ok
) {
504 ShowInfoF("Unable to initialize FreeType, using sprite fonts instead");
508 DEBUG(freetype
, 2, "Initialized");
511 FT_Face face
= nullptr;
513 /* If font is an absolute path to a ttf, try loading that first. */
514 FT_Error error
= FT_New_Face(_library
, settings
->font
, 0, &face
);
516 #if defined(WITH_COCOA)
517 extern void MacOSRegisterExternalFont(const char *file_path
);
518 if (error
== FT_Err_Ok
) MacOSRegisterExternalFont(settings
->font
);
521 if (error
!= FT_Err_Ok
) {
522 /* Check if font is a relative filename in one of our search-paths. */
523 std::string full_font
= FioFindFullPath(BASE_DIR
, settings
->font
);
524 if (!full_font
.empty()) {
525 error
= FT_New_Face(_library
, full_font
.c_str(), 0, &face
);
526 #if defined(WITH_COCOA)
527 if (error
== FT_Err_Ok
) MacOSRegisterExternalFont(full_font
.c_str());
532 /* Try loading based on font face name (OS-wide fonts). */
533 if (error
!= FT_Err_Ok
) error
= GetFontByFaceName(settings
->font
, &face
);
535 if (error
== FT_Err_Ok
) {
536 DEBUG(freetype
, 2, "Requested '%s', using '%s %s'", settings
->font
, face
->family_name
, face
->style_name
);
538 /* Attempt to select the unicode character map */
539 error
= FT_Select_Charmap(face
, ft_encoding_unicode
);
540 if (error
== FT_Err_Ok
) goto found_face
; // Success
542 if (error
== FT_Err_Invalid_CharMap_Handle
) {
543 /* Try to pick a different character map instead. We default to
544 * the first map, but platform_id 0 encoding_id 0 should also
545 * be unicode (strange system...) */
546 FT_CharMap found
= face
->charmaps
[0];
549 for (i
= 0; i
< face
->num_charmaps
; i
++) {
550 FT_CharMap charmap
= face
->charmaps
[i
];
551 if (charmap
->platform_id
== 0 && charmap
->encoding_id
== 0) {
556 if (found
!= nullptr) {
557 error
= FT_Set_Charmap(face
, found
);
558 if (error
== FT_Err_Ok
) goto found_face
;
565 static const char *SIZE_TO_NAME
[] = { "medium", "small", "large", "mono" };
566 ShowInfoF("Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", settings
->font
, SIZE_TO_NAME
[fs
], error
);
570 new FreeTypeFontCache(fs
, face
, settings
->size
);
575 * Free everything that was allocated for this font cache.
577 FreeTypeFontCache::~FreeTypeFontCache()
579 FT_Done_Face(this->face
);
580 this->face
= nullptr;
581 this->ClearFontCache();
585 * Reset cached glyphs.
587 void FreeTypeFontCache::ClearFontCache()
589 /* Font scaling might have changed, determine font size anew if it was automatically selected. */
590 if (this->face
!= nullptr) this->SetFontSize(this->fs
, this->face
, this->req_size
);
592 this->TrueTypeFontCache::ClearFontCache();
596 const Sprite
*FreeTypeFontCache::InternalGetGlyph(GlyphID key
, bool aa
)
598 FT_GlyphSlot slot
= this->face
->glyph
;
600 FT_Load_Glyph(this->face
, key
, aa
? FT_LOAD_TARGET_NORMAL
: FT_LOAD_TARGET_MONO
);
601 FT_Render_Glyph(this->face
->glyph
, aa
? FT_RENDER_MODE_NORMAL
: FT_RENDER_MODE_MONO
);
603 /* Despite requesting a normal glyph, FreeType may have returned a bitmap */
604 aa
= (slot
->bitmap
.pixel_mode
== FT_PIXEL_MODE_GRAY
);
606 /* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */
607 uint width
= std::max(1U, (uint
)slot
->bitmap
.width
+ (this->fs
== FS_NORMAL
));
608 uint height
= std::max(1U, (uint
)slot
->bitmap
.rows
+ (this->fs
== FS_NORMAL
));
610 /* Limit glyph size to prevent overflows later on. */
611 if (width
> MAX_GLYPH_DIM
|| height
> MAX_GLYPH_DIM
) usererror("Font glyph is too large");
613 /* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */
614 SpriteLoader::Sprite sprite
;
615 sprite
.AllocateData(ZOOM_LVL_NORMAL
, width
* height
);
616 sprite
.type
= ST_FONT
;
617 sprite
.width
= width
;
618 sprite
.height
= height
;
619 sprite
.x_offs
= slot
->bitmap_left
;
620 sprite
.y_offs
= this->ascender
- slot
->bitmap_top
;
622 /* Draw shadow for medium size */
623 if (this->fs
== FS_NORMAL
&& !aa
) {
624 for (uint y
= 0; y
< (uint
)slot
->bitmap
.rows
; y
++) {
625 for (uint x
= 0; x
< (uint
)slot
->bitmap
.width
; x
++) {
626 if (aa
? (slot
->bitmap
.buffer
[x
+ y
* slot
->bitmap
.pitch
] > 0) : HasBit(slot
->bitmap
.buffer
[(x
/ 8) + y
* slot
->bitmap
.pitch
], 7 - (x
% 8))) {
627 sprite
.data
[1 + x
+ (1 + y
) * sprite
.width
].m
= SHADOW_COLOUR
;
628 sprite
.data
[1 + x
+ (1 + y
) * sprite
.width
].a
= aa
? slot
->bitmap
.buffer
[x
+ y
* slot
->bitmap
.pitch
] : 0xFF;
634 for (uint y
= 0; y
< (uint
)slot
->bitmap
.rows
; y
++) {
635 for (uint x
= 0; x
< (uint
)slot
->bitmap
.width
; x
++) {
636 if (aa
? (slot
->bitmap
.buffer
[x
+ y
* slot
->bitmap
.pitch
] > 0) : HasBit(slot
->bitmap
.buffer
[(x
/ 8) + y
* slot
->bitmap
.pitch
], 7 - (x
% 8))) {
637 sprite
.data
[x
+ y
* sprite
.width
].m
= FACE_COLOUR
;
638 sprite
.data
[x
+ y
* sprite
.width
].a
= aa
? slot
->bitmap
.buffer
[x
+ y
* slot
->bitmap
.pitch
] : 0xFF;
643 GlyphEntry new_glyph
;
644 new_glyph
.sprite
= BlitterFactory::GetCurrentBlitter()->Encode(&sprite
, AllocateFont
);
645 new_glyph
.width
= slot
->advance
.x
>> 6;
647 this->SetGlyphPtr(key
, &new_glyph
);
649 return new_glyph
.sprite
;
653 GlyphID
FreeTypeFontCache::MapCharToGlyph(WChar key
)
655 assert(IsPrintable(key
));
657 if (key
>= SCC_SPRITE_START
&& key
<= SCC_SPRITE_END
) {
658 return this->parent
->MapCharToGlyph(key
);
661 return FT_Get_Char_Index(this->face
, key
);
664 const void *FreeTypeFontCache::InternalGetFontTable(uint32 tag
, size_t &length
)
667 FT_Byte
*result
= nullptr;
669 FT_Load_Sfnt_Table(this->face
, tag
, 0, nullptr, &len
);
672 result
= MallocT
<FT_Byte
>(len
);
673 FT_Load_Sfnt_Table(this->face
, tag
, 0, result
, &len
);
680 #endif /* WITH_FREETYPE */
684 * (Re)initialize the freetype related things, i.e. load the non-sprite fonts.
685 * @param monospace Whether to initialise the monospace or regular fonts.
687 void InitFreeType(bool monospace
)
689 for (FontSize fs
= FS_BEGIN
; fs
< FS_END
; fs
++) {
690 if (monospace
!= (fs
== FS_MONO
)) continue;
692 FontCache
*fc
= FontCache::Get(fs
);
693 if (fc
->HasParent()) delete fc
;
696 LoadFreeTypeFont(fs
);
697 #elif defined(_WIN32)
698 extern void LoadWin32Font(FontSize fs
);
700 #elif defined(WITH_COCOA)
701 extern void LoadCoreTextFont(FontSize fs
);
702 LoadCoreTextFont(fs
);
708 * Free everything allocated w.r.t. fonts.
710 void UninitFreeType()
712 for (FontSize fs
= FS_BEGIN
; fs
< FS_END
; fs
++) {
713 FontCache
*fc
= FontCache::Get(fs
);
714 if (fc
->HasParent()) delete fc
;
718 FT_Done_FreeType(_library
);
720 #endif /* WITH_FREETYPE */
723 #if !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA)
726 FT_Error
GetFontByFaceName(const char *font_name
, FT_Face
*face
) { return FT_Err_Cannot_Open_Resource
; }
727 #endif /* WITH_FREETYPE */
729 bool SetFallbackFont(FreeTypeSettings
*settings
, const char *language_isocode
, int winlangid
, MissingGlyphSearcher
*callback
) { return false; }
730 #endif /* !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA) */