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 bool GetDrawGlyphShadow();
91 virtual GlyphID
MapCharToGlyph(WChar key
) { assert(IsPrintable(key
)); return SPRITE_GLYPH
| key
; }
92 virtual const void *GetFontTable(uint32 tag
, size_t &length
) { length
= 0; return nullptr; }
93 virtual const char *GetFontName() { return "sprite"; }
94 virtual bool IsBuiltInFont() { return true; }
98 * Create a new sprite font cache.
99 * @param fs The font size to create the cache for.
101 SpriteFontCache::SpriteFontCache(FontSize fs
) : FontCache(fs
), glyph_to_spriteid_map(nullptr)
103 this->InitializeUnicodeGlyphMap();
104 this->height
= ScaleFontTrad(this->GetDefaultFontHeight(this->fs
));
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
);
180 this->height
= ScaleFontTrad(this->GetDefaultFontHeight(this->fs
));
183 const Sprite
*SpriteFontCache::GetGlyph(GlyphID key
)
185 SpriteID sprite
= this->GetUnicodeGlyph(key
);
186 if (sprite
== 0) sprite
= this->GetUnicodeGlyph('?');
187 return GetSprite(sprite
, ST_FONT
);
190 uint
SpriteFontCache::GetGlyphWidth(GlyphID key
)
192 SpriteID sprite
= this->GetUnicodeGlyph(key
);
193 if (sprite
== 0) sprite
= this->GetUnicodeGlyph('?');
194 return SpriteExists(sprite
) ? GetSprite(sprite
, ST_FONT
)->width
+ ScaleFontTrad(this->fs
!= FS_NORMAL
? 1 : 0) : 0;
197 bool SpriteFontCache::GetDrawGlyphShadow()
202 /* static */ FontCache
*FontCache::caches
[FS_END
] = { new SpriteFontCache(FS_NORMAL
), new SpriteFontCache(FS_SMALL
), new SpriteFontCache(FS_LARGE
), new SpriteFontCache(FS_MONO
) };
206 * Create a new TrueTypeFontCache.
207 * @param fs The font size that is going to be cached.
208 * @param pixels The number of pixels this font should be high.
210 TrueTypeFontCache::TrueTypeFontCache(FontSize fs
, int pixels
) : FontCache(fs
), req_size(pixels
), glyph_to_sprite(nullptr)
215 * Free everything that was allocated for this font cache.
217 TrueTypeFontCache::~TrueTypeFontCache()
219 /* Virtual functions get called statically in destructors, so make it explicit to remove any confusion. */
220 this->TrueTypeFontCache::ClearFontCache();
222 for (auto &iter
: this->font_tables
) {
223 free(iter
.second
.second
);
228 * Reset cached glyphs.
230 void TrueTypeFontCache::ClearFontCache()
232 if (this->glyph_to_sprite
== nullptr) return;
234 for (int i
= 0; i
< 256; i
++) {
235 if (this->glyph_to_sprite
[i
] == nullptr) continue;
237 for (int j
= 0; j
< 256; j
++) {
238 if (this->glyph_to_sprite
[i
][j
].duplicate
) continue;
239 free(this->glyph_to_sprite
[i
][j
].sprite
);
242 free(this->glyph_to_sprite
[i
]);
245 free(this->glyph_to_sprite
);
246 this->glyph_to_sprite
= nullptr;
248 Layouter::ResetFontCache(this->fs
);
252 TrueTypeFontCache::GlyphEntry
*TrueTypeFontCache::GetGlyphPtr(GlyphID key
)
254 if (this->glyph_to_sprite
== nullptr) return nullptr;
255 if (this->glyph_to_sprite
[GB(key
, 8, 8)] == nullptr) return nullptr;
256 return &this->glyph_to_sprite
[GB(key
, 8, 8)][GB(key
, 0, 8)];
259 void TrueTypeFontCache::SetGlyphPtr(GlyphID key
, const GlyphEntry
*glyph
, bool duplicate
)
261 if (this->glyph_to_sprite
== nullptr) {
262 Debug(freetype
, 3, "Allocating root glyph cache for size {}", this->fs
);
263 this->glyph_to_sprite
= CallocT
<GlyphEntry
*>(256);
266 if (this->glyph_to_sprite
[GB(key
, 8, 8)] == nullptr) {
267 Debug(freetype
, 3, "Allocating glyph cache for range 0x{:02X}00, size {}", GB(key
, 8, 8), this->fs
);
268 this->glyph_to_sprite
[GB(key
, 8, 8)] = CallocT
<GlyphEntry
>(256);
271 Debug(freetype
, 4, "Set glyph for unicode character 0x{:04X}, size {}", key
, this->fs
);
272 this->glyph_to_sprite
[GB(key
, 8, 8)][GB(key
, 0, 8)].sprite
= glyph
->sprite
;
273 this->glyph_to_sprite
[GB(key
, 8, 8)][GB(key
, 0, 8)].width
= glyph
->width
;
274 this->glyph_to_sprite
[GB(key
, 8, 8)][GB(key
, 0, 8)].duplicate
= duplicate
;
278 /* Check if a glyph should be rendered with anti-aliasing. */
279 static bool GetFontAAState(FontSize size
, bool check_blitter
= true)
281 /* AA is only supported for 32 bpp */
282 if (check_blitter
&& BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 32) return false;
285 default: NOT_REACHED();
286 case FS_NORMAL
: return _freetype
.medium
.aa
;
287 case FS_SMALL
: return _freetype
.small
.aa
;
288 case FS_LARGE
: return _freetype
.large
.aa
;
289 case FS_MONO
: return _freetype
.mono
.aa
;
293 bool TrueTypeFontCache::GetDrawGlyphShadow()
295 return this->fs
== FS_NORMAL
&& GetFontAAState(FS_NORMAL
);
298 uint
TrueTypeFontCache::GetGlyphWidth(GlyphID key
)
300 if ((key
& SPRITE_GLYPH
) != 0) return this->parent
->GetGlyphWidth(key
);
302 GlyphEntry
*glyph
= this->GetGlyphPtr(key
);
303 if (glyph
== nullptr || glyph
->sprite
== nullptr) {
305 glyph
= this->GetGlyphPtr(key
);
311 const Sprite
*TrueTypeFontCache::GetGlyph(GlyphID key
)
313 if ((key
& SPRITE_GLYPH
) != 0) return this->parent
->GetGlyph(key
);
315 /* Check for the glyph in our cache */
316 GlyphEntry
*glyph
= this->GetGlyphPtr(key
);
317 if (glyph
!= nullptr && glyph
->sprite
!= nullptr) return glyph
->sprite
;
320 GlyphID question_glyph
= this->MapCharToGlyph('?');
321 if (question_glyph
== 0) {
322 /* The font misses the '?' character. Use built-in sprite.
323 * Note: We cannot use the baseset as this also has to work in the bootstrap GUI. */
324 #define CPSET { 0, 0, 0, 0, 1 }
325 #define CP___ { 0, 0, 0, 0, 0 }
326 static SpriteLoader::CommonPixel builtin_questionmark_data
[10 * 8] = {
327 CP___
, CP___
, CPSET
, CPSET
, CPSET
, CPSET
, CP___
, CP___
,
328 CP___
, CPSET
, CPSET
, CP___
, CP___
, CPSET
, CPSET
, CP___
,
329 CP___
, CP___
, CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
,
330 CP___
, CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
,
331 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
332 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
333 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
334 CP___
, CP___
, CP___
, CP___
, CP___
, CP___
, CP___
, CP___
,
335 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
336 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
340 static const SpriteLoader::Sprite builtin_questionmark
= {
347 builtin_questionmark_data
350 Sprite
*spr
= BlitterFactory::GetCurrentBlitter()->Encode(&builtin_questionmark
, SimpleSpriteAlloc
);
351 assert(spr
!= nullptr);
352 GlyphEntry new_glyph
;
353 new_glyph
.sprite
= spr
;
354 new_glyph
.width
= spr
->width
+ (this->fs
!= FS_NORMAL
);
355 this->SetGlyphPtr(key
, &new_glyph
, false);
356 return new_glyph
.sprite
;
358 /* Use '?' for missing characters. */
359 this->GetGlyph(question_glyph
);
360 glyph
= this->GetGlyphPtr(question_glyph
);
361 this->SetGlyphPtr(key
, glyph
, true);
362 return glyph
->sprite
;
366 return this->InternalGetGlyph(key
, GetFontAAState(this->fs
));
369 const void *TrueTypeFontCache::GetFontTable(uint32 tag
, size_t &length
)
371 const FontTable::iterator iter
= this->font_tables
.Find(tag
);
372 if (iter
!= this->font_tables
.data() + this->font_tables
.size()) {
373 length
= iter
->second
.first
;
374 return iter
->second
.second
;
377 const void *result
= this->InternalGetFontTable(tag
, length
);
379 this->font_tables
.Insert(tag
, std::pair
<size_t, const void *>(length
, result
));
385 #include <ft2build.h>
386 #include FT_FREETYPE_H
388 #include FT_TRUETYPE_TABLES_H
390 /** Font cache for fonts that are based on a freetype font. */
391 class FreeTypeFontCache
: public TrueTypeFontCache
{
393 FT_Face face
; ///< The font face associated with this font.
395 void SetFontSize(FontSize fs
, FT_Face face
, int pixels
);
396 virtual const void *InternalGetFontTable(uint32 tag
, size_t &length
);
397 virtual const Sprite
*InternalGetGlyph(GlyphID key
, bool aa
);
400 FreeTypeFontCache(FontSize fs
, FT_Face face
, int pixels
);
401 ~FreeTypeFontCache();
402 virtual void ClearFontCache();
403 virtual GlyphID
MapCharToGlyph(WChar key
);
404 virtual const char *GetFontName() { return face
->family_name
; }
405 virtual bool IsBuiltInFont() { return false; }
408 FT_Library _library
= nullptr;
412 * Create a new FreeTypeFontCache.
413 * @param fs The font size that is going to be cached.
414 * @param face The font that has to be loaded.
415 * @param pixels The number of pixels this font should be high.
417 FreeTypeFontCache::FreeTypeFontCache(FontSize fs
, FT_Face face
, int pixels
) : TrueTypeFontCache(fs
, pixels
), face(face
)
419 assert(face
!= nullptr);
421 this->SetFontSize(fs
, face
, pixels
);
424 void FreeTypeFontCache::SetFontSize(FontSize fs
, FT_Face face
, int pixels
)
427 /* Try to determine a good height based on the minimal height recommended by the font. */
428 int scaled_height
= ScaleFontTrad(this->GetDefaultFontHeight(this->fs
));
429 pixels
= scaled_height
;
431 TT_Header
*head
= (TT_Header
*)FT_Get_Sfnt_Table(this->face
, ft_sfnt_head
);
432 if (head
!= nullptr) {
433 /* Font height is minimum height plus the difference between the default
434 * height for this font size and the small size. */
435 int diff
= scaled_height
- ScaleFontTrad(this->GetDefaultFontHeight(FS_SMALL
));
436 pixels
= Clamp(std::min
<uint
>(head
->Lowest_Rec_PPEM
, MAX_FONT_MIN_REC_SIZE
) + diff
, scaled_height
, MAX_FONT_SIZE
);
439 pixels
= ScaleFontTrad(pixels
);
441 this->used_size
= pixels
;
443 FT_Error err
= FT_Set_Pixel_Sizes(this->face
, 0, pixels
);
444 if (err
!= FT_Err_Ok
) {
446 /* Find nearest size to that requested */
447 FT_Bitmap_Size
*bs
= this->face
->available_sizes
;
448 int i
= this->face
->num_fixed_sizes
;
449 if (i
> 0) { // In pathetic cases one might get no fixed sizes at all.
453 if (abs(pixels
- bs
->height
) >= abs(pixels
- n
)) continue;
455 chosen
= this->face
->num_fixed_sizes
- i
;
458 /* Don't use FT_Set_Pixel_Sizes here - it might give us another
459 * error, even though the size is available (FS#5885). */
460 err
= FT_Select_Size(this->face
, chosen
);
464 if (err
== FT_Err_Ok
) {
465 this->units_per_em
= this->face
->units_per_EM
;
466 this->ascender
= this->face
->size
->metrics
.ascender
>> 6;
467 this->descender
= this->face
->size
->metrics
.descender
>> 6;
468 this->height
= this->ascender
- this->descender
;
470 /* Both FT_Set_Pixel_Sizes and FT_Select_Size failed. */
471 Debug(freetype
, 0, "Font size selection failed. Using FontCache defaults.");
476 * Loads the freetype font.
477 * First type to load the fontname as if it were a path. If that fails,
478 * try to resolve the filename of the font using fontconfig, where the
479 * format is 'font family name' or 'font family name, font style'.
480 * @param fs The font size to load.
482 static void LoadFreeTypeFont(FontSize fs
)
484 FreeTypeSubSetting
*settings
= nullptr;
486 default: NOT_REACHED();
487 case FS_SMALL
: settings
= &_freetype
.small
; break;
488 case FS_NORMAL
: settings
= &_freetype
.medium
; break;
489 case FS_LARGE
: settings
= &_freetype
.large
; break;
490 case FS_MONO
: settings
= &_freetype
.mono
; break;
493 if (settings
->font
.empty()) return;
495 if (_library
== nullptr) {
496 if (FT_Init_FreeType(&_library
) != FT_Err_Ok
) {
497 ShowInfoF("Unable to initialize FreeType, using sprite fonts instead");
501 Debug(freetype
, 2, "Initialized");
504 const char *font_name
= settings
->font
.c_str();
505 FT_Face face
= nullptr;
507 /* If font is an absolute path to a ttf, try loading that first. */
508 FT_Error error
= FT_New_Face(_library
, font_name
, 0, &face
);
510 #if defined(WITH_COCOA)
511 extern void MacOSRegisterExternalFont(const char *file_path
);
512 if (error
== FT_Err_Ok
) MacOSRegisterExternalFont(font_name
);
515 if (error
!= FT_Err_Ok
) {
516 /* Check if font is a relative filename in one of our search-paths. */
517 std::string full_font
= FioFindFullPath(BASE_DIR
, font_name
);
518 if (!full_font
.empty()) {
519 error
= FT_New_Face(_library
, full_font
.c_str(), 0, &face
);
520 #if defined(WITH_COCOA)
521 if (error
== FT_Err_Ok
) MacOSRegisterExternalFont(full_font
.c_str());
526 /* Try loading based on font face name (OS-wide fonts). */
527 if (error
!= FT_Err_Ok
) error
= GetFontByFaceName(font_name
, &face
);
529 if (error
== FT_Err_Ok
) {
530 Debug(freetype
, 2, "Requested '{}', using '{} {}'", font_name
, face
->family_name
, face
->style_name
);
532 /* Attempt to select the unicode character map */
533 error
= FT_Select_Charmap(face
, ft_encoding_unicode
);
534 if (error
== FT_Err_Ok
) goto found_face
; // Success
536 if (error
== FT_Err_Invalid_CharMap_Handle
) {
537 /* Try to pick a different character map instead. We default to
538 * the first map, but platform_id 0 encoding_id 0 should also
539 * be unicode (strange system...) */
540 FT_CharMap found
= face
->charmaps
[0];
543 for (i
= 0; i
< face
->num_charmaps
; i
++) {
544 FT_CharMap charmap
= face
->charmaps
[i
];
545 if (charmap
->platform_id
== 0 && charmap
->encoding_id
== 0) {
550 if (found
!= nullptr) {
551 error
= FT_Set_Charmap(face
, found
);
552 if (error
== FT_Err_Ok
) goto found_face
;
559 static const char *SIZE_TO_NAME
[] = { "medium", "small", "large", "mono" };
560 ShowInfoF("Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", font_name
, SIZE_TO_NAME
[fs
], error
);
564 new FreeTypeFontCache(fs
, face
, settings
->size
);
569 * Free everything that was allocated for this font cache.
571 FreeTypeFontCache::~FreeTypeFontCache()
573 FT_Done_Face(this->face
);
574 this->face
= nullptr;
575 this->ClearFontCache();
579 * Reset cached glyphs.
581 void FreeTypeFontCache::ClearFontCache()
583 /* Font scaling might have changed, determine font size anew if it was automatically selected. */
584 if (this->face
!= nullptr) this->SetFontSize(this->fs
, this->face
, this->req_size
);
586 this->TrueTypeFontCache::ClearFontCache();
590 const Sprite
*FreeTypeFontCache::InternalGetGlyph(GlyphID key
, bool aa
)
592 FT_GlyphSlot slot
= this->face
->glyph
;
594 FT_Load_Glyph(this->face
, key
, aa
? FT_LOAD_TARGET_NORMAL
: FT_LOAD_TARGET_MONO
);
595 FT_Render_Glyph(this->face
->glyph
, aa
? FT_RENDER_MODE_NORMAL
: FT_RENDER_MODE_MONO
);
597 /* Despite requesting a normal glyph, FreeType may have returned a bitmap */
598 aa
= (slot
->bitmap
.pixel_mode
== FT_PIXEL_MODE_GRAY
);
600 /* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */
601 uint width
= std::max(1U, (uint
)slot
->bitmap
.width
+ (this->fs
== FS_NORMAL
));
602 uint height
= std::max(1U, (uint
)slot
->bitmap
.rows
+ (this->fs
== FS_NORMAL
));
604 /* Limit glyph size to prevent overflows later on. */
605 if (width
> MAX_GLYPH_DIM
|| height
> MAX_GLYPH_DIM
) usererror("Font glyph is too large");
607 /* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */
608 SpriteLoader::Sprite sprite
;
609 sprite
.AllocateData(ZOOM_LVL_NORMAL
, width
* height
);
610 sprite
.type
= ST_FONT
;
611 sprite
.colours
= (aa
? SCC_PAL
| SCC_ALPHA
: SCC_PAL
);
612 sprite
.width
= width
;
613 sprite
.height
= height
;
614 sprite
.x_offs
= slot
->bitmap_left
;
615 sprite
.y_offs
= this->ascender
- slot
->bitmap_top
;
617 /* Draw shadow for medium size */
618 if (this->fs
== FS_NORMAL
&& !aa
) {
619 for (uint y
= 0; y
< (uint
)slot
->bitmap
.rows
; y
++) {
620 for (uint x
= 0; x
< (uint
)slot
->bitmap
.width
; x
++) {
621 if (HasBit(slot
->bitmap
.buffer
[(x
/ 8) + y
* slot
->bitmap
.pitch
], 7 - (x
% 8))) {
622 sprite
.data
[1 + x
+ (1 + y
) * sprite
.width
].m
= SHADOW_COLOUR
;
623 sprite
.data
[1 + x
+ (1 + y
) * sprite
.width
].a
= 0xFF;
629 for (uint y
= 0; y
< (uint
)slot
->bitmap
.rows
; y
++) {
630 for (uint x
= 0; x
< (uint
)slot
->bitmap
.width
; x
++) {
631 if (aa
? (slot
->bitmap
.buffer
[x
+ y
* slot
->bitmap
.pitch
] > 0) : HasBit(slot
->bitmap
.buffer
[(x
/ 8) + y
* slot
->bitmap
.pitch
], 7 - (x
% 8))) {
632 sprite
.data
[x
+ y
* sprite
.width
].m
= FACE_COLOUR
;
633 sprite
.data
[x
+ y
* sprite
.width
].a
= aa
? slot
->bitmap
.buffer
[x
+ y
* slot
->bitmap
.pitch
] : 0xFF;
638 GlyphEntry new_glyph
;
639 new_glyph
.sprite
= BlitterFactory::GetCurrentBlitter()->Encode(&sprite
, SimpleSpriteAlloc
);
640 new_glyph
.width
= slot
->advance
.x
>> 6;
642 this->SetGlyphPtr(key
, &new_glyph
);
644 return new_glyph
.sprite
;
648 GlyphID
FreeTypeFontCache::MapCharToGlyph(WChar key
)
650 assert(IsPrintable(key
));
652 if (key
>= SCC_SPRITE_START
&& key
<= SCC_SPRITE_END
) {
653 return this->parent
->MapCharToGlyph(key
);
656 return FT_Get_Char_Index(this->face
, key
);
659 const void *FreeTypeFontCache::InternalGetFontTable(uint32 tag
, size_t &length
)
662 FT_Byte
*result
= nullptr;
664 FT_Load_Sfnt_Table(this->face
, tag
, 0, nullptr, &len
);
667 result
= MallocT
<FT_Byte
>(len
);
668 FT_Load_Sfnt_Table(this->face
, tag
, 0, result
, &len
);
674 #endif /* WITH_FREETYPE */
678 * (Re)initialize the freetype related things, i.e. load the non-sprite fonts.
679 * @param monospace Whether to initialise the monospace or regular fonts.
681 void InitFreeType(bool monospace
)
683 for (FontSize fs
= FS_BEGIN
; fs
< FS_END
; fs
++) {
684 if (monospace
!= (fs
== FS_MONO
)) continue;
686 FontCache
*fc
= FontCache::Get(fs
);
687 if (fc
->HasParent()) delete fc
;
690 LoadFreeTypeFont(fs
);
691 #elif defined(_WIN32)
692 extern void LoadWin32Font(FontSize fs
);
694 #elif defined(WITH_COCOA)
695 extern void LoadCoreTextFont(FontSize fs
);
696 LoadCoreTextFont(fs
);
702 * Free everything allocated w.r.t. fonts.
704 void UninitFreeType()
706 for (FontSize fs
= FS_BEGIN
; fs
< FS_END
; fs
++) {
707 FontCache
*fc
= FontCache::Get(fs
);
708 if (fc
->HasParent()) delete fc
;
712 FT_Done_FreeType(_library
);
714 #endif /* WITH_FREETYPE */
718 * Should any of the active fonts be anti-aliased?
719 * @return True if any of the loaded fonts want anti-aliased drawing.
721 bool HasAntialiasedFonts()
723 for (FontSize fs
= FS_BEGIN
; fs
< FS_END
; fs
++) {
724 if (!FontCache::Get(fs
)->IsBuiltInFont() && GetFontAAState(fs
, false)) return true;
730 #if !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA)
733 FT_Error
GetFontByFaceName(const char *font_name
, FT_Face
*face
) { return FT_Err_Cannot_Open_Resource
; }
734 #endif /* WITH_FREETYPE */
736 bool SetFallbackFont(FreeTypeSettings
*settings
, const char *language_isocode
, int winlangid
, MissingGlyphSearcher
*callback
) { return false; }
737 #endif /* !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA) */