Commit 759f7f78 authored by Cyril Deguet's avatar Cyril Deguet

* ft2_font.cpp: added a cache for glyphs rendered with freetype, because

  freetype is so slooow: now FT2Font::drawString() is about 100 times faster
  in average !
parent 9e9b39ff
...@@ -33,16 +33,18 @@ ...@@ -33,16 +33,18 @@
FT2Font::FT2Font( intf_thread_t *pIntf, const string &rName, int size ): FT2Font::FT2Font( intf_thread_t *pIntf, const string &rName, int size ):
GenericFont( pIntf ), m_name( rName ), m_buffer( NULL ), m_size( size ), GenericFont( pIntf ), m_name( rName ), m_buffer( NULL ), m_size( size ),
m_lib( NULL ), m_face( NULL ), m_dotGlyph( NULL ) m_lib( NULL ), m_face( NULL )
{ {
} }
FT2Font::~FT2Font() FT2Font::~FT2Font()
{ {
if( m_dotGlyph ) // Clear the glyph cache
GlyphMap_t::iterator iter;
for( iter = m_glyphCache.begin(); iter != m_glyphCache.end(); ++iter )
{ {
FT_Done_Glyph( m_dotGlyph ); FT_Done_Glyph( (*iter).second.m_glyph );
} }
if( m_face ) if( m_face )
{ {
...@@ -130,16 +132,6 @@ bool FT2Font::init() ...@@ -130,16 +132,6 @@ bool FT2Font::init()
m_ascender = m_face->size->metrics.ascender >> 6; m_ascender = m_face->size->metrics.ascender >> 6;
m_descender = m_face->size->metrics.descender >> 6; m_descender = m_face->size->metrics.descender >> 6;
// Render the '.' symbol and compute its size
m_dotIndex = FT_Get_Char_Index( m_face, '.' );
FT_Load_Glyph( m_face, m_dotIndex, FT_LOAD_DEFAULT );
FT_Get_Glyph( m_face->glyph, &m_dotGlyph );
FT_BBox dotSize;
FT_Glyph_Get_CBox( m_dotGlyph, ft_glyph_bbox_pixels, &dotSize );
m_dotWidth = dotSize.xMax - dotSize.xMin;
m_dotAdvance = m_face->glyph->advance.x >> 6;
FT_Glyph_To_Bitmap( &m_dotGlyph, ft_render_mode_normal, NULL, 1 );
return true; return true;
} }
...@@ -147,7 +139,6 @@ bool FT2Font::init() ...@@ -147,7 +139,6 @@ bool FT2Font::init()
GenericBitmap *FT2Font::drawString( const UString &rString, uint32_t color, GenericBitmap *FT2Font::drawString( const UString &rString, uint32_t color,
int maxWidth ) const int maxWidth ) const
{ {
int err;
uint32_t code; uint32_t code;
int n; int n;
int penX = 0; int penX = 0;
...@@ -178,7 +169,7 @@ GenericBitmap *FT2Font::drawString( const UString &rString, uint32_t color, ...@@ -178,7 +169,7 @@ GenericBitmap *FT2Font::drawString( const UString &rString, uint32_t color,
#endif #endif
// Array of glyph bitmaps and position // Array of glyph bitmaps and position
FT_Glyph *glyphs = new FT_Glyph[len]; FT_BitmapGlyphRec **glyphs = new (FT_BitmapGlyphRec*)[len];
int *pos = new int[len]; int *pos = new int[len];
// Does the font support kerning ? // Does the font support kerning ?
...@@ -189,42 +180,36 @@ GenericBitmap *FT2Font::drawString( const UString &rString, uint32_t color, ...@@ -189,42 +180,36 @@ GenericBitmap *FT2Font::drawString( const UString &rString, uint32_t color,
int maxIndex = 0; int maxIndex = 0;
// Position of the first trailing dot // Position of the first trailing dot
int firstDotX = 0; int firstDotX = 0;
/// Get the dot glyph
Glyph_t &dotGlyph = getGlyph( '.' );
// First, render all the glyphs // First, render all the glyphs
for( n = 0; n < len; n++ ) for( n = 0; n < len; n++ )
{ {
code = *(pString++); code = *(pString++);
// Load the glyph // Get the glyph for this character
int glyphIndex = FT_Get_Char_Index( m_face, code ); Glyph_t &glyph = getGlyph( code );
err = FT_Load_Glyph( m_face, glyphIndex, FT_LOAD_DEFAULT ); glyphs[n] = (FT_BitmapGlyphRec*)(glyph.m_glyph);
err = FT_Get_Glyph( m_face->glyph, &glyphs[n] );
// Retrieve kerning distance and move pen position // Retrieve kerning distance and move pen position
if( useKerning && previous && glyphIndex ) if( useKerning && previous && glyph.m_index )
{ {
FT_Vector delta; FT_Vector delta;
FT_Get_Kerning( m_face, previous, glyphIndex, FT_Get_Kerning( m_face, previous, glyph.m_index,
ft_kerning_default, &delta ); ft_kerning_default, &delta );
penX += delta.x >> 6; penX += delta.x >> 6;
} }
// Get the glyph size
FT_BBox glyphSize;
FT_Glyph_Get_CBox( glyphs[n], ft_glyph_bbox_pixels, &glyphSize );
// Render the glyph
err = FT_Glyph_To_Bitmap( &glyphs[n], ft_render_mode_normal, NULL, 1 );
pos[n] = penX; pos[n] = penX;
width1 = penX + glyphSize.xMax - glyphSize.xMin; width1 = penX + glyph.m_size.xMax - glyph.m_size.xMin;
yMin = __MIN( yMin, glyphSize.yMin ); yMin = __MIN( yMin, glyph.m_size.yMin );
yMax = __MAX( yMax, glyphSize.yMax ); yMax = __MAX( yMax, glyph.m_size.yMax );
// Next position // Next position
penX += m_face->glyph->advance.x >> 6; penX += glyph.m_advance;
// Save glyph index // Save glyph index
previous = glyphIndex; previous = glyph.m_index;
if( maxWidth != -1 ) if( maxWidth != -1 )
{ {
...@@ -233,13 +218,15 @@ GenericBitmap *FT2Font::drawString( const UString &rString, uint32_t color, ...@@ -233,13 +218,15 @@ GenericBitmap *FT2Font::drawString( const UString &rString, uint32_t color,
if( useKerning ) if( useKerning )
{ {
FT_Vector delta; FT_Vector delta;
FT_Get_Kerning( m_face, glyphIndex, m_dotIndex, FT_Get_Kerning( m_face, glyph.m_index, dotGlyph.m_index,
ft_kerning_default, &delta ); ft_kerning_default, &delta );
curX += delta.x >> 6; curX += delta.x >> 6;
} }
if( curX + 2 * m_dotAdvance + m_dotWidth < maxWidth ) int dotWidth = 2 * dotGlyph.m_advance +
dotGlyph.m_size.xMax - dotGlyph.m_size.xMin;
if( curX + dotWidth < maxWidth )
{ {
width2 = curX + 2 * m_dotAdvance + m_dotWidth; width2 = curX + dotWidth;
maxIndex++; maxIndex++;
firstDotX = curX; firstDotX = curX;
} }
...@@ -279,21 +266,18 @@ GenericBitmap *FT2Font::drawString( const UString &rString, uint32_t color, ...@@ -279,21 +266,18 @@ GenericBitmap *FT2Font::drawString( const UString &rString, uint32_t color,
FT_BitmapGlyphRec *pBmpGlyph = (FT_BitmapGlyphRec*)glyphs[n]; FT_BitmapGlyphRec *pBmpGlyph = (FT_BitmapGlyphRec*)glyphs[n];
// Draw the glyph on the bitmap // Draw the glyph on the bitmap
pBmp->draw( pBmpGlyph->bitmap, pos[n], yMax - pBmpGlyph->top, color ); pBmp->draw( pBmpGlyph->bitmap, pos[n], yMax - pBmpGlyph->top, color );
// Free the glyph
FT_Done_Glyph( glyphs[n] );
} }
// Draw the trailing dots if the text is truncated // Draw the trailing dots if the text is truncated
if( maxIndex < len ) if( maxIndex < len )
{ {
int penX = firstDotX; int penX = firstDotX;
FT_BitmapGlyphRec *pBmpGlyph = (FT_BitmapGlyphRec*)m_dotGlyph; FT_BitmapGlyphRec *pBmpGlyph = (FT_BitmapGlyphRec*)dotGlyph.m_glyph;
for( n = 0; n < 3; n++ ) for( n = 0; n < 3; n++ )
{ {
// Draw the glyph on the bitmap // Draw the glyph on the bitmap
pBmp->draw( pBmpGlyph->bitmap, penX, yMax - pBmpGlyph->top, pBmp->draw( pBmpGlyph->bitmap, penX, yMax - pBmpGlyph->top,
color ); color );
penX += m_dotAdvance; penX += dotGlyph.m_advance;
} }
} }
...@@ -302,3 +286,30 @@ GenericBitmap *FT2Font::drawString( const UString &rString, uint32_t color, ...@@ -302,3 +286,30 @@ GenericBitmap *FT2Font::drawString( const UString &rString, uint32_t color,
return pBmp; return pBmp;
} }
FT2Font::Glyph_t &FT2Font::getGlyph( uint32_t code ) const
{
// Try to find the glyph in the cache
GlyphMap_t::iterator iter = m_glyphCache.find( code );
if( iter != m_glyphCache.end() )
{
return (*iter).second;
}
else
{
// Add a new glyph in the cache
Glyph_t &glyph = m_glyphCache[code];
// Load and render the glyph
glyph.m_index = FT_Get_Char_Index( m_face, code );
FT_Load_Glyph( m_face, glyph.m_index, FT_LOAD_DEFAULT );
FT_Get_Glyph( m_face->glyph, &glyph.m_glyph );
FT_Glyph_Get_CBox( glyph.m_glyph, ft_glyph_bbox_pixels,
&glyph.m_size );
glyph.m_advance = m_face->glyph->advance.x >> 6;
FT_Glyph_To_Bitmap( &glyph.m_glyph, ft_render_mode_normal, NULL, 1 );
return glyph;
}
}
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include FT_FREETYPE_H #include FT_FREETYPE_H
#include FT_GLYPH_H #include FT_GLYPH_H
#include <string> #include <string>
#include <map>
#include "generic_font.hpp" #include "generic_font.hpp"
...@@ -54,6 +55,15 @@ class FT2Font: public GenericFont ...@@ -54,6 +55,15 @@ class FT2Font: public GenericFont
virtual int getSize() const { return m_height; } virtual int getSize() const { return m_height; }
private: private:
typedef struct
{
FT_Glyph m_glyph;
FT_BBox m_size;
int m_index;
int m_advance;
} Glyph_t;
typedef map<uint32_t,Glyph_t> GlyphMap_t;
/// File name /// File name
const string m_name; const string m_name;
/// Buffer to store the font /// Buffer to store the font
...@@ -66,11 +76,11 @@ class FT2Font: public GenericFont ...@@ -66,11 +76,11 @@ class FT2Font: public GenericFont
FT_Face m_face; FT_Face m_face;
/// Font metrics /// Font metrics
int m_height, m_ascender, m_descender; int m_height, m_ascender, m_descender;
/// Index, glyph, width and advance of the dot symbol /// Glyph cache
int m_dotIndex; mutable GlyphMap_t m_glyphCache;
FT_Glyph m_dotGlyph;
int m_dotWidth; /// Get the glyph corresponding to the given code
int m_dotAdvance; Glyph_t &getGlyph( uint32_t code ) const;
}; };
......
...@@ -416,9 +416,9 @@ unsigned long X11Display::getPixelValue( uint8_t r, uint8_t g, uint8_t b ) ...@@ -416,9 +416,9 @@ unsigned long X11Display::getPixelValue( uint8_t r, uint8_t g, uint8_t b )
const const
{ {
unsigned long value; unsigned long value;
value = ( ((uint32_t)r >> m_redRightShift) << m_redLeftShift ) |
( ((uint32_t)g >> m_greenRightShift) << m_greenLeftShift ) | PUT_PIXEL(value, r, g, b, uint32_t)
( ((uint32_t)b >> m_blueRightShift) << m_blueLeftShift );
if( m_pixelSize == 1 ) if( m_pixelSize == 1 )
{ {
return 255 - value; return 255 - value;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment