const Sprite *GetGlyph(FontSize size, WChar key) { FT_Face face = GetFontFace(size); FT_GlyphSlot slot; GlyphEntry new_glyph; GlyphEntry *glyph; SpriteLoader::Sprite sprite; int width; int height; int x; int y; assert(IsPrintable(key)); /* Bail out if no face loaded, or for our special characters */ if (face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) { SpriteID sprite = GetUnicodeGlyph(size, key); if (sprite == 0) sprite = GetUnicodeGlyph(size, '?'); /* Load the sprite if it's known. */ if (sprite != 0) return GetSprite(sprite, ST_FONT); /* For the 'rare' case there is no font available at all. */ if (face == NULL) error("No sprite font and no real font either... bailing!"); /* Use the '?' from the freetype font. */ key = '?'; } /* Check for the glyph in our cache */ glyph = GetGlyphPtr(size, key); if (glyph != NULL && glyph->sprite != NULL) return glyph->sprite; slot = face->glyph; bool aa = GetFontAAState(size); FT_UInt glyph_index = FT_Get_Char_Index(face, key); if (glyph_index == 0) { if (key == '?') { /* The font misses the '?' character. Use sprite font. */ SpriteID sprite = GetUnicodeGlyph(size, key); Sprite *spr = (Sprite*)GetRawSprite(sprite, ST_FONT, AllocateFont); assert(spr != NULL); new_glyph.sprite = spr; new_glyph.width = spr->width + (size != FS_NORMAL); SetGlyphPtr(size, key, &new_glyph, false); return new_glyph.sprite; } else { /* Use '?' for missing characters. */ GetGlyph(size, '?'); glyph = GetGlyphPtr(size, '?'); SetGlyphPtr(size, key, glyph, true); return glyph->sprite; } } FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); FT_Render_Glyph(face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO); /* Despite requesting a normal glyph, FreeType may have returned a bitmap */ aa = (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY); /* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */ width = max(1, slot->bitmap.width + (size == FS_NORMAL)); height = max(1, slot->bitmap.rows + (size == FS_NORMAL)); /* Limit glyph size to prevent overflows later on. */ if (width > 256 || height > 256) usererror("Font glyph is too large"); /* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */ sprite.AllocateData(width * height); sprite.type = ST_FONT; sprite.width = width; sprite.height = height; sprite.x_offs = slot->bitmap_left; sprite.y_offs = _ascender[size] - slot->bitmap_top; /* Draw shadow for medium size */ if (size == FS_NORMAL && !aa) { for (y = 0; y < slot->bitmap.rows; y++) { for (x = 0; x < slot->bitmap.width; x++) { if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) { sprite.data[1 + x + (1 + y) * sprite.width].m = SHADOW_COLOUR; sprite.data[1 + x + (1 + y) * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF; } } } } for (y = 0; y < slot->bitmap.rows; y++) { for (x = 0; x < slot->bitmap.width; x++) { if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) { sprite.data[x + y * sprite.width].m = FACE_COLOUR; sprite.data[x + y * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF; } } } new_glyph.sprite = BlitterFactoryBase::GetCurrentBlitter()->Encode(&sprite, AllocateFont); new_glyph.width = slot->advance.x >> 6; SetGlyphPtr(size, key, &new_glyph); return new_glyph.sprite; }
const Sprite *FreeTypeFontCache::GetGlyph(GlyphID key) { if ((key & SPRITE_GLYPH) != 0) return parent->GetGlyph(key); /* Check for the glyph in our cache */ GlyphEntry *glyph = this->GetGlyphPtr(key); if (glyph != NULL && glyph->sprite != NULL) return glyph->sprite; FT_GlyphSlot slot = this->face->glyph; bool aa = GetFontAAState(this->fs); GlyphEntry new_glyph; if (key == 0) { GlyphID question_glyph = this->MapCharToGlyph('?'); if (question_glyph == 0) { /* The font misses the '?' character. Use built-in sprite. * Note: We cannot use the baseset as this also has to work in the bootstrap GUI. */ #define CPSET { 0, 0, 0, 0, 1 } #define CP___ { 0, 0, 0, 0, 0 } static SpriteLoader::CommonPixel builtin_questionmark_data[10 * 8] = { CP___, CP___, CPSET, CPSET, CPSET, CPSET, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, }; #undef CPSET #undef CP___ static const SpriteLoader::Sprite builtin_questionmark = { 10, // height 8, // width 0, // x_offs 0, // y_offs ST_FONT, builtin_questionmark_data }; Sprite *spr = BlitterFactory::GetCurrentBlitter()->Encode(&builtin_questionmark, AllocateFont); assert(spr != NULL); new_glyph.sprite = spr; new_glyph.width = spr->width + (this->fs != FS_NORMAL); this->SetGlyphPtr(key, &new_glyph, false); return new_glyph.sprite; } else { /* Use '?' for missing characters. */ this->GetGlyph(question_glyph); glyph = this->GetGlyphPtr(question_glyph); this->SetGlyphPtr(key, glyph, true); return glyph->sprite; } } FT_Load_Glyph(this->face, key, FT_LOAD_DEFAULT); FT_Render_Glyph(this->face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO); /* Despite requesting a normal glyph, FreeType may have returned a bitmap */ aa = (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY); /* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */ int width = max(1, slot->bitmap.width + (this->fs == FS_NORMAL)); int height = max(1, slot->bitmap.rows + (this->fs == FS_NORMAL)); /* Limit glyph size to prevent overflows later on. */ if (width > 256 || height > 256) usererror("Font glyph is too large"); /* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */ SpriteLoader::Sprite sprite; sprite.AllocateData(ZOOM_LVL_NORMAL, width * height); sprite.type = ST_FONT; sprite.width = width; sprite.height = height; sprite.x_offs = slot->bitmap_left; sprite.y_offs = this->ascender - slot->bitmap_top; /* Draw shadow for medium size */ if (this->fs == FS_NORMAL && !aa) { for (int y = 0; y < slot->bitmap.rows; y++) { for (int x = 0; x < slot->bitmap.width; x++) { if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) { sprite.data[1 + x + (1 + y) * sprite.width].m = SHADOW_COLOUR; sprite.data[1 + x + (1 + y) * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF; } } } } for (int y = 0; y < slot->bitmap.rows; y++) { for (int x = 0; x < slot->bitmap.width; x++) { if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) { sprite.data[x + y * sprite.width].m = FACE_COLOUR; sprite.data[x + y * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF; } } } new_glyph.sprite = BlitterFactory::GetCurrentBlitter()->Encode(&sprite, AllocateFont); new_glyph.width = slot->advance.x >> 6; this->SetGlyphPtr(key, &new_glyph); return new_glyph.sprite; }
const Sprite *GetGlyph(FontSize size, WChar key) { FT_Face face = GetFontFace(size); FT_GlyphSlot slot; GlyphEntry new_glyph; GlyphEntry *glyph; SpriteLoader::Sprite sprite; int width; int height; int x; int y; assert(IsPrintable(key)); /* Bail out if no face loaded, or for our special characters */ if (face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) { SpriteID sprite = GetUnicodeGlyph(size, key); if (sprite == 0) sprite = GetUnicodeGlyph(size, '?'); return GetSprite(sprite, ST_FONT); } /* Check for the glyph in our cache */ glyph = GetGlyphPtr(size, key); if (glyph != NULL && glyph->sprite != NULL) return glyph->sprite; slot = face->glyph; bool aa = GetFontAAState(size); FT_Load_Char(face, key, FT_LOAD_DEFAULT); FT_Render_Glyph(face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO); /* Despite requesting a normal glyph, FreeType may have returned a bitmap */ aa = (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY); /* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */ width = max(1, slot->bitmap.width + (size == FS_NORMAL)); height = max(1, slot->bitmap.rows + (size == FS_NORMAL)); /* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */ sprite.AllocateData(width * height); sprite.width = width; sprite.height = height; sprite.x_offs = slot->bitmap_left; sprite.y_offs = _ascender[size] - slot->bitmap_top; /* Draw shadow for medium size */ if (size == FS_NORMAL) { for (y = 0; y < slot->bitmap.rows; y++) { for (x = 0; x < slot->bitmap.width; x++) { if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) { sprite.data[1 + x + (1 + y) * sprite.width].m = SHADOW_COLOUR; sprite.data[1 + x + (1 + y) * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF; } } } } for (y = 0; y < slot->bitmap.rows; y++) { for (x = 0; x < slot->bitmap.width; x++) { if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) { sprite.data[x + y * sprite.width].m = FACE_COLOUR; sprite.data[x + y * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF; } } } new_glyph.sprite = BlitterFactoryBase::GetCurrentBlitter()->Encode(&sprite, AllocateFont); new_glyph.width = slot->advance.x >> 6; SetGlyphPtr(size, key, &new_glyph); return new_glyph.sprite; }