[Scummvm-git-logs] scummvm master -> 312fe24ecc86cdc759f1ae3e13c03cb288cf8325
bluegr
noreply at scummvm.org
Fri Nov 14 09:47:24 UTC 2025
This automated email contains information about 10 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
0442ca3038 VIDEO: Various fixes and cleanups for Subtitles
3a3ff2c8ed VIDEO: Use integer constants for font styles
c46252ddb9 VIDEO: Store the Surface inside the Subtitles class
76ff394365 VIDEO: Clip the subtitles drawing rectangle to avoid overdraw
b892897270 PRIVATE: Hide the overlay when subtitle is done
00c0100cf4 PRIVATE: Fix dev mode subtitle rendering
55b4236d8e PRIVATE: Fix memory leak at engine close
7a55588e6e VIDEO: Fix subtitles word wrapping
c8b5a760f3 GRAPHICS: Add a FontManager helper letting delete an unmanaged Font
312fe24ecc VIDEO: Free the fonts when destroying the Subtitles and changing fonts
Commit: 0442ca3038ed39d891a6eae8764a71f3592f6821
https://github.com/scummvm/scummvm/commit/0442ca3038ed39d891a6eae8764a71f3592f6821
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2025-11-14T11:47:16+02:00
Commit Message:
VIDEO: Various fixes and cleanups for Subtitles
- Avoid copying SRT parts, load them in place instead
- Remove getSubtitle function which is useless
- Put back drawSubtitle as a const function
- Repair subtitle dev mode
- Don't compute aggregated subtitle text if it's not needed
Changed paths:
video/subtitles.cpp
video/subtitles.h
diff --git a/video/subtitles.cpp b/video/subtitles.cpp
index 116f8b4b43a..892e2451497 100644
--- a/video/subtitles.cpp
+++ b/video/subtitles.cpp
@@ -253,9 +253,9 @@ bool SRTParser::parseFile(const Common::Path &fname) {
break;
}
- Common::Array<SubtitlePart> parts;
- parseTextAndTags(text, parts);
- _entries.push_back(new SRTEntry(seq, start, end, parts));
+ SRTEntry *entry = new SRTEntry(seq, start, end);
+ parseTextAndTags(text, entry->parts);
+ _entries.push_back(entry);
}
qsort(_entries.data(), _entries.size(), sizeof(SRTEntry *), &SRTEntryComparator);
@@ -277,18 +277,6 @@ const Common::Array<SubtitlePart> *SRTParser::getSubtitleParts(uint32 timestamp)
return &(*entry)->parts;
}
-Common::String SRTParser::getSubtitle(uint32 timestamp) const {
- const Common::Array<SubtitlePart> *parts = getSubtitleParts(timestamp);
- if (!parts)
- return "";
-
- Common::String subtitle;
- for (const auto &part : *parts) {
- subtitle += part.text;
- }
- return subtitle;
-}
-
#define SHADOW 1
Subtitles::Subtitles() : _loaded(false), _hPad(0), _vPad(0), _overlayHasAlpha(true),
@@ -366,19 +354,19 @@ void Subtitles::setPadding(uint16 horizontal, uint16 vertical) {
_vPad = vertical;
}
-bool Subtitles::drawSubtitle(uint32 timestamp, bool force, bool showSFX) {
- const Common::Array<SubtitlePart> *parts = nullptr;
+bool Subtitles::drawSubtitle(uint32 timestamp, bool force, bool showSFX) const {
+ const Common::Array<SubtitlePart> *parts;
+ bool isSFX = false;
if (_loaded) {
parts = _srtParser.getSubtitleParts(timestamp);
- }
-
- Common::String subtitle;
- if (parts) {
- for (const auto &part : *parts) {
- subtitle += part.text;
+ if (parts && !parts->empty()) {
+ isSFX = (*parts)[0].tag != "sfx";
}
} else if (_subtitleDev) {
- subtitle = _fname.toString('/');
+ // Force refresh
+ _parts = nullptr;
+
+ Common::String subtitle = _fname.toString('/');
uint32 hours, mins, secs, msecs;
secs = timestamp / 1000;
hours = secs / 3600;
@@ -386,6 +374,13 @@ bool Subtitles::drawSubtitle(uint32 timestamp, bool force, bool showSFX) {
secs %= 60;
msecs = timestamp % 1000;
subtitle += " " + Common::String::format("%02u:%02u:%02u,%03u", hours, mins, secs, msecs);
+
+ if (_devParts.empty()) {
+ _devParts.push_back(SubtitlePart("", ""));
+ }
+ _devParts[0].text = subtitle;
+
+ parts = &_devParts;
} else {
return false;
}
@@ -424,16 +419,23 @@ bool Subtitles::drawSubtitle(uint32 timestamp, bool force, bool showSFX) {
force = true;
}
- if (!force && _overlayHasAlpha && subtitle == _subtitle)
+ if (!force && _overlayHasAlpha && parts == _parts)
return false;
- if (force || subtitle != _subtitle) {
- debug(1, "%d: %s", timestamp, subtitle.c_str());
+ if (force || parts != _parts) {
+ if (debugLevelSet(1)) {
+ Common::String subtitle;
+ if (parts) {
+ for (const auto &part : *parts) {
+ subtitle += part.text;
+ }
+ }
+ debug(1, "%d: %s", timestamp, subtitle.c_str());
+ }
- _subtitle = subtitle;
_parts = parts;
- if ((!parts || parts->empty() || (*parts)[0].tag != "sfx") || showSFX)
+ if (!isSFX || showSFX)
renderSubtitle();
}
diff --git a/video/subtitles.h b/video/subtitles.h
index ad771ab25cf..e66f088c94e 100644
--- a/video/subtitles.h
+++ b/video/subtitles.h
@@ -48,8 +48,8 @@ struct SRTEntry {
Common::Array<SubtitlePart> parts;
- SRTEntry(uint seq_, uint32 start_, uint32 end_, const Common::Array<SubtitlePart> &parts_) {
- seq = seq_; start = start_; end = end_; parts = parts_;
+ SRTEntry(uint seq_, uint32 start_, uint32 end_) {
+ seq = seq_; start = start_; end = end_;
}
// Dummy constructor for bsearch
@@ -68,7 +68,6 @@ public:
bool parseFile(const Common::Path &fname);
void parseTextAndTags(const Common::String &text, Common::Array<SubtitlePart> &parts) const;
const Common::Array<SubtitlePart> *getSubtitleParts(uint32 timestamp) const;
- Common::String getSubtitle(uint32 timestamp) const;
private:
Common::Array<SRTEntry *> _entries;
@@ -80,12 +79,12 @@ public:
~Subtitles();
void loadSRTFile(const Common::Path &fname);
- void close() { _loaded = false; _subtitle.clear(); _fname.clear(); _srtParser.cleanup(); }
+ void close() { _loaded = false; _parts = nullptr; _fname.clear(); _srtParser.cleanup(); }
void setFont(const char *fontname, int height = 18, Common::String type = "regular");
void setBBox(const Common::Rect &bbox);
void setColor(byte r, byte g, byte b);
void setPadding(uint16 horizontal, uint16 vertical);
- bool drawSubtitle(uint32 timestamp, bool force = false, bool showSFX = false);
+ bool drawSubtitle(uint32 timestamp, bool force = false, bool showSFX = false) const;
bool isLoaded() const { return _loaded || _subtitleDev; }
private:
@@ -96,6 +95,8 @@ private:
bool _subtitleDev;
bool _overlayHasAlpha;
+ mutable Common::Array<SubtitlePart> _devParts;
+
Common::HashMap<Common::String, const Graphics::Font *> _fonts;
int _fontHeight;
@@ -107,7 +108,6 @@ private:
mutable int16 _lastOverlayWidth, _lastOverlayHeight;
Common::Path _fname;
- mutable Common::String _subtitle;
mutable const Common::Array<SubtitlePart> *_parts;
uint32 _color;
uint32 _blackColor;
Commit: 3a3ff2c8ed90ce747a888b419f90ad5baed74b97
https://github.com/scummvm/scummvm/commit/3a3ff2c8ed90ce747a888b419f90ad5baed74b97
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2025-11-14T11:47:16+02:00
Commit Message:
VIDEO: Use integer constants for font styles
This avoids matching with strings when there is no need.
Changed paths:
engines/hypno/hypno.cpp
engines/private/private.cpp
video/subtitles.cpp
video/subtitles.h
diff --git a/engines/hypno/hypno.cpp b/engines/hypno/hypno.cpp
index 0eb33bde496..f33adab007f 100644
--- a/engines/hypno/hypno.cpp
+++ b/engines/hypno/hypno.cpp
@@ -571,8 +571,8 @@ void HypnoEngine::adjustSubtitleSize() {
_subtitles->setBBox(Common::Rect(20, h - 160 * scale, w - 20, h - 20));
int fontSize = MAX(8, int(50 * scale));
_subtitles->setColor(0xff, 0xff, 0x80);
- _subtitles->setFont("NotoSerif-Regular.ttf", fontSize, "regular");
- _subtitles->setFont("NotoSerif-Italic.ttf", fontSize, "italic");
+ _subtitles->setFont("NotoSerif-Regular.ttf", fontSize, Video::Subtitles::kFontStyleRegular);
+ _subtitles->setFont("NotoSerif-Italic.ttf", fontSize, Video::Subtitles::kFontStyleItalic);
}
}
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index 25928fde118..bf9f5638110 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -1639,8 +1639,8 @@ void PrivateEngine::adjustSubtitleSize() {
}
int fontSize = MAX(8, int(50 * scale));
_subtitles->setColor(0xff, 0xff, 0x80);
- _subtitles->setFont("LiberationSans-Regular.ttf", fontSize, "regular");
- _subtitles->setFont("LiberationSans-Italic.ttf", fontSize, "italic");
+ _subtitles->setFont("LiberationSans-Regular.ttf", fontSize, Video::Subtitles::kFontStyleRegular);
+ _subtitles->setFont("LiberationSans-Italic.ttf", fontSize, Video::Subtitles::kFontStyleItalic);
}
}
diff --git a/video/subtitles.cpp b/video/subtitles.cpp
index 892e2451497..62d5e5ba7eb 100644
--- a/video/subtitles.cpp
+++ b/video/subtitles.cpp
@@ -289,7 +289,7 @@ Subtitles::~Subtitles() {
delete _surface;
}
-void Subtitles::setFont(const char *fontname, int height, Common::String type) {
+void Subtitles::setFont(const char *fontname, int height, FontStyle type) {
_fontHeight = height;
#ifdef USE_FREETYPE2
@@ -320,7 +320,6 @@ void Subtitles::setFont(const char *fontname, int height, Common::String type) {
_fonts[type] = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
}
-
}
void Subtitles::loadSRTFile(const Common::Path &fname) {
@@ -470,8 +469,8 @@ void Subtitles::renderSubtitle() const {
int currentLineWidth = 0;
for (const auto &part : *_parts) {
- const Graphics::Font *font = _fonts[part.tag == "i" ? "italic" : "regular"];
- if (!font) font = _fonts["regular"];
+ const Graphics::Font *font = _fonts[part.tag == "i" ? kFontStyleItalic : kFontStyleRegular];
+ if (!font) font = _fonts[kFontStyleRegular];
Common::U32String u32_text(part.text);
int partWidth = font->getStringWidth(u32_text);
@@ -490,8 +489,8 @@ void Subtitles::renderSubtitle() const {
for (const auto &line : lines) {
int lineWidth = 0;
for (const auto &part : line) {
- const Graphics::Font *font = _fonts[part.tag == "i" ? "italic" : "regular"];
- if (!font) font = _fonts["regular"];
+ const Graphics::Font *font = _fonts[part.tag == "i" ? kFontStyleItalic : kFontStyleRegular];
+ if (!font) font = _fonts[kFontStyleRegular];
lineWidth += font->getStringWidth(convertUtf8ToUtf32(part.text));
}
totalWidth = MAX(totalWidth, lineWidth);
@@ -501,8 +500,8 @@ void Subtitles::renderSubtitle() const {
for (const auto &line : lines) {
int lineWidth = 0;
for (const auto &part : line) {
- const Graphics::Font *font = _fonts[part.tag == "i" ? "italic" : "regular"];
- if (!font) font = _fonts["regular"];
+ const Graphics::Font *font = _fonts[part.tag == "i" ? kFontStyleItalic : kFontStyleRegular];
+ if (!font) font = _fonts[kFontStyleRegular];
lineWidth += font->getStringWidth(convertUtf8ToUtf32(part.text));
}
@@ -510,8 +509,9 @@ void Subtitles::renderSubtitle() const {
int currentX = originX;
for (const auto &part : line) {
- Common::String fontType = part.tag == "i" ? "italic" : "regular";
- const Graphics::Font *font = _fonts[fontType] ? _fonts[fontType] : _fonts["regular"];
+ FontStyle fontType = part.tag == "i" ? kFontStyleItalic : kFontStyleRegular;
+ const Graphics::Font *font = _fonts[fontType];
+ if (!font) font = _fonts[kFontStyleRegular];
Common::U32String u32_text = convertBiDiU32String(Common::U32String(part.text)).visual;
int partWidth = font->getStringWidth(u32_text);
@@ -523,7 +523,7 @@ void Subtitles::renderSubtitle() const {
currentX += partWidth;
}
- height += _fonts["regular"]->getFontHeight();
+ height += _fonts[kFontStyleRegular]->getFontHeight();
if (height + _vPad > _realBBox.bottom)
break;
}
diff --git a/video/subtitles.h b/video/subtitles.h
index e66f088c94e..ffe9fe15321 100644
--- a/video/subtitles.h
+++ b/video/subtitles.h
@@ -75,12 +75,17 @@ private:
class Subtitles {
public:
+ enum FontStyle : int {
+ kFontStyleRegular = 0,
+ kFontStyleItalic,
+ };
+
Subtitles();
~Subtitles();
void loadSRTFile(const Common::Path &fname);
void close() { _loaded = false; _parts = nullptr; _fname.clear(); _srtParser.cleanup(); }
- void setFont(const char *fontname, int height = 18, Common::String type = "regular");
+ void setFont(const char *fontname, int height = 18, FontStyle type = kFontStyleRegular);
void setBBox(const Common::Rect &bbox);
void setColor(byte r, byte g, byte b);
void setPadding(uint16 horizontal, uint16 vertical);
@@ -97,7 +102,7 @@ private:
mutable Common::Array<SubtitlePart> _devParts;
- Common::HashMap<Common::String, const Graphics::Font *> _fonts;
+ Common::HashMap<int, const Graphics::Font *> _fonts;
int _fontHeight;
Graphics::Surface *_surface;
Commit: c46252ddb936dc7d0f9c0fae97711eee58b6ca0e
https://github.com/scummvm/scummvm/commit/c46252ddb936dc7d0f9c0fae97711eee58b6ca0e
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2025-11-14T11:47:16+02:00
Commit Message:
VIDEO: Store the Surface inside the Subtitles class
Using a pointer is useless as the surface object is allocated once in the
constructor.
The Surface data is still allocated as needed and is freed in the
destructor.
This fixes a memory leak on the Surface data.
Changed paths:
video/subtitles.cpp
video/subtitles.h
diff --git a/video/subtitles.cpp b/video/subtitles.cpp
index 62d5e5ba7eb..7f7a38121c2 100644
--- a/video/subtitles.cpp
+++ b/video/subtitles.cpp
@@ -281,12 +281,11 @@ const Common::Array<SubtitlePart> *SRTParser::getSubtitleParts(uint32 timestamp)
Subtitles::Subtitles() : _loaded(false), _hPad(0), _vPad(0), _overlayHasAlpha(true),
_lastOverlayWidth(-1), _lastOverlayHeight(-1) {
- _surface = new Graphics::Surface();
_subtitleDev = ConfMan.getBool("subtitle_dev");
}
Subtitles::~Subtitles() {
- delete _surface;
+ _surface.free();
}
void Subtitles::setFont(const char *fontname, int height, FontStyle type) {
@@ -336,16 +335,16 @@ void Subtitles::setBBox(const Common::Rect &bbox) {
Graphics::PixelFormat overlayFormat = g_system->getOverlayFormat();
_overlayHasAlpha = overlayFormat.aBits() != 0;
- _surface->create(_requestedBBox.width() + SHADOW * 2, _requestedBBox.height() + SHADOW * 2, overlayFormat);
+ _surface.create(_requestedBBox.width() + SHADOW * 2, _requestedBBox.height() + SHADOW * 2, overlayFormat);
// Force recalculation of real bounding box
_lastOverlayWidth = -1;
_lastOverlayHeight = -1;
}
void Subtitles::setColor(byte r, byte g, byte b) {
- _color = _surface->format.ARGBToColor(255, r, g, b);
- _blackColor = _surface->format.ARGBToColor(255, 0, 0, 0);
- _transparentColor = _surface->format.ARGBToColor(0, 0, 0, 0);
+ _color = _surface.format.ARGBToColor(255, r, g, b);
+ _blackColor = _surface.format.ARGBToColor(255, 0, 0, 0);
+ _transparentColor = _surface.format.ARGBToColor(0, 0, 0, 0);
}
void Subtitles::setPadding(uint16 horizontal, uint16 vertical) {
@@ -440,13 +439,13 @@ bool Subtitles::drawSubtitle(uint32 timestamp, bool force, bool showSFX) const {
if (_overlayHasAlpha) {
// When we have alpha, draw the whole surface without thinking it more
- g_system->copyRectToOverlay(_surface->getPixels(), _surface->pitch, _realBBox.left, _realBBox.top, _realBBox.width(), _realBBox.height());
+ g_system->copyRectToOverlay(_surface.getPixels(), _surface.pitch, _realBBox.left, _realBBox.top, _realBBox.width(), _realBBox.height());
} else {
// When overlay doesn't have alpha, showing it hides the underlying game screen
// We force a copy of the game screen to the overlay by clearing it
// We then draw the smallest possible surface to minimize black rectangle behind text
g_system->clearOverlay();
- g_system->copyRectToOverlay((byte *)_surface->getPixels() + _drawRect.top * _surface->pitch + _drawRect.left * _surface->format.bytesPerPixel, _surface->pitch,
+ g_system->copyRectToOverlay((byte *)_surface.getPixels() + _drawRect.top * _surface.pitch + _drawRect.left * _surface.format.bytesPerPixel, _surface.pitch,
_realBBox.left + _drawRect.left, _realBBox.top + _drawRect.top, _drawRect.width(), _drawRect.height());
}
@@ -454,7 +453,7 @@ bool Subtitles::drawSubtitle(uint32 timestamp, bool force, bool showSFX) const {
}
void Subtitles::renderSubtitle() const {
- _surface->fillRect(Common::Rect(0, 0, _surface->w, _surface->h), _transparentColor);
+ _surface.fillRect(Common::Rect(0, 0, _surface.w, _surface.h), _transparentColor);
if (!_parts || _parts->empty()) {
_drawRect.left = 0;
@@ -515,11 +514,11 @@ void Subtitles::renderSubtitle() const {
Common::U32String u32_text = convertBiDiU32String(Common::U32String(part.text)).visual;
int partWidth = font->getStringWidth(u32_text);
- font->drawString(_surface, u32_text, currentX, height, partWidth, _blackColor, Graphics::kTextAlignLeft);
- font->drawString(_surface, u32_text, currentX + SHADOW * 2, height, partWidth, _blackColor, Graphics::kTextAlignLeft);
- font->drawString(_surface, u32_text, currentX, height + SHADOW * 2, partWidth, _blackColor, Graphics::kTextAlignLeft);
- font->drawString(_surface, u32_text, currentX + SHADOW * 2, height + SHADOW * 2, partWidth, _blackColor, Graphics::kTextAlignLeft);
- font->drawString(_surface, u32_text, currentX + SHADOW, height + SHADOW, partWidth, _color, Graphics::kTextAlignLeft);
+ font->drawString(&_surface, u32_text, currentX, height, partWidth, _blackColor, Graphics::kTextAlignLeft);
+ font->drawString(&_surface, u32_text, currentX + SHADOW * 2, height, partWidth, _blackColor, Graphics::kTextAlignLeft);
+ font->drawString(&_surface, u32_text, currentX, height + SHADOW * 2, partWidth, _blackColor, Graphics::kTextAlignLeft);
+ font->drawString(&_surface, u32_text, currentX + SHADOW * 2, height + SHADOW * 2, partWidth, _blackColor, Graphics::kTextAlignLeft);
+ font->drawString(&_surface, u32_text, currentX + SHADOW, height + SHADOW, partWidth, _color, Graphics::kTextAlignLeft);
currentX += partWidth;
}
diff --git a/video/subtitles.h b/video/subtitles.h
index ffe9fe15321..23c86abc1be 100644
--- a/video/subtitles.h
+++ b/video/subtitles.h
@@ -27,9 +27,10 @@
#include "common/hashmap.h"
#include "common/rect.h"
+#include "graphics/surface.h"
+
namespace Graphics {
class Font;
-struct Surface;
}
namespace Video {
@@ -105,7 +106,7 @@ private:
Common::HashMap<int, const Graphics::Font *> _fonts;
int _fontHeight;
- Graphics::Surface *_surface;
+ mutable Graphics::Surface _surface;
mutable Common::Rect _drawRect;
Common::Rect _requestedBBox;
Commit: 76ff3943656f89fda22fc25871d860b569647a1d
https://github.com/scummvm/scummvm/commit/76ff3943656f89fda22fc25871d860b569647a1d
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2025-11-14T11:47:16+02:00
Commit Message:
VIDEO: Clip the subtitles drawing rectangle to avoid overdraw
If the drawRect is bigger (read taller in height), in Surface SDL mode,
there is an overflow when copying the data.
Changed paths:
video/subtitles.cpp
diff --git a/video/subtitles.cpp b/video/subtitles.cpp
index 7f7a38121c2..26c4af50f14 100644
--- a/video/subtitles.cpp
+++ b/video/subtitles.cpp
@@ -533,6 +533,7 @@ void Subtitles::renderSubtitle() const {
_drawRect.top = 0;
_drawRect.setWidth(totalWidth + SHADOW * 2);
_drawRect.setHeight(height + SHADOW * 2);
+ _drawRect.clip(_realBBox.width(), _realBBox.height());
}
} // End of namespace Video
Commit: b8928972708e1f22745f6d30cc21b09ea8bffc57
https://github.com/scummvm/scummvm/commit/b8928972708e1f22745f6d30cc21b09ea8bffc57
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2025-11-14T11:47:16+02:00
Commit Message:
PRIVATE: Hide the overlay when subtitle is done
clearOverlay only clears the screen.
Changed paths:
engines/private/private.cpp
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index bf9f5638110..470882c0454 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -440,7 +440,7 @@ Common::Error PrivateEngine::run() {
if (_subtitles != nullptr) {
delete _subtitles;
_subtitles = nullptr;
- g_system->clearOverlay();
+ g_system->hideOverlay();
}
_currentMovie = "";
} else if (!_videoDecoder->needsUpdate() && mouseMoved) {
@@ -480,7 +480,7 @@ Common::Error PrivateEngine::run() {
} else {
delete _subtitles;
_subtitles = nullptr;
- g_system->clearOverlay();
+ g_system->hideOverlay();
}
}
}
@@ -1668,7 +1668,7 @@ void PrivateEngine::loadSubtitles(const Common::Path &path) {
} else if (_subtitles != nullptr) {
delete _subtitles;
_subtitles = nullptr;
- g_system->clearOverlay();
+ g_system->hideOverlay();
}
}
void PrivateEngine::playVideo(const Common::String &name) {
@@ -1750,7 +1750,7 @@ void PrivateEngine::skipVideo() {
if (_subtitles != nullptr) {
delete _subtitles;
_subtitles = nullptr;
- g_system->clearOverlay();
+ g_system->hideOverlay();
}
_currentMovie = "";
}
Commit: 00c0100cf47bfefe104a95de6eae6072738131d1
https://github.com/scummvm/scummvm/commit/00c0100cf47bfefe104a95de6eae6072738131d1
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2025-11-14T11:47:16+02:00
Commit Message:
PRIVATE: Fix dev mode subtitle rendering
Changed paths:
engines/private/private.cpp
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index 470882c0454..7f14efc2626 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -1660,16 +1660,24 @@ void PrivateEngine::loadSubtitles(const Common::Path &path) {
subPath = subPath.appendComponent(language);
subPath = subPath.appendComponent(subPathStr);
debugC(1, kPrivateDebugFunction, "Loading subtitles from %s", subPath.toString().c_str());
- if (Common::File::exists(subPath)) {
- _subtitles = new Video::Subtitles();
- _subtitles->loadSRTFile(subPath);
- g_system->showOverlay(false);
- adjustSubtitleSize();
- } else if (_subtitles != nullptr) {
+
+ if (_subtitles != nullptr) {
delete _subtitles;
_subtitles = nullptr;
g_system->hideOverlay();
}
+
+ _subtitles = new Video::Subtitles();
+ _subtitles->loadSRTFile(subPath);
+ if (!_subtitles->isLoaded()) {
+ delete _subtitles;
+ _subtitles = nullptr;
+ return;
+ }
+
+ g_system->showOverlay(false);
+ g_system->clearOverlay();
+ adjustSubtitleSize();
}
void PrivateEngine::playVideo(const Common::String &name) {
debugC(1, kPrivateDebugFunction, "%s(%s)", __FUNCTION__, name.c_str());
Commit: 55b4236d8ef5bad275d005e4dd43c23c96950554
https://github.com/scummvm/scummvm/commit/55b4236d8ef5bad275d005e4dd43c23c96950554
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2025-11-14T11:47:16+02:00
Commit Message:
PRIVATE: Fix memory leak at engine close
Changed paths:
engines/private/private.cpp
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index 7f14efc2626..25f536aab6d 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -1770,6 +1770,11 @@ void PrivateEngine::destroyVideo() {
delete _videoDecoder;
_videoDecoder = nullptr;
_pausedVideo = nullptr;
+ if (_subtitles != nullptr) {
+ delete _subtitles;
+ _subtitles = nullptr;
+ g_system->hideOverlay();
+ }
}
void PrivateEngine::stopSound(bool all) {
Commit: 7a55588e6ec5bdf5a43388c6dc665a04dd20106e
https://github.com/scummvm/scummvm/commit/7a55588e6ec5bdf5a43388c6dc665a04dd20106e
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2025-11-14T11:47:16+02:00
Commit Message:
VIDEO: Fix subtitles word wrapping
Changed paths:
video/subtitles.cpp
diff --git a/video/subtitles.cpp b/video/subtitles.cpp
index 26c4af50f14..98a6439a1de 100644
--- a/video/subtitles.cpp
+++ b/video/subtitles.cpp
@@ -51,7 +51,6 @@ void SRTParser::cleanup() {
void SRTParser::parseTextAndTags(const Common::String &text, Common::Array<SubtitlePart> &parts) const {
Common::String currentText = text;
- currentText.replace('\n', ' ');
while (true) {
Common::String::size_type pos_i_start = currentText.find("<i>");
@@ -358,7 +357,7 @@ bool Subtitles::drawSubtitle(uint32 timestamp, bool force, bool showSFX) const {
if (_loaded) {
parts = _srtParser.getSubtitleParts(timestamp);
if (parts && !parts->empty()) {
- isSFX = (*parts)[0].tag != "sfx";
+ isSFX = (*parts)[0].tag == "sfx";
}
} else if (_subtitleDev) {
// Force refresh
@@ -452,87 +451,125 @@ bool Subtitles::drawSubtitle(uint32 timestamp, bool force, bool showSFX) const {
return true;
}
+struct SubtitleRenderingPart {
+ Common::U32String text;
+ const Graphics::Font *font;
+ bool newLine;
+ int left;
+ int right;
+};
+
void Subtitles::renderSubtitle() const {
_surface.fillRect(Common::Rect(0, 0, _surface.w, _surface.h), _transparentColor);
if (!_parts || _parts->empty()) {
- _drawRect.left = 0;
- _drawRect.top = 0;
- _drawRect.right = 0;
- _drawRect.bottom = 0;
+ _drawRect.setEmpty();
return;
}
- Common::Array<Common::Array<SubtitlePart>> lines;
- lines.push_back(Common::Array<SubtitlePart>());
+ Common::Array<SubtitleRenderingPart> splitParts;
- int currentLineWidth = 0;
+ // First, calculate all positions as if we were left aligned
+ bool newLine = true;
+ int currentX = 0;
for (const auto &part : *_parts) {
const Graphics::Font *font = _fonts[part.tag == "i" ? kFontStyleItalic : kFontStyleRegular];
if (!font) font = _fonts[kFontStyleRegular];
- Common::U32String u32_text(part.text);
- int partWidth = font->getStringWidth(u32_text);
+ Common::Array<Common::U32String> lines;
+
+ font->wordWrapText(part.text.decode(Common::kUtf8), _realBBox.width(), lines, currentX);
- if (currentLineWidth + partWidth > _realBBox.width()) {
- lines.push_back(Common::Array<SubtitlePart>());
- currentLineWidth = 0;
+ if (lines.empty()) {
+ continue;
+ }
+ splitParts.reserve(splitParts.size() + lines.size());
+
+ int width = 0;
+ for (auto line = lines.begin(); line != lines.end() - 1; line++) {
+ width = font->getStringWidth(*line);
+ splitParts.emplace_back(SubtitleRenderingPart{*line, font, newLine, currentX, currentX + width});
+ newLine = true;
+ currentX = 0;
+ }
+ width = font->getStringWidth(lines.back());
+ splitParts.emplace_back(SubtitleRenderingPart{lines.back(), font, newLine, currentX, currentX + width});
+ newLine = false;
+ currentX += width;
+
+ // Last newline doesn't trigger an empty line in wordWrapText
+ if (part.text.hasSuffix("\n")) {
+ newLine = true;
+ currentX = 0;
}
- lines.back().push_back(part);
- currentLineWidth += partWidth;
}
- int height = _vPad;
- int totalWidth = 0;
+ // Then, center all lines and calculate the drawing box
+ auto lineBegin = splitParts.begin();
+ int minX = _realBBox.width();
+ int maxWidth = 0;
- for (const auto &line : lines) {
- int lineWidth = 0;
- for (const auto &part : line) {
- const Graphics::Font *font = _fonts[part.tag == "i" ? kFontStyleItalic : kFontStyleRegular];
- if (!font) font = _fonts[kFontStyleRegular];
- lineWidth += font->getStringWidth(convertUtf8ToUtf32(part.text));
+ for (auto splitPart = splitParts.begin() + 1; splitPart != splitParts.end(); splitPart++) {
+ if (!splitPart->newLine) {
+ continue;
}
- totalWidth = MAX(totalWidth, lineWidth);
+ int width = MIN(splitPart[-1].right + 2 * _hPad, (int)_realBBox.width());
+ int origin = (_realBBox.width() - width) / 2;
+ minX = MIN(minX, origin);
+ maxWidth = MAX(maxWidth, width);
+
+ for(auto part = lineBegin; part != splitPart; part++) {
+ part->left += origin;
+ part->right += origin;
+ }
+
+ lineBegin = splitPart;
}
- totalWidth = MIN(totalWidth + 2 * _hPad, (int)_realBBox.width());
-
- for (const auto &line : lines) {
- int lineWidth = 0;
- for (const auto &part : line) {
- const Graphics::Font *font = _fonts[part.tag == "i" ? kFontStyleItalic : kFontStyleRegular];
- if (!font) font = _fonts[kFontStyleRegular];
- lineWidth += font->getStringWidth(convertUtf8ToUtf32(part.text));
+ if (lineBegin != splitParts.end()) {
+ int width = MIN(splitParts.back().right + 2 * _hPad, (int)_realBBox.width());
+ int origin = (_realBBox.width() - width) / 2;
+ minX = MIN(minX, origin);
+ maxWidth = MAX(maxWidth, width);
+
+ for(auto part = lineBegin; part != splitParts.end(); part++) {
+ part->left += origin;
+ part->right += origin;
}
+ }
- int originX = (_realBBox.width() - lineWidth) / 2;
- int currentX = originX;
+ // Finally, render every part on the surface
+ int currentY = _vPad;
+ int lineHeight = 0;
+ for (const auto &part : splitParts) {
+ const Graphics::Font *font = part.font;
+ int partWidth = part.right - part.left;
+
+ if (part.newLine) {
+ currentY += lineHeight;
+ if (currentY + _vPad > _realBBox.bottom) {
+ lineHeight = 0;
+ break;
+ }
+
+ lineHeight = font->getFontHeight();
+ }
- for (const auto &part : line) {
- FontStyle fontType = part.tag == "i" ? kFontStyleItalic : kFontStyleRegular;
- const Graphics::Font *font = _fonts[fontType];
- if (!font) font = _fonts[kFontStyleRegular];
- Common::U32String u32_text = convertBiDiU32String(Common::U32String(part.text)).visual;
- int partWidth = font->getStringWidth(u32_text);
+ Common::U32String u32_text = convertBiDiU32String(part.text).visual;
- font->drawString(&_surface, u32_text, currentX, height, partWidth, _blackColor, Graphics::kTextAlignLeft);
- font->drawString(&_surface, u32_text, currentX + SHADOW * 2, height, partWidth, _blackColor, Graphics::kTextAlignLeft);
- font->drawString(&_surface, u32_text, currentX, height + SHADOW * 2, partWidth, _blackColor, Graphics::kTextAlignLeft);
- font->drawString(&_surface, u32_text, currentX + SHADOW * 2, height + SHADOW * 2, partWidth, _blackColor, Graphics::kTextAlignLeft);
- font->drawString(&_surface, u32_text, currentX + SHADOW, height + SHADOW, partWidth, _color, Graphics::kTextAlignLeft);
+ font->drawString(&_surface, u32_text, part.left, currentY, partWidth, _blackColor, Graphics::kTextAlignLeft);
+ font->drawString(&_surface, u32_text, part.left + SHADOW * 2, currentY, partWidth, _blackColor, Graphics::kTextAlignLeft);
+ font->drawString(&_surface, u32_text, part.left, currentY + SHADOW * 2, partWidth, _blackColor, Graphics::kTextAlignLeft);
+ font->drawString(&_surface, u32_text, part.left + SHADOW * 2, currentY + SHADOW * 2, partWidth, _blackColor, Graphics::kTextAlignLeft);
+ font->drawString(&_surface, u32_text, part.left + SHADOW, currentY + SHADOW, partWidth, _color, Graphics::kTextAlignLeft);
- currentX += partWidth;
- }
- height += _fonts[kFontStyleRegular]->getFontHeight();
- if (height + _vPad > _realBBox.bottom)
- break;
}
- height += _vPad;
+ currentY += lineHeight + _vPad;
- _drawRect.left = (_realBBox.width() - totalWidth) / 2;
+ _drawRect.left = minX;
_drawRect.top = 0;
- _drawRect.setWidth(totalWidth + SHADOW * 2);
- _drawRect.setHeight(height + SHADOW * 2);
+ _drawRect.setWidth(maxWidth + SHADOW * 2);
+ _drawRect.setHeight(currentY + SHADOW * 2);
_drawRect.clip(_realBBox.width(), _realBBox.height());
}
Commit: c8b5a760f3fb8ed968999e4ce4984400056d65ad
https://github.com/scummvm/scummvm/commit/c8b5a760f3fb8ed968999e4ce4984400056d65ad
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2025-11-14T11:47:16+02:00
Commit Message:
GRAPHICS: Add a FontManager helper letting delete an unmanaged Font
If the Font is alocated by FontMan, it must not be deallocated.
Changed paths:
graphics/fontman.cpp
graphics/fontman.h
diff --git a/graphics/fontman.cpp b/graphics/fontman.cpp
index f89aaee68ad..154409eb1d5 100644
--- a/graphics/fontman.cpp
+++ b/graphics/fontman.cpp
@@ -186,4 +186,18 @@ const Font *FontManager::getFontByUsage(FontUsage usage) const {
return 0;
}
+void FontManager::mayDeleteFont(const Font *font) const {
+ if (font == nullptr)
+ return;
+
+ if (font == g_sysfont || font == g_sysfont_big || font == g_consolefont)
+ return;
+
+ if (Common::find(_ownedFonts.begin(), _ownedFonts.end(), font) != _ownedFonts.end())
+ return;
+
+ // Then we can assume it's not const
+ delete const_cast<Font *>(font);
+}
+
} // End of namespace Graphics
diff --git a/graphics/fontman.h b/graphics/fontman.h
index 48bd039ea9a..6acf7454d14 100644
--- a/graphics/fontman.h
+++ b/graphics/fontman.h
@@ -106,6 +106,14 @@ public:
//const Font *getFontBySize(int size???) const;
+ /**
+ * Delete the font if it's not one in use by the FontManager
+ * This may be used when mixing directly loaded fonts and FontManager ones.
+ *
+ * @param font the font object to delete
+ */
+ void mayDeleteFont(const Font *font) const;
+
private:
friend class Common::Singleton<SingletonBaseType>;
FontManager();
Commit: 312fe24ecc86cdc759f1ae3e13c03cb288cf8325
https://github.com/scummvm/scummvm/commit/312fe24ecc86cdc759f1ae3e13c03cb288cf8325
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2025-11-14T11:47:16+02:00
Commit Message:
VIDEO: Free the fonts when destroying the Subtitles and changing fonts
Changed paths:
video/subtitles.cpp
diff --git a/video/subtitles.cpp b/video/subtitles.cpp
index 98a6439a1de..ab7b85ff29c 100644
--- a/video/subtitles.cpp
+++ b/video/subtitles.cpp
@@ -285,11 +285,19 @@ Subtitles::Subtitles() : _loaded(false), _hPad(0), _vPad(0), _overlayHasAlpha(tr
Subtitles::~Subtitles() {
_surface.free();
+ for (const auto &font : _fonts) {
+ FontMan.mayDeleteFont(font._value);
+ }
}
void Subtitles::setFont(const char *fontname, int height, FontStyle type) {
_fontHeight = height;
+ if (_fonts[type]) {
+ FontMan.mayDeleteFont(_fonts[type]);
+ _fonts[type] = nullptr;
+ }
+
#ifdef USE_FREETYPE2
Graphics::Font *font = nullptr;
Common::File *file = new Common::File();
More information about the Scummvm-git-logs
mailing list