Browse Source

Text: split out HarfBuzz layouting into new HarfBuzzFont class.

It now allows to transparently select between FreeType and HarfBuzz
layouting. The new class is built only if USE_HARFBUZZ is enabled.
pull/278/head
Vladimír Vondruš 13 years ago
parent
commit
2afda6f34d
  1. 13
      src/Text/CMakeLists.txt
  2. 54
      src/Text/FreeTypeFont.cpp
  3. 21
      src/Text/FreeTypeFont.h
  4. 106
      src/Text/HarfBuzzFont.cpp
  5. 75
      src/Text/HarfBuzzFont.h
  6. 5
      src/Text/Text.h
  7. 5
      src/Text/TextRenderer.h

13
src/Text/CMakeLists.txt

@ -1,11 +1,6 @@
find_package(Freetype REQUIRED)
include_directories(${FREETYPE_INCLUDE_DIRS})
if(USE_HARFBUZZ)
find_package(HarfBuzz REQUIRED)
include_directories(${HARFBUZZ_INCLUDE_DIRS})
endif()
set(MagnumText_SRCS
AbstractFont.cpp
FreeTypeFont.cpp
@ -18,6 +13,14 @@ set(MagnumText_HEADERS
magnumTextVisibility.h)
if(USE_HARFBUZZ)
find_package(HarfBuzz REQUIRED)
include_directories(${HARFBUZZ_INCLUDE_DIRS})
set(MagnumText_SRCS ${MagnumText_SRCS} HarfBuzzFont.cpp)
set(MagnumText_HEADERS ${MagnumText_HEADERS} HarfBuzzFont.h)
endif()
add_library(MagnumText SHARED ${MagnumText_SRCS})
target_link_libraries(MagnumText Magnum MagnumTextureTools ${FREETYPE_LIBRARIES})

54
src/Text/FreeTypeFont.cpp

@ -18,9 +18,6 @@
#include <algorithm>
#include <ft2build.h>
#include FT_FREETYPE_H
#ifdef MAGNUM_USE_HARFBUZZ
#include <hb-ft.h>
#endif
#include <Utility/Unicode.h>
#include "Extensions.h"
@ -35,21 +32,12 @@ namespace {
class FreeTypeLayouter: public AbstractLayouter {
public:
FreeTypeLayouter(FreeTypeFont& font, const Float size, const std::string& text);
~FreeTypeLayouter();
std::tuple<Rectangle, Rectangle, Vector2> renderGlyph(const Vector2& cursorPosition, const UnsignedInt i) override;
private:
#ifdef MAGNUM_USE_HARFBUZZ
const FreeTypeFont& font;
hb_buffer_t* buffer;
hb_glyph_info_t* glyphInfo;
hb_glyph_position_t* glyphPositions;
#else
FreeTypeFont& font;
std::vector<FT_UInt> glyphs;
#endif
const Float size;
};
@ -78,11 +66,6 @@ FreeTypeFont::FreeTypeFont(FreeTypeFontRenderer& renderer, const unsigned char*
void FreeTypeFont::finishConstruction() {
CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Set_Char_Size(_ftFont, 0, _size*64, 100, 100) == 0);
#ifdef MAGNUM_USE_HARFBUZZ
/* Create Harfbuzz font */
_hbFont = hb_ft_font_create(_ftFont, nullptr);
#endif
#ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_rg);
#else
@ -182,9 +165,6 @@ void FreeTypeFont::prerenderDistanceField(const std::string& characters, const V
}
FreeTypeFont::~FreeTypeFont() {
#ifdef MAGNUM_USE_HARFBUZZ
hb_font_destroy(_hbFont);
#endif
FT_Done_Face(_ftFont);
}
@ -203,20 +183,6 @@ AbstractLayouter* FreeTypeFont::layout(const Float size, const std::string& text
namespace {
FreeTypeLayouter::FreeTypeLayouter(FreeTypeFont& 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);
_glyphCount = text.size();
@ -225,38 +191,18 @@ FreeTypeLayouter::FreeTypeLayouter(FreeTypeFont& font, const Float size, const s
std::tie(codepoint, i) = Corrade::Utility::Unicode::nextChar(text, i);
glyphs.push_back(FT_Get_Char_Index(font.font(), codepoint));
}
#endif
}
FreeTypeLayouter::~FreeTypeLayouter() {
#ifdef MAGNUM_USE_HARFBUZZ
/* Destroy HarfBuzz buffer */
hb_buffer_destroy(buffer);
#endif
}
std::tuple<Rectangle, Rectangle, Vector2> FreeTypeLayouter::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 */

21
src/Text/FreeTypeFont.h

@ -31,10 +31,6 @@ struct FT_LibraryRec_;
typedef FT_LibraryRec_* FT_Library;
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 {
@ -148,25 +144,24 @@ class MAGNUM_TEXT_EXPORT FreeTypeFont: public AbstractFont {
*/
const std::tuple<Rectangle, Rectangle>& operator[](char32_t character) const;
/** @brief %Font handle */
#ifdef MAGNUM_USE_HARFBUZZ
inline hb_font_t* font() { return _hbFont; }
#else
/** @brief FreeType font handle */
inline FT_Face font() { return _ftFont; }
#endif
AbstractLayouter* layout(const Float size, const std::string& text) override;
#ifdef DOXYGEN_GENERATING_OUTPUT
private:
#else
protected:
#endif
FT_Face _ftFont;
private:
void MAGNUM_TEXT_LOCAL finishConstruction();
void MAGNUM_TEXT_LOCAL prerenderInternal(const std::string& characters, const Vector2i& atlasSize, const Int radius, Texture2D* output);
std::unordered_map<char32_t, std::tuple<Rectangle, Rectangle>> glyphs;
FT_Face _ftFont;
Float _size;
#ifdef MAGNUM_USE_HARFBUZZ
hb_font_t* _hbFont;
#endif
};
}}

106
src/Text/HarfBuzzFont.cpp

@ -0,0 +1,106 @@
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
#include "HarfBuzzFont.h"
#include <hb-ft.h>
namespace Magnum { namespace Text {
namespace {
class HarfBuzzLayouter: public AbstractLayouter {
public:
HarfBuzzLayouter(HarfBuzzFont& font, const Float size, const std::string& text);
~HarfBuzzLayouter();
std::tuple<Rectangle, Rectangle, Vector2> renderGlyph(const Vector2& cursorPosition, const UnsignedInt i) override;
private:
const HarfBuzzFont& font;
hb_buffer_t* buffer;
hb_glyph_info_t* glyphInfo;
hb_glyph_position_t* glyphPositions;
const Float size;
};
}
HarfBuzzFont::HarfBuzzFont(FreeTypeFontRenderer& renderer, const std::string& fontFile, Float size): FreeTypeFont(renderer, fontFile, size) {
finishConstruction();
}
HarfBuzzFont::HarfBuzzFont(FreeTypeFontRenderer& renderer, const unsigned char* data, std::size_t dataSize, Float size): FreeTypeFont(renderer, data, dataSize, size) {
finishConstruction();
}
void HarfBuzzFont::finishConstruction() {
/* Create Harfbuzz font */
_hbFont = hb_ft_font_create(_ftFont, nullptr);
}
HarfBuzzFont::~HarfBuzzFont() {
hb_font_destroy(_hbFont);
}
AbstractLayouter* HarfBuzzFont::layout(const Float size, const std::string& text) {
return new HarfBuzzLayouter(*this, size, text);
}
namespace {
HarfBuzzLayouter::HarfBuzzLayouter(HarfBuzzFont& font, const Float size, const std::string& text): font(font), size(size) {
/* 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);
}
HarfBuzzLayouter::~HarfBuzzLayouter() {
/* Destroy HarfBuzz buffer */
hb_buffer_destroy(buffer);
}
std::tuple<Rectangle, Rectangle, Vector2> HarfBuzzLayouter::renderGlyph(const Vector2& cursorPosition, const UnsignedInt i) {
/* Position of the texture in the resulting glyph, texture coordinates */
Rectangle texturePosition, textureCoordinates;
std::tie(texturePosition, textureCoordinates) = font[glyphInfo[i].codepoint];
/* 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());
/* 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);
}
}
}}

75
src/Text/HarfBuzzFont.h

@ -0,0 +1,75 @@
#ifndef Magnum_Text_HarfBuzzFont_h
#define Magnum_Text_HarfBuzzFont_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
/** @file
* @brief Class Magnum::Text::HarfBuzzFont
*/
#include "Text/FreeTypeFont.h"
#ifndef DOXYGEN_GENERATING_OUTPUT
struct hb_font_t;
#endif
#ifndef MAGNUM_USE_HARFBUZZ
#error Magnum is not compiled with HarfBuzz support
#endif
namespace Magnum { namespace Text {
/**
@brief HarfBuzz font
Improves FreeTypeFont with [HarfBuzz](http://www.freedesktop.org/wiki/Software/HarfBuzz)
text layouting capabilities, such as kerning, ligatures etc. See FreeTypeFont
class documentation for more information about usage.
*/
class MAGNUM_TEXT_EXPORT HarfBuzzFont: public FreeTypeFont {
public:
/**
* @brief Create font from file
* @param renderer %Font renderer
* @param fontFile %Font file
* @param size %Font size
*/
explicit HarfBuzzFont(FreeTypeFontRenderer& renderer, const std::string& fontFile, Float size);
/**
* @brief Create font from memory
* @param renderer %Font renderer
* @param data %Font data
* @param dataSize %Font data size
* @param size %Font size
*/
explicit HarfBuzzFont(FreeTypeFontRenderer& renderer, const unsigned char* data, std::size_t dataSize, Float size);
~HarfBuzzFont();
/** @brief HarfBuzz font handle */
inline hb_font_t* font() { return _hbFont; }
AbstractLayouter* layout(const Float size, const std::string& text) override;
private:
void MAGNUM_TEXT_LOCAL finishConstruction();
hb_font_t* _hbFont;
};
}}
#endif

5
src/Text/Text.h

@ -21,6 +21,8 @@
#include "Types.h"
#include "magnumConfigure.h"
namespace Magnum { namespace Text {
class AbstractFont;
@ -28,6 +30,9 @@ class AbstractLayouter;
class FreeTypeFontRenderer;
class FreeTypeFont;
#ifdef MAGNUM_USE_HARFBUZZ
class HarfBuzzFont;
#endif
class AbstractTextRenderer;
template<UnsignedInt> class TextRenderer;

5
src/Text/TextRenderer.h

@ -121,9 +121,8 @@ class MAGNUM_TEXT_EXPORT AbstractTextRenderer {
/**
@brief %Text renderer
Lays out the text into mesh using [HarfBuzz](http://www.freedesktop.org/wiki/Software/HarfBuzz)
library. Use of ligatures, kerning etc. depends on features supported by
particular font. See also Font.
Lays out the text into mesh using given Font. Use of ligatures, kerning etc.
depends on features supported by particular font and its layouter.
@section TextRenderer-usage Usage

Loading…
Cancel
Save