Browse Source

Text: add queries for and search by glyph names to AbstractFont.

pull/638/head
Vladimír Vondruš 2 years ago
parent
commit
477b3109c7
  1. 3
      doc/changelog.dox
  2. 20
      src/Magnum/Text/AbstractFont.cpp
  3. 48
      src/Magnum/Text/AbstractFont.h
  4. 134
      src/Magnum/Text/Test/AbstractFontTest.cpp

3
doc/changelog.dox

@ -840,6 +840,9 @@ See also:
- New @ref Text::AbstractFont::fillGlyphCache() overload taking a list of
glyph IDs instead of a UTF-8 string to allow filling the glyph cache with
glyphs that don't directly map to Unicode
- New @ref Text::AbstractFont::glyphName() and
@relativeref{Text::AbstractFont,glyphForName()} APIs for querying glyph
names and retrieving IDs for particular glyph names.
- @ref Text::AbstractFont::fillGlyphCache() now returns a @cpp bool @ce to
allow font plugin implementations to gracefully report failures

20
src/Magnum/Text/AbstractFont.cpp

@ -276,6 +276,26 @@ void AbstractFont::glyphIdsInto(const Containers::StridedArrayView1D<const char3
#endif
}
Containers::String AbstractFont::glyphName(const UnsignedInt glyph) {
CORRADE_ASSERT(isOpened(), "Text::AbstractFont::glyphName(): no font opened", {});
CORRADE_ASSERT(glyph < _glyphCount, "Text::AbstractFont::glyphName(): index" << glyph << "out of range for" << _glyphCount << "glyphs", {});
return doGlyphName(glyph);
}
Containers::String AbstractFont::doGlyphName(UnsignedInt) { return {}; }
UnsignedInt AbstractFont::glyphForName(const Containers::StringView name) {
CORRADE_ASSERT(isOpened(), "Text::AbstractFont::glyphForName(): no font opened", {});
const UnsignedInt glyph = doGlyphForName(name);
CORRADE_ASSERT(glyph < _glyphCount, "Text::AbstractFont::glyphForName(): implementation-returned index" << glyph << "out of range for" << _glyphCount << "glyphs", {});
return glyph;
}
UnsignedInt AbstractFont::doGlyphForName(Containers::StringView) { return 0; }
Vector2 AbstractFont::glyphSize(const UnsignedInt glyph) {
CORRADE_ASSERT(isOpened(), "Text::AbstractFont::glyphSize(): no font opened", {});
CORRADE_ASSERT(glyph < _glyphCount, "Text::AbstractFont::glyphSize(): index" << glyph << "out of range for" << _glyphCount << "glyphs", {});

48
src/Magnum/Text/AbstractFont.h

@ -74,7 +74,11 @@ enum class FontFeature: UnsignedByte {
* @see @ref AbstractFont::fillGlyphCache(),
* @ref AbstractFont::createGlyphCache()
*/
PreparedGlyphCache = 1 << 2
PreparedGlyphCache = 1 << 2,
/* Glyph names are not exposed as a feature because even though the
implementation may support these, a particular font file may not, and
it'd give a false impression. */
};
/**
@ -469,6 +473,31 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
*/
void glyphIdsInto(const Containers::StridedArrayView1D<const char32_t>& characters, const Containers::StridedArrayView1D<UnsignedInt>& glyphs);
/**
* @brief Glyph name
* @m_since_latest
*
* Returns a name of the glyph in the font file, if present and
* supported by the implementation, or an empty string. Expects that a
* font is opened and @p glyph is less than @ref glyphCount().
* @see @ref glyphForName()
*/
Containers::String glyphName(UnsignedInt glyph);
/**
* @brief Glyph for given name
* @m_since_latest
*
* If the implementation supports querying glyphs by name and the name
* exists, returns a corresponding glyph ID, otherwise returns
* @cpp 0 @ce for an invalid glyph. Note that certain named glyphs can
* also map to glyph @cpp 0 @ce, in particular @cpp ".notdef" @ce in
* TTF and OTF fonts, the way to distinguish them is to ask for name of
* the zero glyph and compare. The returned index is guaranteed to be
* less than @ref glyphCount().
*/
UnsignedInt glyphForName(Containers::StringView name);
/**
* @brief Glyph size in pixels
* @param glyph Glyph ID
@ -686,6 +715,23 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
*/
virtual void doGlyphIdsInto(const Containers::StridedArrayView1D<const char32_t>& characters, const Containers::StridedArrayView1D<UnsignedInt>& glyphs) = 0;
/**
* @brief Implementation for @ref glyphName()
* @m_since_latest
*
* Default implementation returns an empty string.
*/
virtual Containers::String doGlyphName(UnsignedInt glyph);
/**
* @brief Implementation for @ref glyphForName()
* @m_since_latest
*
* The implementation is expected to return a value smaller than
* @ref glyphCount(). Default implementation returns @cpp 0 @ce.
*/
virtual UnsignedInt doGlyphForName(Containers::StringView name);
/**
* @brief Implementation for @ref glyphSize()
* @m_since_latest

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

@ -86,6 +86,11 @@ struct AbstractFontTest: TestSuite::Tester {
void glyphIdInvalidSize();
void glyphIdOutOfRange();
void glyphName();
void glyphNameNotImplemented();
void glyphNameNoFont();
void glyphNameOutOfRange();
void glyphSizeAdvance();
void glyphSizeAdvanceNoFont();
void glyphSizeAdvanceOutOfRange();
@ -155,6 +160,11 @@ AbstractFontTest::AbstractFontTest() {
&AbstractFontTest::glyphIdInvalidSize,
&AbstractFontTest::glyphIdOutOfRange,
&AbstractFontTest::glyphName,
&AbstractFontTest::glyphNameNotImplemented,
&AbstractFontTest::glyphNameNoFont,
&AbstractFontTest::glyphNameOutOfRange,
&AbstractFontTest::glyphSizeAdvance,
&AbstractFontTest::glyphSizeAdvanceNoFont,
&AbstractFontTest::glyphSizeAdvanceOutOfRange,
@ -938,6 +948,130 @@ void AbstractFontTest::glyphIdOutOfRange() {
CORRADE_COMPARE(out.str(), "Text::AbstractFont::glyphIdsInto(): implementation-returned index 4 for character U+2345 out of range for 4 glyphs\n");
}
void AbstractFontTest::glyphName() {
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, 4};
}
void doGlyphIdsInto(const Containers::StridedArrayView1D<const char32_t>&, const Containers::StridedArrayView1D<UnsignedInt>&) override {}
Containers::String doGlyphName(UnsignedInt glyph) override {
return glyph == 3 ? "WHATEVER" : "";
}
UnsignedInt doGlyphForName(Containers::StringView name) override {
return name == "whatever" ? 3 : 0;
}
Vector2 doGlyphSize(UnsignedInt) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractShaper> doCreateShaper() override { return {}; }
private:
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.glyphName(3), "WHATEVER");
CORRADE_COMPARE(font.glyphForName("whatever"), 3);
}
void AbstractFontTest::glyphNameNotImplemented() {
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, 4};
}
void doGlyphIdsInto(const Containers::StridedArrayView1D<const char32_t>&, const Containers::StridedArrayView1D<UnsignedInt>&) override {}
Vector2 doGlyphSize(UnsignedInt) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractShaper> doCreateShaper() override { return {}; }
private:
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.glyphName(3), "");
CORRADE_COMPARE(font.glyphForName("whatever"), 0);
}
void AbstractFontTest::glyphNameNoFont() {
CORRADE_SKIP_IF_NO_ASSERT();
struct MyFont: AbstractFont {
FontFeatures doFeatures() const override { return {}; }
bool doIsOpened() const override { return false; }
void doClose() override {}
void doGlyphIdsInto(const Containers::StridedArrayView1D<const char32_t>&, const Containers::StridedArrayView1D<UnsignedInt>&) override {}
Vector2 doGlyphSize(UnsignedInt) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractShaper> doCreateShaper() override { return {}; }
} font;
std::ostringstream out;
Error redirectError{&out};
font.glyphName(0);
font.glyphForName("");
CORRADE_COMPARE(out.str(),
"Text::AbstractFont::glyphName(): no font opened\n"
"Text::AbstractFont::glyphForName(): no font opened\n");
}
void AbstractFontTest::glyphNameOutOfRange() {
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, 4};
}
void doGlyphIdsInto(const Containers::StridedArrayView1D<const char32_t>&, const Containers::StridedArrayView1D<UnsignedInt>&) override {}
UnsignedInt doGlyphForName(Containers::StringView) override { return 4; }
Vector2 doGlyphSize(UnsignedInt) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractShaper> doCreateShaper() override { return {}; }
private:
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.glyphName(4);
font.glyphForName("");
CORRADE_COMPARE(out.str(),
"Text::AbstractFont::glyphName(): index 4 out of range for 4 glyphs\n"
"Text::AbstractFont::glyphForName(): implementation-returned index 4 out of range for 4 glyphs\n");
}
void AbstractFontTest::glyphSizeAdvance() {
struct MyFont: AbstractFont {
FontFeatures doFeatures() const override { return FontFeature::OpenData; }

Loading…
Cancel
Save