34 static const int _default_font_ascender[FS_END] = { 8, 5, 15, 8};
41 ascender(_default_font_ascender[fs]), descender(_default_font_ascender[fs] -
_default_font_height[fs]),
87 virtual const void *
GetFontTable(uint32 tag,
size_t &length) { length = 0;
return NULL; }
128 default: NOT_REACHED();
130 case FS_NORMAL: base = SPR_ASCII_SPACE;
break;
131 case FS_SMALL: base = SPR_ASCII_SPACE_SMALL;
break;
132 case FS_LARGE: base = SPR_ASCII_SPACE_BIG;
break;
137 if (!SpriteExists(sprite))
continue;
142 for (uint i = 0; i <
lengthof(_default_unicode_map); i++) {
143 byte key = _default_unicode_map[i].key;
163 for (uint i = 0; i < 256; i++) {
179 return GetSprite(sprite,
ST_FONT);
202 #include <ft2build.h>
203 #include FT_FREETYPE_H
205 #include FT_TRUETYPE_TABLES_H
251 virtual const void *
GetFontTable(uint32 tag,
size_t &length);
255 FT_Library _library = NULL;
259 static const byte FACE_COLOUR = 1;
260 static const byte SHADOW_COLOUR = 2;
270 assert(face != NULL);
276 TT_Header *head = (TT_Header *)FT_Get_Sfnt_Table(this->face, ft_sfnt_head);
281 pixels =
Clamp(
min(head->Lowest_Rec_PPEM, 20) + diff, _default_font_height[this->fs],
MAX_FONT_SIZE);
285 FT_Error err = FT_Set_Pixel_Sizes(this->face, 0, pixels);
286 if (err != FT_Err_Ok) {
289 FT_Bitmap_Size *bs = this->face->available_sizes;
290 int i = this->face->num_fixed_sizes;
295 if (
abs(pixels - bs->height) >=
abs(pixels - n))
continue;
297 chosen = this->face->num_fixed_sizes - i;
302 err = FT_Select_Size(this->face, chosen);
306 if (err == FT_Err_Ok) {
308 this->
ascender = this->face->size->metrics.ascender >> 6;
309 this->
descender = this->face->size->metrics.descender >> 6;
313 DEBUG(freetype, 0,
"Font size selection failed. Using FontCache defaults.");
328 default: NOT_REACHED();
337 if (_library == NULL) {
338 if (FT_Init_FreeType(&_library) != FT_Err_Ok) {
339 ShowInfoF(
"Unable to initialize FreeType, using sprite fonts instead");
343 DEBUG(freetype, 2,
"Initialized");
347 FT_Error
error = FT_New_Face(_library, settings->
font, 0, &face);
351 if (error == FT_Err_Ok) {
352 DEBUG(freetype, 2,
"Requested '%s', using '%s %s'", settings->
font, face->family_name, face->style_name);
355 error = FT_Select_Charmap(face, ft_encoding_unicode);
356 if (error == FT_Err_Ok)
goto found_face;
358 if (error == FT_Err_Invalid_CharMap_Handle) {
362 FT_CharMap found = face->charmaps[0];
365 for (i = 0; i < face->num_charmaps; i++) {
366 FT_CharMap charmap = face->charmaps[i];
367 if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
373 error = FT_Set_Charmap(face, found);
374 if (error == FT_Err_Ok)
goto found_face;
381 static const char *SIZE_TO_NAME[] = {
"medium",
"small",
"large",
"mono" };
382 ShowInfoF(
"Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", settings->
font, SIZE_TO_NAME[fs], error);
395 FT_Done_Face(this->
face);
399 free(iter->second.second);
410 for (
int i = 0; i < 256; i++) {
413 for (
int j = 0; j < 256; j++) {
435 void FreeTypeFontCache::SetGlyphPtr(
GlyphID key,
const GlyphEntry *glyph,
bool duplicate)
438 DEBUG(freetype, 3,
"Allocating root glyph cache for size %u", this->
fs);
443 DEBUG(freetype, 3,
"Allocating glyph cache for range 0x%02X00, size %u",
GB(key, 8, 8), this->
fs);
447 DEBUG(freetype, 4,
"Set glyph for unicode character 0x%04X, size %u", key, this->
fs);
453 static void *AllocateFont(
size_t size)
455 return MallocT<byte>(size);
460 static bool GetFontAAState(
FontSize size)
466 default: NOT_REACHED();
481 if (glyph != NULL && glyph->
sprite != NULL)
return glyph->
sprite;
483 FT_GlyphSlot slot = this->
face->glyph;
485 bool aa = GetFontAAState(this->
fs);
490 if (question_glyph == 0) {
493 #define CPSET { 0, 0, 0, 0, 1 }
494 #define CP___ { 0, 0, 0, 0, 0 }
496 CP___, CP___, CPSET, CPSET, CPSET, CPSET, CP___, CP___,
497 CP___, CPSET, CPSET, CP___, CP___, CPSET, CPSET, CP___,
498 CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___,
499 CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___,
500 CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
501 CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
502 CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
503 CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___,
504 CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
505 CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
515 builtin_questionmark_data
522 this->SetGlyphPtr(key, &new_glyph,
false);
527 glyph = this->GetGlyphPtr(question_glyph);
528 this->SetGlyphPtr(key, glyph,
true);
532 FT_Load_Glyph(this->
face, key, FT_LOAD_DEFAULT);
533 FT_Render_Glyph(this->
face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
536 aa = (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
539 uint width =
max(1U, (uint)slot->bitmap.width + (this->fs ==
FS_NORMAL));
543 if (width > 256 || height > 256)
usererror(
"Font glyph is too large");
549 sprite.
width = width;
551 sprite.
x_offs = slot->bitmap_left;
556 for (uint y = 0; y < (uint)slot->bitmap.rows; y++) {
557 for (uint x = 0; x < (uint)slot->bitmap.width; x++) {
558 if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) :
HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
559 sprite.
data[1 + x + (1 + y) * sprite.
width].
m = SHADOW_COLOUR;
560 sprite.
data[1 + x + (1 + y) * sprite.
width].
a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF;
566 for (uint y = 0; y < (uint)slot->bitmap.rows; y++) {
567 for (uint x = 0; x < (uint)slot->bitmap.width; x++) {
568 if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) :
HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
569 sprite.
data[x + y * sprite.
width].
m = FACE_COLOUR;
570 sprite.
data[x + y * sprite.
width].
a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF;
576 new_glyph.
width = slot->advance.x >> 6;
578 this->SetGlyphPtr(key, &new_glyph);
595 if (glyph == NULL || glyph->
sprite == NULL) {
597 glyph = this->GetGlyphPtr(key);
605 assert(IsPrintable(key));
607 if (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) {
611 return FT_Get_Char_Index(this->
face, key);
618 length = iter->second.first;
619 return iter->second.second;
623 FT_Byte *result = NULL;
625 FT_Load_Sfnt_Table(this->
face, tag, 0, NULL, &len);
628 result = MallocT<FT_Byte>(len);
629 FT_Load_Sfnt_Table(this->
face, tag, 0, result, &len);
646 if (monospace != (fs ==
FS_MONO))
continue;
668 FT_Done_FreeType(_library);