Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

ft2_font.cpp

00001 /*****************************************************************************
00002  * ft2_font.cpp
00003  *****************************************************************************
00004  * Copyright (C) 2003 the VideoLAN team
00005  * $Id: ft2_font.cpp 11664 2005-07-09 06:17:09Z courmisch $
00006  *
00007  * Authors: Cyril Deguet     <[email protected]>
00008  *          Olivier Teulière <[email protected]>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
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     // Clear the glyph cache
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     // Initalise libfreetype
00069     if( FT_Init_FreeType( &m_lib ) )
00070     {
00071         msg_Err( getIntf(), "Failed to initalize libfreetype" );
00072         return false;
00073     }
00074 
00075     // Open the font
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     // Get the file size
00087     fseek( file, 0, SEEK_END );
00088     int size = ftell( file );
00089     rewind( file );
00090     // Allocate the buffer
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     // Read the font data
00099     fread( m_buffer, size, 1, file );
00100     fclose( file );
00101 
00102     // Load the font from the buffer
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     // Select the charset
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     // Set the pixel size
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     // Get the font metrucs
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     // Check if freetype has been initialized
00150     if( !m_face )
00151     {
00152         return NULL;
00153     }
00154 
00155     // Get the length of the string
00156     int len = rString.length();
00157 
00158     // Use fribidi if available
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     // Array of glyph bitmaps and position
00172     FT_BitmapGlyphRec **glyphs = new FT_BitmapGlyphRec*[len];
00173     int *pos = new int[len];
00174 
00175     // Does the font support kerning ?
00176     FT_Bool useKerning = FT_HAS_KERNING( m_face );
00177     int previous = 0;
00178 
00179     // Index of the last glyph when the text is truncated with trailing ...
00180     int maxIndex = 0;
00181     // Position of the first trailing dot
00182     int firstDotX = 0;
00184     Glyph_t &dotGlyph = getGlyph( '.' );
00185 
00186     // First, render all the glyphs
00187     for( n = 0; n < len; n++ )
00188     {
00189         code = *(pString++);
00190         // Get the glyph for this character
00191         Glyph_t &glyph = getGlyph( code );
00192         glyphs[n] = (FT_BitmapGlyphRec*)(glyph.m_glyph);
00193 
00194         // Retrieve kerning distance and move pen position
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         // Next position
00209         penX += glyph.m_advance;
00210 
00211         // Save glyph index
00212         previous = glyph.m_index;
00213 
00214         if( maxWidth != -1 )
00215         {
00216             // Check if the truncated text with the '...' fit in the maxWidth
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             // No check
00237             width2 = width1;
00238             maxIndex++;
00239         }
00240 
00241         // Stop here if the text is too large
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     // Adjust the size for vertical padding
00256     yMax = __MAX( yMax, m_ascender );
00257     yMin = __MIN( yMin, m_descender );
00258 
00259     // Create the bitmap
00260     FT2Bitmap *pBmp = new FT2Bitmap( getIntf(), __MIN( width1, width2 ),
00261                                      yMax - yMin );
00262 
00263     // Draw the glyphs on the bitmap
00264     for( n = 0; n < maxIndex; n++ )
00265     {
00266         FT_BitmapGlyphRec *pBmpGlyph = (FT_BitmapGlyphRec*)glyphs[n];
00267         // Draw the glyph on the bitmap
00268         pBmp->draw( pBmpGlyph->bitmap, pos[n], yMax - pBmpGlyph->top, color );
00269     }
00270     // Draw the trailing dots if the text is truncated
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             // Draw the glyph on the bitmap
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     // Try to find the glyph in the cache
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         // Add a new glyph in the cache
00302         Glyph_t &glyph = m_glyphCache[code];
00303 
00304         // Load and render the glyph
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 

Generated on Tue Dec 20 10:14:42 2005 for vlc-0.8.4a by  doxygen 1.4.2