1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2003 VideoLAN
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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 #include "ft2_font.hpp"
26 #include "ft2_bitmap.hpp"
27 #include "../utils/ustring.hpp"
30 FT2Font::FT2Font( intf_thread_t *pIntf, const string &rName, int size ):
31 GenericFont( pIntf ), m_name( rName ), m_buffer( NULL ), m_size( size ),
32 m_lib( NULL ), m_face( NULL ), m_dotGlyph( NULL )
41 FT_Done_Glyph( m_dotGlyph );
45 FT_Done_Face( m_face );
49 FT_Done_FreeType( m_lib );
62 // Initalise libfreetype
63 if( FT_Init_FreeType( &m_lib ) )
65 msg_Err( getIntf(), "Failed to initalize libfreetype" );
70 FILE *file = fopen( m_name.c_str(), "rb" );
73 msg_Dbg( getIntf(), "Loading font %s", m_name.c_str() );
77 msg_Dbg( getIntf(), "Unable to open the font %s", m_name.c_str() );
81 fseek( file, 0, SEEK_END );
82 int size = ftell( file );
84 // Allocate the buffer
85 m_buffer = malloc( size );
88 msg_Err( getIntf(), "Not enough memory for the font %s",
93 fread( m_buffer, size, 1, file );
96 // Load the font from the buffer
97 err = FT_New_Memory_Face( m_lib, (const FT_Byte*)m_buffer, size, 0,
99 if ( err == FT_Err_Unknown_File_Format )
101 msg_Err( getIntf(), "Unsupported font format (%s)", m_name.c_str() );
106 msg_Err( getIntf(), "Error opening font (%s)", m_name.c_str() );
110 // Select the charset
111 if( FT_Select_Charmap( m_face, ft_encoding_unicode ) )
113 msg_Err( getIntf(), "Font has no UNICODE table (%s)", m_name.c_str() );
117 // Set the pixel size
118 if( FT_Set_Pixel_Sizes( m_face, 0, m_size ) )
120 msg_Warn( getIntf(), "Cannot set a pixel size of %d (%s)", m_size,
124 // Get the font metrucs
125 m_height = m_face->size->metrics.height >> 6;
126 m_ascender = m_face->size->metrics.ascender >> 6;
127 m_descender = m_face->size->metrics.descender >> 6;
129 // Render the '.' symbol and compute its size
130 m_dotIndex = FT_Get_Char_Index( m_face, '.' );
131 FT_Load_Glyph( m_face, m_dotIndex, FT_LOAD_DEFAULT );
132 FT_Get_Glyph( m_face->glyph, &m_dotGlyph );
134 FT_Glyph_Get_CBox( m_dotGlyph, ft_glyph_bbox_pixels, &dotSize );
135 m_dotWidth = dotSize.xMax - dotSize.xMin;
136 m_dotAdvance = m_face->glyph->advance.x >> 6;
137 FT_Glyph_To_Bitmap( &m_dotGlyph, ft_render_mode_normal, NULL, 1 );
143 GenericBitmap *FT2Font::drawString( const UString &rString, uint32_t color,
150 int width1 = 0, width2 = 0;
151 int yMin = 0, yMax = 0;
152 uint32_t *pString = (uint32_t*)rString.u_str();
154 // Check if freetype has been initialized
160 // Get the length of the string
161 int len = rString.length();
163 // Array of glyph bitmaps and position
164 FT_Glyph *glyphs = new FT_Glyph[len];
165 int *pos = new int[len];
167 // Does the font support kerning ?
168 FT_Bool useKerning = FT_HAS_KERNING( m_face );
171 // Index of the last glyph when the text is truncated with trailing ...
173 // Position of the first trailing dot
176 // First, render all the glyphs
177 for( n = 0; n < len; n++ )
181 int glyphIndex = FT_Get_Char_Index( m_face, code );
182 err = FT_Load_Glyph( m_face, glyphIndex, FT_LOAD_DEFAULT );
183 err = FT_Get_Glyph( m_face->glyph, &glyphs[n] );
185 // Retrieve kerning distance and move pen position
186 if( useKerning && previous && glyphIndex )
189 FT_Get_Kerning( m_face, previous, glyphIndex,
190 ft_kerning_default, &delta );
191 penX += delta.x >> 6;
194 // Get the glyph size
196 FT_Glyph_Get_CBox( glyphs[n], ft_glyph_bbox_pixels, &glyphSize );
199 err = FT_Glyph_To_Bitmap( &glyphs[n], ft_render_mode_normal, NULL, 1 );
202 width1 = penX + glyphSize.xMax - glyphSize.xMin;
203 yMin = __MIN( yMin, glyphSize.yMin );
204 yMax = __MAX( yMax, glyphSize.yMax );
207 penX += m_face->glyph->advance.x >> 6;
210 previous = glyphIndex;
214 // Check if the truncated text with the '...' fit in the maxWidth
219 FT_Get_Kerning( m_face, glyphIndex, m_dotIndex,
220 ft_kerning_default, &delta );
221 curX += delta.x >> 6;
223 if( curX + 2 * m_dotAdvance + m_dotWidth < maxWidth )
225 width2 = curX + 2 * m_dotAdvance + m_dotWidth;
237 // Stop here if the text is too large
238 if( maxWidth != -1 && width1 > maxWidth )
244 // Adjust the size for vertical padding
245 yMax = __MAX( yMax, m_ascender );
246 yMin = __MIN( yMin, m_descender );
249 FT2Bitmap *pBmp = new FT2Bitmap( getIntf(), __MIN( width1, width2 ),
252 // Draw the glyphs on the bitmap
253 for( n = 0; n < maxIndex; n++ )
255 FT_BitmapGlyphRec *pBmpGlyph = (FT_BitmapGlyphRec*)glyphs[n];
256 // Draw the glyph on the bitmap
257 pBmp->draw( pBmpGlyph->bitmap, pos[n], yMax - pBmpGlyph->top, color );
260 FT_Done_Glyph( glyphs[n] );
262 // Draw the trailing dots if the text is truncated
265 int penX = firstDotX;
266 FT_BitmapGlyphRec *pBmpGlyph = (FT_BitmapGlyphRec*)m_dotGlyph;
267 for( n = 0; n < 3; n++ )
269 // Draw the glyph on the bitmap
270 pBmp->draw( pBmpGlyph->bitmap, penX, yMax - pBmpGlyph->top,
272 penX += m_dotAdvance;