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