diff --git a/src/Text/Font.cpp b/src/Text/Font.cpp index f99416904..30c03f11d 100644 --- a/src/Text/Font.cpp +++ b/src/Text/Font.cpp @@ -197,4 +197,68 @@ const std::tuple& Font::operator[](char32_t character) con return it->second; } +TextLayouter::TextLayouter(Font& font, const Float size, const std::string& text): font(font), size(size) { + #ifdef MAGNUM_USE_HARFBUZZ + /* Prepare HarfBuzz buffer */ + buffer = hb_buffer_create(); + hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); + hb_buffer_set_script(buffer, HB_SCRIPT_LATIN); + hb_buffer_set_language(buffer, hb_language_from_string("en", 2)); + + /* Layout the text */ + hb_buffer_add_utf8(buffer, text.c_str(), -1, 0, -1); + hb_shape(font.font(), buffer, nullptr, 0); + + glyphInfo = hb_buffer_get_glyph_infos(buffer, &_glyphCount); + glyphPositions = hb_buffer_get_glyph_positions(buffer, &_glyphCount); + #else + /* Get glyph codes from characters */ + glyphs.reserve(text.size()+1); + for(std::size_t i = 0; i != text.size(); ) { + UnsignedInt codepoint; + std::tie(codepoint, i) = Corrade::Utility::Unicode::nextChar(text, i); + glyphs.push_back(FT_Get_Char_Index(font.font(), codepoint)); + } + #endif +} + +TextLayouter::~TextLayouter() { + #ifdef MAGNUM_USE_HARFBUZZ + /* Destroy HarfBuzz buffer */ + hb_buffer_destroy(buffer); + #endif +} + +std::tuple TextLayouter::renderGlyph(const Vector2& cursorPosition, const UnsignedInt i) { + /* Position of the texture in the resulting glyph, texture coordinates */ + Rectangle texturePosition, textureCoordinates; + #ifdef MAGNUM_USE_HARFBUZZ + std::tie(texturePosition, textureCoordinates) = font[glyphInfo[i].codepoint]; + #else + std::tie(texturePosition, textureCoordinates) = font[glyphs[i]]; + #endif + + #ifdef MAGNUM_USE_HARFBUZZ + /* Glyph offset and advance to next glyph in normalized coordinates */ + Vector2 offset = Vector2(glyphPositions[i].x_offset, + glyphPositions[i].y_offset)/(64*font.size()); + Vector2 advance = Vector2(glyphPositions[i].x_advance, + glyphPositions[i].y_advance)/(64*font.size()); + #else + /* Load glyph */ + CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Load_Glyph(font.font(), glyphs[i], FT_LOAD_DEFAULT) == 0); + const FT_GlyphSlot slot = font.font()->glyph; + Vector2 offset = Vector2(0, 0); /** @todo really? */ + Vector2 advance = Vector2(slot->advance.x, slot->advance.y)/(64*font.size()); + #endif + + /* Absolute quad position, composed from cursor position, glyph offset + and texture position, denormalized to requested text size */ + Rectangle quadPosition = Rectangle::fromSize( + (cursorPosition + offset + Vector2(texturePosition.left(), texturePosition.bottom()))*size, + texturePosition.size()*size); + + return std::make_tuple(quadPosition, textureCoordinates, advance); +} + }} diff --git a/src/Text/Font.h b/src/Text/Font.h index 82592e9b0..a864c01ee 100644 --- a/src/Text/Font.h +++ b/src/Text/Font.h @@ -16,7 +16,7 @@ */ /** @file - * @brief Class Magnum::Text::Font + * @brief Class Magnum::Text::Font, Magnum::Text::TextLayouter */ #include @@ -31,6 +31,9 @@ struct FT_FaceRec_; typedef FT_FaceRec_* FT_Face; struct hb_font_t; +struct hb_buffer_t; +struct hb_glyph_info_t; +struct hb_glyph_position_t; #endif namespace Magnum { namespace Text { @@ -159,6 +162,57 @@ class MAGNUM_TEXT_EXPORT Font { #endif }; +/** +@brief %Text layouter + +Provides low-level text rendering using Font, used internally in TextRenderer. +*/ +class TextLayouter { + public: + /** + * @brief Constructor + * @param font %Font + * @param size %Font size + * @param text Text to layout + */ + TextLayouter(Font& font, const Float size, const std::string& text); + + ~TextLayouter(); + + /** @brief Count of glyphs in laid out text */ + inline UnsignedInt glyphCount() { + #ifdef MAGNUM_USE_HARFBUZZ + return _glyphCount; + #else + return glyphs.size(); + #endif + } + + /** + * @brief Render glyph + * @param i Glyph index + * @param cursorPosition Cursor position + * + * Returns quad position, texture coordinates and advance to next + * glyph. + */ + std::tuple renderGlyph(const Vector2& cursorPosition, const UnsignedInt i); + + private: + #ifdef MAGNUM_USE_HARFBUZZ + const Font& font; + hb_buffer_t* buffer; + hb_glyph_info_t* glyphInfo; + hb_glyph_position_t* glyphPositions; + UnsignedInt _glyphCount; + #else + Font& font; + std::vector glyphs; + #endif + + const Float size; +}; + }} #endif diff --git a/src/Text/Text.h b/src/Text/Text.h index 08b708df2..03e126beb 100644 --- a/src/Text/Text.h +++ b/src/Text/Text.h @@ -25,6 +25,7 @@ namespace Magnum { namespace Text { class Font; class FontRenderer; +class TextLayouter; class AbstractTextRenderer; template class TextRenderer; diff --git a/src/Text/TextRenderer.cpp b/src/Text/TextRenderer.cpp index 634e90244..218fa0a77 100644 --- a/src/Text/TextRenderer.cpp +++ b/src/Text/TextRenderer.cpp @@ -15,14 +15,6 @@ #include "TextRenderer.h" -#ifdef MAGNUM_USE_HARFBUZZ -#include -#else -#include -#include FT_FREETYPE_H -#include -#endif - #include "Context.h" #include "Extensions.h" #include "Mesh.h" @@ -33,101 +25,6 @@ namespace Magnum { namespace Text { namespace { -class TextLayouter { - public: - TextLayouter(Font& font, const Float size, const std::string& text); - - ~TextLayouter(); - - inline UnsignedInt glyphCount() { - #ifdef MAGNUM_USE_HARFBUZZ - return _glyphCount; - #else - return glyphs.size(); - #endif - } - - std::tuple renderGlyph(const Vector2& cursorPosition, const UnsignedInt i); - - private: - #ifdef MAGNUM_USE_HARFBUZZ - const Font& font; - hb_buffer_t* buffer; - hb_glyph_info_t* glyphInfo; - hb_glyph_position_t* glyphPositions; - UnsignedInt _glyphCount; - #else - Font& font; - std::vector glyphs; - #endif - - const Float size; -}; - -TextLayouter::TextLayouter(Font& font, const Float size, const std::string& text): font(font), size(size) { - #ifdef MAGNUM_USE_HARFBUZZ - /* Prepare HarfBuzz buffer */ - buffer = hb_buffer_create(); - hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); - hb_buffer_set_script(buffer, HB_SCRIPT_LATIN); - hb_buffer_set_language(buffer, hb_language_from_string("en", 2)); - - /* Layout the text */ - hb_buffer_add_utf8(buffer, text.c_str(), -1, 0, -1); - hb_shape(font.font(), buffer, nullptr, 0); - - glyphInfo = hb_buffer_get_glyph_infos(buffer, &_glyphCount); - glyphPositions = hb_buffer_get_glyph_positions(buffer, &_glyphCount); - #else - /* Get glyph codes from characters */ - glyphs.reserve(text.size()+1); - for(std::size_t i = 0; i != text.size(); ) { - UnsignedInt codepoint; - std::tie(codepoint, i) = Corrade::Utility::Unicode::nextChar(text, i); - glyphs.push_back(FT_Get_Char_Index(font.font(), codepoint)); - } - #endif -} - -TextLayouter::~TextLayouter() { - #ifdef MAGNUM_USE_HARFBUZZ - /* Destroy HarfBuzz buffer */ - hb_buffer_destroy(buffer); - #endif -} - -std::tuple TextLayouter::renderGlyph(const Vector2& cursorPosition, const UnsignedInt i) { - /* Position of the texture in the resulting glyph, texture coordinates */ - Rectangle texturePosition, textureCoordinates; - #ifdef MAGNUM_USE_HARFBUZZ - std::tie(texturePosition, textureCoordinates) = font[glyphInfo[i].codepoint]; - #else - std::tie(texturePosition, textureCoordinates) = font[glyphs[i]]; - #endif - - #ifdef MAGNUM_USE_HARFBUZZ - /* Glyph offset and advance to next glyph in normalized coordinates */ - Vector2 offset = Vector2(glyphPositions[i].x_offset, - glyphPositions[i].y_offset)/(64*font.size()); - Vector2 advance = Vector2(glyphPositions[i].x_advance, - glyphPositions[i].y_advance)/(64*font.size()); - #else - /* Load glyph */ - CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Load_Glyph(font.font(), glyphs[i], FT_LOAD_DEFAULT) == 0); - const FT_GlyphSlot slot = font.font()->glyph; - Vector2 offset = Vector2(0, 0); /** @todo really? */ - Vector2 advance = Vector2(slot->advance.x, slot->advance.y)/(64*font.size()); - #endif - - /* Absolute quad position, composed from cursor position, glyph offset - and texture position, denormalized to requested text size */ - Rectangle quadPosition = Rectangle::fromSize( - (cursorPosition + offset + Vector2(texturePosition.left(), texturePosition.bottom()))*size, - texturePosition.size()*size); - - return std::make_tuple(quadPosition, textureCoordinates, advance); -} - template void createIndices(void* output, const UnsignedInt glyphCount) { T* const out = reinterpret_cast(output); for(UnsignedInt i = 0; i != glyphCount; ++i) {