1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2003 the VideoLAN team
7 * Authors: Cyril Deguet <asmax@via.ecp.fr>
8 * Olivier Teulière <ipkiss@via.ecp.fr>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 #include "ft2_font.hpp"
26 #include "ft2_bitmap.hpp"
27 #include "../utils/ustring.hpp"
30 #include <fribidi/fribidi.h>
34 FT2Font::FT2Font( intf_thread_t *pIntf, const string &rName, int size ):
35 GenericFont( pIntf ), m_name( rName ), m_buffer( NULL ), m_size( size ),
36 m_lib( NULL ), m_face( NULL )
43 // Clear the glyph cache
44 GlyphMap_t::iterator iter;
45 for( iter = m_glyphCache.begin(); iter != m_glyphCache.end(); ++iter )
47 FT_Done_Glyph( (*iter).second.m_glyph );
51 FT_Done_Face( m_face );
55 FT_Done_FreeType( m_lib );
68 // Initalise libfreetype
69 if( FT_Init_FreeType( &m_lib ) )
71 msg_Err( getIntf(), "Failed to initalize libfreetype" );
76 FILE *file = fopen( m_name.c_str(), "rb" );
79 msg_Dbg( getIntf(), "Loading font %s", m_name.c_str() );
83 msg_Dbg( getIntf(), "Unable to open the font %s", m_name.c_str() );
87 fseek( file, 0, SEEK_END );
88 int size = ftell( file );
90 // Allocate the buffer
91 m_buffer = malloc( size );
94 msg_Err( getIntf(), "Not enough memory for the font %s",
99 fread( m_buffer, size, 1, file );
102 // Load the font from the buffer
103 err = FT_New_Memory_Face( m_lib, (const FT_Byte*)m_buffer, size, 0,
105 if ( err == FT_Err_Unknown_File_Format )
107 msg_Err( getIntf(), "Unsupported font format (%s)", m_name.c_str() );
112 msg_Err( getIntf(), "Error opening font (%s)", m_name.c_str() );
116 // Select the charset
117 if( FT_Select_Charmap( m_face, ft_encoding_unicode ) )
119 msg_Err( getIntf(), "Font has no UNICODE table (%s)", m_name.c_str() );
123 // Set the pixel size
124 if( FT_Set_Pixel_Sizes( m_face, 0, m_size ) )
126 msg_Warn( getIntf(), "Cannot set a pixel size of %d (%s)", m_size,
130 // Get the font metrucs
131 m_height = m_face->size->metrics.height >> 6;
132 m_ascender = m_face->size->metrics.ascender >> 6;
133 m_descender = m_face->size->metrics.descender >> 6;
139 GenericBitmap *FT2Font::drawString( const UString &rString, uint32_t color,
145 int width1 = 0, width2 = 0;
146 int yMin = 0, yMax = 0;
147 uint32_t *pString = (uint32_t*)rString.u_str();
149 // Check if freetype has been initialized
155 // Get the length of the string
156 int len = rString.length();
158 // Use fribidi if available
160 uint32_t *pFribidiString = NULL;
163 pFribidiString = new uint32_t[len+1];
164 FriBidiCharType baseDir = FRIBIDI_TYPE_ON;
165 fribidi_log2vis( (FriBidiChar*)pString, len, &baseDir,
166 (FriBidiChar*)pFribidiString, 0, 0, 0 );
167 pString = pFribidiString;
171 // Array of glyph bitmaps and position
172 FT_BitmapGlyphRec **glyphs = new FT_BitmapGlyphRec*[len];
173 int *pos = new int[len];
175 // Does the font support kerning ?
176 FT_Bool useKerning = FT_HAS_KERNING( m_face );
179 // Index of the last glyph when the text is truncated with trailing ...
181 // Position of the first trailing dot
183 /// Get the dot glyph
184 Glyph_t &dotGlyph = getGlyph( '.' );
186 // First, render all the glyphs
187 for( n = 0; n < len; n++ )
190 // Get the glyph for this character
191 Glyph_t &glyph = getGlyph( code );
192 glyphs[n] = (FT_BitmapGlyphRec*)(glyph.m_glyph);
194 // Retrieve kerning distance and move pen position
195 if( useKerning && previous && glyph.m_index )
198 FT_Get_Kerning( m_face, previous, glyph.m_index,
199 ft_kerning_default, &delta );
200 penX += delta.x >> 6;
204 width1 = penX + glyph.m_size.xMax - glyph.m_size.xMin;
205 yMin = __MIN( yMin, glyph.m_size.yMin );
206 yMax = __MAX( yMax, glyph.m_size.yMax );
209 penX += glyph.m_advance;
212 previous = glyph.m_index;
216 // Check if the truncated text with the '...' fit in the maxWidth
221 FT_Get_Kerning( m_face, glyph.m_index, dotGlyph.m_index,
222 ft_kerning_default, &delta );
223 curX += delta.x >> 6;
225 int dotWidth = 2 * dotGlyph.m_advance +
226 dotGlyph.m_size.xMax - dotGlyph.m_size.xMin;
227 if( curX + dotWidth < maxWidth )
229 width2 = curX + dotWidth;
241 // Stop here if the text is too large
242 if( maxWidth != -1 && width1 > maxWidth )
251 delete[] pFribidiString;
255 // Adjust the size for vertical padding
256 yMax = __MAX( yMax, m_ascender );
257 yMin = __MIN( yMin, m_descender );
260 FT2Bitmap *pBmp = new FT2Bitmap( getIntf(), __MIN( width1, width2 ),
263 // Draw the glyphs on the bitmap
264 for( n = 0; n < maxIndex; n++ )
266 FT_BitmapGlyphRec *pBmpGlyph = (FT_BitmapGlyphRec*)glyphs[n];
267 // Draw the glyph on the bitmap
268 pBmp->draw( pBmpGlyph->bitmap, pos[n], yMax - pBmpGlyph->top, color );
270 // Draw the trailing dots if the text is truncated
273 int penX = firstDotX;
274 FT_BitmapGlyphRec *pBmpGlyph = (FT_BitmapGlyphRec*)dotGlyph.m_glyph;
275 for( n = 0; n < 3; n++ )
277 // Draw the glyph on the bitmap
278 pBmp->draw( pBmpGlyph->bitmap, penX, yMax - pBmpGlyph->top,
280 penX += dotGlyph.m_advance;
291 FT2Font::Glyph_t &FT2Font::getGlyph( uint32_t code ) const
293 // Try to find the glyph in the cache
294 GlyphMap_t::iterator iter = m_glyphCache.find( code );
295 if( iter != m_glyphCache.end() )
297 return (*iter).second;
301 // Add a new glyph in the cache
302 Glyph_t &glyph = m_glyphCache[code];
304 // Load and render the glyph
305 glyph.m_index = FT_Get_Char_Index( m_face, code );
306 FT_Load_Glyph( m_face, glyph.m_index, FT_LOAD_DEFAULT );
307 FT_Get_Glyph( m_face->glyph, &glyph.m_glyph );
308 FT_Glyph_Get_CBox( glyph.m_glyph, ft_glyph_bbox_pixels,
310 glyph.m_advance = m_face->glyph->advance.x >> 6;
311 FT_Glyph_To_Bitmap( &glyph.m_glyph, ft_render_mode_normal, NULL, 1 );