00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "ft2_font.hpp"
00026 #include "ft2_bitmap.hpp"
00027 #include "../utils/ustring.hpp"
00028
00029 #ifdef HAVE_FRIBIDI
00030 #include <fribidi/fribidi.h>
00031 #endif
00032
00033
00034 FT2Font::FT2Font( intf_thread_t *pIntf, const string &rName, int size ):
00035 GenericFont( pIntf ), m_name( rName ), m_buffer( NULL ), m_size( size ),
00036 m_lib( NULL ), m_face( NULL )
00037 {
00038 }
00039
00040
00041 FT2Font::~FT2Font()
00042 {
00043
00044 GlyphMap_t::iterator iter;
00045 for( iter = m_glyphCache.begin(); iter != m_glyphCache.end(); ++iter )
00046 {
00047 FT_Done_Glyph( (*iter).second.m_glyph );
00048 }
00049 if( m_face )
00050 {
00051 FT_Done_Face( m_face );
00052 }
00053 if( m_lib )
00054 {
00055 FT_Done_FreeType( m_lib );
00056 }
00057 if( m_buffer )
00058 {
00059 free( m_buffer );
00060 }
00061 }
00062
00063
00064 bool FT2Font::init()
00065 {
00066 int err;
00067
00068
00069 if( FT_Init_FreeType( &m_lib ) )
00070 {
00071 msg_Err( getIntf(), "Failed to initalize libfreetype" );
00072 return false;
00073 }
00074
00075
00076 FILE *file = fopen( m_name.c_str(), "rb" );
00077 if( file )
00078 {
00079 msg_Dbg( getIntf(), "Loading font %s", m_name.c_str() );
00080 }
00081 else
00082 {
00083 msg_Dbg( getIntf(), "Unable to open the font %s", m_name.c_str() );
00084 return false;
00085 }
00086
00087 fseek( file, 0, SEEK_END );
00088 int size = ftell( file );
00089 rewind( file );
00090
00091 m_buffer = malloc( size );
00092 if( !m_buffer )
00093 {
00094 msg_Err( getIntf(), "Not enough memory for the font %s",
00095 m_name.c_str() );
00096 return false;
00097 }
00098
00099 fread( m_buffer, size, 1, file );
00100 fclose( file );
00101
00102
00103 err = FT_New_Memory_Face( m_lib, (const FT_Byte*)m_buffer, size, 0,
00104 &m_face );
00105 if ( err == FT_Err_Unknown_File_Format )
00106 {
00107 msg_Err( getIntf(), "Unsupported font format (%s)", m_name.c_str() );
00108 return false;
00109 }
00110 else if ( err )
00111 {
00112 msg_Err( getIntf(), "Error opening font (%s)", m_name.c_str() );
00113 return false;
00114 }
00115
00116
00117 if( FT_Select_Charmap( m_face, ft_encoding_unicode ) )
00118 {
00119 msg_Err( getIntf(), "Font has no UNICODE table (%s)", m_name.c_str() );
00120 return false;
00121 }
00122
00123
00124 if( FT_Set_Pixel_Sizes( m_face, 0, m_size ) )
00125 {
00126 msg_Warn( getIntf(), "Cannot set a pixel size of %d (%s)", m_size,
00127 m_name.c_str() );
00128 }
00129
00130
00131 m_height = m_face->size->metrics.height >> 6;
00132 m_ascender = m_face->size->metrics.ascender >> 6;
00133 m_descender = m_face->size->metrics.descender >> 6;
00134
00135 return true;
00136 }
00137
00138
00139 GenericBitmap *FT2Font::drawString( const UString &rString, uint32_t color,
00140 int maxWidth ) const
00141 {
00142 uint32_t code;
00143 int n;
00144 int penX = 0;
00145 int width1 = 0, width2 = 0;
00146 int yMin = 0, yMax = 0;
00147 uint32_t *pString = (uint32_t*)rString.u_str();
00148
00149
00150 if( !m_face )
00151 {
00152 return NULL;
00153 }
00154
00155
00156 int len = rString.length();
00157
00158
00159 #ifdef HAVE_FRIBIDI
00160 uint32_t *pFribidiString = NULL;
00161 if( len > 0 )
00162 {
00163 pFribidiString = new uint32_t[len+1];
00164 FriBidiCharType baseDir = FRIBIDI_TYPE_ON;
00165 fribidi_log2vis( (FriBidiChar*)pString, len, &baseDir,
00166 (FriBidiChar*)pFribidiString, 0, 0, 0 );
00167 pString = pFribidiString;
00168 }
00169 #endif
00170
00171
00172 FT_BitmapGlyphRec **glyphs = new FT_BitmapGlyphRec*[len];
00173 int *pos = new int[len];
00174
00175
00176 FT_Bool useKerning = FT_HAS_KERNING( m_face );
00177 int previous = 0;
00178
00179
00180 int maxIndex = 0;
00181
00182 int firstDotX = 0;
00184 Glyph_t &dotGlyph = getGlyph( '.' );
00185
00186
00187 for( n = 0; n < len; n++ )
00188 {
00189 code = *(pString++);
00190
00191 Glyph_t &glyph = getGlyph( code );
00192 glyphs[n] = (FT_BitmapGlyphRec*)(glyph.m_glyph);
00193
00194
00195 if( useKerning && previous && glyph.m_index )
00196 {
00197 FT_Vector delta;
00198 FT_Get_Kerning( m_face, previous, glyph.m_index,
00199 ft_kerning_default, &delta );
00200 penX += delta.x >> 6;
00201 }
00202
00203 pos[n] = penX;
00204 width1 = penX + glyph.m_size.xMax - glyph.m_size.xMin;
00205 yMin = __MIN( yMin, glyph.m_size.yMin );
00206 yMax = __MAX( yMax, glyph.m_size.yMax );
00207
00208
00209 penX += glyph.m_advance;
00210
00211
00212 previous = glyph.m_index;
00213
00214 if( maxWidth != -1 )
00215 {
00216
00217 int curX = penX;
00218 if( useKerning )
00219 {
00220 FT_Vector delta;
00221 FT_Get_Kerning( m_face, glyph.m_index, dotGlyph.m_index,
00222 ft_kerning_default, &delta );
00223 curX += delta.x >> 6;
00224 }
00225 int dotWidth = 2 * dotGlyph.m_advance +
00226 dotGlyph.m_size.xMax - dotGlyph.m_size.xMin;
00227 if( curX + dotWidth < maxWidth )
00228 {
00229 width2 = curX + dotWidth;
00230 maxIndex++;
00231 firstDotX = curX;
00232 }
00233 }
00234 else
00235 {
00236
00237 width2 = width1;
00238 maxIndex++;
00239 }
00240
00241
00242 if( maxWidth != -1 && width1 > maxWidth )
00243 {
00244 break;
00245 }
00246 }
00247
00248 #ifdef HAVE_FRIBIDI
00249 if( len > 0 )
00250 {
00251 delete[] pFribidiString;
00252 }
00253 #endif
00254
00255
00256 yMax = __MAX( yMax, m_ascender );
00257 yMin = __MIN( yMin, m_descender );
00258
00259
00260 FT2Bitmap *pBmp = new FT2Bitmap( getIntf(), __MIN( width1, width2 ),
00261 yMax - yMin );
00262
00263
00264 for( n = 0; n < maxIndex; n++ )
00265 {
00266 FT_BitmapGlyphRec *pBmpGlyph = (FT_BitmapGlyphRec*)glyphs[n];
00267
00268 pBmp->draw( pBmpGlyph->bitmap, pos[n], yMax - pBmpGlyph->top, color );
00269 }
00270
00271 if( maxIndex < len )
00272 {
00273 int penX = firstDotX;
00274 FT_BitmapGlyphRec *pBmpGlyph = (FT_BitmapGlyphRec*)dotGlyph.m_glyph;
00275 for( n = 0; n < 3; n++ )
00276 {
00277
00278 pBmp->draw( pBmpGlyph->bitmap, penX, yMax - pBmpGlyph->top,
00279 color );
00280 penX += dotGlyph.m_advance;
00281 }
00282 }
00283
00284 delete [] glyphs;
00285 delete [] pos;
00286
00287 return pBmp;
00288 }
00289
00290
00291 FT2Font::Glyph_t &FT2Font::getGlyph( uint32_t code ) const
00292 {
00293
00294 GlyphMap_t::iterator iter = m_glyphCache.find( code );
00295 if( iter != m_glyphCache.end() )
00296 {
00297 return (*iter).second;
00298 }
00299 else
00300 {
00301
00302 Glyph_t &glyph = m_glyphCache[code];
00303
00304
00305 glyph.m_index = FT_Get_Char_Index( m_face, code );
00306 FT_Load_Glyph( m_face, glyph.m_index, FT_LOAD_DEFAULT );
00307 FT_Get_Glyph( m_face->glyph, &glyph.m_glyph );
00308 FT_Glyph_Get_CBox( glyph.m_glyph, ft_glyph_bbox_pixels,
00309 &glyph.m_size );
00310 glyph.m_advance = m_face->glyph->advance.x >> 6;
00311 FT_Glyph_To_Bitmap( &glyph.m_glyph, ft_render_mode_normal, NULL, 1 );
00312 return glyph;
00313 }
00314 }
00315