33 static const int _default_font_ascender[FS_END] = { 8, 5, 15, 8};
42 ascender(_default_font_ascender[fs]), descender(_default_font_ascender[fs] -
_default_font_height[fs]),
58 int FontCache::GetDefaultFontHeight(
FontSize fs)
92 virtual const void *
GetFontTable(uint32 tag,
size_t &length) { length = 0;
return nullptr; }
135 default: NOT_REACHED();
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;
144 if (!SpriteExists(sprite))
continue;
149 for (uint i = 0; i <
lengthof(_default_unicode_map); i++) {
150 byte key = _default_unicode_map[i].key;
170 for (uint i = 0; i < 256; i++) {
187 return GetSprite(sprite,
ST_FONT);
223 free(iter.second.second);
234 for (
int i = 0; i < 256; i++) {
237 for (
int j = 0; j < 256; j++) {
259 void TrueTypeFontCache::SetGlyphPtr(
GlyphID key,
const GlyphEntry *glyph,
bool duplicate)
262 Debug(freetype, 3,
"Allocating root glyph cache for size {}", this->
fs);
267 Debug(freetype, 3,
"Allocating glyph cache for range 0x{:02X}00, size {}",
GB(key, 8, 8), this->
fs);
271 Debug(freetype, 4,
"Set glyph for unicode character 0x{:04X}, size {}", key, this->
fs);
279 static bool GetFontAAState(
FontSize size,
bool check_blitter =
true)
285 default: NOT_REACHED();
303 if (glyph ==
nullptr || glyph->
sprite ==
nullptr) {
305 glyph = this->GetGlyphPtr(key);
313 if ((key & SPRITE_GLYPH) != 0)
return this->
parent->
GetGlyph(key);
317 if (glyph !=
nullptr && glyph->
sprite !=
nullptr)
return glyph->
sprite;
321 if (question_glyph == 0) {
324 #define CPSET { 0, 0, 0, 0, 1 }
325 #define CP___ { 0, 0, 0, 0, 0 }
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___,
347 builtin_questionmark_data
351 assert(spr !=
nullptr);
355 this->SetGlyphPtr(key, &new_glyph,
false);
360 glyph = this->GetGlyphPtr(question_glyph);
361 this->SetGlyphPtr(key, glyph,
true);
366 return this->InternalGetGlyph(key, GetFontAAState(this->
fs));
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);
385 #include <ft2build.h>
386 #include FT_FREETYPE_H
388 #include FT_TRUETYPE_TABLES_H
396 virtual const void *InternalGetFontTable(uint32 tag,
size_t &length);
397 virtual const Sprite *InternalGetGlyph(
GlyphID key,
bool aa);
408 FT_Library _library =
nullptr;
419 assert(
face !=
nullptr);
421 this->SetFontSize(
fs,
face, pixels);
424 void FreeTypeFontCache::SetFontSize(
FontSize fs, FT_Face face,
int pixels)
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) {
443 FT_Error err = FT_Set_Pixel_Sizes(this->face, 0, pixels);
444 if (err != FT_Err_Ok) {
447 FT_Bitmap_Size *bs = this->face->available_sizes;
448 int i = this->face->num_fixed_sizes;
453 if (
abs(pixels - bs->height) >=
abs(pixels - n))
continue;
455 chosen = this->face->num_fixed_sizes - i;
460 err = FT_Select_Size(this->face, chosen);
464 if (err == FT_Err_Ok) {
466 this->
ascender = this->face->size->metrics.ascender >> 6;
467 this->
descender = this->face->size->metrics.descender >> 6;
471 Debug(freetype, 0,
"Font size selection failed. Using FontCache defaults.");
486 default: NOT_REACHED();
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;
508 FT_Error
error = FT_New_Face(_library, font_name, 0, &face);
510 #if defined(WITH_COCOA)
515 if (
error != FT_Err_Ok) {
518 if (!full_font.empty()) {
519 error = FT_New_Face(_library, full_font.c_str(), 0, &face);
520 #if defined(WITH_COCOA)
529 if (
error == FT_Err_Ok) {
530 Debug(freetype, 2,
"Requested '{}', using '{} {}'", font_name, face->family_name, face->style_name);
533 error = FT_Select_Charmap(face, ft_encoding_unicode);
534 if (
error == FT_Err_Ok)
goto found_face;
536 if (
error == FT_Err_Invalid_CharMap_Handle) {
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);
573 FT_Done_Face(this->face);
574 this->face =
nullptr;
584 if (this->face !=
nullptr) this->SetFontSize(this->fs, this->face, this->
req_size);
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);
598 aa = (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
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));
612 sprite.
width = width;
614 sprite.
x_offs = slot->bitmap_left;
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;
640 new_glyph.
width = slot->advance.x >> 6;
642 this->SetGlyphPtr(key, &new_glyph);
644 return new_glyph.sprite;
650 assert(IsPrintable(key));
652 if (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) {
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);
684 if (monospace != (fs ==
FS_MONO))
continue;
691 #elif defined(_WIN32)
694 #elif defined(WITH_COCOA)
712 FT_Done_FreeType(_library);
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; }