diff options
Diffstat (limited to 'graphics/fonts/ttf.cpp')
-rw-r--r-- | graphics/fonts/ttf.cpp | 114 |
1 files changed, 86 insertions, 28 deletions
diff --git a/graphics/fonts/ttf.cpp b/graphics/fonts/ttf.cpp index b9e9610d77..09a00672e3 100644 --- a/graphics/fonts/ttf.cpp +++ b/graphics/fonts/ttf.cpp @@ -101,17 +101,17 @@ public: TTFFont(); virtual ~TTFFont(); - bool load(Common::SeekableReadStream &stream, int size, uint dpi, bool monochrome, const uint32 *mapping); + bool load(Common::SeekableReadStream &stream, int size, uint dpi, TTFRenderMode renderMode, const uint32 *mapping); virtual int getFontHeight() const; virtual int getMaxCharWidth() const; - virtual int getCharWidth(byte chr) const; + virtual int getCharWidth(uint32 chr) const; - virtual int getKerningOffset(byte left, byte right) const; + virtual int getKerningOffset(uint32 left, uint32 right) const; - virtual void drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const; + virtual void drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const; private: bool _initialized; FT_Face _face; @@ -126,21 +126,24 @@ private: Surface image; int xOffset, yOffset; int advance; + FT_UInt slot; }; - bool cacheGlyph(Glyph &glyph, FT_UInt &slot, uint chr); - typedef Common::HashMap<byte, Glyph> GlyphCache; - GlyphCache _glyphs; + bool cacheGlyph(Glyph &glyph, uint32 chr) const; + typedef Common::HashMap<uint32, Glyph> GlyphCache; + mutable GlyphCache _glyphs; + bool _allowLateCaching; + void assureCached(uint32 chr) const; - FT_UInt _glyphSlots[256]; - - bool _monochrome; + FT_Int32 _loadFlags; + FT_Render_Mode _renderMode; bool _hasKerning; }; TTFFont::TTFFont() : _initialized(false), _face(), _ttfFile(0), _size(0), _width(0), _height(0), _ascent(0), - _descent(0), _glyphs(), _glyphSlots(), _monochrome(false), _hasKerning(false) { + _descent(0), _glyphs(), _loadFlags(FT_LOAD_TARGET_NORMAL), _renderMode(FT_RENDER_MODE_NORMAL), + _hasKerning(false), _allowLateCaching(false) { } TTFFont::~TTFFont() { @@ -157,7 +160,7 @@ TTFFont::~TTFFont() { } } -bool TTFFont::load(Common::SeekableReadStream &stream, int size, uint dpi, bool monochrome, const uint32 *mapping) { +bool TTFFont::load(Common::SeekableReadStream &stream, int size, uint dpi, TTFRenderMode renderMode, const uint32 *mapping) { if (!g_ttf.isInitialized()) return false; @@ -202,7 +205,22 @@ bool TTFFont::load(Common::SeekableReadStream &stream, int size, uint dpi, bool return false; } - _monochrome = monochrome; + switch (renderMode) { + case kTTFRenderModeNormal: + _loadFlags = FT_LOAD_TARGET_NORMAL; + _renderMode = FT_RENDER_MODE_NORMAL; + break; + + case kTTFRenderModeLight: + _loadFlags = FT_LOAD_TARGET_LIGHT; + _renderMode = FT_RENDER_MODE_LIGHT; + break; + + case kTTFRenderModeMonochrome: + _loadFlags = FT_LOAD_TARGET_MONO; + _renderMode = FT_RENDER_MODE_MONO; + break; + } FT_Fixed yScale = _face->size->metrics.y_scale; _ascent = ftCeil26_6(FT_MulFix(_face->ascender, yScale)); @@ -212,19 +230,26 @@ bool TTFFont::load(Common::SeekableReadStream &stream, int size, uint dpi, bool _height = _ascent - _descent + 1; if (!mapping) { + // Allow loading of all unicode characters. + _allowLateCaching = true; + // Load all ISO-8859-1 characters. for (uint i = 0; i < 256; ++i) { - if (!cacheGlyph(_glyphs[i], _glyphSlots[i], i)) - _glyphSlots[i] = 0; + if (!cacheGlyph(_glyphs[i], i)) { + _glyphs.erase(i); + } } } else { + // We have a fixed map of characters do not load more later. + _allowLateCaching = false; + for (uint i = 0; i < 256; ++i) { const uint32 unicode = mapping[i] & 0x7FFFFFFF; const bool isRequired = (mapping[i] & 0x80000000) != 0; // Check whether loading an important glyph fails and error out if // that is the case. - if (!cacheGlyph(_glyphs[i], _glyphSlots[i], unicode)) { - _glyphSlots[i] = 0; + if (!cacheGlyph(_glyphs[i], unicode)) { + _glyphs.erase(i); if (isRequired) return false; } @@ -243,7 +268,8 @@ int TTFFont::getMaxCharWidth() const { return _width; } -int TTFFont::getCharWidth(byte chr) const { +int TTFFont::getCharWidth(uint32 chr) const { + assureCached(chr); GlyphCache::const_iterator glyphEntry = _glyphs.find(chr); if (glyphEntry == _glyphs.end()) return 0; @@ -251,12 +277,29 @@ int TTFFont::getCharWidth(byte chr) const { return glyphEntry->_value.advance; } -int TTFFont::getKerningOffset(byte left, byte right) const { +int TTFFont::getKerningOffset(uint32 left, uint32 right) const { if (!_hasKerning) return 0; - FT_UInt leftGlyph = _glyphSlots[left]; - FT_UInt rightGlyph = _glyphSlots[right]; + assureCached(left); + assureCached(right); + + FT_UInt leftGlyph, rightGlyph; + GlyphCache::const_iterator glyphEntry; + + glyphEntry = _glyphs.find(left); + if (glyphEntry != _glyphs.end()) { + leftGlyph = glyphEntry->_value.slot; + } else { + return 0; + } + + glyphEntry = _glyphs.find(right); + if (glyphEntry != _glyphs.end()) { + rightGlyph = glyphEntry->_value.slot; + } else { + return 0; + } if (!leftGlyph || !rightGlyph) return 0; @@ -304,7 +347,8 @@ void renderGlyph(uint8 *dstPos, const int dstPitch, const uint8 *srcPos, const i } // End of anonymous namespace -void TTFFont::drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const { +void TTFFont::drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const { + assureCached(chr); GlyphCache::const_iterator glyphEntry = _glyphs.find(chr); if (glyphEntry == _glyphs.end()) return; @@ -376,18 +420,20 @@ void TTFFont::drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const } } -bool TTFFont::cacheGlyph(Glyph &glyph, FT_UInt &slot, uint chr) { - slot = FT_Get_Char_Index(_face, chr); +bool TTFFont::cacheGlyph(Glyph &glyph, uint32 chr) const { + FT_UInt slot = FT_Get_Char_Index(_face, chr); if (!slot) return false; + glyph.slot = slot; + // We use the light target and render mode to improve the looks of the // glyphs. It is most noticable in FreeSansBold.ttf, where otherwise the // 't' glyph looks like it is cut off on the right side. - if (FT_Load_Glyph(_face, slot, (_monochrome ? FT_LOAD_TARGET_MONO : FT_LOAD_TARGET_LIGHT))) + if (FT_Load_Glyph(_face, slot, _loadFlags)) return false; - if (FT_Render_Glyph(_face->glyph, (_monochrome ? FT_RENDER_MODE_MONO : FT_RENDER_MODE_LIGHT))) + if (FT_Render_Glyph(_face->glyph, _renderMode)) return false; if (_face->glyph->format != FT_GLYPH_FORMAT_BITMAP) @@ -456,16 +502,28 @@ bool TTFFont::cacheGlyph(Glyph &glyph, FT_UInt &slot, uint chr) { default: warning("TTFFont::cacheGlyph: Unsupported pixel mode %d", bitmap.pixel_mode); + glyph.image.free(); return false; } return true; } -Font *loadTTFFont(Common::SeekableReadStream &stream, int size, uint dpi, bool monochrome, const uint32 *mapping) { +void TTFFont::assureCached(uint32 chr) const { + if (!chr || !_allowLateCaching || _glyphs.contains(chr)) { + return; + } + + Glyph newGlyph; + if (cacheGlyph(newGlyph, chr)) { + _glyphs[chr] = newGlyph; + } +} + +Font *loadTTFFont(Common::SeekableReadStream &stream, int size, uint dpi, TTFRenderMode renderMode, const uint32 *mapping) { TTFFont *font = new TTFFont(); - if (!font->load(stream, size, dpi, monochrome, mapping)) { + if (!font->load(stream, size, dpi, renderMode, mapping)) { delete font; return 0; } |