| 134 | |
| 135 | |
| 136 | const Sprite *FreeTypeFontCache::InternalGetGlyph(GlyphID key, bool aa) |
| 137 | { |
| 138 | FT_GlyphSlot slot = this->face->glyph; |
| 139 | |
| 140 | FT_Load_Glyph(this->face, key, aa ? FT_LOAD_TARGET_NORMAL : FT_LOAD_TARGET_MONO); |
| 141 | FT_Render_Glyph(this->face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO); |
| 142 | |
| 143 | /* Despite requesting a normal glyph, FreeType may have returned a bitmap */ |
| 144 | aa = (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY); |
| 145 | |
| 146 | /* Add 1 scaled pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */ |
| 147 | uint shadow = (this->fs == FS_NORMAL) ? ScaleGUITrad(1) : 0; |
| 148 | uint width = std::max(1U, (uint)slot->bitmap.width + shadow); |
| 149 | uint height = std::max(1U, (uint)slot->bitmap.rows + shadow); |
| 150 | |
| 151 | /* Limit glyph size to prevent overflows later on. */ |
| 152 | if (width > MAX_GLYPH_DIM || height > MAX_GLYPH_DIM) UserError("Font glyph is too large"); |
| 153 | |
| 154 | /* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */ |
| 155 | SpriteLoader::SpriteCollection spritecollection; |
| 156 | SpriteLoader::Sprite &sprite = spritecollection[ZoomLevel::Min]; |
| 157 | sprite.AllocateData(ZoomLevel::Min, static_cast<size_t>(width) * height); |
| 158 | sprite.colours = SpriteComponent::Palette; |
| 159 | if (aa) sprite.colours.Set(SpriteComponent::Alpha); |
| 160 | sprite.width = width; |
| 161 | sprite.height = height; |
| 162 | sprite.x_offs = slot->bitmap_left; |
| 163 | sprite.y_offs = this->ascender - slot->bitmap_top; |
| 164 | |
| 165 | /* Draw shadow for medium size */ |
| 166 | if (this->fs == FS_NORMAL && !aa) { |
| 167 | for (uint y = 0; y < (uint)slot->bitmap.rows; y++) { |
| 168 | for (uint x = 0; x < (uint)slot->bitmap.width; x++) { |
| 169 | if (HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) { |
| 170 | sprite.data[shadow + x + (shadow + y) * sprite.width].m = SHADOW_COLOUR; |
| 171 | sprite.data[shadow + x + (shadow + y) * sprite.width].a = 0xFF; |
| 172 | } |
| 173 | } |
| 174 | } |
| 175 | } |
| 176 | |
| 177 | for (uint y = 0; y < (uint)slot->bitmap.rows; y++) { |
| 178 | for (uint x = 0; x < (uint)slot->bitmap.width; x++) { |
| 179 | if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) { |
| 180 | sprite.data[x + y * sprite.width].m = FACE_COLOUR; |
| 181 | sprite.data[x + y * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF; |
| 182 | } |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | UniquePtrSpriteAllocator allocator; |
| 187 | BlitterFactory::GetCurrentBlitter()->Encode(SpriteType::Font, spritecollection, allocator); |
| 188 | |
| 189 | GlyphEntry new_glyph; |
| 190 | new_glyph.data = std::move(allocator.data); |
| 191 | new_glyph.width = slot->advance.x >> 6; |
| 192 | |
| 193 | return this->SetGlyphPtr(key, std::move(new_glyph)).GetSprite(); |
no test coverage detected