aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--graphics/font.cpp40
-rw-r--r--graphics/font.h9
-rw-r--r--graphics/fonts/ttf.cpp37
-rw-r--r--gui/ThemeEngine.cpp4
-rw-r--r--gui/ThemeEngine.h2
-rw-r--r--gui/gui-manager.h1
-rw-r--r--gui/widgets/editable.cpp11
-rw-r--r--gui/widgets/edittext.cpp5
8 files changed, 92 insertions, 17 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;
diff --git a/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp
index 585789b515..46a0eda0c5 100644
--- a/gui/ThemeEngine.cpp
+++ b/gui/ThemeEngine.cpp
@@ -1373,6 +1373,10 @@ int ThemeEngine::getCharWidth(byte c, FontStyle font) const {
return ready() ? _texts[fontStyleToData(font)]->_fontPtr->getCharWidth(c) : 0;
}
+int ThemeEngine::getKerningOffset(byte left, byte right, FontStyle font) const {
+ return ready() ? _texts[fontStyleToData(font)]->_fontPtr->getKerningOffset(left, right) : 0;
+}
+
TextData ThemeEngine::getTextData(DrawData ddId) const {
return _widgets[ddId] ? (TextData)_widgets[ddId]->_textDataId : kTextDataNone;
}
diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h
index c49952ba0f..f041f85ab9 100644
--- a/gui/ThemeEngine.h
+++ b/gui/ThemeEngine.h
@@ -310,6 +310,8 @@ public:
int getCharWidth(byte c, FontStyle font = kFontStyleBold) const;
+ int getKerningOffset(byte left, byte right, FontStyle font = kFontStyleBold) const;
+
//@}
diff --git a/gui/gui-manager.h b/gui/gui-manager.h
index addd2e6611..49542fd001 100644
--- a/gui/gui-manager.h
+++ b/gui/gui-manager.h
@@ -81,6 +81,7 @@ public:
int getFontHeight(ThemeEngine::FontStyle style = ThemeEngine::kFontStyleBold) const { return _theme->getFontHeight(style); }
int getStringWidth(const Common::String &str, ThemeEngine::FontStyle style = ThemeEngine::kFontStyleBold) const { return _theme->getStringWidth(str, style); }
int getCharWidth(byte c, ThemeEngine::FontStyle style = ThemeEngine::kFontStyleBold) const { return _theme->getCharWidth(c, style); }
+ int getKerningOffset(byte left, byte right, ThemeEngine::FontStyle font = ThemeEngine::kFontStyleBold) const { return _theme->getKerningOffset(left, right, font); }
/**
* Tell the GuiManager to check whether the screen resolution has changed.
diff --git a/gui/widgets/editable.cpp b/gui/widgets/editable.cpp
index 4a0ee54828..6fae9346b2 100644
--- a/gui/widgets/editable.cpp
+++ b/gui/widgets/editable.cpp
@@ -238,8 +238,13 @@ void EditableWidget::defaultKeyDownHandler(Common::KeyState &state, bool &dirty,
int EditableWidget::getCaretOffset() const {
int caretpos = 0;
- for (int i = 0; i < _caretPos; i++)
- caretpos += g_gui.getCharWidth(_editString[i], _font);
+
+ uint last = 0;
+ for (int i = 0; i < _caretPos; ++i) {
+ const uint cur = _editString[i];
+ caretpos += g_gui.getCharWidth(cur, _font) + g_gui.getKerningOffset(last, cur, _font);
+ last = cur;
+ }
caretpos -= _editScrollOffset;
@@ -270,6 +275,8 @@ void EditableWidget::drawCaret(bool erase) {
if ((uint)_caretPos < _editString.size()) {
GUI::EditableWidget::String chr(_editString[_caretPos]);
int chrWidth = g_gui.getCharWidth(_editString[_caretPos], _font);
+ const uint last = (_caretPos > 0) ? _editString[_caretPos - 1] : 0;
+ x += g_gui.getKerningOffset(last, _editString[_caretPos], _font);
g_gui.theme()->drawText(Common::Rect(x, y, x + chrWidth, y + editRect.height() - 2), chr, _state, Graphics::kTextAlignLeft, _inversion, 0, false, _font);
}
}
diff --git a/gui/widgets/edittext.cpp b/gui/widgets/edittext.cpp
index 0337fe1e87..af8ab8aa5b 100644
--- a/gui/widgets/edittext.cpp
+++ b/gui/widgets/edittext.cpp
@@ -67,10 +67,13 @@ void EditTextWidget::handleMouseDown(int x, int y, int button, int clickCount) {
int width = 0;
uint i;
+ uint last = 0;
for (i = 0; i < _editString.size(); ++i) {
- width += g_gui.theme()->getCharWidth(_editString[i], _font);
+ const uint cur = _editString[i];
+ width += g_gui.getCharWidth(cur, _font) + g_gui.getKerningOffset(last, cur, _font);
if (width >= x)
break;
+ last = cur;
}
if (setCaretPos(i))
draw();