]> git.sesse.net Git - vlc/blob - modules/misc/freetype.c
* parser/xmlparser.cpp: added DTD validation
[vlc] / modules / misc / freetype.c
1 /*****************************************************************************
2  * freetype.c : Put text on the video, using freetype2
3  *****************************************************************************
4  * Copyright (C) 2002, 2003 VideoLAN
5  * $Id: freetype.c,v 1.39 2003/12/22 02:24:52 sam Exp $
6  *
7  * Authors: Sigmund Augdal <sigmunau@idi.ntnu.no>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28 #include <string.h>
29
30 #ifdef HAVE_LINUX_LIMITS_H
31 #   include <linux/limits.h>
32 #endif
33
34 #include <vlc/vlc.h>
35 #include <vlc/vout.h>
36 #include <osd.h>
37 #include <math.h>
38
39 #ifdef HAVE_ERRNO_H
40 #   include <errno.h>
41 #endif
42
43 #include <ft2build.h>
44 #include FT_FREETYPE_H
45 #include FT_GLYPH_H
46
47 #ifdef SYS_DARWIN
48 #define DEFAULT_FONT "/System/Library/Fonts/LucidaGrande.dfont"
49 #elif defined( SYS_BEOS )
50 #define DEFAULT_FONT "/boot/beos/etc/fonts/ttfonts/Swiss721.ttf"
51 #elif defined( WIN32 )
52 #define DEFAULT_FONT "" /* Default font found at run-time */
53 #else
54 #define DEFAULT_FONT "/usr/share/fonts/truetype/freefont/FreeSerifBold.ttf"
55 #endif
56
57 #if defined(HAVE_ICONV)
58 #include <iconv.h>
59 #endif
60 #if defined(HAVE_FRIBIDI)
61 #include <fribidi/fribidi.h>
62 #endif
63
64 typedef struct line_desc_t line_desc_t;
65
66 /*****************************************************************************
67  * Local prototypes
68  *****************************************************************************/
69 static int  Create    ( vlc_object_t * );
70 static void Destroy   ( vlc_object_t * );
71
72 static void Render    ( vout_thread_t *, picture_t *,
73                         const subpicture_t * );
74 static void RenderI420( vout_thread_t *, picture_t *,
75                         const subpicture_t * );
76 static void RenderYUY2( vout_thread_t *, picture_t *,
77                         const subpicture_t * );
78 static void RenderRV32( vout_thread_t *, picture_t *,
79                         const subpicture_t * );
80 static subpicture_t *AddText ( vout_thread_t *, char *, text_style_t *, int,
81                                int, int, mtime_t, mtime_t );
82
83 static void FreeString( subpicture_t * );
84
85 #if !defined(HAVE_ICONV)
86 static int  GetUnicodeCharFromUTF8( byte_t ** );
87 #endif
88
89 static line_desc_t *NewLine( byte_t * );
90
91 /*****************************************************************************
92  * Module descriptor
93  *****************************************************************************/
94 #define FONT_TEXT N_("Font")
95 #define FONT_LONGTEXT N_("Font filename")
96 #define FONTSIZE_TEXT N_("Font size in pixels")
97 #define FONTSIZE_LONGTEXT N_("The size of the fonts used by the osd module. " \
98     "If set to something different than 0 this option will override the " \
99     "relative font size " )
100 #define FONTSIZER_TEXT N_("Font size")
101 #define FONTSIZER_LONGTEXT N_("The size of the fonts used by the osd module" )
102
103 static int   pi_sizes[] = { 20, 18, 16, 12, 6 };
104 static char *ppsz_sizes_text[] = { N_("Smaller"), N_("Small"), N_("Normal"),
105                                    N_("Large"), N_("Larger") };
106
107 vlc_module_begin();
108     add_category_hint( N_("Fonts"), NULL, VLC_FALSE );
109     add_file( "freetype-font", DEFAULT_FONT, NULL, FONT_TEXT, FONT_LONGTEXT, VLC_FALSE );
110     add_integer( "freetype-fontsize", 0, NULL, FONTSIZE_TEXT, FONTSIZE_LONGTEXT, VLC_TRUE );
111     add_integer( "freetype-rel-fontsize", 16, NULL, FONTSIZER_TEXT, FONTSIZER_LONGTEXT,
112                  VLC_FALSE );
113         change_integer_list( pi_sizes, ppsz_sizes_text, 0 );
114     set_description( _("freetype2 font renderer") );
115     set_capability( "text renderer", 100 );
116     add_shortcut( "text" );
117     set_callbacks( Create, Destroy );
118 vlc_module_end();
119
120 /**
121  * Private data in a subpicture. Describes a string.
122  */
123 struct subpicture_sys_t
124 {
125     int            i_x_margin;
126     int            i_y_margin;
127     int            i_width;
128     int            i_height;
129     int            i_flags;
130     /** The string associated with this subpicture */
131     byte_t        *psz_text;
132     line_desc_t   *p_lines;
133 };
134
135 struct line_desc_t
136 {
137     /** NULL-terminated list of glyphs making the string */
138     FT_BitmapGlyph *pp_glyphs;
139     /** list of relative positions for the glyphs */
140     FT_Vector      *p_glyph_pos;
141     int             i_height;
142     int             i_width;
143     line_desc_t    *p_next;
144 };
145
146 /*****************************************************************************
147  * text_renderer_sys_t: freetype local data
148  *****************************************************************************
149  * This structure is part of the video output thread descriptor.
150  * It describes the freetype specific properties of an output thread.
151  *****************************************************************************/
152 struct text_renderer_sys_t
153 {
154     FT_Library     p_library;   /* handle to library     */
155     FT_Face        p_face;      /* handle to face object */
156     vlc_mutex_t   *lock;
157     vlc_bool_t     i_use_kerning;
158     uint8_t        pi_gamma[256];
159 };
160
161 /*****************************************************************************
162  * Create: allocates osd-text video thread output method
163  *****************************************************************************
164  * This function allocates and initializes a Clone vout method.
165  *****************************************************************************/
166 #define gamma_value 2.0
167 static int Create( vlc_object_t *p_this )
168 {
169     vout_thread_t *p_vout = (vout_thread_t *)p_this;
170     char *psz_fontfile;
171     int i, i_error;
172     int i_fontsize = 0;
173     double gamma_inv = 1.0f / gamma_value;
174     vlc_value_t val;
175
176     /* Allocate structure */
177     p_vout->p_text_renderer_data = malloc( sizeof( text_renderer_sys_t ) );
178     if( p_vout->p_text_renderer_data == NULL )
179     {
180         msg_Err( p_vout, "out of memory" );
181         return VLC_ENOMEM;
182     }
183
184     for (i = 0; i < 256; i++) {
185         p_vout->p_text_renderer_data->pi_gamma[i] =
186             (uint8_t)( pow( (double)i / 255.0f, gamma_inv) * 255.0f );
187     }
188
189     var_Create( p_vout, "freetype-font", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
190     var_Create( p_vout, "freetype-fontsize",
191                 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
192     var_Create( p_vout, "freetype-rel-fontsize",
193                 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
194
195     /* Look what method was requested */
196     var_Get( p_vout, "freetype-font", &val );
197     psz_fontfile = val.psz_string;
198
199     if( !psz_fontfile || !*psz_fontfile )
200     {
201         if( psz_fontfile ) free( psz_fontfile );
202         psz_fontfile = (char *)malloc( PATH_MAX + 1 );
203 #ifdef WIN32
204         GetWindowsDirectory( psz_fontfile, PATH_MAX + 1 );
205         strcat( psz_fontfile, "\\fonts\\arial.ttf" );
206 #elif SYS_DARWIN
207         strcpy( psz_fontfile, DEFAULT_FONT );
208 #else
209         msg_Err( p_vout, "user didn't specify a font" );
210         free( p_vout->p_text_renderer_data );
211         return VLC_EGENERIC;
212 #endif
213     }
214
215     i_error = FT_Init_FreeType( &p_vout->p_text_renderer_data->p_library );
216     if( i_error )
217     {
218         msg_Err( p_vout, "couldn't initialize freetype" );
219         free( p_vout->p_text_renderer_data );
220         return VLC_EGENERIC;
221     }
222
223     i_error = FT_New_Face( p_vout->p_text_renderer_data->p_library,
224                            psz_fontfile ? psz_fontfile : "", 0,
225                            &p_vout->p_text_renderer_data->p_face );
226     if( i_error == FT_Err_Unknown_File_Format )
227     {
228         msg_Err( p_vout, "file %s have unknown format", psz_fontfile );
229         FT_Done_FreeType( p_vout->p_text_renderer_data->p_library );
230         free( p_vout->p_text_renderer_data );
231         if( psz_fontfile ) free( psz_fontfile );
232         return VLC_EGENERIC;
233     }
234     else if( i_error )
235     {
236         msg_Err( p_vout, "failed to load font file %s", psz_fontfile );
237         FT_Done_FreeType( p_vout->p_text_renderer_data->p_library );
238         free( p_vout->p_text_renderer_data );
239         if( psz_fontfile ) free( psz_fontfile );
240         return VLC_EGENERIC;
241     }
242     if( psz_fontfile ) free( psz_fontfile );
243
244     i_error = FT_Select_Charmap( p_vout->p_text_renderer_data->p_face,
245                                  ft_encoding_unicode );
246     if( i_error )
247     {
248         msg_Err( p_vout, "Font has no unicode translation table" );
249         FT_Done_Face( p_vout->p_text_renderer_data->p_face );
250         FT_Done_FreeType( p_vout->p_text_renderer_data->p_library );
251         free( p_vout->p_text_renderer_data );
252         return VLC_EGENERIC;
253     }
254
255     p_vout->p_text_renderer_data->i_use_kerning =
256         FT_HAS_KERNING(p_vout->p_text_renderer_data->p_face);
257
258     var_Get( p_vout, "freetype-fontsize", &val );
259
260     if( val.i_int )
261     {
262         i_fontsize = val.i_int;
263     }
264     else
265     {
266         var_Get( p_vout, "freetype-rel-fontsize", &val );
267         i_fontsize = (int) p_vout->render.i_height / val.i_int;
268     }
269     msg_Dbg( p_vout, "Using fontsize: %i", i_fontsize);
270
271     i_error = FT_Set_Pixel_Sizes( p_vout->p_text_renderer_data->p_face, 0,
272                                   i_fontsize );
273     if( i_error )
274     {
275         msg_Err( p_vout, "couldn't set font size to %d", i_fontsize );
276         free( p_vout->p_text_renderer_data );
277         return VLC_EGENERIC;
278     }
279     p_vout->pf_add_string = AddText;
280     return VLC_SUCCESS;
281 }
282
283 /*****************************************************************************
284  * Destroy: destroy Clone video thread output method
285  *****************************************************************************
286  * Clean up all data and library connections
287  *****************************************************************************/
288 static void Destroy( vlc_object_t *p_this )
289 {
290     vout_thread_t *p_vout = (vout_thread_t *)p_this;
291     FT_Done_Face( p_vout->p_text_renderer_data->p_face );
292     FT_Done_FreeType( p_vout->p_text_renderer_data->p_library );
293     free( p_vout->p_text_renderer_data );
294 }
295
296 /*****************************************************************************
297  * Render: place string in picture
298  *****************************************************************************
299  * This function merges the previously rendered freetype glyphs into a picture
300  *****************************************************************************/
301 static void Render( vout_thread_t *p_vout, picture_t *p_pic,
302                     const subpicture_t *p_subpic )
303 {
304     switch( p_vout->output.i_chroma )
305     {
306         /* I420 target, no scaling */
307         case VLC_FOURCC('I','4','2','0'):
308         case VLC_FOURCC('I','Y','U','V'):
309         case VLC_FOURCC('Y','V','1','2'):
310             RenderI420( p_vout, p_pic, p_subpic );
311             break;
312 #if 0
313         /* RV16 target, scaling */
314         case VLC_FOURCC('R','V','1','6'):
315             RenderRV16( p_vout, p_pic, p_subpic );
316             break;
317 #endif
318         /* RV32 target, scaling */
319         case VLC_FOURCC('R','V','2','4'):
320         case VLC_FOURCC('R','V','3','2'):
321             RenderRV32( p_vout, p_pic, p_subpic );
322             break;
323         /* NVidia or BeOS overlay, no scaling */
324         case VLC_FOURCC('Y','U','Y','2'):
325             RenderYUY2( p_vout, p_pic, p_subpic );
326             break;
327
328         default:
329             msg_Err( p_vout, "unknown chroma, can't render SPU" );
330             break;
331     }
332 }
333
334 /**
335  * Draw a string on a i420 (or similar) picture
336  */
337 static void RenderI420( vout_thread_t *p_vout, picture_t *p_pic,
338                     const subpicture_t *p_subpic )
339 {
340     subpicture_sys_t *p_string = p_subpic->p_sys;
341     int i_plane, x, y, pen_x, pen_y;
342     unsigned int i;
343     line_desc_t *p_line;
344
345     for( p_line = p_subpic->p_sys->p_lines; p_line != NULL; p_line = p_line->p_next )
346     {
347         for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
348         {
349             uint8_t *p_in;
350             int i_pic_pitch = p_pic->p[ i_plane ].i_pitch;
351             int i_pic_width = p_pic->p[ i_plane ].i_visible_pitch;
352
353             p_in = p_pic->p[ i_plane ].p_pixels;
354
355             if ( i_plane == 0 )
356             {
357                 if ( p_string->i_flags & OSD_ALIGN_BOTTOM )
358                 {
359                     pen_y = p_pic->p[ i_plane ].i_lines - p_string->i_height -
360                         p_string->i_y_margin;
361                 }
362                 else
363                 {
364                     pen_y = p_string->i_y_margin;
365                 }
366                 pen_y += p_vout->p_text_renderer_data->p_face->size->metrics.ascender >> 6;
367                 if ( p_string->i_flags & OSD_ALIGN_RIGHT )
368                 {
369                     pen_x = i_pic_width - p_line->i_width
370                         - p_string->i_x_margin;
371                 }
372                 else if ( p_string->i_flags & OSD_ALIGN_LEFT )
373                 {
374                     pen_x = p_string->i_x_margin;
375                 }
376                 else
377                 {
378                     pen_x = i_pic_width / 2 - p_line->i_width / 2
379                         + p_string->i_x_margin;
380                 }
381
382                 for( i = 0; p_line->pp_glyphs[i] != NULL; i++ )
383                 {
384                     FT_BitmapGlyph p_glyph = p_line->pp_glyphs[ i ];
385 #define alpha p_vout->p_text_renderer_data->pi_gamma[ p_glyph->bitmap.buffer[ x + y * p_glyph->bitmap.width ] ]
386 #define pixel p_in[ ( p_line->p_glyph_pos[ i ].y + pen_y + y - p_glyph->top ) * i_pic_pitch + x + pen_x + p_line->p_glyph_pos[ i ].x + p_glyph->left ]
387                     for(y = 0; y < p_glyph->bitmap.rows; y++ )
388                     {
389                         for( x = 0; x < p_glyph->bitmap.width; x++ )
390                         {
391                             pen_y--;
392                             pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
393                             pen_y++; pen_x--;
394                             pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
395                             pen_x += 2;
396                             pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
397                             pen_y++; pen_x--;
398                             pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
399                             pen_y--;
400                         }
401                     }
402                     for(y = 0; y < p_glyph->bitmap.rows; y++ )
403                     {
404                         for( x = 0; x < p_glyph->bitmap.width; x++ )
405                         {
406                             pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 ) +
407                                 ( 255 * alpha >> 8 );
408                         }
409                     }
410 #undef alpha
411 #undef pixel
412                 }
413             }
414             else
415             {
416                 if ( p_string->i_flags & OSD_ALIGN_BOTTOM )
417                 {
418                     pen_y = p_pic->p[i_plane].i_lines - ( p_string->i_height>>1) -
419                         (p_string->i_y_margin>>1);
420                 }
421                 else
422                 {
423                     pen_y = p_string->i_y_margin >> 1;
424                 }
425                 pen_y += p_vout->p_text_renderer_data->p_face->size->metrics.ascender >> 7;
426                 if ( p_string->i_flags & OSD_ALIGN_RIGHT )
427                 {
428                     pen_x = i_pic_width - ( p_line->i_width >> 1 )
429                         - ( p_string->i_x_margin >> 1 );
430                 }
431                 else if ( p_string->i_flags & OSD_ALIGN_LEFT )
432                 {
433                     pen_x = p_string->i_x_margin >> 1;
434                 }
435                 else
436                 {
437                     pen_x = i_pic_width / 2 - p_line->i_width / 4
438                         + p_string->i_x_margin / 2;
439                 }
440
441                 for( i = 0; p_line->pp_glyphs[i] != NULL; i++ )
442                 {
443                     FT_BitmapGlyph p_glyph = p_line->pp_glyphs[ i ];
444 #define alpha p_vout->p_text_renderer_data->pi_gamma[ p_glyph->bitmap.buffer[ ( x + y * p_glyph->bitmap.width ) ] ]
445 #define pixel p_in[ ( ( p_line->p_glyph_pos[ i ].y >> 1 ) + pen_y + ( y >> 1 ) -  ( p_glyph->top >> 1 ) ) * i_pic_pitch + ( x >> 1 ) + pen_x + ( p_line->p_glyph_pos[ i ].x >> 1 ) + ( p_glyph->left >>1) ]
446                     for( y = 0; y < p_glyph->bitmap.rows; y+=2 )
447                     {
448                         for( x = 0; x < p_glyph->bitmap.width; x+=2 )
449                         {
450                             pixel = ( ( pixel * ( 0xFF - alpha ) ) >> 8 ) +
451                                 ( 0x80 * alpha >> 8 );
452 #undef alpha
453 #undef pixel
454                         }
455                     }
456                 }
457             }
458         }
459     }
460 }
461
462 /**
463  * Draw a string on a YUY2 picture
464  */
465 static void RenderYUY2( vout_thread_t *p_vout, picture_t *p_pic,
466                         const subpicture_t *p_subpic )
467 {
468     subpicture_sys_t *p_string = p_subpic->p_sys;
469     int x, y, pen_x, pen_y;
470     unsigned int i;
471     line_desc_t *p_line;
472
473     for( p_line = p_subpic->p_sys->p_lines; p_line != NULL;
474          p_line = p_line->p_next )
475     {
476         uint8_t *p_in;
477         int i_pic_pitch = p_pic->p[0].i_pitch;
478         int i_pic_width = p_pic->p[0].i_visible_pitch;
479
480         p_in = p_pic->p[0].p_pixels;
481
482         if ( p_string->i_flags & OSD_ALIGN_BOTTOM )
483         {
484             pen_y = p_pic->p[0].i_lines - p_string->i_height -
485                 p_string->i_y_margin;
486         }
487         else
488         {
489             pen_y = p_string->i_y_margin;
490         }
491         pen_y += p_vout->p_text_renderer_data->p_face->size->metrics.ascender >> 6;
492         if ( p_string->i_flags & OSD_ALIGN_RIGHT )
493         {
494             pen_x = i_pic_width - p_line->i_width
495                 - p_string->i_x_margin;
496         }
497         else if ( p_string->i_flags & OSD_ALIGN_LEFT )
498         {
499             pen_x = p_string->i_x_margin;
500         }
501         else
502         {
503             pen_x = i_pic_width / 2 /2 - p_line->i_width / 2 + p_string->i_x_margin;
504         }
505
506         for( i = 0; p_line->pp_glyphs[i] != NULL; i++ )
507         {
508             FT_BitmapGlyph p_glyph = p_line->pp_glyphs[ i ];
509 #define alpha p_vout->p_text_renderer_data->pi_gamma[ p_glyph->bitmap.buffer[ x + y * p_glyph->bitmap.width ] ]
510 #define pixel p_in[ ( p_line->p_glyph_pos[ i ].y + pen_y + y - p_glyph->top ) * i_pic_pitch + 2 * ( x + pen_x + p_line->p_glyph_pos[ i ].x + p_glyph->left ) ]
511             for(y = 0; y < p_glyph->bitmap.rows; y++ )
512             {
513                 for( x = 0; x < p_glyph->bitmap.width; x++ )
514                 {
515                     pen_y--;
516                     pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
517                     pen_y++; pen_x--;
518                     pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
519                     pen_x += 2;
520                     pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
521                     pen_y++; pen_x--;
522                     pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
523                     pen_y--;
524                 }
525             }
526             for(y = 0; y < p_glyph->bitmap.rows; y++ )
527             {
528                 for( x = 0; x < p_glyph->bitmap.width; x++ )
529                 {
530                     pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 ) +
531                         ( 255 * alpha >> 8 );
532                 }
533             }
534 #undef alpha
535 #undef pixel
536         }
537     }
538 }
539
540 /**
541  * Draw a string on a RV32 picture
542  */
543 static void RenderRV32( vout_thread_t *p_vout, picture_t *p_pic,
544                     const subpicture_t *p_subpic )
545 {
546     subpicture_sys_t *p_string = p_subpic->p_sys;
547     int i_plane, x, y, pen_x, pen_y;
548     unsigned int i;
549     line_desc_t *p_line;
550
551     i_plane = 0;
552
553     for( p_line = p_subpic->p_sys->p_lines; p_line != NULL; p_line = p_line->p_next )
554     {
555         uint8_t *p_in;
556         int i_pic_pitch = p_pic->p[ i_plane ].i_pitch;
557         int i_pic_width = p_pic->p[ i_plane ].i_visible_pitch;
558
559         p_in = p_pic->p[ i_plane ].p_pixels;
560
561         if ( p_string->i_flags & OSD_ALIGN_BOTTOM )
562         {
563             pen_y = p_pic->p[ i_plane ].i_lines - p_string->i_height -
564                 p_string->i_y_margin;
565         }
566         else
567         {
568             pen_y = p_string->i_y_margin;
569         }
570         pen_y += p_vout->p_text_renderer_data->p_face->size->metrics.ascender >> 6;
571         if ( p_string->i_flags & OSD_ALIGN_RIGHT )
572         {
573             pen_x = i_pic_width - p_line->i_width
574                 - p_string->i_x_margin;
575         }
576         else if ( p_string->i_flags & OSD_ALIGN_LEFT )
577         {
578             pen_x = p_string->i_x_margin;
579         }
580         else
581         {
582             pen_x = i_pic_width / 2 / 4 - p_line->i_width / 2
583                 + p_string->i_x_margin;
584         }
585
586         for( i = 0; p_line->pp_glyphs[i] != NULL; i++ )
587         {
588             FT_BitmapGlyph p_glyph = p_line->pp_glyphs[ i ];
589 #define alpha p_vout->p_text_renderer_data->pi_gamma[ p_glyph->bitmap.buffer[ x + y * p_glyph->bitmap.width ] ]
590 #define pixel( c ) p_in[ ( p_line->p_glyph_pos[ i ].y + pen_y + y - p_glyph->top ) * i_pic_pitch + ( x + pen_x + p_line->p_glyph_pos[ i ].x + p_glyph->left ) * 4 + c ]
591             for(y = 0; y < p_glyph->bitmap.rows; y++ )
592             {
593                 for( x = 0; x < p_glyph->bitmap.width; x++ )
594                 {
595                     pen_y--;
596                     pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
597                     pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
598                     pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
599                     pen_y++; pen_x--;
600                     pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
601                     pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
602                     pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
603                     pen_x += 2;
604                     pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
605                     pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
606                     pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
607                     pen_y++; pen_x--;
608                     pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
609                     pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
610                     pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
611                     pen_y--;
612                 }
613             }
614             for(y = 0; y < p_glyph->bitmap.rows; y++ )
615             {
616                 for( x = 0; x < p_glyph->bitmap.width; x++ )
617                 {
618                     pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 ) +
619                         ( 255 * alpha >> 8 );
620                     pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 ) +
621                         ( 255 * alpha >> 8 );
622                     pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 ) +
623                         ( 255 * alpha >> 8 );
624                 }
625             }
626 #undef alpha
627 #undef pixel
628         }
629     }
630 }
631
632 /**
633  * This function receives a string and creates a subpicture for it. It
634  * also calculates the size needed for this string, and renders the
635  * needed glyphs into memory. It is used as pf_add_string callback in
636  * the vout method by this module
637  */
638 static subpicture_t *AddText ( vout_thread_t *p_vout, char *psz_string,
639                      text_style_t *p_style, int i_flags, int i_hmargin,
640                      int i_vmargin, mtime_t i_start, mtime_t i_stop )
641 {
642     subpicture_sys_t *p_string;
643     int i, i_pen_y, i_pen_x, i_error, i_glyph_index, i_previous;
644     subpicture_t *p_subpic;
645     line_desc_t  *p_line,  *p_next;
646     uint32_t *p_unicode_string, i_char;
647     int i_string_length;
648     iconv_t iconv_handle;
649
650     FT_BBox line;
651     FT_BBox glyph_size;
652     FT_Vector result;
653     FT_Glyph tmp_glyph;
654
655     /* Sanity check */
656     if ( !psz_string || !*psz_string )
657     {
658         return NULL;
659     }
660
661     result.x = 0;
662     result.y = 0;
663     line.xMin = 0;
664     line.xMax = 0;
665     line.yMin = 0;
666     line.yMax = 0;
667
668     p_line = 0;
669     p_string = 0;
670     p_subpic = 0;
671
672     /* Create and initialize a subpicture */
673     p_subpic = vout_CreateSubPicture( p_vout, MEMORY_SUBPICTURE );
674     if ( p_subpic == NULL )
675     {
676         return NULL;
677     }
678     p_subpic->p_sys = 0;
679     p_subpic->pf_render = Render;
680     p_subpic->pf_destroy = FreeString;
681     p_subpic->i_start = i_start;
682     p_subpic->i_stop = i_stop;
683     if( i_stop == 0 )
684     {
685         p_subpic->b_ephemer = VLC_TRUE;
686     }
687     else
688     {
689         p_subpic->b_ephemer = VLC_FALSE;
690     }
691
692     /* Create and initialize private data for the subpicture */
693     p_string = malloc( sizeof(subpicture_sys_t) );
694     if ( p_string == NULL )
695     {
696         msg_Err( p_vout, "Out of memory" );
697         goto error;
698     }
699     p_subpic->p_sys = p_string;
700     p_string->i_flags = i_flags;
701     p_string->i_x_margin = i_hmargin;
702     p_string->i_y_margin = i_vmargin;
703     p_string->p_lines = 0;
704     p_string->psz_text = strdup( psz_string );
705
706 #if defined(HAVE_ICONV)
707     p_unicode_string = malloc( ( strlen(psz_string) + 1 ) * sizeof(uint32_t) );
708     if( p_unicode_string == NULL )
709     {
710         msg_Err( p_vout, "Out of memory" );
711         goto error;
712     }
713 #if defined(WORDS_BIGENDIAN)
714     iconv_handle = iconv_open( "UCS-4BE", "UTF-8" );
715 #else
716     iconv_handle = iconv_open( "UCS-4LE", "UTF-8" );
717 #endif
718     if( iconv_handle == (iconv_t)-1 )
719     {
720         msg_Warn( p_vout, "Unable to do convertion" );
721         goto error;
722     }
723
724     {
725         char *p_in_buffer, *p_out_buffer;
726         size_t i_in_bytes, i_out_bytes, i_out_bytes_left, i_ret;
727         i_in_bytes = strlen( psz_string );
728         i_out_bytes = i_in_bytes * sizeof( uint32_t );
729         i_out_bytes_left = i_out_bytes;
730         p_in_buffer = psz_string;
731         p_out_buffer = (char *)p_unicode_string;
732         i_ret = iconv( iconv_handle, &p_in_buffer, &i_in_bytes, &p_out_buffer, &i_out_bytes_left );
733         if( i_in_bytes )
734         {
735             msg_Warn( p_vout, "Failed to convert string to unicode (%s), bytes left %d", strerror(errno), i_in_bytes );
736             goto error;
737         }
738         *(uint32_t*)p_out_buffer = 0;
739         i_string_length = ( i_out_bytes - i_out_bytes_left ) / sizeof(uint32_t);
740     }
741
742 #if defined(HAVE_FRIBIDI)
743     {
744         uint32_t *p_fribidi_string;
745         FriBidiCharType base_dir = FRIBIDI_TYPE_ON;
746         p_fribidi_string = malloc( ( i_string_length + 1 ) * sizeof(uint32_t) );
747         fribidi_log2vis( (FriBidiChar*)p_unicode_string, i_string_length,
748                          &base_dir, (FriBidiChar*)p_fribidi_string, NULL, NULL,
749                          NULL );
750         free( p_unicode_string );
751         p_unicode_string = p_fribidi_string;
752         p_fribidi_string[ i_string_length ] = 0;
753     }
754 #endif
755 #endif
756
757     /* Calculate relative glyph positions and a bounding box for the
758      * entire string */
759     p_line = NewLine( psz_string );
760     if( p_line == NULL )
761     {
762         msg_Err( p_vout, "Out of memory" );
763         goto error;
764     }
765     p_string->p_lines = p_line;
766     i_pen_x = 0;
767     i_pen_y = 0;
768     i_previous = 0;
769     i = 0;
770
771 #define face p_vout->p_text_renderer_data->p_face
772 #define glyph face->glyph
773
774     while( *p_unicode_string )
775     {
776         i_char = *p_unicode_string++;
777         if ( i_char == '\r' ) /* ignore CR chars wherever they may be */
778         {
779             continue;
780         }
781
782         if ( i_char == '\n' )
783         {
784             p_next = NewLine( psz_string );
785             if( p_next == NULL )
786             {
787                 msg_Err( p_vout, "Out of memory" );
788                 goto error;
789             }
790             p_line->p_next = p_next;
791             p_line->i_width = line.xMax;
792             p_line->i_height = face->size->metrics.height >> 6;
793             p_line->pp_glyphs[ i ] = NULL;
794             p_line = p_next;
795             result.x = __MAX( result.x, line.xMax );
796             result.y += face->size->metrics.height >> 6;
797             i_pen_x = 0;
798             line.xMin = 0;
799             line.xMax = 0;
800             line.yMin = 0;
801             line.yMax = 0;
802             i_pen_y += face->size->metrics.height >> 6;
803             msg_Dbg( p_vout, "Creating new line, i is %d", i );
804             i = 0;
805             continue;
806         }
807
808         i_glyph_index = FT_Get_Char_Index( face, i_char );
809         if ( p_vout->p_text_renderer_data->i_use_kerning && i_glyph_index
810             && i_previous )
811         {
812             FT_Vector delta;
813             FT_Get_Kerning( face, i_previous, i_glyph_index,
814                             ft_kerning_default, &delta );
815             i_pen_x += delta.x >> 6;
816
817         }
818         p_line->p_glyph_pos[ i ].x = i_pen_x;
819         p_line->p_glyph_pos[ i ].y = i_pen_y;
820         i_error = FT_Load_Glyph( face, i_glyph_index, FT_LOAD_DEFAULT );
821         if ( i_error )
822         {
823             msg_Err( p_vout, "FT_Load_Glyph returned %d", i_error );
824             goto error;
825         }
826         i_error = FT_Get_Glyph( glyph, &tmp_glyph );
827         if ( i_error )
828         {
829             msg_Err( p_vout, "FT_Get_Glyph returned %d", i_error );
830             goto error;
831         }
832         FT_Glyph_Get_CBox( tmp_glyph, ft_glyph_bbox_pixels, &glyph_size );
833         i_error = FT_Glyph_To_Bitmap( &tmp_glyph, ft_render_mode_normal,
834                                       NULL, 1 );
835         if ( i_error ) continue;
836         p_line->pp_glyphs[ i ] = (FT_BitmapGlyph)tmp_glyph;
837
838         /* Do rest */
839         line.xMax = p_line->p_glyph_pos[i].x + glyph_size.xMax - glyph_size.xMin;
840         line.yMax = __MAX( line.yMax, glyph_size.yMax );
841         line.yMin = __MIN( line.yMin, glyph_size.yMin );
842
843         i_previous = i_glyph_index;
844         i_pen_x += glyph->advance.x >> 6;
845         i++;
846     }
847     p_line->i_width = line.xMax;
848     p_line->i_height = face->size->metrics.height >> 6;
849     p_line->pp_glyphs[ i ] = NULL;
850     result.x = __MAX( result.x, line.xMax );
851     result.y += line.yMax - line.yMin;
852     p_string->i_height = result.y;
853     p_string->i_width = result.x;
854     vout_DisplaySubPicture( p_vout, p_subpic );
855     return p_subpic;
856
857 #undef face
858 #undef glyph
859
860  error:
861     FreeString( p_subpic );
862     vout_DestroySubPicture( p_vout, p_subpic );
863     return NULL;
864 }
865
866 static void FreeString( subpicture_t *p_subpic )
867 {
868     unsigned int i;
869     subpicture_sys_t *p_string = p_subpic->p_sys;
870     line_desc_t *p_line, *p_next;
871
872     if( p_subpic->p_sys == NULL ) return;
873
874     for( p_line = p_string->p_lines; p_line != NULL; p_line = p_next )
875     {
876         p_next = p_line->p_next;
877         for( i = 0; p_line->pp_glyphs[ i ] != NULL; i++ )
878         {
879             FT_Done_Glyph( (FT_Glyph)p_line->pp_glyphs[ i ] );
880         }
881         free( p_line->pp_glyphs );
882         free( p_line->p_glyph_pos );
883         free( p_line );
884     }
885
886     free( p_string->psz_text );
887     free( p_string );
888 }
889
890 #if !defined( HAVE_ICONV )
891 /* convert one or more utf8 bytes into a unicode character */
892 static int GetUnicodeCharFromUTF8( byte_t **ppsz_utf8_string )
893 {
894     int i_remaining_bytes, i_char = 0;
895     if( ( **ppsz_utf8_string & 0xFC ) == 0xFC )
896     {
897         i_char = **ppsz_utf8_string & 1;
898         i_remaining_bytes = 5;
899     }
900     else if( ( **ppsz_utf8_string & 0xF8 ) == 0xF8 )
901     {
902         i_char = **ppsz_utf8_string & 3;
903         i_remaining_bytes = 4;
904     }
905     else if( ( **ppsz_utf8_string & 0xF0 ) == 0xF0 )
906     {
907         i_char = **ppsz_utf8_string & 7;
908         i_remaining_bytes = 3;
909     }
910     else if( ( **ppsz_utf8_string & 0xE0 ) == 0xE0 )
911     {
912         i_char = **ppsz_utf8_string & 15;
913         i_remaining_bytes = 2;
914     }
915     else if( ( **ppsz_utf8_string & 0xC0 ) == 0xC0 )
916     {
917         i_char = **ppsz_utf8_string & 31;
918         i_remaining_bytes = 1;
919     }
920     else
921     {
922         i_char = **ppsz_utf8_string;
923         i_remaining_bytes = 0;
924     }
925     while( i_remaining_bytes )
926     {
927         (*ppsz_utf8_string)++;
928         i_remaining_bytes--;
929         i_char = ( i_char << 6 ) + ( **ppsz_utf8_string & 0x3F );
930     }
931     (*ppsz_utf8_string)++;
932     return i_char;
933 }
934 #endif
935
936 static line_desc_t *NewLine( byte_t *psz_string )
937 {
938     int i_count;
939     line_desc_t *p_line = malloc( sizeof(line_desc_t) );
940     if( !p_line )
941     {
942         return NULL;
943     }
944     p_line->i_height = 0;
945     p_line->i_width = 0;
946     p_line->p_next = NULL;
947
948     /* We don't use CountUtf8Characters() here because we are not acutally
949      * sure the string is utf8. Better be safe than sorry. */
950     i_count = strlen( psz_string );
951
952     p_line->pp_glyphs = malloc( sizeof(FT_BitmapGlyph)
953                                 * ( i_count + 1 ) );
954     if( p_line->pp_glyphs == NULL )
955     {
956         free( p_line );
957         return NULL;
958     }
959     p_line->p_glyph_pos = malloc( sizeof( FT_Vector )
960                                   * i_count + 1 );
961     if( p_line->p_glyph_pos == NULL )
962     {
963         free( p_line->pp_glyphs );
964         free( p_line );
965         return NULL;
966     }
967
968     return p_line;
969 }