Browse Source

Text: initial support for line height in AbstractFont.

Got finally pissed with the requirement of setting AbstractFont::_size
manually and took this as opportunity to rework the internal plugin API
in a better way. Bumped the interface version, as this is binary
incompatible. MagnumFont doesn't support lineHeight yet.
pull/34/head
Vladimír Vondruš 13 years ago
parent
commit
858c9787f0
  1. 33
      src/Plugins/MagnumFont/MagnumFont.cpp
  2. 8
      src/Plugins/MagnumFont/MagnumFont.h
  3. 2
      src/Plugins/MagnumFont/pluginRegistrationMagnumFont.cpp
  4. 13
      src/Plugins/MagnumFontConverter/Test/MagnumFontConverterTest.cpp
  5. 33
      src/Text/AbstractFont.cpp
  6. 42
      src/Text/AbstractFont.h
  7. 3
      src/Text/Test/AbstractFontTest.cpp

33
src/Plugins/MagnumFont/MagnumFont.cpp

@ -67,11 +67,11 @@ auto MagnumFont::doFeatures() const -> Features { return Feature::OpenData|Featu
bool MagnumFont::doIsOpened() const { return _opened; } bool MagnumFont::doIsOpened() const { return _opened; }
void MagnumFont::doOpenData(const std::vector<std::pair<std::string, Containers::ArrayReference<const unsigned char>>>& data, const Float) { std::pair<Float, Float> MagnumFont::doOpenData(const std::vector<std::pair<std::string, Containers::ArrayReference<const unsigned char>>>& data, const Float) {
/* We need just the configuration file and image file */ /* We need just the configuration file and image file */
if(data.size() != 2) { if(data.size() != 2) {
Error() << "Text::MagnumFont::openData(): wanted two files, got" << data.size(); Error() << "Text::MagnumFont::openData(): wanted two files, got" << data.size();
return; return {};
} }
/* Open the configuration file */ /* Open the configuration file */
@ -79,51 +79,51 @@ void MagnumFont::doOpenData(const std::vector<std::pair<std::string, Containers:
Utility::Configuration conf(in, Utility::Configuration::Flag::SkipComments); Utility::Configuration conf(in, Utility::Configuration::Flag::SkipComments);
if(!conf.isValid() || conf.isEmpty()) { if(!conf.isValid() || conf.isEmpty()) {
Error() << "Text::MagnumFont::openData(): cannot open file" << data[0].first; Error() << "Text::MagnumFont::openData(): cannot open file" << data[0].first;
return; return {};
} }
/* Check version */ /* Check version */
if(conf.value<UnsignedInt>("version") != 1) { if(conf.value<UnsignedInt>("version") != 1) {
Error() << "Text::MagnumFont::openData(): unsupported file version, expected 1 but got" Error() << "Text::MagnumFont::openData(): unsupported file version, expected 1 but got"
<< conf.value<UnsignedInt>("version"); << conf.value<UnsignedInt>("version");
return; return {};
} }
/* Check that we have also the image file */ /* Check that we have also the image file */
if(conf.value("image") != data[1].first) { if(conf.value("image") != data[1].first) {
Error() << "Text::MagnumFont::openData(): expected file" Error() << "Text::MagnumFont::openData(): expected file"
<< conf.value("image") << "but got" << data[1].first; << conf.value("image") << "but got" << data[1].first;
return; return {};
} }
/* Open and load image file */ /* Open and load image file */
Trade::TgaImporter importer; Trade::TgaImporter importer;
if(!importer.openData(data[1].second)) { if(!importer.openData(data[1].second)) {
Error() << "Text::MagnumFont::openData(): cannot open image file"; Error() << "Text::MagnumFont::openData(): cannot open image file";
return; return {};
} }
std::optional<Trade::ImageData2D> image = importer.image2D(0); std::optional<Trade::ImageData2D> image = importer.image2D(0);
if(!image) { if(!image) {
Error() << "Text::MagnumFont::openData(): cannot load image file"; Error() << "Text::MagnumFont::openData(): cannot load image file";
return; return {};
} }
openInternal(std::move(conf), std::move(*image)); return openInternal(std::move(conf), std::move(*image));
} }
void MagnumFont::doOpenFile(const std::string& filename, Float) { std::pair<Float, Float> MagnumFont::doOpenFile(const std::string& filename, Float) {
/* Open the configuration file */ /* Open the configuration file */
Utility::Configuration conf(filename, Utility::Configuration::Flag::ReadOnly|Utility::Configuration::Flag::SkipComments); Utility::Configuration conf(filename, Utility::Configuration::Flag::ReadOnly|Utility::Configuration::Flag::SkipComments);
if(!conf.isValid() || conf.isEmpty()) { if(!conf.isValid() || conf.isEmpty()) {
Error() << "Text::MagnumFont::openFile(): cannot open file" << filename << conf.isValid(); Error() << "Text::MagnumFont::openFile(): cannot open file" << filename << conf.isValid();
return; return {};
} }
/* Check version */ /* Check version */
if(conf.value<UnsignedInt>("version") != 1) { if(conf.value<UnsignedInt>("version") != 1) {
Error() << "Text::MagnumFont::openFile(): unsupported file version, expected 1 but got" Error() << "Text::MagnumFont::openFile(): unsupported file version, expected 1 but got"
<< conf.value<UnsignedInt>("version"); << conf.value<UnsignedInt>("version");
return; return {};
} }
/* Open and load image file */ /* Open and load image file */
@ -131,21 +131,20 @@ void MagnumFont::doOpenFile(const std::string& filename, Float) {
Trade::TgaImporter importer; Trade::TgaImporter importer;
if(!importer.openFile(imageFilename)) { if(!importer.openFile(imageFilename)) {
Error() << "Text::MagnumFont::openFile(): cannot open image file" << imageFilename; Error() << "Text::MagnumFont::openFile(): cannot open image file" << imageFilename;
return; return {};
} }
std::optional<Trade::ImageData2D> image = importer.image2D(0); std::optional<Trade::ImageData2D> image = importer.image2D(0);
if(!image) { if(!image) {
Error() << "Text::MagnumFont::openFile(): cannot load image file"; Error() << "Text::MagnumFont::openFile(): cannot load image file";
return; return {};
} }
openInternal(std::move(conf), std::move(*image)); return openInternal(std::move(conf), std::move(*image));
} }
void MagnumFont::openInternal(Utility::Configuration&& conf, Trade::ImageData2D&& image) { std::pair<Float, Float> MagnumFont::openInternal(Utility::Configuration&& conf, Trade::ImageData2D&& image) {
/* Everything okay, save the data internally */ /* Everything okay, save the data internally */
_opened = new Data{std::move(conf), std::move(image), {}, {}}; _opened = new Data{std::move(conf), std::move(image), {}, {}};
_size = _opened->conf.value<Float>("fontSize");
/* Glyph advances */ /* Glyph advances */
const std::vector<Utility::ConfigurationGroup*> glyphs = _opened->conf.groups("glyph"); const std::vector<Utility::ConfigurationGroup*> glyphs = _opened->conf.groups("glyph");
@ -160,6 +159,8 @@ void MagnumFont::openInternal(Utility::Configuration&& conf, Trade::ImageData2D&
CORRADE_INTERNAL_ASSERT(glyphId < _opened->glyphAdvance.size()); CORRADE_INTERNAL_ASSERT(glyphId < _opened->glyphAdvance.size());
_opened->glyphId.emplace(c->value<char32_t>("unicode"), glyphId); _opened->glyphId.emplace(c->value<char32_t>("unicode"), glyphId);
} }
return {_opened->conf.value<Float>("fontSize"), 0};
} }
void MagnumFont::doClose() { void MagnumFont::doClose() {

8
src/Plugins/MagnumFont/MagnumFont.h

@ -115,9 +115,9 @@ class MagnumFont: public AbstractFont {
bool doIsOpened() const override; bool doIsOpened() const override;
void doOpenData(const std::vector<std::pair<std::string, Containers::ArrayReference<const unsigned char>>>& data, Float) override; std::pair<Float, Float> doOpenData(const std::vector<std::pair<std::string, Containers::ArrayReference<const unsigned char>>>& data, Float) override;
void doOpenFile(const std::string& filename, Float) override; std::pair<Float, Float> doOpenFile(const std::string& filename, Float) override;
void doClose() override; void doClose() override;
@ -129,9 +129,9 @@ class MagnumFont: public AbstractFont {
std::unique_ptr<AbstractLayouter> doLayout(const GlyphCache& cache, Float size, const std::string& text) override; std::unique_ptr<AbstractLayouter> doLayout(const GlyphCache& cache, Float size, const std::string& text) override;
Data* _opened; std::pair<Float, Float> openInternal(Utility::Configuration&& conf, Trade::ImageData2D&& image);
void openInternal(Utility::Configuration&& conf, Trade::ImageData2D&& image); Data* _opened;
}; };
}} }}

2
src/Plugins/MagnumFont/pluginRegistrationMagnumFont.cpp

@ -25,4 +25,4 @@
#include "MagnumFont/MagnumFont.h" #include "MagnumFont/MagnumFont.h"
CORRADE_PLUGIN_REGISTER(MagnumFont, Magnum::Text::MagnumFont, CORRADE_PLUGIN_REGISTER(MagnumFont, Magnum::Text::MagnumFont,
"cz.mosra.magnum.Text.AbstractFont/0.2.1") "cz.mosra.magnum.Text.AbstractFont/0.2.2")

13
src/Plugins/MagnumFontConverter/Test/MagnumFontConverterTest.cpp

@ -60,11 +60,15 @@ void MagnumFontConverterTest::exportFont() {
/* Fake font with fake cache */ /* Fake font with fake cache */
class FakeFont: public Text::AbstractFont { class FakeFont: public Text::AbstractFont {
public: public:
explicit FakeFont() { _size = 16.0f; } explicit FakeFont(): _opened(false) {}
private: private:
void doClose() {} void doClose() { _opened = false; }
bool doIsOpened() const { return true; } bool doIsOpened() const { return _opened; }
std::pair<Float, Float> doOpenFile(const std::string&, Float) {
_opened = true;
return {16.0f, 0};
}
Features doFeatures() const { return {}; } Features doFeatures() const { return {}; }
std::unique_ptr<AbstractLayouter> doLayout(const GlyphCache&, Float, const std::string&) { return nullptr; } std::unique_ptr<AbstractLayouter> doLayout(const GlyphCache&, Float, const std::string&) { return nullptr; }
@ -86,7 +90,10 @@ void MagnumFontConverterTest::exportFont() {
CORRADE_ASSERT_UNREACHABLE(); CORRADE_ASSERT_UNREACHABLE();
} }
bool _opened;
} font; } font;
font.openFile({}, {});
/* Create fake cache */ /* Create fake cache */
MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_rg); MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_rg);

33
src/Text/AbstractFont.cpp

@ -34,7 +34,7 @@ namespace Magnum { namespace Text {
AbstractFont::AbstractFont(): _size(0.0f) {} AbstractFont::AbstractFont(): _size(0.0f) {}
AbstractFont::AbstractFont(PluginManager::AbstractManager* manager, std::string plugin): AbstractPlugin(manager, std::move(plugin)), _size(0.0f) {} AbstractFont::AbstractFont(PluginManager::AbstractManager* manager, std::string plugin): AbstractPlugin(manager, std::move(plugin)), _size(0.0f), _lineHeight(0.0f) {}
bool AbstractFont::openData(const std::vector<std::pair<std::string, Containers::ArrayReference<const unsigned char>>>& data, const Float size) { bool AbstractFont::openData(const std::vector<std::pair<std::string, Containers::ArrayReference<const unsigned char>>>& data, const Float size) {
CORRADE_ASSERT(features() & Feature::OpenData, CORRADE_ASSERT(features() & Feature::OpenData,
@ -43,18 +43,19 @@ bool AbstractFont::openData(const std::vector<std::pair<std::string, Containers:
"Text::AbstractFont::openData(): no data passed", false); "Text::AbstractFont::openData(): no data passed", false);
close(); close();
doOpenData(data, size); std::tie(_size, _lineHeight) = doOpenData(data, size);
CORRADE_INTERNAL_ASSERT(isOpened() || (_size == 0.0f && _lineHeight == 0.0f));
return isOpened(); return isOpened();
} }
void AbstractFont::doOpenData(const std::vector<std::pair<std::string, Containers::ArrayReference<const unsigned char>>>& data, const Float size) { std::pair<Float, Float> AbstractFont::doOpenData(const std::vector<std::pair<std::string, Containers::ArrayReference<const unsigned char>>>& data, const Float size) {
CORRADE_ASSERT(!(features() & Feature::MultiFile), CORRADE_ASSERT(!(features() & Feature::MultiFile),
"Text::AbstractFont::openData(): feature advertised but not implemented", ); "Text::AbstractFont::openData(): feature advertised but not implemented", {});
CORRADE_ASSERT(data.size() == 1, CORRADE_ASSERT(data.size() == 1,
"Text::AbstractFont::openData(): expected just one file for single-file format", ); "Text::AbstractFont::openData(): expected just one file for single-file format", {});
close(); close();
doOpenSingleData(data[0].second, size); return doOpenSingleData(data[0].second, size);
} }
bool AbstractFont::openSingleData(const Containers::ArrayReference<const unsigned char> data, const Float size) { bool AbstractFont::openSingleData(const Containers::ArrayReference<const unsigned char> data, const Float size) {
@ -64,29 +65,31 @@ bool AbstractFont::openSingleData(const Containers::ArrayReference<const unsigne
"Text::AbstractFont::openSingleData(): the format is not single-file", false); "Text::AbstractFont::openSingleData(): the format is not single-file", false);
close(); close();
doOpenSingleData(data, size); std::tie(_size, _lineHeight) = doOpenSingleData(data, size);
CORRADE_INTERNAL_ASSERT(isOpened() || (_size == 0.0f && _lineHeight == 0.0f));
return isOpened(); return isOpened();
} }
void AbstractFont::doOpenSingleData(Containers::ArrayReference<const unsigned char>, Float) { std::pair<Float, Float> AbstractFont::doOpenSingleData(Containers::ArrayReference<const unsigned char>, Float) {
CORRADE_ASSERT(false, "Text::AbstractFont::openSingleData(): feature advertised but not implemented", ); CORRADE_ASSERT(false, "Text::AbstractFont::openSingleData(): feature advertised but not implemented", {});
} }
bool AbstractFont::openFile(const std::string& filename, const Float size) { bool AbstractFont::openFile(const std::string& filename, const Float size) {
close(); close();
doOpenFile(filename, size); std::tie(_size, _lineHeight) = doOpenFile(filename, size);
CORRADE_INTERNAL_ASSERT(isOpened() || (_size == 0.0f && _lineHeight == 0.0f));
return isOpened(); return isOpened();
} }
void AbstractFont::doOpenFile(const std::string& filename, const Float size) { std::pair<Float, Float> AbstractFont::doOpenFile(const std::string& filename, const Float size) {
CORRADE_ASSERT(features() & Feature::OpenData && !(features() & Feature::MultiFile), CORRADE_ASSERT(features() & Feature::OpenData && !(features() & Feature::MultiFile),
"Text::AbstractFont::openFile(): not implemented", ); "Text::AbstractFont::openFile(): not implemented", {});
/* Open file */ /* Open file */
std::ifstream in(filename.data(), std::ios::binary); std::ifstream in(filename.data(), std::ios::binary);
if(!in.good()) { if(!in.good()) {
Error() << "Trade::AbstractFont::openFile(): cannot open file" << filename; Error() << "Trade::AbstractFont::openFile(): cannot open file" << filename;
return; return {};
} }
/* Create array to hold file contents */ /* Create array to hold file contents */
@ -98,12 +101,14 @@ void AbstractFont::doOpenFile(const std::string& filename, const Float size) {
in.read(reinterpret_cast<char*>(data.begin()), data.size()); in.read(reinterpret_cast<char*>(data.begin()), data.size());
in.close(); in.close();
doOpenSingleData(data, size); return doOpenSingleData(data, size);
} }
void AbstractFont::close() { void AbstractFont::close() {
if(isOpened()) { if(isOpened()) {
doClose(); doClose();
_size = 0.0f;
_lineHeight = 0.0f;
CORRADE_INTERNAL_ASSERT(!isOpened()); CORRADE_INTERNAL_ASSERT(!isOpened());
} }
} }

42
src/Text/AbstractFont.h

@ -67,7 +67,7 @@ checked by the implementation:
there is any file opened. there is any file opened.
*/ */
class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin { class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
CORRADE_PLUGIN_INTERFACE("cz.mosra.magnum.Text.AbstractFont/0.2.1") CORRADE_PLUGIN_INTERFACE("cz.mosra.magnum.Text.AbstractFont/0.2.2")
public: public:
/** /**
@ -150,6 +150,9 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
/** @brief Font size */ /** @brief Font size */
Float size() const { return _size; } Float size() const { return _size; }
/** @brief Line height */
Float lineHeight() const { return _lineHeight; }
/** /**
* @brief Glyph ID for given character * @brief Glyph ID for given character
* *
@ -199,13 +202,6 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
*/ */
std::unique_ptr<AbstractLayouter> layout(const GlyphCache& cache, Float size, const std::string& text); std::unique_ptr<AbstractLayouter> layout(const GlyphCache& cache, Float size, const std::string& text);
#ifdef DOXYGEN_GENERATING_OUTPUT
private:
#else
protected:
#endif
Float _size;
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
protected: protected:
#else #else
@ -220,22 +216,29 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
/** /**
* @brief Implementation for @ref openData() * @brief Implementation for @ref openData()
* *
* If the plugin doesn't have @ref Feature::MultiFile, default * Return size and line height of opened font on successful opening,
* implementation calls @ref doOpenSingleData(). * zeros otherwise. If the plugin doesn't have @ref Feature::MultiFile,
* default implementation calls @ref doOpenSingleData().
*/ */
virtual void doOpenData(const std::vector<std::pair<std::string, Containers::ArrayReference<const unsigned char>>>& data, Float size); virtual std::pair<Float, Float> doOpenData(const std::vector<std::pair<std::string, Containers::ArrayReference<const unsigned char>>>& data, Float size);
/** @brief Implementation for @ref openSingleData() */ /**
virtual void doOpenSingleData(Containers::ArrayReference<const unsigned char> data, Float size); * @brief Implementation for @ref openSingleData()
*
* Return size and line height of opened font on successful opening,
* zeros otherwise.
*/
virtual std::pair<Float, Float> doOpenSingleData(Containers::ArrayReference<const unsigned char> data, Float size);
/** /**
* @brief Implementation for @ref openFile() * @brief Implementation for @ref openFile()
* *
* If @ref Feature::OpenData is supported and the plugin doesn't have * Return size and line height of opened font on successful opening,
* @ref Feature::MultiFile, default implementation opens the file and * zeros otherwise. If @ref Feature::OpenData is supported and the
* calls @ref doOpenSingleData() with its contents. * plugin doesn't have @ref Feature::MultiFile, default implementation
* opens the file and calls @ref doOpenSingleData() with its contents.
*/ */
virtual void doOpenFile(const std::string& filename, Float size); virtual std::pair<Float, Float> doOpenFile(const std::string& filename, Float size);
/** @brief Implementation for @ref close() */ /** @brief Implementation for @ref close() */
virtual void doClose() = 0; virtual void doClose() = 0;
@ -266,6 +269,11 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
/** @brief Implementation for @ref layout() */ /** @brief Implementation for @ref layout() */
virtual std::unique_ptr<AbstractLayouter> doLayout(const GlyphCache& cache, Float size, const std::string& text) = 0; virtual std::unique_ptr<AbstractLayouter> doLayout(const GlyphCache& cache, Float size, const std::string& text) = 0;
#ifdef DOXYGEN_GENERATING_OUTPUT
private:
#endif
Float _size, _lineHeight;
}; };
CORRADE_ENUMSET_OPERATORS(AbstractFont::Features) CORRADE_ENUMSET_OPERATORS(AbstractFont::Features)

3
src/Text/Test/AbstractFontTest.cpp

@ -55,8 +55,9 @@ class SingleDataFont: public Text::AbstractFont {
bool doIsOpened() const override { return opened; } bool doIsOpened() const override { return opened; }
void doClose() override {} void doClose() override {}
void doOpenSingleData(const Containers::ArrayReference<const unsigned char> data, Float) override { std::pair<Float, Float> doOpenSingleData(const Containers::ArrayReference<const unsigned char> data, Float) override {
opened = (data.size() == 1 && data[0] == 0xa5); opened = (data.size() == 1 && data[0] == 0xa5);
return {};
} }
UnsignedInt doGlyphId(char32_t) override { return 0; } UnsignedInt doGlyphId(char32_t) override { return 0; }

Loading…
Cancel
Save