[Scummvm-cvs-logs] scummvm master -> 2a75e9f1adad1599b8153ff39286a72ba51b3b52

lordhoto lordhoto at gmail.com
Sun Sep 7 21:23:53 CEST 2014


This automated email contains information about 3 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
d55cd8f3b4 GRAPHICS: Allow to query the bounding box of chars/strings drawn with Font API.
248ea3c1ab GRAPHICS: Allow negative xOffset in TTF.
2a75e9f1ad Merge pull request #500 from lordhoto/ttf-improvements


Commit: d55cd8f3b44de42d9be09280634584b6424945f9
    https://github.com/scummvm/scummvm/commit/d55cd8f3b44de42d9be09280634584b6424945f9
Author: Johannes Schickel (lordhoto at scummvm.org)
Date: 2014-09-03T22:55:48+02:00

Commit Message:
GRAPHICS: Allow to query the bounding box of chars/strings drawn with Font API.

Changed paths:
    graphics/font.cpp
    graphics/font.h
    graphics/fonts/ttf.cpp



diff --git a/graphics/font.cpp b/graphics/font.cpp
index 1ed67fa..dba4824 100644
--- a/graphics/font.cpp
+++ b/graphics/font.cpp
@@ -31,9 +31,54 @@ int Font::getKerningOffset(uint32 left, uint32 right) const {
 	return 0;
 }
 
+Common::Rect Font::getBoundingBox(uint32 chr) const {
+	return Common::Rect(getCharWidth(chr), getFontHeight());
+}
+
 namespace {
 
 template<class StringType>
+Common::Rect getBoundingBoxImpl(const Font &font, const StringType &str, int x, int y, int w, TextAlign align, int deltax) {
+	// We follow the logic of drawStringImpl here. The only exception is
+	// that we do allow an empty width to be specified here. This allows us
+	// to obtain the complete bounding box of a string.
+	const int leftX = x, rightX = w ? (x + w) : 0x7FFFFFFF;
+	int width = font.getStringWidth(str);
+
+	if (align == kTextAlignCenter)
+		x = x + (w - width)/2;
+	else if (align == kTextAlignRight)
+		x = x + w - width;
+	x += deltax;
+
+	bool first = true;
+	Common::Rect bbox;
+
+	typename StringType::unsigned_type last = 0;
+	for (typename StringType::const_iterator i = str.begin(), end = str.end(); i != end; ++i) {
+		const typename StringType::unsigned_type cur = *i;
+		x += font.getKerningOffset(last, cur);
+		last = cur;
+		w = font.getCharWidth(cur);
+		if (x+w > rightX)
+			break;
+		if (x+w >= leftX) {
+			Common::Rect charBox = font.getBoundingBox(cur);
+			charBox.translate(x, y);
+			if (first) {
+				bbox = charBox;
+				first = false;
+			} else {
+				bbox.extend(charBox);
+			}
+		}
+		x += w;
+	}
+
+	return bbox;
+}
+
+template<class StringType>
 int getStringWidthImpl(const Font &font, const StringType &str) {
 	int space = 0;
 	typename StringType::unsigned_type last = 0;
@@ -49,6 +94,8 @@ int getStringWidthImpl(const Font &font, const StringType &str) {
 
 template<class StringType>
 void drawStringImpl(const Font &font, Surface *dst, const StringType &str, int x, int y, int w, uint32 color, TextAlign align, int deltax) {
+	// The logic in getBoundingImpl is the same as we use here. In case we
+	// ever change something here we will need to change it there too.
 	assert(dst != 0);
 
 	const int leftX = x, rightX = x + w;
@@ -175,6 +222,40 @@ int wordWrapTextImpl(const Font &font, const StringType &str, int maxWidth, Comm
 
 } // End of anonymous namespace
 
+Common::Rect Font::getBoundingBox(const Common::String &input, int x, int y, const int w, TextAlign align, int deltax, bool useEllipsis) const {
+	// In case no width was given we cannot use ellipsis or any alignment
+	// apart from left alignment.
+	if (w == 0) {
+		if (useEllipsis) {
+			warning("Font::getBoundingBox: Requested ellipsis when no width was specified");
+		}
+
+		if (align != kTextAlignLeft) {
+			warning("Font::getBoundingBox: Requested text alignment when no width was specified");
+		}
+
+		useEllipsis = false;
+		align = kTextAlignLeft;
+	}
+
+	const Common::String str = useEllipsis ? handleEllipsis(input, w) : input;
+	return getBoundingBoxImpl(*this, str, x, y, w, align, deltax);
+}
+
+Common::Rect Font::getBoundingBox(const Common::U32String &str, int x, int y, const int w, TextAlign align) const {
+	// In case no width was given we cannot any alignment apart from left
+	// alignment.
+	if (w == 0) {
+		if (align != kTextAlignLeft) {
+			warning("Font::getBoundingBox: Requested text alignment when no width was specified");
+		}
+
+		align = kTextAlignLeft;
+	}
+
+	return getBoundingBoxImpl(*this, str, x, y, w, align, 0);
+}
+
 int Font::getStringWidth(const Common::String &str) const {
 	return getStringWidthImpl(*this, str);
 }
@@ -183,12 +264,28 @@ int Font::getStringWidth(const Common::U32String &str) const {
 	return getStringWidthImpl(*this, str);
 }
 
-void Font::drawString(Surface *dst, const Common::String &sOld, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const {
-	Common::String s = sOld;
+void Font::drawString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const {
+	Common::String renderStr = useEllipsis ? handleEllipsis(str, w) : str;
+	drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax);
+}
+
+void Font::drawString(Surface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align) const {
+	drawStringImpl(*this, dst, str, x, y, w, color, align, 0);
+}
+
+int Font::wordWrapText(const Common::String &str, int maxWidth, Common::Array<Common::String> &lines) const {
+	return wordWrapTextImpl(*this, str, maxWidth, lines);
+}
+
+int Font::wordWrapText(const Common::U32String &str, int maxWidth, Common::Array<Common::U32String> &lines) const {
+	return wordWrapTextImpl(*this, str, maxWidth, lines);
+}
+
+Common::String Font::handleEllipsis(const Common::String &input, int w) const {
+	Common::String s = input;
 	int width = getStringWidth(s);
-	Common::String str;
 
-	if (useEllipsis && width > w && s.hasSuffix("...")) {
+	if (width > w && s.hasSuffix("...")) {
 		// String is too wide. Check whether it ends in an ellipsis
 		// ("..."). If so, remove that and try again!
 		s.deleteLastChar();
@@ -197,7 +294,9 @@ void Font::drawString(Surface *dst, const Common::String &sOld, int x, int y, in
 		width = getStringWidth(s);
 	}
 
-	if (useEllipsis && width > w) {
+	if (width > w) {
+		Common::String str;
+
 		// String is too wide. So we shorten it "intelligently" by
 		// replacing parts of the string by an ellipsis. There are
 		// three possibilities for this: replace the start, the end, or
@@ -212,9 +311,9 @@ void Font::drawString(Surface *dst, const Common::String &sOld, int x, int y, in
 		const int halfWidth = (w - ellipsisWidth) / 2;
 		int w2 = 0;
 		Common::String::unsigned_type last = 0;
-		uint i;
+		uint i = 0;
 
-		for (i = 0; i < s.size(); ++i) {
+		for (; i < s.size(); ++i) {
 			const Common::String::unsigned_type cur = s[i];
 			int charWidth = getCharWidth(cur) + getKerningOffset(last, cur);
 			if (w2 + charWidth > halfWidth)
@@ -247,24 +346,10 @@ void Font::drawString(Surface *dst, const Common::String &sOld, int x, int y, in
 			str += s[i];
 		}
 
-		width = getStringWidth(str);
+		return str;
 	} else {
-		str = s;
+		return s;
 	}
-
-	drawStringImpl(*this, dst, str, x, y, w, color, align, deltax);
-}
-
-void Font::drawString(Surface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align) const {
-	drawStringImpl(*this, dst, str, x, y, w, color, align, 0);
-}
-
-int Font::wordWrapText(const Common::String &str, int maxWidth, Common::Array<Common::String> &lines) const {
-	return wordWrapTextImpl(*this, str, maxWidth, lines);
-}
-
-int Font::wordWrapText(const Common::U32String &str, int maxWidth, Common::Array<Common::U32String> &lines) const {
-	return wordWrapTextImpl(*this, str, maxWidth, lines);
 }
 
 } // End of namespace Graphics
diff --git a/graphics/font.h b/graphics/font.h
index f333107..35f6792 100644
--- a/graphics/font.h
+++ b/graphics/font.h
@@ -25,6 +25,7 @@
 
 #include "common/str.h"
 #include "common/ustr.h"
+#include "common/rect.h"
 
 namespace Common {
 template<class T> class Array;
@@ -84,10 +85,51 @@ public:
 	virtual int getKerningOffset(uint32 left, uint32 right) const;
 
 	/**
+	 * Calculate the bounding box of a character. It is assumed that
+	 * the character shall be drawn at position (0, 0).
+	 *
+	 * The idea here is that the character might be drawn outside the
+	 * rect (0, 0) to (getCharWidth(chr), getFontHeight()) for some fonts.
+	 * This is common among TTF fonts.
+	 *
+	 * The default implementation simply returns the rect with a width
+	 * of getCharWidth(chr) and height of getFontHeight().
+	 *
+	 * @param chr The character to draw.
+	 * @return The bounding box of the drawn glyph.
+	 */
+	virtual Common::Rect getBoundingBox(uint32 chr) const;
+
+	/**
+	 * Return the bounding box of a string drawn with drawString.
+	 *
+	 * @param x The x position where to start drawing
+	 * @param y The y position where to start drawing
+	 * @param w The width of the text area. This can be 0 to allow for
+	 *          obtaining the whole bounding box for a string. Note that this
+	 *          does not work with an align different from kTextAlignLeft or
+	 *          with useEllipsis.
+	 * @param align The text alignment. This can be used to center a string
+	 *              in the given area or to align it to the right.
+	 * @param delatx Offset to the x starting position of the string.
+	 * @param useEllipsis Try to fit the string in the area by inserting an
+	 *                    ellipsis. Be ware that the default is false for this
+	 *                    one unlike for drawString!
+	 * @return The actual area where the string is drawn.
+	 */
+	Common::Rect getBoundingBox(const Common::String &str, int x = 0, int y = 0, const int w = 0, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false) const;
+	Common::Rect getBoundingBox(const Common::U32String &str, int x = 0, int y = 0, const int w = 0, TextAlign align = kTextAlignLeft) const;
+
+	/**
 	 * Draw a character at a specific point on a surface.
 	 *
-	 * Note that the point describes the top left edge point of the
-	 * character's bounding box.
+	 * Note that the point describes the top left edge point where to draw
+	 * the character. This can be different from top left edge point of the
+	 * character's bounding box! For example, TTF fonts sometimes move
+	 * characters like 't' one (or more) pixels to the left to create better
+	 * visual results. To query the actual bounding box of a character use
+	 * getBoundingBox.
+	 * @see getBoundingBox
 	 *
 	 * The Font implemenation should take care of not drawing outside of the
 	 * specified surface.
@@ -106,6 +148,11 @@ public:
 
 	/**
 	 * Compute and return the width the string str has when rendered using this font.
+	 * This describes the logical width of the string when drawn at (0, 0).
+	 * This can be different from the actual bounding box of the string. Use
+	 * getBoundingBox when you need the bounding box of a drawn string.
+	 * @see getBoundingBox
+	 * @see drawChar
 	 */
 	int getStringWidth(const Common::String &str) const;
 	int getStringWidth(const Common::U32String &str) const;
@@ -125,6 +172,9 @@ public:
 	 */
 	int wordWrapText(const Common::String &str, int maxWidth, Common::Array<Common::String> &lines) const;
 	int wordWrapText(const Common::U32String &str, int maxWidth, Common::Array<Common::U32String> &lines) const;
+
+private:
+	Common::String handleEllipsis(const Common::String &str, int w) const;
 };
 
 } // End of namespace Graphics
diff --git a/graphics/fonts/ttf.cpp b/graphics/fonts/ttf.cpp
index 09a0067..4b63c6c 100644
--- a/graphics/fonts/ttf.cpp
+++ b/graphics/fonts/ttf.cpp
@@ -111,6 +111,8 @@ public:
 
 	virtual int getKerningOffset(uint32 left, uint32 right) const;
 
+	virtual Common::Rect getBoundingBox(uint32 chr) const;
+
 	virtual void drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const;
 private:
 	bool _initialized;
@@ -309,6 +311,19 @@ int TTFFont::getKerningOffset(uint32 left, uint32 right) const {
 	return (kerningVector.x / 64);
 }
 
+Common::Rect TTFFont::getBoundingBox(uint32 chr) const {
+	assureCached(chr);
+	GlyphCache::const_iterator glyphEntry = _glyphs.find(chr);
+	if (glyphEntry == _glyphs.end()) {
+		return Common::Rect();
+	} else {
+		const int xOffset = glyphEntry->_value.xOffset;
+		const int yOffset = glyphEntry->_value.yOffset;
+		const Graphics::Surface &image = glyphEntry->_value.image;
+		return Common::Rect(xOffset, yOffset, xOffset + image.w, yOffset + image.h);
+	}
+}
+
 namespace {
 
 template<typename ColorType>


Commit: 248ea3c1aba84fb8ae2f7021deebae64b967b9c6
    https://github.com/scummvm/scummvm/commit/248ea3c1aba84fb8ae2f7021deebae64b967b9c6
Author: Johannes Schickel (lordhoto at scummvm.org)
Date: 2014-09-03T22:55:48+02:00

Commit Message:
GRAPHICS: Allow negative xOffset in TTF.

This should improve the visual looks of many fonts. However, it might result
in the first line of the glyph to be drawn left of the position specified in
drawChar.

Changed paths:
    graphics/fonts/ttf.cpp



diff --git a/graphics/fonts/ttf.cpp b/graphics/fonts/ttf.cpp
index 4b63c6c..ba57613 100644
--- a/graphics/fonts/ttf.cpp
+++ b/graphics/fonts/ttf.cpp
@@ -454,25 +454,11 @@ bool TTFFont::cacheGlyph(Glyph &glyph, uint32 chr) const {
 	if (_face->glyph->format != FT_GLYPH_FORMAT_BITMAP)
 		return false;
 
-	FT_Glyph_Metrics &metrics = _face->glyph->metrics;
-
 	glyph.xOffset = _face->glyph->bitmap_left;
-	int xMax = glyph.xOffset + ftCeil26_6(metrics.width);
 	glyph.yOffset = _ascent - _face->glyph->bitmap_top;
 
 	glyph.advance = ftCeil26_6(_face->glyph->advance.x);
 
-	// In case we got a negative xMin we adjust that, this might make some
-	// characters make a bit odd, but it's the only way we can assure no
-	// invalid memory writes with the current font API
-	if (glyph.xOffset < 0) {
-		xMax -= glyph.xOffset;
-		glyph.xOffset = 0;
-
-		if (xMax > glyph.advance)
-			glyph.advance = xMax;
-	}
-
 	const FT_Bitmap &bitmap = _face->glyph->bitmap;
 	glyph.image.create(bitmap.width, bitmap.rows, PixelFormat::createFormatCLUT8());
 


Commit: 2a75e9f1adad1599b8153ff39286a72ba51b3b52
    https://github.com/scummvm/scummvm/commit/2a75e9f1adad1599b8153ff39286a72ba51b3b52
Author: Johannes Schickel (lordhoto at gmail.com)
Date: 2014-09-07T21:23:24+02:00

Commit Message:
Merge pull request #500 from lordhoto/ttf-improvements

Improve TTF Rendering (includes Font API changes).

Changed paths:
    graphics/font.cpp
    graphics/font.h
    graphics/fonts/ttf.cpp









More information about the Scummvm-git-logs mailing list