aboutsummaryrefslogtreecommitdiff
path: root/graphics
diff options
context:
space:
mode:
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;