Codechange: [Win32] simplify when/where GdiFlush() is called
[openttd-github.git] / src / fontcache.cpp
blobbe36ac107661aa135f6b6ddc5ad11b0d60fdad51
1 /*
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/>.
6 */
8 /** @file fontcache.cpp Cache for characters from fonts. */
10 #include "stdafx.h"
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;
37 /**
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]),
43 units_per_em(1)
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];
64 /**
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 {
77 private:
78 SpriteID **glyph_to_spriteid_map; ///< Mapping of glyphs to sprite IDs.
80 void ClearGlyphToSpriteMap();
81 public:
82 SpriteFontCache(FontSize fs);
83 ~SpriteFontCache();
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; }
98 /**
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();
133 SpriteID base;
134 switch (this->fs) {
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;
151 if (key == CLRA) {
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
154 * entry only. */
155 this->SetUnicodeGlyph(_default_unicode_map[i].code, 0);
156 } else {
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()
203 return false;
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;
292 switch (size) {
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) {
312 this->GetGlyph(key);
313 glyph = this->GetGlyphPtr(key);
316 return glyph->width;
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;
327 if (key == 0) {
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___,
346 #undef CPSET
347 #undef CP___
348 static const SpriteLoader::Sprite builtin_questionmark = {
349 10, // height
350 8, // width
351 0, // x_offs
352 0, // y_offs
353 ST_FONT,
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;
364 } else {
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));
387 return result;
391 #ifdef WITH_FREETYPE
392 #include <ft2build.h>
393 #include FT_FREETYPE_H
394 #include FT_GLYPH_H
395 #include FT_TRUETYPE_TABLES_H
397 /** Font cache for fonts that are based on a freetype font. */
398 class FreeTypeFontCache : public TrueTypeFontCache {
399 private:
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);
406 public:
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)
433 if (pixels == 0) {
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);
445 } else {
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.
457 int n = bs->height;
458 FT_Int chosen = 0;
459 for (; --i; bs++) {
460 if (abs(pixels - bs->height) >= abs(pixels - n)) continue;
461 n = bs->height;
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;
476 } else {
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;
492 switch (fs) {
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");
505 return;
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);
519 #endif
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());
528 #endif
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];
547 int i;
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) {
552 found = charmap;
556 if (found != nullptr) {
557 error = FT_Set_Charmap(face, found);
558 if (error == FT_Err_Ok) goto found_face;
563 FT_Done_Face(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);
567 return;
569 found_face:
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)
666 FT_ULong len = 0;
667 FT_Byte *result = nullptr;
669 FT_Load_Sfnt_Table(this->face, tag, 0, nullptr, &len);
671 if (len > 0) {
672 result = MallocT<FT_Byte>(len);
673 FT_Load_Sfnt_Table(this->face, tag, 0, result, &len);
676 length = len;
677 return result;
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;
695 #ifdef WITH_FREETYPE
696 LoadFreeTypeFont(fs);
697 #elif defined(_WIN32)
698 extern void LoadWin32Font(FontSize fs);
699 LoadWin32Font(fs);
700 #elif defined(WITH_COCOA)
701 extern void LoadCoreTextFont(FontSize fs);
702 LoadCoreTextFont(fs);
703 #endif
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;
717 #ifdef WITH_FREETYPE
718 FT_Done_FreeType(_library);
719 _library = nullptr;
720 #endif /* WITH_FREETYPE */
723 #if !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA)
725 #ifdef WITH_FREETYPE
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) */