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
- Added @ref Text::AbstractFont::glyphCount()
- Added @ref Text::Renderer::fontSize()
@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;
_descent = properties.descent;
_lineHeight = properties.lineHeight;
_glyphCount = properties.glyphCount;
return true;
}
@ -166,6 +167,7 @@ bool AbstractFont::openFile(const Containers::StringView filename, const Float s
_ascent = properties.ascent;
_descent = properties.descent;
_lineHeight = properties.lineHeight;
_glyphCount = properties.glyphCount;
return true;
}
@ -237,6 +239,11 @@ Float AbstractFont::lineHeight() const {
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) {
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) {
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);
}

29
src/Magnum/Text/AbstractFont.h

@ -435,6 +435,18 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
*/
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
*
@ -451,7 +463,8 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
*
* Distance the cursor for the next glyph that follows @p glyph.
* 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
* and conversions. In performance-critical code the @ref layout()
* function should be used instead.
@ -503,8 +516,8 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
struct Properties {
#if defined(CORRADE_TARGET_GCC) && !defined(CORRADE_TARGET_CLANG) && __GNUC__ < 5
/* Otherwise GCC 4.8 loudly complains about missing initializers */
constexpr /*implicit*/ Properties() noexcept: size{}, ascent{}, descent{}, lineHeight{} {}
constexpr /*implicit*/ Properties(Float size, Float ascent, Float descent, Float lineHeight) noexcept: size{size}, ascent{ascent}, descent{descent}, lineHeight{lineHeight} {}
constexpr /*implicit*/ Properties() noexcept: size{}, ascent{}, descent{}, lineHeight{}, glyphCount{} {}
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
/**
@ -530,6 +543,13 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
* @see @ref lineHeight()
*/
Float lineHeight;
/**
* Total count of glyphs in the font
* @see @ref glyphCount()
* @m_since_latest
*/
UnsignedInt glyphCount;
};
protected:
@ -617,6 +637,7 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
} _fileCallbackTemplate{nullptr, nullptr};
Float _size{}, _ascent{}, _descent{}, _lineHeight{};
UnsignedInt _glyphCount{};
};
/**
@ -702,7 +723,7 @@ updated interface string.
*/
/* Silly indentation to make the string appear in pluginInterface() docs */
#define MAGNUM_TEXT_ABSTRACTFONT_PLUGIN_INTERFACE /* [interface] */ \
"cz.mosra.magnum.Text.AbstractFont/0.3.1"
"cz.mosra.magnum.Text.AbstractFont/0.3.2"
/* [interface] */
#ifndef DOXYGEN_GENERATING_OUTPUT

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

@ -77,6 +77,7 @@ struct AbstractFontTest: TestSuite::Tester {
void glyphAdvance();
void glyphAdvanceNoFont();
void glyphAdvanceOutOfRange();
void layout();
void layoutNoFont();
@ -130,6 +131,7 @@ AbstractFontTest::AbstractFontTest() {
&AbstractFontTest::glyphAdvance,
&AbstractFontTest::glyphAdvanceNoFont,
&AbstractFontTest::glyphAdvanceOutOfRange,
&AbstractFontTest::layout,
&AbstractFontTest::layoutNoFont,
@ -181,7 +183,7 @@ void AbstractFontTest::openData() {
Properties doOpenData(const Containers::ArrayView<const char> data, Float size) override {
_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 {}; }
@ -201,6 +203,7 @@ void AbstractFontTest::openData() {
CORRADE_COMPARE(font.ascent(), 1.0f);
CORRADE_COMPARE(font.descent(), 2.0f);
CORRADE_COMPARE(font.lineHeight(), 3.0f);
CORRADE_COMPARE(font.glyphCount(), 15);
}
void AbstractFontTest::openFileAsData() {
@ -211,7 +214,7 @@ void AbstractFontTest::openFileAsData() {
Properties doOpenData(const Containers::ArrayView<const char> data, Float size) override {
_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 {}; }
@ -231,6 +234,7 @@ void AbstractFontTest::openFileAsData() {
CORRADE_COMPARE(font.ascent(), 1.0f);
CORRADE_COMPARE(font.descent(), 2.0f);
CORRADE_COMPARE(font.lineHeight(), 3.0f);
CORRADE_COMPARE(font.glyphCount(), 15);
}
void AbstractFontTest::openFileAsDataNotFound() {
@ -512,7 +516,7 @@ void AbstractFontTest::setFileCallbackOpenFileDirectly() {
Properties doOpenFile(Containers::StringView filename, Float size) override {
/* Called because FileCallback is supported */
_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 {
@ -544,6 +548,7 @@ void AbstractFontTest::setFileCallbackOpenFileDirectly() {
CORRADE_COMPARE(font.ascent(), 1.0f);
CORRADE_COMPARE(font.descent(), 2.0f);
CORRADE_COMPARE(font.lineHeight(), 3.0f);
CORRADE_COMPARE(font.glyphCount(), 15);
}
void AbstractFontTest::setFileCallbackOpenFileThroughBaseImplementation() {
@ -559,7 +564,7 @@ void AbstractFontTest::setFileCallbackOpenFileThroughBaseImplementation() {
Properties doOpenData(Containers::ArrayView<const char> data, Float size) override {
_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 {}; }
@ -602,6 +607,7 @@ void AbstractFontTest::setFileCallbackOpenFileThroughBaseImplementation() {
CORRADE_COMPARE(font.ascent(), 1.0f);
CORRADE_COMPARE(font.descent(), 2.0f);
CORRADE_COMPARE(font.lineHeight(), 3.0f);
CORRADE_COMPARE(font.glyphCount(), 15);
}
void AbstractFontTest::setFileCallbackOpenFileThroughBaseImplementationFailed() {
@ -649,7 +655,7 @@ void AbstractFontTest::setFileCallbackOpenFileAsData() {
Properties doOpenData(Containers::ArrayView<const char> data, Float size) override {
_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 {}; }
@ -693,6 +699,7 @@ void AbstractFontTest::setFileCallbackOpenFileAsData() {
CORRADE_COMPARE(font.ascent(), 1.0f);
CORRADE_COMPARE(font.descent(), 2.0f);
CORRADE_COMPARE(font.lineHeight(), 3.0f);
CORRADE_COMPARE(font.glyphCount(), 15);
}
void AbstractFontTest::setFileCallbackOpenFileAsDataFailed() {
@ -735,7 +742,7 @@ void AbstractFontTest::properties() {
Properties doOpenData(const Containers::ArrayView<const char>, Float size) override {
_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 {}; }
@ -752,6 +759,7 @@ void AbstractFontTest::properties() {
CORRADE_COMPARE(font.ascent(), 1.0f);
CORRADE_COMPARE(font.descent(), 2.0f);
CORRADE_COMPARE(font.lineHeight(), 3.0f);
CORRADE_COMPARE(font.glyphCount(), 15);
}
void AbstractFontTest::propertiesNoFont() {
@ -775,11 +783,13 @@ void AbstractFontTest::propertiesNoFont() {
font.ascent();
font.descent();
font.lineHeight();
font.glyphCount();
CORRADE_COMPARE(out.str(),
"Text::AbstractFont::size(): no font opened\n"
"Text::AbstractFont::ascent(): 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() {
@ -821,17 +831,25 @@ void AbstractFontTest::glyphIdNoFont() {
void AbstractFontTest::glyphAdvance() {
struct MyFont: AbstractFont {
FontFeatures doFeatures() const override { return {}; }
bool doIsOpened() const override { return true; }
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, 98};
}
UnsignedInt doGlyphId(char32_t) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt a) override { return {a*10.0f, -Float(a)/10.0f}; }
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));
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");
}
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 {
using AbstractGlyphCache::AbstractGlyphCache;

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

@ -350,7 +350,7 @@ void RendererGLTest::multiline() {
Properties doOpenFile(Containers::StringView, Float) override {
_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; }

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"),
_opened->conf.value<Float>("ascent"),
_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 {
@ -150,7 +151,7 @@ UnsignedInt MagnumFont::doGlyphId(const char32_t character) {
}
Vector2 MagnumFont::doGlyphAdvance(const UnsignedInt glyph) {
return glyph < _opened->glyphAdvance.size() ? _opened->glyphAdvance[glyph] : Vector2();
return _opened->glyphAdvance[glyph];
}
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->descent(), -10.0f);
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() {

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

@ -95,7 +95,7 @@ void MagnumFontConverterTest::exportFont() {
bool doIsOpened() const override { return _opened; }
Properties doOpenFile(Containers::StringView, Float) override {
_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 {}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, Containers::StringView) override { return nullptr; }

Loading…
Cancel
Save