diff --git a/doc/changelog.dox b/doc/changelog.dox index 5a1117840..b8e865e34 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -837,6 +837,8 @@ See also: - Added a @ref Text::GlyphCache::GlyphCache(NoCreateT) and @ref Text::DistanceFieldGlyphCache::DistanceFieldGlyphCache(NoCreateT) constructor allowing to construct the object without a GL context present +- @ref Text::AbstractFont::fillGlyphCache() now returns a @cpp bool @ce to + allow font plugin implementations to gracefully report failures @subsubsection changelog-latest-changes-texturetools TextureTools library diff --git a/src/Magnum/Text/AbstractFont.cpp b/src/Magnum/Text/AbstractFont.cpp index 2017e0614..f25ce80cd 100644 --- a/src/Magnum/Text/AbstractFont.cpp +++ b/src/Magnum/Text/AbstractFont.cpp @@ -272,21 +272,22 @@ Vector2 AbstractFont::glyphAdvance(const UnsignedInt glyph) { return doGlyphAdvance(glyph); } -void AbstractFont::fillGlyphCache(AbstractGlyphCache& cache, const Containers::StringView characters) { +bool AbstractFont::fillGlyphCache(AbstractGlyphCache& cache, const Containers::StringView characters) { CORRADE_ASSERT(isOpened(), - "Text::AbstractFont::fillGlyphCache(): no font opened", ); + "Text::AbstractFont::fillGlyphCache(): no font opened", {}); CORRADE_ASSERT(!(features() & FontFeature::PreparedGlyphCache), - "Text::AbstractFont::fillGlyphCache(): feature not supported", ); + "Text::AbstractFont::fillGlyphCache(): feature not supported", {}); const Containers::Optional> utf32 = Utility::Unicode::utf32(characters); CORRADE_ASSERT(utf32, - "Text::AbstractFont::fillGlyphCache(): not a valid UTF-8 string:" << characters, ); + "Text::AbstractFont::fillGlyphCache(): not a valid UTF-8 string:" << characters, {}); - doFillGlyphCache(cache, *utf32); + return doFillGlyphCache(cache, *utf32); } -void AbstractFont::doFillGlyphCache(AbstractGlyphCache&, Containers::ArrayView) { - CORRADE_ASSERT_UNREACHABLE("Text::AbstractFont::fillGlyphCache(): feature advertised but not implemented", ); +bool AbstractFont::doFillGlyphCache(AbstractGlyphCache&, Containers::ArrayView) { + CORRADE_ASSERT_UNREACHABLE("Text::AbstractFont::fillGlyphCache(): feature advertised but not implemented", {}); + return {}; } Containers::Pointer AbstractFont::createGlyphCache() { diff --git a/src/Magnum/Text/AbstractFont.h b/src/Magnum/Text/AbstractFont.h index 941f39467..35699a87a 100644 --- a/src/Magnum/Text/AbstractFont.h +++ b/src/Magnum/Text/AbstractFont.h @@ -501,8 +501,13 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin { * @ref FontFeature::PreparedGlyphCache do not support partial glyph * cache filling, use @ref createGlyphCache() instead. Expects that a * font is opened and @p characters is valid UTF-8. + * + * On success returns @cpp true @ce. On failure, for example if the + * @p cache doesn't have expected format or the @p characters can't + * fit, prints a message to @relativeref{Magnum,Error} and returns + * @cpp false @ce. */ - void fillGlyphCache(AbstractGlyphCache& cache, Containers::StringView characters); + bool fillGlyphCache(AbstractGlyphCache& cache, Containers::StringView characters); /** * @brief Create glyph cache @@ -661,7 +666,7 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin { * The string is converted from UTF-8 to UTF-32, duplicate characters * are *not* removed. */ - virtual void doFillGlyphCache(AbstractGlyphCache& cache, Containers::ArrayView characters); + virtual bool doFillGlyphCache(AbstractGlyphCache& cache, Containers::ArrayView characters); /** @brief Implementation for @ref createGlyphCache() */ virtual Containers::Pointer doCreateGlyphCache(); diff --git a/src/Magnum/Text/Test/AbstractFontTest.cpp b/src/Magnum/Text/Test/AbstractFontTest.cpp index b364a0ca2..578cd8ed8 100644 --- a/src/Magnum/Text/Test/AbstractFontTest.cpp +++ b/src/Magnum/Text/Test/AbstractFontTest.cpp @@ -88,6 +88,7 @@ struct AbstractFontTest: TestSuite::Tester { void glyphSizeAdvanceOutOfRange(); void fillGlyphCache(); + void fillGlyphCacheFailed(); void fillGlyphCacheNotSupported(); void fillGlyphCacheNotImplemented(); void fillGlyphCacheNoFont(); @@ -151,6 +152,7 @@ AbstractFontTest::AbstractFontTest() { &AbstractFontTest::glyphSizeAdvanceOutOfRange, &AbstractFontTest::fillGlyphCache, + &AbstractFontTest::fillGlyphCacheFailed, &AbstractFontTest::fillGlyphCacheNotSupported, &AbstractFontTest::fillGlyphCacheNotImplemented, &AbstractFontTest::fillGlyphCacheNoFont, @@ -929,12 +931,13 @@ void AbstractFontTest::fillGlyphCache() { Vector2 doGlyphAdvance(UnsignedInt) override { return {}; } Containers::Pointer doCreateShaper() override { return {}; } - void doFillGlyphCache(AbstractGlyphCache& cache, Containers::ArrayView characters) override { + bool doFillGlyphCache(AbstractGlyphCache& cache, Containers::ArrayView characters) override { CORRADE_COMPARE(cache.size(), (Vector3i{100, 100, 1})); CORRADE_COMPARE_AS(characters, Containers::arrayView({ 'h', 'e', 'l', 'o' }), TestSuite::Compare::Container); called = true; + return true; } bool called = false; @@ -945,10 +948,36 @@ void AbstractFontTest::fillGlyphCache() { DummyGlyphCache cache{PixelFormat::R8Unorm, {100, 100}}; - font.fillGlyphCache(cache, "helo"); + CORRADE_VERIFY(font.fillGlyphCache(cache, "helo")); CORRADE_VERIFY(font.called); } +void AbstractFontTest::fillGlyphCacheFailed() { + struct MyFont: AbstractFont { + FontFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doGlyphId(char32_t) override { return {}; } + Vector2 doGlyphSize(UnsignedInt) override { return {}; } + Vector2 doGlyphAdvance(UnsignedInt) override { return {}; } + Containers::Pointer doCreateShaper() override { return {}; } + + bool doFillGlyphCache(AbstractGlyphCache&, Containers::ArrayView) override { + return false; + } + + bool called = false; + } font; + + /* Capture correct function name */ + CORRADE_VERIFY(true); + + DummyGlyphCache cache{PixelFormat::R8Unorm, {100, 100}}; + + CORRADE_VERIFY(!font.fillGlyphCache(cache, "")); +} + void AbstractFontTest::fillGlyphCacheNotSupported() { CORRADE_SKIP_IF_NO_ASSERT();