skins2: fix RadialSlider
[vlc/asuraparaju-public.git] / modules / gui / skins2 / src / ft2_font.cpp
blob1fad1e058170b4f8cfcd28003646730b4241bcba
1 /*****************************************************************************
2 * ft2_font.cpp
3 *****************************************************************************
4 * Copyright (C) 2003 the VideoLAN team
5 * $Id$
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 <errno.h>
26 #include "ft2_font.hpp"
27 #include "ft2_bitmap.hpp"
28 #include "ft2_err.h"
29 #include "../utils/ustring.hpp"
31 #ifdef HAVE_FRIBIDI
32 #include <fribidi/fribidi.h>
33 #endif
36 FT2Font::FT2Font( intf_thread_t *pIntf, const string &rName, int size ):
37 GenericFont( pIntf ), m_name( rName ), m_buffer( NULL ), m_size( size ),
38 m_lib( NULL ), m_face( NULL )
43 FT2Font::~FT2Font()
45 GlyphMap_t::iterator iter;
46 for( iter = m_glyphCache.begin(); iter != m_glyphCache.end(); ++iter )
47 FT_Done_Glyph( (*iter).second.m_glyph );
48 if( m_face ) FT_Done_Face( m_face );
49 if( m_lib ) FT_Done_FreeType( m_lib );
50 delete[] m_buffer;
54 bool FT2Font::init()
56 unsigned err;
58 if( err = FT_Init_FreeType( &m_lib ) )
60 msg_Err( getIntf(), "failed to initialize freetype (%s)",
61 ft2_strerror( err ) );
62 return false;
65 FILE *file = fopen( m_name.c_str(), "rb" );
66 if( !file )
68 msg_Dbg( getIntf(), "failed to open font %s (%s)",
69 m_name.c_str(), strerror(errno) );
70 return false;
72 msg_Dbg( getIntf(), "loading font %s", m_name.c_str() );
74 fseek( file, 0, SEEK_END );
75 long size = ftell( file );
76 rewind( file );
78 if( -1==size )
80 msg_Dbg( getIntf(), "fseek loading font %s (%s)",
81 m_name.c_str(), strerror(errno) );
82 fclose( file );
83 return false;
86 m_buffer = new (std::nothrow) char[size];
87 if( !m_buffer )
89 fclose( file );
90 return false;
93 fread( m_buffer, size, 1, file );
94 fclose( file );
97 err = FT_New_Memory_Face( m_lib, (const FT_Byte*)m_buffer, size, 0,
98 &m_face );
99 if ( err == FT_Err_Unknown_File_Format )
101 msg_Err( getIntf(), "unsupported font format (%s)", m_name.c_str() );
102 return false;
104 else if ( err )
106 msg_Err( getIntf(), "error opening font %s (%s)",
107 m_name.c_str(), ft2_strerror(err) );
108 return false;
111 // Select the charset
112 if( err = FT_Select_Charmap( m_face, ft_encoding_unicode ) )
114 msg_Err( getIntf(), "font %s has no UNICODE table (%s)",
115 m_name.c_str(), ft2_strerror(err) );
116 return false;
119 // Set the pixel size
120 if( err = FT_Set_Pixel_Sizes( m_face, 0, m_size ) )
122 msg_Warn( getIntf(), "cannot set a pixel size of %d for %s (%s)",
123 m_size, m_name.c_str(), ft2_strerror(err) );
126 // Get the font metrucs
127 m_height = m_face->size->metrics.height >> 6;
128 m_ascender = m_face->size->metrics.ascender >> 6;
129 m_descender = m_face->size->metrics.descender >> 6;
131 return true;
135 GenericBitmap *FT2Font::drawString( const UString &rString, uint32_t color,
136 int maxWidth ) const
138 uint32_t code;
139 int n;
140 int penX = 0;
141 int width1 = 0, width2 = 0;
142 int yMin = 0, yMax = 0;
143 uint32_t *pString = (uint32_t*)rString.u_str();
145 // Check if freetype has been initialized
146 if( !m_face )
148 return NULL;
151 // Get the length of the string
152 int len = rString.length();
154 // Use fribidi if available
155 #ifdef HAVE_FRIBIDI
156 uint32_t *pFribidiString = NULL;
157 if( len > 0 )
159 pFribidiString = new uint32_t[len+1];
160 FriBidiCharType baseDir = FRIBIDI_TYPE_ON;
161 fribidi_log2vis( (FriBidiChar*)pString, len, &baseDir,
162 (FriBidiChar*)pFribidiString, 0, 0, 0 );
163 pString = pFribidiString;
165 #endif
167 // Array of glyph bitmaps and position
168 FT_BitmapGlyphRec **glyphs = new FT_BitmapGlyphRec*[len];
169 int *pos = new int[len];
171 // Does the font support kerning ?
172 FT_Bool useKerning = FT_HAS_KERNING( m_face );
173 int previous = 0;
175 // Index of the last glyph when the text is truncated with trailing ...
176 int maxIndex = 0;
177 // Position of the first trailing dot
178 int firstDotX = 0;
179 /// Get the dot glyph
180 Glyph_t &dotGlyph = getGlyph( '.' );
182 // First, render all the glyphs
183 for( n = 0; n < len; n++ )
185 code = *(pString++);
186 // Get the glyph for this character
187 Glyph_t &glyph = getGlyph( code );
188 glyphs[n] = (FT_BitmapGlyphRec*)(glyph.m_glyph);
190 // Retrieve kerning distance and move pen position
191 if( useKerning && previous && glyph.m_index )
193 FT_Vector delta;
194 FT_Get_Kerning( m_face, previous, glyph.m_index,
195 ft_kerning_default, &delta );
196 penX += delta.x >> 6;
199 pos[n] = penX;
200 width1 = penX + glyph.m_size.xMax - glyph.m_size.xMin;
201 yMin = __MIN( yMin, glyph.m_size.yMin );
202 yMax = __MAX( yMax, glyph.m_size.yMax );
204 // Next position
205 penX += glyph.m_advance;
207 // Save glyph index
208 previous = glyph.m_index;
210 if( maxWidth != -1 )
212 // Check if the truncated text with the '...' fit in the maxWidth
213 int curX = penX;
214 if( useKerning )
216 FT_Vector delta;
217 FT_Get_Kerning( m_face, glyph.m_index, dotGlyph.m_index,
218 ft_kerning_default, &delta );
219 curX += delta.x >> 6;
221 int dotWidth = 2 * dotGlyph.m_advance +
222 dotGlyph.m_size.xMax - dotGlyph.m_size.xMin;
223 if( curX + dotWidth < maxWidth )
225 width2 = curX + dotWidth;
226 maxIndex++;
227 firstDotX = curX;
230 else
232 // No check
233 width2 = width1;
234 maxIndex++;
237 // Stop here if the text is too large
238 if( maxWidth != -1 && width1 > maxWidth )
240 break;
244 #ifdef HAVE_FRIBIDI
245 if( len > 0 )
247 delete[] pFribidiString;
249 #endif
251 // Adjust the size for vertical padding
252 yMax = __MAX( yMax, m_ascender );
253 yMin = __MIN( yMin, m_descender );
255 // Create the bitmap
256 FT2Bitmap *pBmp = new FT2Bitmap( getIntf(), __MIN( width1, width2 ),
257 yMax - yMin );
259 // Draw the glyphs on the bitmap
260 for( n = 0; n < maxIndex; n++ )
262 FT_BitmapGlyphRec *pBmpGlyph = (FT_BitmapGlyphRec*)glyphs[n];
263 // Draw the glyph on the bitmap
264 pBmp->draw( pBmpGlyph->bitmap, pos[n], yMax - pBmpGlyph->top, color );
266 // Draw the trailing dots if the text is truncated
267 if( maxIndex < len )
269 int penX = firstDotX;
270 FT_BitmapGlyphRec *pBmpGlyph = (FT_BitmapGlyphRec*)dotGlyph.m_glyph;
271 for( n = 0; n < 3; n++ )
273 // Draw the glyph on the bitmap
274 pBmp->draw( pBmpGlyph->bitmap, penX, yMax - pBmpGlyph->top,
275 color );
276 penX += dotGlyph.m_advance;
280 delete [] glyphs;
281 delete [] pos;
283 return pBmp;
287 FT2Font::Glyph_t &FT2Font::getGlyph( uint32_t code ) const
289 // Try to find the glyph in the cache
290 GlyphMap_t::iterator iter = m_glyphCache.find( code );
291 if( iter != m_glyphCache.end() )
293 return (*iter).second;
295 else
297 // Add a new glyph in the cache
298 Glyph_t &glyph = m_glyphCache[code];
300 // Load and render the glyph
301 glyph.m_index = FT_Get_Char_Index( m_face, code );
302 FT_Load_Glyph( m_face, glyph.m_index, FT_LOAD_DEFAULT );
303 FT_Get_Glyph( m_face->glyph, &glyph.m_glyph );
304 FT_Glyph_Get_CBox( glyph.m_glyph, ft_glyph_bbox_pixels,
305 &glyph.m_size );
306 glyph.m_advance = m_face->glyph->advance.x >> 6;
307 FT_Glyph_To_Bitmap( &glyph.m_glyph, ft_render_mode_normal, NULL, 1 );
308 return glyph;