diff --git a/src/Magnum/Text/AbstractFont.cpp b/src/Magnum/Text/AbstractFont.cpp index c4a33e737..34c25b76a 100644 --- a/src/Magnum/Text/AbstractFont.cpp +++ b/src/Magnum/Text/AbstractFont.cpp @@ -108,7 +108,11 @@ void AbstractFont::setFileCallback(Containers::Optional>(*)(const std::string&, InputFileCallbackPolicy, void*), void*) {} -bool AbstractFont::openData(Containers::ArrayView data, const Float size) { +bool AbstractFont::openData(const Containers::ArrayView data, const Float size) { + return openData(data, size, 0); +} + +bool AbstractFont::openData(Containers::ArrayView data, const Float size, const UnsignedInt fontIndex) { CORRADE_ASSERT(features() & FontFeature::OpenData, "Text::AbstractFont::openData(): feature not supported", false); @@ -116,16 +120,19 @@ bool AbstractFont::openData(Containers::ArrayView data, const Float the check doesn't be done on the plugin side) because for some file formats it could be valid (MagnumFont in particular). */ close(); + _fontIndex = fontIndex; const Properties properties = doOpenData(Containers::arrayCast(data), size); /* If opening succeeded, save the returned values. If not, the values were set to their default values by close() already. */ if(isOpened()) { + CORRADE_INTERNAL_ASSERT(!properties.fontCount || fontIndex < properties.fontCount); _size = properties.size; _ascent = properties.ascent; _descent = properties.descent; _lineHeight = properties.lineHeight; _glyphCount = properties.glyphCount; + _fontCount = properties.fontCount ? properties.fontCount : 1; return true; } @@ -137,7 +144,12 @@ auto AbstractFont::doOpenData(Containers::ArrayView, Float) -> Prope } bool AbstractFont::openFile(const Containers::StringView filename, const Float size) { + return openFile(filename, size, 0); +} + +bool AbstractFont::openFile(const Containers::StringView filename, const Float size, const UnsignedInt fontIndex) { close(); + _fontIndex = fontIndex; Properties properties; /* If file loading callbacks are not set or the font implementation @@ -174,11 +186,13 @@ bool AbstractFont::openFile(const Containers::StringView filename, const Float s /* If opening succeeded, save the returned values. If not, the values were set to their default values by close() already. */ if(isOpened()) { + CORRADE_INTERNAL_ASSERT(!properties.fontCount || fontIndex < properties.fontCount); _size = properties.size; _ascent = properties.ascent; _descent = properties.descent; _lineHeight = properties.lineHeight; _glyphCount = properties.glyphCount; + _fontCount = properties.fontCount ? properties.fontCount : 1; return true; } @@ -228,6 +242,13 @@ void AbstractFont::close() { _lineHeight = {}; _descent = {}; _lineHeight = {}; + _fontIndex = {}; + _fontCount = {}; +} + +UnsignedInt AbstractFont::fontCount() const { + CORRADE_ASSERT(isOpened(), "Text::AbstractFont::fontCount(): no font opened", {}); + return _fontCount; } Float AbstractFont::size() const { diff --git a/src/Magnum/Text/AbstractFont.h b/src/Magnum/Text/AbstractFont.h index 5a350959c..48fcc90cf 100644 --- a/src/Magnum/Text/AbstractFont.h +++ b/src/Magnum/Text/AbstractFont.h @@ -400,28 +400,40 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin { * @brief Open raw data * @param data File data * @param size Font size in points + * @param fontIndex Font index to open * * Closes previous file, if it was opened, and tries to open given - * raw data. Available only if @ref FontFeature::OpenData is supported. - * On failure prints a message to @relativeref{Magnum,Error} and - * returns @cpp false @ce. - * @see @ref features(), @ref openFile() + * raw data. The @p fontIndex is useful for opening a particular font + * from a collection such as TrueType Collection (`*.ttc`) files. + * Available only if @ref FontFeature::OpenData is supported. On + * failure prints a message to @relativeref{Magnum,Error} and returns + * @cpp false @ce. + * @see @ref features(), @ref openFile(), @ref fontIndex(), + * @ref fontCount() */ + bool openData(Containers::ArrayView data, Float size, UnsignedInt fontIndex); + /** @overload */ bool openData(Containers::ArrayView data, Float size); /** * @brief Open a file * @param filename Font file * @param size Size to open the font in, in points + * @param fontIndex Font index to open * * Closes previous file, if it was opened, and tries to open given - * file. On failure prints a message to @relativeref{Magnum,Error} and - * returns @cpp false @ce. If file loading callbacks are set via + * file. The @p fontIndex is useful for opening a particular font from + * a collection such as TrueType Collection (`*.ttc`) files. On + * failure prints a message to @relativeref{Magnum,Error} and returns + * @cpp false @ce. If file loading callbacks are set via * @ref setFileCallback() and @ref FontFeature::OpenData is supported, * this function uses the callback to load the file and passes the * memory view to @ref openData() instead. See @ref setFileCallback() * for more information. + * @see @ref fontIndex(), @ref fontCount() */ + bool openFile(Containers::StringView filename, Float size, UnsignedInt fontIndex); + /** @overload */ bool openFile(Containers::StringView filename, Float size); /** @@ -437,6 +449,28 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin { */ void close(); + /** + * @brief Opened font index + * @m_since_latest + * + * Returns the font index passed to @ref openFile() or @ref openData(). + * For files containing just one font, this value is @cpp 0 @ce. + * @see @ref fontCount() + */ + UnsignedInt fontIndex() const { return _fontIndex; } + + /** + * @brief Count of fonts in the opened file + * @m_since_latest + * + * For files containing just one font, this value is @cpp 1 @ce. For + * font collections such as TrueType Collection (`*.ttc`) files, this + * is the count of fonts in the collection. Expects that a font is + * opened. + * @see @ref fontIndex() + */ + UnsignedInt fontCount() const; + /** * @brief Font size in points * @@ -655,11 +689,8 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin { * Returned from @ref doOpenFile(), @ref doOpenData(). */ 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{}, 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 + constexpr /*implicit*/ Properties() noexcept: size{}, ascent{}, descent{}, lineHeight{}, glyphCount{}, fontCount{} {} + constexpr /*implicit*/ Properties(Float size, Float ascent, Float descent, Float lineHeight, UnsignedInt glyphCount, UnsignedInt fontCount = 0) noexcept: size{size}, ascent{ascent}, descent{descent}, lineHeight{lineHeight}, glyphCount{glyphCount}, fontCount{fontCount} {} /** * Font size in points @@ -691,6 +722,17 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin { * @m_since_latest */ UnsignedInt glyphCount; + + /** + * Count of fonts in the opened file + * + * If left at @cpp 0 @ce by an implementation, the public + * @ref fontCount() reports @cpp 1 @ce. Implementations supporting + * font collections should return the real count. + * @see @ref fontCount() + * @m_since_latest + */ + UnsignedInt fontCount; }; protected: @@ -823,7 +865,7 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin { #endif Float _size{}, _ascent{}, _descent{}, _lineHeight{}; - UnsignedInt _glyphCount{}; + UnsignedInt _glyphCount{}, _fontIndex{}, _fontCount{}; }; #ifdef MAGNUM_BUILD_DEPRECATED @@ -917,7 +959,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.7" +"cz.mosra.magnum.Text.AbstractFont/0.3.8" /* [interface] */ #ifndef DOXYGEN_GENERATING_OUTPUT diff --git a/src/Magnum/Text/Test/AbstractFontTest.cpp b/src/Magnum/Text/Test/AbstractFontTest.cpp index 648b7a570..772372364 100644 --- a/src/Magnum/Text/Test/AbstractFontTest.cpp +++ b/src/Magnum/Text/Test/AbstractFontTest.cpp @@ -57,6 +57,7 @@ struct AbstractFontTest: TestSuite::Tester { void construct(); void openData(); + void openDataFontIndex(); void openFileAsData(); void openFileAsDataNotFound(); @@ -131,6 +132,7 @@ AbstractFontTest::AbstractFontTest() { addTests({&AbstractFontTest::construct, &AbstractFontTest::openData, + &AbstractFontTest::openDataFontIndex, &AbstractFontTest::openFileAsData, &AbstractFontTest::openFileAsDataNotFound, @@ -250,6 +252,41 @@ void AbstractFontTest::openData() { CORRADE_COMPARE(font.descent(), 2.0f); CORRADE_COMPARE(font.lineHeight(), 3.0f); CORRADE_COMPARE(font.glyphCount(), 15); + CORRADE_COMPARE(font.fontIndex(), 0); + CORRADE_COMPARE(font.fontCount(), 1); +} + +void AbstractFontTest::openDataFontIndex() { + struct: AbstractFont { + FontFeatures doFeatures() const override { return FontFeature::OpenData; } + bool doIsOpened() const override { return _opened; } + void doClose() override {} + + Properties doOpenData(const Containers::ArrayView data, Float size) override { + CORRADE_COMPARE(fontIndex(), 2); + _opened = (data.size() == 1 && data[0] == '\xa5'); + return {size, 1.0f, 2.0f, 3.0f, 15, 3}; + } + + void doGlyphIdsInto(const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&) override {} + Vector2 doGlyphSize(UnsignedInt) override { return {}; } + Vector2 doGlyphAdvance(UnsignedInt) override { return {}; } + Containers::Pointer doCreateShaper() override { return {}; } + + bool _opened = false; + } font; + + CORRADE_VERIFY(!font.isOpened()); + const char a5 = '\xa5'; + font.openData({&a5, 1}, 13.0f, 2); + CORRADE_VERIFY(font.isOpened()); + CORRADE_COMPARE(font.size(), 13.0f); + CORRADE_COMPARE(font.ascent(), 1.0f); + CORRADE_COMPARE(font.descent(), 2.0f); + CORRADE_COMPARE(font.lineHeight(), 3.0f); + CORRADE_COMPARE(font.glyphCount(), 15); + CORRADE_COMPARE(font.fontIndex(), 2); + CORRADE_COMPARE(font.fontCount(), 3); } void AbstractFontTest::openFileAsData() { @@ -280,6 +317,8 @@ void AbstractFontTest::openFileAsData() { CORRADE_COMPARE(font.descent(), 2.0f); CORRADE_COMPARE(font.lineHeight(), 3.0f); CORRADE_COMPARE(font.glyphCount(), 15); + CORRADE_COMPARE(font.fontIndex(), 0); + CORRADE_COMPARE(font.fontCount(), 1); } void AbstractFontTest::openFileAsDataNotFound() { @@ -811,12 +850,14 @@ void AbstractFontTest::propertiesNoFont() { font.descent(); font.lineHeight(); font.glyphCount(); + font.fontCount(); CORRADE_COMPARE(out, "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::glyphCount(): no font opened\n"); + "Text::AbstractFont::glyphCount(): no font opened\n" + "Text::AbstractFont::fontCount(): no font opened\n"); } void AbstractFontTest::glyphId() {