Browse Source

Text: add AbstractFont::glyphCount().

And check glyph IDs against it in glyphAdvance().
pull/168/head
Vladimír Vondruš 3 years ago
parent
commit
fc46801a7e
  1. 1
      doc/changelog.dox
  2. 8
      src/Magnum/Text/AbstractFont.cpp
  3. 29
      src/Magnum/Text/AbstractFont.h
  4. 67
      src/Magnum/Text/Test/AbstractFontTest.cpp
  5. 2
      src/Magnum/Text/Test/RendererGLTest.cpp
  6. 5
      src/MagnumPlugins/MagnumFont/MagnumFont.cpp
  7. 3
      src/MagnumPlugins/MagnumFont/Test/MagnumFontTest.cpp
  8. 2
      src/MagnumPlugins/MagnumFontConverter/Test/MagnumFontConverterTest.cpp

1
doc/changelog.dox

@ -767,6 +767,7 @@ See also:
@subsubsection changelog-latest-changes-text Text library @subsubsection changelog-latest-changes-text Text library
- Added @ref Text::AbstractFont::glyphCount()
- Added @ref Text::Renderer::fontSize() - Added @ref Text::Renderer::fontSize()
@subsubsection changelog-latest-changes-trade Trade library @subsubsection changelog-latest-changes-trade Trade library

8
src/Magnum/Text/AbstractFont.cpp

@ -114,6 +114,7 @@ bool AbstractFont::openData(Containers::ArrayView<const void> data, const Float
_ascent = properties.ascent; _ascent = properties.ascent;
_descent = properties.descent; _descent = properties.descent;
_lineHeight = properties.lineHeight; _lineHeight = properties.lineHeight;
_glyphCount = properties.glyphCount;
return true; return true;
} }
@ -166,6 +167,7 @@ bool AbstractFont::openFile(const Containers::StringView filename, const Float s
_ascent = properties.ascent; _ascent = properties.ascent;
_descent = properties.descent; _descent = properties.descent;
_lineHeight = properties.lineHeight; _lineHeight = properties.lineHeight;
_glyphCount = properties.glyphCount;
return true; return true;
} }
@ -237,6 +239,11 @@ Float AbstractFont::lineHeight() const {
return _lineHeight; return _lineHeight;
} }
UnsignedInt AbstractFont::glyphCount() const {
CORRADE_ASSERT(isOpened(), "Text::AbstractFont::glyphCount(): no font opened", 0);
return _glyphCount;
}
UnsignedInt AbstractFont::glyphId(const char32_t character) { UnsignedInt AbstractFont::glyphId(const char32_t character) {
CORRADE_ASSERT(isOpened(), "Text::AbstractFont::glyphId(): no font opened", 0); CORRADE_ASSERT(isOpened(), "Text::AbstractFont::glyphId(): no font opened", 0);
@ -245,6 +252,7 @@ UnsignedInt AbstractFont::glyphId(const char32_t character) {
Vector2 AbstractFont::glyphAdvance(const UnsignedInt glyph) { Vector2 AbstractFont::glyphAdvance(const UnsignedInt glyph) {
CORRADE_ASSERT(isOpened(), "Text::AbstractFont::glyphAdvance(): no font opened", {}); CORRADE_ASSERT(isOpened(), "Text::AbstractFont::glyphAdvance(): no font opened", {});
CORRADE_ASSERT(glyph < _glyphCount, "Text::AbstractFont::glyphAdvance(): index" << glyph << "out of range for" << _glyphCount << "glyphs", {});
return doGlyphAdvance(glyph); return doGlyphAdvance(glyph);
} }

29
src/Magnum/Text/AbstractFont.h

@ -435,6 +435,18 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
*/ */
Float lineHeight() const; Float lineHeight() const;
/**
* @brief Total count of glyphs in the font
* @m_since_latest
*
* Expects that a font is opened.
* @note This function is meant to be used only for font observations
* and conversions. In performance-critical code the
* @ref fillGlyphCache() and @ref layout() functions should be
* used instead.
*/
UnsignedInt glyphCount() const;
/** /**
* @brief Glyph ID for given character * @brief Glyph ID for given character
* *
@ -451,7 +463,8 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
* *
* Distance the cursor for the next glyph that follows @p glyph. * Distance the cursor for the next glyph that follows @p glyph.
* Doesn't consider kerning or any other advanced shaping features. * Doesn't consider kerning or any other advanced shaping features.
* Expects that a font is opened. * Expects that a font is opened and @p glyph is less than
* @ref glyphCount().
* @note This function is meant to be used only for font observations * @note This function is meant to be used only for font observations
* and conversions. In performance-critical code the @ref layout() * and conversions. In performance-critical code the @ref layout()
* function should be used instead. * function should be used instead.
@ -503,8 +516,8 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
struct Properties { struct Properties {
#if defined(CORRADE_TARGET_GCC) && !defined(CORRADE_TARGET_CLANG) && __GNUC__ < 5 #if defined(CORRADE_TARGET_GCC) && !defined(CORRADE_TARGET_CLANG) && __GNUC__ < 5
/* Otherwise GCC 4.8 loudly complains about missing initializers */ /* Otherwise GCC 4.8 loudly complains about missing initializers */
constexpr /*implicit*/ Properties() noexcept: size{}, ascent{}, descent{}, lineHeight{} {} constexpr /*implicit*/ Properties() noexcept: size{}, ascent{}, descent{}, lineHeight{}, glyphCount{} {}
constexpr /*implicit*/ Properties(Float size, Float ascent, Float descent, Float lineHeight) noexcept: size{size}, ascent{ascent}, descent{descent}, lineHeight{lineHeight} {} constexpr /*implicit*/ Properties(Float size, Float ascent, Float descent, Float lineHeight, UnsignedInt glyphCount) noexcept: size{size}, ascent{ascent}, descent{descent}, lineHeight{lineHeight}, glyphCount{glyphCount} {}
#endif #endif
/** /**
@ -530,6 +543,13 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
* @see @ref lineHeight() * @see @ref lineHeight()
*/ */
Float lineHeight; Float lineHeight;
/**
* Total count of glyphs in the font
* @see @ref glyphCount()
* @m_since_latest
*/
UnsignedInt glyphCount;
}; };
protected: protected:
@ -617,6 +637,7 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
} _fileCallbackTemplate{nullptr, nullptr}; } _fileCallbackTemplate{nullptr, nullptr};
Float _size{}, _ascent{}, _descent{}, _lineHeight{}; Float _size{}, _ascent{}, _descent{}, _lineHeight{};
UnsignedInt _glyphCount{};
}; };
/** /**
@ -702,7 +723,7 @@ updated interface string.
*/ */
/* Silly indentation to make the string appear in pluginInterface() docs */ /* Silly indentation to make the string appear in pluginInterface() docs */
#define MAGNUM_TEXT_ABSTRACTFONT_PLUGIN_INTERFACE /* [interface] */ \ #define MAGNUM_TEXT_ABSTRACTFONT_PLUGIN_INTERFACE /* [interface] */ \
"cz.mosra.magnum.Text.AbstractFont/0.3.1" "cz.mosra.magnum.Text.AbstractFont/0.3.2"
/* [interface] */ /* [interface] */
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT

67
src/Magnum/Text/Test/AbstractFontTest.cpp

@ -77,6 +77,7 @@ struct AbstractFontTest: TestSuite::Tester {
void glyphAdvance(); void glyphAdvance();
void glyphAdvanceNoFont(); void glyphAdvanceNoFont();
void glyphAdvanceOutOfRange();
void layout(); void layout();
void layoutNoFont(); void layoutNoFont();
@ -130,6 +131,7 @@ AbstractFontTest::AbstractFontTest() {
&AbstractFontTest::glyphAdvance, &AbstractFontTest::glyphAdvance,
&AbstractFontTest::glyphAdvanceNoFont, &AbstractFontTest::glyphAdvanceNoFont,
&AbstractFontTest::glyphAdvanceOutOfRange,
&AbstractFontTest::layout, &AbstractFontTest::layout,
&AbstractFontTest::layoutNoFont, &AbstractFontTest::layoutNoFont,
@ -181,7 +183,7 @@ void AbstractFontTest::openData() {
Properties doOpenData(const Containers::ArrayView<const char> data, Float size) override { Properties doOpenData(const Containers::ArrayView<const char> data, Float size) override {
_opened = (data.size() == 1 && data[0] == '\xa5'); _opened = (data.size() == 1 && data[0] == '\xa5');
return {size, 1.0f, 2.0f, 3.0f}; return {size, 1.0f, 2.0f, 3.0f, 15};
} }
UnsignedInt doGlyphId(char32_t) override { return {}; } UnsignedInt doGlyphId(char32_t) override { return {}; }
@ -201,6 +203,7 @@ void AbstractFontTest::openData() {
CORRADE_COMPARE(font.ascent(), 1.0f); CORRADE_COMPARE(font.ascent(), 1.0f);
CORRADE_COMPARE(font.descent(), 2.0f); CORRADE_COMPARE(font.descent(), 2.0f);
CORRADE_COMPARE(font.lineHeight(), 3.0f); CORRADE_COMPARE(font.lineHeight(), 3.0f);
CORRADE_COMPARE(font.glyphCount(), 15);
} }
void AbstractFontTest::openFileAsData() { void AbstractFontTest::openFileAsData() {
@ -211,7 +214,7 @@ void AbstractFontTest::openFileAsData() {
Properties doOpenData(const Containers::ArrayView<const char> data, Float size) override { Properties doOpenData(const Containers::ArrayView<const char> data, Float size) override {
_opened = (data.size() == 1 && data[0] == '\xa5'); _opened = (data.size() == 1 && data[0] == '\xa5');
return {size, 1.0f, 2.0f, 3.0f}; return {size, 1.0f, 2.0f, 3.0f, 15};
} }
UnsignedInt doGlyphId(char32_t) override { return {}; } UnsignedInt doGlyphId(char32_t) override { return {}; }
@ -231,6 +234,7 @@ void AbstractFontTest::openFileAsData() {
CORRADE_COMPARE(font.ascent(), 1.0f); CORRADE_COMPARE(font.ascent(), 1.0f);
CORRADE_COMPARE(font.descent(), 2.0f); CORRADE_COMPARE(font.descent(), 2.0f);
CORRADE_COMPARE(font.lineHeight(), 3.0f); CORRADE_COMPARE(font.lineHeight(), 3.0f);
CORRADE_COMPARE(font.glyphCount(), 15);
} }
void AbstractFontTest::openFileAsDataNotFound() { void AbstractFontTest::openFileAsDataNotFound() {
@ -512,7 +516,7 @@ void AbstractFontTest::setFileCallbackOpenFileDirectly() {
Properties doOpenFile(Containers::StringView filename, Float size) override { Properties doOpenFile(Containers::StringView filename, Float size) override {
/* Called because FileCallback is supported */ /* Called because FileCallback is supported */
_opened = filename == "file.dat" && fileCallback() && fileCallbackUserData(); _opened = filename == "file.dat" && fileCallback() && fileCallbackUserData();
return {size, 1.0f, 2.0f, 3.0f}; return {size, 1.0f, 2.0f, 3.0f, 15};
} }
Properties doOpenData(Containers::ArrayView<const char>, Float) override { Properties doOpenData(Containers::ArrayView<const char>, Float) override {
@ -544,6 +548,7 @@ void AbstractFontTest::setFileCallbackOpenFileDirectly() {
CORRADE_COMPARE(font.ascent(), 1.0f); CORRADE_COMPARE(font.ascent(), 1.0f);
CORRADE_COMPARE(font.descent(), 2.0f); CORRADE_COMPARE(font.descent(), 2.0f);
CORRADE_COMPARE(font.lineHeight(), 3.0f); CORRADE_COMPARE(font.lineHeight(), 3.0f);
CORRADE_COMPARE(font.glyphCount(), 15);
} }
void AbstractFontTest::setFileCallbackOpenFileThroughBaseImplementation() { void AbstractFontTest::setFileCallbackOpenFileThroughBaseImplementation() {
@ -559,7 +564,7 @@ void AbstractFontTest::setFileCallbackOpenFileThroughBaseImplementation() {
Properties doOpenData(Containers::ArrayView<const char> data, Float size) override { Properties doOpenData(Containers::ArrayView<const char> data, Float size) override {
_opened = (data.size() == 1 && data[0] == '\xb0'); _opened = (data.size() == 1 && data[0] == '\xb0');
return {size, 1.0f, 2.0f, 3.0f}; return {size, 1.0f, 2.0f, 3.0f, 15};
} }
UnsignedInt doGlyphId(char32_t) override { return {}; } UnsignedInt doGlyphId(char32_t) override { return {}; }
@ -602,6 +607,7 @@ void AbstractFontTest::setFileCallbackOpenFileThroughBaseImplementation() {
CORRADE_COMPARE(font.ascent(), 1.0f); CORRADE_COMPARE(font.ascent(), 1.0f);
CORRADE_COMPARE(font.descent(), 2.0f); CORRADE_COMPARE(font.descent(), 2.0f);
CORRADE_COMPARE(font.lineHeight(), 3.0f); CORRADE_COMPARE(font.lineHeight(), 3.0f);
CORRADE_COMPARE(font.glyphCount(), 15);
} }
void AbstractFontTest::setFileCallbackOpenFileThroughBaseImplementationFailed() { void AbstractFontTest::setFileCallbackOpenFileThroughBaseImplementationFailed() {
@ -649,7 +655,7 @@ void AbstractFontTest::setFileCallbackOpenFileAsData() {
Properties doOpenData(Containers::ArrayView<const char> data, Float size) override { Properties doOpenData(Containers::ArrayView<const char> data, Float size) override {
_opened = (data.size() == 1 && data[0] == '\xb0'); _opened = (data.size() == 1 && data[0] == '\xb0');
return {size, 1.0f, 2.0f, 3.0f}; return {size, 1.0f, 2.0f, 3.0f, 15};
} }
UnsignedInt doGlyphId(char32_t) override { return {}; } UnsignedInt doGlyphId(char32_t) override { return {}; }
@ -693,6 +699,7 @@ void AbstractFontTest::setFileCallbackOpenFileAsData() {
CORRADE_COMPARE(font.ascent(), 1.0f); CORRADE_COMPARE(font.ascent(), 1.0f);
CORRADE_COMPARE(font.descent(), 2.0f); CORRADE_COMPARE(font.descent(), 2.0f);
CORRADE_COMPARE(font.lineHeight(), 3.0f); CORRADE_COMPARE(font.lineHeight(), 3.0f);
CORRADE_COMPARE(font.glyphCount(), 15);
} }
void AbstractFontTest::setFileCallbackOpenFileAsDataFailed() { void AbstractFontTest::setFileCallbackOpenFileAsDataFailed() {
@ -735,7 +742,7 @@ void AbstractFontTest::properties() {
Properties doOpenData(const Containers::ArrayView<const char>, Float size) override { Properties doOpenData(const Containers::ArrayView<const char>, Float size) override {
_opened = true; _opened = true;
return {size, 1.0f, 2.0f, 3.0f}; return {size, 1.0f, 2.0f, 3.0f, 15};
} }
UnsignedInt doGlyphId(char32_t) override { return {}; } UnsignedInt doGlyphId(char32_t) override { return {}; }
@ -752,6 +759,7 @@ void AbstractFontTest::properties() {
CORRADE_COMPARE(font.ascent(), 1.0f); CORRADE_COMPARE(font.ascent(), 1.0f);
CORRADE_COMPARE(font.descent(), 2.0f); CORRADE_COMPARE(font.descent(), 2.0f);
CORRADE_COMPARE(font.lineHeight(), 3.0f); CORRADE_COMPARE(font.lineHeight(), 3.0f);
CORRADE_COMPARE(font.glyphCount(), 15);
} }
void AbstractFontTest::propertiesNoFont() { void AbstractFontTest::propertiesNoFont() {
@ -775,11 +783,13 @@ void AbstractFontTest::propertiesNoFont() {
font.ascent(); font.ascent();
font.descent(); font.descent();
font.lineHeight(); font.lineHeight();
font.glyphCount();
CORRADE_COMPARE(out.str(), CORRADE_COMPARE(out.str(),
"Text::AbstractFont::size(): no font opened\n" "Text::AbstractFont::size(): no font opened\n"
"Text::AbstractFont::ascent(): no font opened\n" "Text::AbstractFont::ascent(): no font opened\n"
"Text::AbstractFont::descent(): no font opened\n" "Text::AbstractFont::descent(): no font opened\n"
"Text::AbstractFont::lineHeight(): no font opened\n"); "Text::AbstractFont::lineHeight(): no font opened\n"
"Text::AbstractFont::glyphCount(): no font opened\n");
} }
void AbstractFontTest::glyphId() { void AbstractFontTest::glyphId() {
@ -821,17 +831,25 @@ void AbstractFontTest::glyphIdNoFont() {
void AbstractFontTest::glyphAdvance() { void AbstractFontTest::glyphAdvance() {
struct MyFont: AbstractFont { struct MyFont: AbstractFont {
FontFeatures doFeatures() const override { return {}; } FontFeatures doFeatures() const override { return FontFeature::OpenData; }
bool doIsOpened() const override { return true; } bool doIsOpened() const override { return _opened; }
void doClose() override {} void doClose() override {}
Properties doOpenData(Containers::ArrayView<const char>, Float) override {
_opened = true;
return {0.0f, 0.0f, 0.0f, 0.0f, 98};
}
UnsignedInt doGlyphId(char32_t) override { return {}; } UnsignedInt doGlyphId(char32_t) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt a) override { return {a*10.0f, -Float(a)/10.0f}; } Vector2 doGlyphAdvance(UnsignedInt a) override { return {a*10.0f, -Float(a)/10.0f}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, Containers::StringView) override { Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, Containers::StringView) override {
return nullptr; return nullptr;
} }
bool _opened = false;
} font; } font;
/* Have to explicitly open in order to make glyphCount() non-zero */
CORRADE_VERIFY(font.openData(nullptr, 0.0f));
CORRADE_COMPARE(font.glyphAdvance(97), (Vector2{970.0f, -9.7f})); CORRADE_COMPARE(font.glyphAdvance(97), (Vector2{970.0f, -9.7f}));
} }
@ -856,6 +874,37 @@ void AbstractFontTest::glyphAdvanceNoFont() {
CORRADE_COMPARE(out.str(), "Text::AbstractFont::glyphAdvance(): no font opened\n"); CORRADE_COMPARE(out.str(), "Text::AbstractFont::glyphAdvance(): no font opened\n");
} }
void AbstractFontTest::glyphAdvanceOutOfRange() {
CORRADE_SKIP_IF_NO_ASSERT();
struct MyFont: AbstractFont {
FontFeatures doFeatures() const override { return FontFeature::OpenData; }
bool doIsOpened() const override { return _opened; }
void doClose() override {}
Properties doOpenData(Containers::ArrayView<const char>, Float) override {
_opened = true;
return {0.0f, 0.0f, 0.0f, 0.0f, 3};
}
UnsignedInt doGlyphId(char32_t) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, Containers::StringView) override {
return nullptr;
}
bool _opened = false;
} font;
/* Have to explicitly open in order to make glyphCount() non-zero */
CORRADE_VERIFY(font.openData(nullptr, 0.0f));
std::ostringstream out;
Error redirectError{&out};
font.glyphAdvance(3);
CORRADE_COMPARE(out.str(),
"Text::AbstractFont::glyphAdvance(): index 3 out of range for 3 glyphs\n");
}
struct DummyGlyphCache: AbstractGlyphCache { struct DummyGlyphCache: AbstractGlyphCache {
using AbstractGlyphCache::AbstractGlyphCache; using AbstractGlyphCache::AbstractGlyphCache;

2
src/Magnum/Text/Test/RendererGLTest.cpp

@ -350,7 +350,7 @@ void RendererGLTest::multiline() {
Properties doOpenFile(Containers::StringView, Float) override { Properties doOpenFile(Containers::StringView, Float) override {
_opened = true; _opened = true;
return {0.5f, 0.45f, -0.25f, 0.75f}; return {0.5f, 0.45f, -0.25f, 0.75f, 1};
} }
UnsignedInt doGlyphId(char32_t) override { return 0; } UnsignedInt doGlyphId(char32_t) override { return 0; }

5
src/MagnumPlugins/MagnumFont/MagnumFont.cpp

@ -134,7 +134,8 @@ auto MagnumFont::doOpenData(const Containers::ArrayView<const char> data, const
return {_opened->conf.value<Float>("fontSize"), return {_opened->conf.value<Float>("fontSize"),
_opened->conf.value<Float>("ascent"), _opened->conf.value<Float>("ascent"),
_opened->conf.value<Float>("descent"), _opened->conf.value<Float>("descent"),
_opened->conf.value<Float>("lineHeight")}; _opened->conf.value<Float>("lineHeight"),
UnsignedInt(glyphs.size())};
} }
auto MagnumFont::doOpenFile(const Containers::StringView filename, const Float size) -> Properties { auto MagnumFont::doOpenFile(const Containers::StringView filename, const Float size) -> Properties {
@ -150,7 +151,7 @@ UnsignedInt MagnumFont::doGlyphId(const char32_t character) {
} }
Vector2 MagnumFont::doGlyphAdvance(const UnsignedInt glyph) { Vector2 MagnumFont::doGlyphAdvance(const UnsignedInt glyph) {
return glyph < _opened->glyphAdvance.size() ? _opened->glyphAdvance[glyph] : Vector2(); return _opened->glyphAdvance[glyph];
} }
Containers::Pointer<AbstractGlyphCache> MagnumFont::doCreateGlyphCache() { Containers::Pointer<AbstractGlyphCache> MagnumFont::doCreateGlyphCache() {

3
src/MagnumPlugins/MagnumFont/Test/MagnumFontTest.cpp

@ -93,7 +93,8 @@ void MagnumFontTest::properties() {
CORRADE_COMPARE(font->ascent(), 25.0f); CORRADE_COMPARE(font->ascent(), 25.0f);
CORRADE_COMPARE(font->descent(), -10.0f); CORRADE_COMPARE(font->descent(), -10.0f);
CORRADE_COMPARE(font->lineHeight(), 39.7333f); CORRADE_COMPARE(font->lineHeight(), 39.7333f);
CORRADE_COMPARE(font->glyphAdvance(font->glyphId(U'W')), Vector2(23.0f, 0.0f)); CORRADE_COMPARE(font->glyphCount(), 3);
CORRADE_COMPARE(font->glyphAdvance(font->glyphId(U'W')), (Vector2{23.0f, 0.0f}));
} }
void MagnumFontTest::layout() { void MagnumFontTest::layout() {

2
src/MagnumPlugins/MagnumFontConverter/Test/MagnumFontConverterTest.cpp

@ -95,7 +95,7 @@ void MagnumFontConverterTest::exportFont() {
bool doIsOpened() const override { return _opened; } bool doIsOpened() const override { return _opened; }
Properties doOpenFile(Containers::StringView, Float) override { Properties doOpenFile(Containers::StringView, Float) override {
_opened = true; _opened = true;
return {16.0f, 25.0f, -10.0f, 39.7333f}; return {16.0f, 25.0f, -10.0f, 39.7333f, 3};
} }
FontFeatures doFeatures() const override { return {}; } FontFeatures doFeatures() const override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, Containers::StringView) override { return nullptr; } Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, Containers::StringView) override { return nullptr; }

Loading…
Cancel
Save