aboutsummaryrefslogtreecommitdiff
path: root/graphics
diff options
context:
space:
mode:
authorJohannes Schickel2012-01-08 02:33:34 +0100
committerWillem Jan Palenstijn2012-01-29 16:26:20 +0100
commit9f3fbe1bd773664b1e86241e71875cd97230d791 (patch)
tree1eae5b18934a2433aef7205a86bdd9a999261346 /graphics
parentd21ae1aa40f7ef5442d98c377800a0157af069c8 (diff)
downloadscummvm-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.cpp40
-rw-r--r--graphics/font.h9
-rw-r--r--graphics/fonts/ttf.cpp37
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;