diff options
author | Johannes Schickel | 2012-01-08 02:33:34 +0100 |
---|---|---|
committer | Willem Jan Palenstijn | 2012-01-29 16:26:20 +0100 |
commit | 9f3fbe1bd773664b1e86241e71875cd97230d791 (patch) | |
tree | 1eae5b18934a2433aef7205a86bdd9a999261346 /graphics | |
parent | d21ae1aa40f7ef5442d98c377800a0157af069c8 (diff) | |
download | scummvm-rg350-9f3fbe1bd773664b1e86241e71875cd97230d791.tar.gz scummvm-rg350-9f3fbe1bd773664b1e86241e71875cd97230d791.tar.bz2 scummvm-rg350-9f3fbe1bd773664b1e86241e71875cd97230d791.zip |
GRAPHICS/GUI: Implement kerning support for Font.
This adapts the related graphics code, which is the generic Font API and the
TTF font implementation.
It furthermore adapts the GUI to properly take care of kerning in text input
widgets.
Diffstat (limited to 'graphics')
-rw-r--r-- | graphics/font.cpp | 40 | ||||
-rw-r--r-- | graphics/font.h | 9 | ||||
-rw-r--r-- | graphics/fonts/ttf.cpp | 37 |
3 files changed, 72 insertions, 14 deletions
diff --git a/graphics/font.cpp b/graphics/font.cpp index 3f7152a95e..8775bccc7b 100644 --- a/graphics/font.cpp +++ b/graphics/font.cpp @@ -26,11 +26,20 @@ namespace Graphics { +int Font::getKerningOffset(byte left, byte right) const { + return 0; +} + int Font::getStringWidth(const Common::String &str) const { int space = 0; + uint last = 0; + + for (uint i = 0; i < str.size(); ++i) { + const uint cur = str[i]; + space += getCharWidth(cur) + getKerningOffset(last, cur); + last = cur; + } - for (uint i = 0; i < str.size(); ++i) - space += getCharWidth(str[i]); return space; } @@ -65,17 +74,22 @@ void Font::drawString(Surface *dst, const Common::String &sOld, int x, int y, in // for now. const int halfWidth = (w - ellipsisWidth) / 2; int w2 = 0; + uint last = 0; for (i = 0; i < s.size(); ++i) { - int charWidth = getCharWidth(s[i]); + const uint cur = s[i]; + int charWidth = getCharWidth(cur) + getKerningOffset(last, cur); if (w2 + charWidth > halfWidth) break; + last = cur; w2 += charWidth; - str += s[i]; + str += cur; } + // At this point we know that the first 'i' chars are together 'w2' // pixels wide. We took the first i-1, and add "..." to them. str += "..."; + last = '.'; // The original string is width wide. Of those we already skipped past // w2 pixels, which means (width - w2) remain. @@ -85,7 +99,9 @@ void Font::drawString(Surface *dst, const Common::String &sOld, int x, int y, in // (width + ellipsisWidth - w) int skip = width + ellipsisWidth - w; for (; i < s.size() && skip > 0; ++i) { - skip -= getCharWidth(s[i]); + const uint cur = s[i]; + skip -= getCharWidth(cur) + getKerningOffset(last, cur); + last = cur; } // Append the remaining chars, if any @@ -104,8 +120,12 @@ void Font::drawString(Surface *dst, const Common::String &sOld, int x, int y, in x = x + w - width; x += deltax; + uint last = 0; for (i = 0; i < str.size(); ++i) { - w = getCharWidth(str[i]); + const uint cur = str[i]; + x += getKerningOffset(last, cur); + last = cur; + w = getCharWidth(cur); if (x+w > rightX) break; if (x >= leftX) @@ -153,9 +173,11 @@ int Font::wordWrapText(const Common::String &str, int maxWidth, Common::Array<Co // of a line. If we encounter such a word, we have to wrap it over multiple // lines. + uint last = 0; for (Common::String::const_iterator x = str.begin(); x != str.end(); ++x) { const byte c = *x; - const int w = getCharWidth(c); + const int w = getCharWidth(c) + getKerningOffset(last, c); + last = c; const bool wouldExceedWidth = (lineWidth + tmpWidth + w > maxWidth); // If this char is a whitespace, then it represents a potential @@ -187,8 +209,10 @@ int Font::wordWrapText(const Common::String &str, int maxWidth, Common::Array<Co wrapper.add(line, lineWidth); // Trim left side while (tmpStr.size() && isspace(static_cast<unsigned char>(tmpStr[0]))) { - tmpWidth -= getCharWidth(tmpStr[0]); tmpStr.deleteChar(0); + // This is not very fast, but it is the simplest way to + // assure we do not mess something up because of kerning. + tmpWidth = getStringWidth(tmpStr); } } else { wrapper.add(tmpStr, tmpWidth); diff --git a/graphics/font.h b/graphics/font.h index 9c0b4affc1..6819b42f52 100644 --- a/graphics/font.h +++ b/graphics/font.h @@ -73,6 +73,15 @@ public: virtual int getCharWidth(byte chr) const = 0; /** + * Query the kerning offset between two characters. + * + * @param left The left character. May be 0. + * @param right The right character. May be 0. + * @return The horizontal displacement. + */ + virtual int getKerningOffset(byte left, byte right) const; + + /** * Draw a character at a specific point on a surface. * * Note that the point describes the top left edge point of the diff --git a/graphics/fonts/ttf.cpp b/graphics/fonts/ttf.cpp index 8a6b87c000..b5bf5c0158 100644 --- a/graphics/fonts/ttf.cpp +++ b/graphics/fonts/ttf.cpp @@ -109,6 +109,8 @@ public: virtual int getCharWidth(byte chr) const; + virtual int getKerningOffset(byte left, byte right) const; + virtual void drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const; private: bool _initialized; @@ -126,16 +128,19 @@ private: int advance; }; - bool cacheGlyph(Glyph &glyph, byte chr); + bool cacheGlyph(Glyph &glyph, FT_UInt &slot, uint chr); typedef Common::HashMap<byte, Glyph> GlyphCache; GlyphCache _glyphs; + FT_UInt _glyphSlots[256]; + bool _monochrome; + bool _hasKerning; }; TTFFont::TTFFont() : _initialized(false), _face(), _ttfFile(0), _size(0), _width(0), _height(0), _ascent(0), - _descent(0), _glyphs(), _monochrome(false) { + _descent(0), _glyphs(), _glyphSlots(), _monochrome(false), _hasKerning(false) { } TTFFont::~TTFFont() { @@ -187,6 +192,9 @@ bool TTFFont::load(Common::SeekableReadStream &stream, int size, bool monochrome return false; } + // Check whether we have kerning support + _hasKerning = (FT_HAS_KERNING(_face) != 0); + if (FT_Set_Char_Size(_face, 0, size * 64, 0, 0)) { delete[] _ttfFile; _ttfFile = 0; @@ -204,8 +212,10 @@ bool TTFFont::load(Common::SeekableReadStream &stream, int size, bool monochrome _height = _ascent - _descent + 1; // Load all ISO-8859-1 characters. - for (uint i = 0; i < 256; ++i) - cacheGlyph(_glyphs[i], i); + for (uint i = 0; i < 256; ++i) { + if (!cacheGlyph(_glyphs[i], _glyphSlots[i], i)) + _glyphSlots[i] = 0; + } _initialized = (_glyphs.size() != 0); return _initialized; @@ -227,6 +237,21 @@ int TTFFont::getCharWidth(byte chr) const { return glyphEntry->_value.advance; } +int TTFFont::getKerningOffset(byte left, byte right) const { + if (!_hasKerning) + return 0; + + FT_UInt leftGlyph = _glyphSlots[left]; + FT_UInt rightGlyph = _glyphSlots[right]; + + if (!leftGlyph || !rightGlyph) + return 0; + + FT_Vector kerningVector; + FT_Get_Kerning(_face, leftGlyph, rightGlyph, FT_KERNING_DEFAULT, &kerningVector); + return (kerningVector.x / 64); +} + namespace { template<typename ColorType> @@ -336,8 +361,8 @@ void TTFFont::drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const } } -bool TTFFont::cacheGlyph(Glyph &glyph, byte chr) { - FT_UInt slot = FT_Get_Char_Index(_face, chr); +bool TTFFont::cacheGlyph(Glyph &glyph, FT_UInt &slot, uint chr) { + slot = FT_Get_Char_Index(_face, chr); if (!slot) return false; |