]> git.sesse.net Git - vlc/blob - modules/gui/skins2/src/ft2_font.cpp
ae8ab9ea9c373f77f837029a2d93f9bd7f1abbe3
[vlc] / modules / gui / skins2 / src / ft2_font.cpp
1 /*****************************************************************************
2  * ft2_font.cpp
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: ft2_font.cpp,v 1.2 2004/02/27 13:24:12 gbazin Exp $
6  *
7  * Authors: Cyril Deguet     <asmax@via.ecp.fr>
8  *          Olivier Teulière <ipkiss@via.ecp.fr>
9  *
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.
14  *
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.
19  *
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  *****************************************************************************/
24
25 #include "ft2_font.hpp"
26 #include "ft2_bitmap.hpp"
27 #include "../utils/ustring.hpp"
28
29
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 {
33 }
34
35
36 FT2Font::~FT2Font()
37 {
38
39     FT_Done_Glyph( m_dotGlyph );
40     FT_Done_Face( m_face );
41     FT_Done_FreeType( m_lib );
42     if( m_buffer )
43     {
44         free( m_buffer );
45     }
46 }
47
48
49 bool FT2Font::init()
50 {
51     int err;
52
53     // Initalise libfreetype
54     if( FT_Init_FreeType( &m_lib ) )
55     {
56         msg_Err( getIntf(), "Failed to initalize libfreetype" );
57         return false;
58     }
59
60     // Open the font
61     FILE *file = fopen( m_name.c_str(), "rb" );
62     if( !file )
63     {
64         msg_Err( getIntf(), "Unable to open the font %s", m_name.c_str() );
65         return false;
66     }
67     // Get the file size
68     fseek( file, 0, SEEK_END );
69     int size = ftell( file );
70     rewind( file );
71     // Allocate the buffer
72     m_buffer = malloc( size );
73     if( !m_buffer )
74     {
75         msg_Err( getIntf(), "Not enough memory for the font %s",
76                  m_name.c_str() );
77         return false;
78     }
79     // Read the font data
80     fread( m_buffer, size, 1, file );
81     fclose( file );
82
83     // Load the font from the buffer
84     err = FT_New_Memory_Face( m_lib, (const FT_Byte*)m_buffer, size, 0,
85                               &m_face );
86     if ( err == FT_Err_Unknown_File_Format )
87     {
88         msg_Err( getIntf(), "Unsupported font format (%s)", m_name.c_str() );
89         return false;
90     }
91     else if ( err )
92     {
93         msg_Err( getIntf(), "Error opening font (%s)", m_name.c_str() );
94         return false;
95     }
96
97     // Select the charset
98     if( FT_Select_Charmap( m_face, ft_encoding_unicode ) )
99     {
100         msg_Err( getIntf(), "Font has no UNICODE table (%s)", m_name.c_str() );
101         return false;
102     }
103
104     // Set the pixel size
105     if( FT_Set_Pixel_Sizes( m_face, 0, m_size ) )
106     {
107         msg_Warn( getIntf(), "Cannot set a pixel size of %d (%s)", m_size,
108                   m_name.c_str() );
109     }
110
111     // Get the font metrucs
112     m_height = m_face->size->metrics.height >> 6;
113     m_ascender = m_face->size->metrics.ascender >> 6;
114     m_descender = m_face->size->metrics.descender >> 6;
115
116     // Render the '.' symbol and compute its size
117     m_dotIndex = FT_Get_Char_Index( m_face, '.' );
118     FT_Load_Glyph( m_face, m_dotIndex, FT_LOAD_DEFAULT );
119     FT_Get_Glyph( m_face->glyph, &m_dotGlyph );
120     FT_BBox dotSize;
121     FT_Glyph_Get_CBox( m_dotGlyph, ft_glyph_bbox_pixels, &dotSize );
122     m_dotWidth = dotSize.xMax - dotSize.xMin;
123     m_dotAdvance = m_face->glyph->advance.x >> 6;
124     FT_Glyph_To_Bitmap( &m_dotGlyph, ft_render_mode_normal, NULL, 1 );
125
126     return true;
127 }
128
129
130 GenericBitmap *FT2Font::drawString( const UString &rString, uint32_t color,
131                                     int maxWidth ) const
132 {
133     int err;
134     uint32_t code;
135     int n;
136     int penX = 0;
137     int width1 = 0, width2 = 0;
138     int yMin = 0, yMax = 0;
139     uint32_t *pString = (uint32_t*)rString.u_str();
140
141     // Get the length of the string
142     int len = rString.length();
143
144     // Array of glyph bitmaps and position
145     FT_Glyph *glyphs = new FT_Glyph[len];
146     int *pos = new int[len];
147
148     // Does the font support kerning ?
149     FT_Bool useKerning = FT_HAS_KERNING( m_face );
150     int previous = 0;
151
152     // Index of the last glyph when the text is truncated with trailing ...
153     int maxIndex = 0;
154     // Position of the first trailing dot
155     int firstDotX = 0;
156
157     // First, render all the glyphs
158     for( n = 0; n < len; n++ )
159     {
160         code = *(pString++);
161         // Load the glyph
162         int glyphIndex = FT_Get_Char_Index( m_face, code );
163         err = FT_Load_Glyph( m_face, glyphIndex, FT_LOAD_DEFAULT );
164         err = FT_Get_Glyph( m_face->glyph, &glyphs[n] );
165
166         // Retrieve kerning distance and move pen position
167         if( useKerning && previous && glyphIndex )
168         {
169             FT_Vector delta;
170             FT_Get_Kerning( m_face, previous, glyphIndex,
171                             ft_kerning_default, &delta );
172             penX += delta.x >> 6;
173         }
174
175         // Get the glyph size
176         FT_BBox glyphSize;
177         FT_Glyph_Get_CBox( glyphs[n], ft_glyph_bbox_pixels, &glyphSize );
178
179         // Render the glyph
180         err = FT_Glyph_To_Bitmap( &glyphs[n], ft_render_mode_normal, NULL, 1 );
181
182         pos[n] = penX;
183         width1 = penX + glyphSize.xMax - glyphSize.xMin;
184         yMin = __MIN( yMin, glyphSize.yMin );
185         yMax = __MAX( yMax, glyphSize.yMax );
186
187         // Next position
188         penX += m_face->glyph->advance.x >> 6;
189
190         // Save glyph index
191         previous = glyphIndex;
192
193         if( maxWidth != -1 )
194         {
195             // Check if the truncated text with the '...' fit in the maxWidth
196             int curX = penX;
197             if( useKerning )
198             {
199                 FT_Vector delta;
200                 FT_Get_Kerning( m_face, glyphIndex, m_dotIndex,
201                                 ft_kerning_default, &delta );
202                 curX += delta.x >> 6;
203             }
204             if( curX + 2 * m_dotAdvance + m_dotWidth < maxWidth )
205             {
206                 width2 = curX + 2 * m_dotAdvance + m_dotWidth;
207                 maxIndex++;
208                 firstDotX = curX;
209             }
210         }
211         else
212         {
213             // No check
214             width2 = width1;
215             maxIndex++;
216         }
217
218         // Stop here if the text is too large
219         if( maxWidth != -1 && width1 > maxWidth )
220         {
221             break;
222         }
223     }
224
225     // Adjust the size for vertical padding
226     yMax == __MAX( yMax, m_ascender );
227     yMin == __MIN( yMin, m_descender );
228
229     // Create the bitmap
230     FT2Bitmap *pBmp = new FT2Bitmap( getIntf(), __MIN( width1, width2 ),
231                                      yMax - yMin );
232
233     // Draw the glyphs on the bitmap
234     for( n = 0; n < maxIndex; n++ )
235     {
236         FT_BitmapGlyphRec *pBmpGlyph = (FT_BitmapGlyphRec*)glyphs[n];
237         // Draw the glyph on the bitmap
238         pBmp->draw( pBmpGlyph->bitmap, pos[n], yMax - pBmpGlyph->top, color );
239
240         // Free the glyph
241         FT_Done_Glyph( glyphs[n] );
242     }
243     // Draw the trailing dots if the text is truncated
244     if( maxIndex < len )
245     {
246         int penX = firstDotX;
247         FT_BitmapGlyphRec *pBmpGlyph = (FT_BitmapGlyphRec*)m_dotGlyph;
248         for( n = 0; n < 3; n++ )
249         {
250             // Draw the glyph on the bitmap
251             pBmp->draw( pBmpGlyph->bitmap, penX, yMax - pBmpGlyph->top,
252                         color );
253             penX += m_dotAdvance;
254         }
255     }
256
257     delete [] glyphs;
258     delete [] pos;
259
260     return pBmp;
261 }