diff --git a/graphics/font.cpp b/graphics/font.cpp index ceb6d8181c1..5b4f7144fc1 100644 --- a/graphics/font.cpp +++ b/graphics/font.cpp @@ -50,7 +50,7 @@ Common::Rect Font::getBoundingBox(uint32 chr) const { namespace { template -Common::Rect getBoundingBoxImpl(const Font &font, const StringType &str, int x, int y, int w, TextAlign align, int deltax) { +Common::Rect getBoundingBoxImpl(const Font &font, const StringType &str, int x, int y, int w, TextAlign align, int deltax, bool allowCharClipping) { // 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. @@ -73,8 +73,12 @@ Common::Rect getBoundingBoxImpl(const Font &font, const StringType &str, int x, last = cur; Common::Rect charBox = font.getBoundingBox(cur); - if (x + charBox.right > rightX) - break; + + if (!allowCharClipping) { + if (x + charBox.right > rightX) + break; + } + if (x + charBox.right >= leftX) { charBox.translate(x, y); if (first) { @@ -106,7 +110,7 @@ int getStringWidthImpl(const Font &font, const StringType &str) { } template -void drawStringImpl(const Font &font, SurfaceType *dst, const StringType &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool alpha) { +void drawStringImpl(const Font &font, SurfaceType *dst, const StringType &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool alpha, bool allowCharClipping) { // 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); @@ -127,8 +131,14 @@ void drawStringImpl(const Font &font, SurfaceType *dst, const StringType &str, i last = cur; Common::Rect charBox = font.getBoundingBox(cur); - if (x + charBox.right > rightX) - break; + + // This assumes that each drawChar/drawAlphaChar implementation + // MUST perform boundary checks, to avoid writing out of bounds! + if (!allowCharClipping) { + if (x + charBox.right > rightX) + break; + } + if (x + charBox.right >= leftX) { if (alpha) font.drawAlphaChar(dst, cur, x, y, color); @@ -417,7 +427,7 @@ StringType handleEllipsis(const Font &font, const StringType &input, int w) { } // 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 { +Common::Rect Font::getBoundingBox(const Common::String &input, int x, int y, const int w, TextAlign align, int deltax, bool useEllipsis, bool allowCharClipping) const { // In case no width was given we cannot use ellipsis or any alignment // apart from left alignment. if (w == 0) { @@ -434,10 +444,10 @@ Common::Rect Font::getBoundingBox(const Common::String &input, int x, int y, con } const Common::String str = useEllipsis ? handleEllipsis(*this, input, w) : input; - return getBoundingBoxImpl(*this, str, x, y, w, align, deltax); + return getBoundingBoxImpl(*this, str, x, y, w, align, deltax, allowCharClipping); } -Common::Rect Font::getBoundingBox(const Common::U32String &input, int x, int y, const int w, TextAlign align, int deltax, bool useEllipsis) const { +Common::Rect Font::getBoundingBox(const Common::U32String &input, int x, int y, const int w, TextAlign align, int deltax, bool useEllipsis, bool allowCharClipping) const { // In case no width was given we cannot any alignment apart from left // alignment. if (w == 0) { @@ -454,7 +464,7 @@ Common::Rect Font::getBoundingBox(const Common::U32String &input, int x, int y, } const Common::U32String str = useEllipsis ? handleEllipsis(*this, input, w) : input; - return getBoundingBoxImpl(*this, str, x, y, w, align, 0); + return getBoundingBoxImpl(*this, str, x, y, w, align, 0, allowCharClipping); } int Font::getStringWidth(const Common::String &str) const { @@ -494,56 +504,56 @@ void Font::drawAlphaChar(ManagedSurface *dst, uint32 chr, int x, int y, uint32 c dst->addDirtyRect(charBox); } -void Font::drawString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const { +void Font::drawString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis, bool allowCharClipping) const { Common::String renderStr = useEllipsis ? handleEllipsis(*this, str, w) : str; - drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, false); + drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, false, allowCharClipping); } -void Font::drawString(Surface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const { +void Font::drawString(Surface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis, bool allowCharClipping) const { Common::U32String renderStr = useEllipsis ? handleEllipsis(*this, str, w) : str; - drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, false); + drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, false, allowCharClipping); } -void Font::drawString(ManagedSurface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const { +void Font::drawString(ManagedSurface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis, bool allowCharClipping) const { Common::String renderStr = useEllipsis ? handleEllipsis(*this, str, w) : str; - drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, false); + drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, false, allowCharClipping); if (w != 0) { dst->addDirtyRect(getBoundingBox(str, x, y, w, align, deltax, useEllipsis)); } } -void Font::drawString(ManagedSurface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const { +void Font::drawString(ManagedSurface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis, bool allowCharClipping) const { Common::U32String renderStr = useEllipsis ? handleEllipsis(*this, str, w) : str; - drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, false); + drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, false, allowCharClipping); if (w != 0) { dst->addDirtyRect(getBoundingBox(str, x, y, w, align, useEllipsis)); } } -void Font::drawAlphaString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const { +void Font::drawAlphaString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis, bool allowCharClipping) const { Common::String renderStr = useEllipsis ? handleEllipsis(*this, str, w) : str; - drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, true); + drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, true, allowCharClipping); } -void Font::drawAlphaString(Surface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const { +void Font::drawAlphaString(Surface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis, bool allowCharClipping) const { Common::U32String renderStr = useEllipsis ? handleEllipsis(*this, str, w) : str; - drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, true); + drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, true, allowCharClipping); } -void Font::drawAlphaString(ManagedSurface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const { +void Font::drawAlphaString(ManagedSurface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis, bool allowCharClipping) const { Common::String renderStr = useEllipsis ? handleEllipsis(*this, str, w) : str; - drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, true); + drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, true, allowCharClipping); if (w != 0) { dst->addDirtyRect(getBoundingBox(str, x, y, w, align, deltax, useEllipsis)); } } -void Font::drawAlphaString(ManagedSurface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const { +void Font::drawAlphaString(ManagedSurface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis, bool allowCharClipping) const { Common::U32String renderStr = useEllipsis ? handleEllipsis(*this, str, w) : str; - drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, true); + drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax, true, allowCharClipping); if (w != 0) { dst->addDirtyRect(getBoundingBox(str, x, y, w, align, useEllipsis)); diff --git a/graphics/font.h b/graphics/font.h index 8562c59ba7c..7884277c724 100644 --- a/graphics/font.h +++ b/graphics/font.h @@ -183,12 +183,13 @@ public: * @param useEllipsis Try to fit the string in the area by inserting an * ellipsis. Note that the default value is false for this * argument, unlike for drawString. + * @param allowCharClipping Allows characters to extend beyond the right boundary. * * @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::String &str, int x = 0, int y = 0, const int w = 0, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false, bool allowCharClipping = false) const; /** @overload */ - Common::Rect getBoundingBox(const Common::U32String &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, int deltax = 0, bool useEllipsis = false, bool allowCharClipping = false) const; /** * Draw a character at a specific point on the surface. @@ -255,15 +256,16 @@ public: * @param align Text alignment. This can be used to center the string in the given area or to align it to the right. * @param deltax Offset to the x starting position of the string. * @param useEllipsis Use ellipsis if needed to fit the string in the area. + * @param allowCharClipping Allows characters to extend beyond the right boundary. * */ - void drawString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false) const; + void drawString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false, bool allowCharClipping = false) const; /** @overload */ - void drawString(Surface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false) const; + void drawString(Surface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false, bool allowCharClipping = false) const; /** @overload */ - void drawString(ManagedSurface *dst, const Common::String &str, int x, int _y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false) const; + void drawString(ManagedSurface *dst, const Common::String &str, int x, int _y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false, bool allowCharClipping = false) const; /** @overload */ - void drawString(ManagedSurface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false) const; + void drawString(ManagedSurface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false, bool allowCharClipping = false) const; /** * Draw the given @p str string to the given @p dst surface. @@ -282,15 +284,16 @@ public: * @param align Text alignment. This can be used to center the string in the given area or to align it to the right. * @param deltax Offset to the x starting position of the string. * @param useEllipsis Use ellipsis if needed to fit the string in the area. + * @param allowCharClipping Allows characters to extend beyond the right boundary. * */ - void drawAlphaString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false) const; + void drawAlphaString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false, bool allowCharClipping = false) const; /** @overload */ - void drawAlphaString(Surface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false) const; + void drawAlphaString(Surface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false, bool allowCharClipping = false) const; /** @overload */ - void drawAlphaString(ManagedSurface *dst, const Common::String &str, int x, int _y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false) const; + void drawAlphaString(ManagedSurface *dst, const Common::String &str, int x, int _y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false, bool allowCharClipping = false) const; /** @overload */ - void drawAlphaString(ManagedSurface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false) const; + void drawAlphaString(ManagedSurface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false, bool allowCharClipping = false) const; /** * Compute and return the width of the string @p str when rendered using this font.