[Scummvm-git-logs] scummvm master -> 14d42e23675238d6c93878d055c880d33cbfe423
sev-
noreply at scummvm.org
Wed Feb 11 22:54:03 UTC 2026
This automated email contains information about 3 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
802abe1a2d GRAPHICS: FONTS: Add allowCharClipping parameter
7b76fa6ceb GRAPHICS: FONTS: Add surface boundary checks to built-in fonts
14d42e2367 SCUMM: HE: Allow clipped string drawing
Commit: 802abe1a2d3f608ea72278eb517865438f75adf2
https://github.com/scummvm/scummvm/commit/802abe1a2d3f608ea72278eb517865438f75adf2
Author: AndywinXp (andywinxp at gmail.com)
Date: 2026-02-11T23:53:58+01:00
Commit Message:
GRAPHICS: FONTS: Add allowCharClipping parameter
This parameter allows for drawing the string until the very end of the allowed boundary,
instead of completely skipping the affected characters.
Changed paths:
graphics/font.cpp
graphics/font.h
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<class StringType>
-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<class SurfaceType, class StringType>
-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.
Commit: 7b76fa6ceb5a047b958c164e695aa1afc9777f0f
https://github.com/scummvm/scummvm/commit/7b76fa6ceb5a047b958c164e695aa1afc9777f0f
Author: AndywinXp (andywinxp at gmail.com)
Date: 2026-02-11T23:53:58+01:00
Commit Message:
GRAPHICS: FONTS: Add surface boundary checks to built-in fonts
This affects:
- AmigaFont
- BgiFont
- DosFont
- WinFont
Changed paths:
graphics/fonts/amigafont.cpp
graphics/fonts/bgifont.cpp
graphics/fonts/dosfont.cpp
graphics/fonts/winfont.cpp
diff --git a/graphics/fonts/amigafont.cpp b/graphics/fonts/amigafont.cpp
index 15c182a8408..9911fb80961 100644
--- a/graphics/fonts/amigafont.cpp
+++ b/graphics/fonts/amigafont.cpp
@@ -279,14 +279,26 @@ uint32 AmigaFont::mapChar(uint32 c) const {
}
template<typename PixelType>
-void drawCharIntern(byte *ptr, uint32 pitch, int num, int bitOffset, byte *charData, int ySize, int modulo, uint32 color) {
+void drawCharIntern(byte *ptr, uint32 pitch, int num, int bitOffset, byte *charData, int ySize, int modulo, uint32 color, Surface *dst, int x, int y) {
PixelType *d = (PixelType *)ptr;
byte *s = charData;
for (int i = 0; i < ySize; i++) {
+ // Boundary check for Y...
+ if (y + i < 0 || y + i >= dst->h) {
+ s += modulo;
+ d = (PixelType *)((byte *)d + pitch) - num;
+ continue;
+ }
for (int j = bitOffset; j < bitOffset + num; j++) {
+ // Boundary check for X...
+ if (x + (j - bitOffset) < 0 || x + (j - bitOffset) >= dst->w) {
+ d++;
+ continue;
+ }
+
byte *b = s + (j >> 3);
byte bit = *b & (0x80 >> (j & 7));
@@ -299,7 +311,6 @@ void drawCharIntern(byte *ptr, uint32 pitch, int num, int bitOffset, byte *charD
s += modulo;
d = (PixelType *)((byte *)d + pitch) - num;
}
-
}
void AmigaFont::drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const {
@@ -308,11 +319,11 @@ void AmigaFont::drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) c
byte *ptr = (byte *)dst->getBasePtr(x, y);
if (dst->format.bytesPerPixel == 1)
- drawCharIntern<byte>(ptr, dst->pitch, getPixels(chr), getOffset(chr), _charData, _font->_ySize, _font->_modulo, color);
+ drawCharIntern<byte>(ptr, dst->pitch, getPixels(chr), getOffset(chr), _charData, _font->_ySize, _font->_modulo, color, dst, x, y);
else if (dst->format.bytesPerPixel == 2)
- drawCharIntern<uint16>(ptr, dst->pitch, getPixels(chr), getOffset(chr), _charData, _font->_ySize, _font->_modulo, color);
+ drawCharIntern<uint16>(ptr, dst->pitch, getPixels(chr), getOffset(chr), _charData, _font->_ySize, _font->_modulo, color, dst, x, y);
else if (dst->format.bytesPerPixel == 4)
- drawCharIntern<uint32>(ptr, dst->pitch, getPixels(chr), getOffset(chr), _charData, _font->_ySize, _font->_modulo, color);
+ drawCharIntern<uint32>(ptr, dst->pitch, getPixels(chr), getOffset(chr), _charData, _font->_ySize, _font->_modulo, color, dst, x, y);
}
diff --git a/graphics/fonts/bgifont.cpp b/graphics/fonts/bgifont.cpp
index 376c02aa300..8206068d9e7 100644
--- a/graphics/fonts/bgifont.cpp
+++ b/graphics/fonts/bgifont.cpp
@@ -187,7 +187,15 @@ void BgiFont::drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) con
int charWidth = font->widths[charIndex];
for (uint16 i = 0; i < _totalHeight; i++) {
+ // Boundary check for Y...
+ if (y + i < 0 || y + (int)i >= dst->h)
+ continue;
+
for (uint16 j = 0; j < charWidth; j++) {
+ // Boundary check for X...
+ if (x + j < 0 || x + (int)j >= dst->w)
+ continue;
+
if (font->surface->getPixel(font->offsets[charIndex] + j, i)) {
if (dst->format.bytesPerPixel == 1)
*((byte *)dst->getBasePtr(x + j, y + i)) = color;
diff --git a/graphics/fonts/dosfont.cpp b/graphics/fonts/dosfont.cpp
index 4fb7579b0c2..dc4c3018eea 100644
--- a/graphics/fonts/dosfont.cpp
+++ b/graphics/fonts/dosfont.cpp
@@ -41,7 +41,17 @@ int DosFont::getCharWidth(uint32 chr) const {
void DosFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
int srcPixel = chr * 8;
for (int sy = 0; sy < 8; sy++) {
+ // Boundary check for Y...
+ if (y + sy < 0 || y + sy >= dst->h) {
+ srcPixel++;
+ continue;
+ }
+
for (int sx = 0; sx < 8; sx++) {
+ // Boundary check for X...
+ if (x + sx < 0 || x + sx >= dst->w)
+ continue;
+
if (Graphics::DosFont::fontData_PCBIOS[srcPixel] & 1 << (7 - sx)) {
if (dst->format.bytesPerPixel == 1)
*((byte *)dst->getBasePtr(x + sx, y + sy)) = color;
diff --git a/graphics/fonts/winfont.cpp b/graphics/fonts/winfont.cpp
index af42abf8812..4b0c27e18f0 100644
--- a/graphics/fonts/winfont.cpp
+++ b/graphics/fonts/winfont.cpp
@@ -329,7 +329,15 @@ void WinFont::drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) con
GlyphEntry &glyph = _glyphs[characterToIndex(chr)];
for (uint16 i = 0; i < _pixHeight; i++) {
+ // Boundary check for Y...
+ if (y + i < 0 || y + (int)i >= dst->h)
+ continue;
+
for (uint16 j = 0; j < glyph.charWidth; j++) {
+ // Boundary check for X...
+ if (x + j < 0 || x + (int)j >= dst->w)
+ continue;
+
if (glyph.bitmap[j + i * glyph.charWidth]) {
if (dst->format.bytesPerPixel == 1)
*((byte *)dst->getBasePtr(x + j, y + i)) = color;
Commit: 14d42e23675238d6c93878d055c880d33cbfe423
https://github.com/scummvm/scummvm/commit/14d42e23675238d6c93878d055c880d33cbfe423
Author: AndywinXp (andywinxp at gmail.com)
Date: 2026-02-11T23:53:58+01:00
Commit Message:
SCUMM: HE: Allow clipped string drawing
Changed paths:
engines/scumm/he/font_he.cpp
diff --git a/engines/scumm/he/font_he.cpp b/engines/scumm/he/font_he.cpp
index 234a89bca2c..19de1e37822 100644
--- a/engines/scumm/he/font_he.cpp
+++ b/engines/scumm/he/font_he.cpp
@@ -216,7 +216,7 @@ bool HEFont::renderString(int imageNum, int imageState, int xPos, int yPos, cons
}
// Draw the string!
- ctx->font->drawString(&surface, string, xPos, yPos, stringWidth, ctx->fgColor, ctx->align);
+ ctx->font->drawString(&surface, string, xPos, yPos, stringWidth, ctx->fgColor, ctx->align, 0, false, true);
return true;
}
More information about the Scummvm-git-logs
mailing list