1 /*****************************************************************************
2 * freetype.c : Put text on the video, using freetype2
3 *****************************************************************************
4 * Copyright (C) 2002, 2003 VideoLAN
5 * $Id: freetype.c,v 1.20 2003/08/27 12:24:52 sigmunau Exp $
7 * Authors: Sigmund Augdal <sigmunau@idi.ntnu.no>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <stdlib.h> /* malloc(), free() */
36 #include FT_FREETYPE_H
40 #define DEFAULT_FONT "/System/Library/Fonts/LucidaGrande.dfont"
41 #elif defined( SYS_BEOS )
42 #define DEFAULT_FONT "/boot/beos/etc/fonts/ttfonts/Swiss721.ttf"
44 #define DEFAULT_FONT ""
47 typedef struct line_desc_t line_desc_t;
49 /*****************************************************************************
51 *****************************************************************************/
52 static int Create ( vlc_object_t * );
53 static void Destroy ( vlc_object_t * );
55 static void Render ( vout_thread_t *, picture_t *,
56 const subpicture_t * );
57 static void RenderI420( vout_thread_t *, picture_t *,
58 const subpicture_t * );
59 static void RenderYUY2( vout_thread_t *, picture_t *,
60 const subpicture_t * );
61 static void RenderRV32( vout_thread_t *, picture_t *,
62 const subpicture_t * );
63 static int AddText ( vout_thread_t *, byte_t *, text_style_t *, int,
64 int, int, mtime_t, mtime_t );
65 static void FreeString( subpicture_t * );
67 static int GetUnicodeCharFromUTF8( byte_t ** );
69 static line_desc_t *NewLine( byte_t * );
71 /*****************************************************************************
73 *****************************************************************************/
74 #define FONT_TEXT N_("Font")
75 #define FONT_LONGTEXT N_("Filename of Font")
76 #define FONTSIZE_TEXT N_("Font size")
77 #define FONTSIZE_LONGTEXT N_("The size of the fonts used by the osd module" )
80 add_category_hint( N_("Fonts"), NULL, VLC_FALSE );
81 add_file( "freetype-font", DEFAULT_FONT, NULL, FONT_TEXT, FONT_LONGTEXT, VLC_FALSE );
82 add_integer( "freetype-fontsize", 16, NULL, FONTSIZE_TEXT, FONTSIZE_LONGTEXT, VLC_FALSE );
83 set_description( _("freetype2 font renderer") );
84 set_capability( "text renderer", 100 );
85 add_shortcut( "text" );
86 set_callbacks( Create, Destroy );
90 * Private data in a aubpicture. Describes a string.
92 struct subpicture_sys_t
99 /** The string associated with this subpicture */
101 line_desc_t *p_lines;
106 /** NULL-terminated list of glyphs making the string */
107 FT_BitmapGlyph *pp_glyphs;
108 /** list of relative positions for the glyphs */
109 FT_Vector *p_glyph_pos;
115 /*****************************************************************************
116 * text_remderer_sys_t: freetype local data
117 *****************************************************************************
118 * This structure is part of the video output thread descriptor.
119 * It describes the freetype specific properties of an output thread.
120 *****************************************************************************/
121 struct text_renderer_sys_t
123 FT_Library p_library; /* handle to library */
124 FT_Face p_face; /* handle to face object */
126 vlc_bool_t i_use_kerning;
127 uint8_t pi_gamma[256];
130 /*****************************************************************************
131 * Create: allocates osd-text video thread output method
132 *****************************************************************************
133 * This function allocates and initializes a Clone vout method.
134 *****************************************************************************/
135 #define gamma_value 2.0
136 static int Create( vlc_object_t *p_this )
138 vout_thread_t *p_vout = (vout_thread_t *)p_this;
141 double gamma_inv = 1.0f / gamma_value;
144 /* Allocate structure */
145 p_vout->p_text_renderer_data = malloc( sizeof( text_renderer_sys_t ) );
146 if( p_vout->p_text_renderer_data == NULL )
148 msg_Err( p_vout, "out of memory" );
152 for (i = 0; i < 256; i++) {
153 p_vout->p_text_renderer_data->pi_gamma[i] =
154 (uint8_t)( pow( (double)i / 255.0f, gamma_inv) * 255.0f );
157 var_Create( p_vout, "freetype-font", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
158 var_Create( p_vout, "freetype-fontsize",
159 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
161 /* Look what method was requested */
162 var_Get( p_vout, "freetype-font", &val );
163 psz_fontfile = val.psz_string;
165 if( !psz_fontfile || !*psz_fontfile )
167 if( psz_fontfile ) free( psz_fontfile );
168 psz_fontfile = (char *)malloc( PATH_MAX + 1 );
170 GetWindowsDirectory( psz_fontfile, PATH_MAX + 1 );
171 strcat( psz_fontfile, "\\fonts\\arial.ttf" );
173 strcpy( psz_fontfile, DEFAULT_FONT );
175 msg_Err( p_vout, "user didn't specify a font" );
176 free( p_vout->p_text_renderer_data );
181 i_error = FT_Init_FreeType( &p_vout->p_text_renderer_data->p_library );
184 msg_Err( p_vout, "couldn't initialize freetype" );
185 free( p_vout->p_text_renderer_data );
189 i_error = FT_New_Face( p_vout->p_text_renderer_data->p_library,
190 psz_fontfile ? psz_fontfile : "", 0,
191 &p_vout->p_text_renderer_data->p_face );
192 if( i_error == FT_Err_Unknown_File_Format )
194 msg_Err( p_vout, "file %s have unknown format", psz_fontfile );
195 FT_Done_FreeType( p_vout->p_text_renderer_data->p_library );
196 free( p_vout->p_text_renderer_data );
197 if( psz_fontfile ) free( psz_fontfile );
202 msg_Err( p_vout, "failed to load font file %s", psz_fontfile );
203 FT_Done_FreeType( p_vout->p_text_renderer_data->p_library );
204 free( p_vout->p_text_renderer_data );
205 if( psz_fontfile ) free( psz_fontfile );
208 if( psz_fontfile ) free( psz_fontfile );
210 i_error = FT_Select_Charmap( p_vout->p_text_renderer_data->p_face,
211 ft_encoding_unicode );
214 msg_Err( p_vout, "Font has no unicode translation table" );
215 FT_Done_Face( p_vout->p_text_renderer_data->p_face );
216 FT_Done_FreeType( p_vout->p_text_renderer_data->p_library );
217 free( p_vout->p_text_renderer_data );
221 p_vout->p_text_renderer_data->i_use_kerning =
222 FT_HAS_KERNING(p_vout->p_text_renderer_data->p_face);
223 var_Get( p_vout, "freetype-fontsize", &val );
225 i_error = FT_Set_Pixel_Sizes( p_vout->p_text_renderer_data->p_face, 0,
229 msg_Err( p_vout, "couldn't set font size to %d", val.i_int );
230 free( p_vout->p_text_renderer_data );
233 p_vout->pf_add_string = AddText;
237 /*****************************************************************************
238 * Destroy: destroy Clone video thread output method
239 *****************************************************************************
240 * Clean up all data and library connections
241 *****************************************************************************/
242 static void Destroy( vlc_object_t *p_this )
244 vout_thread_t *p_vout = (vout_thread_t *)p_this;
245 FT_Done_Face( p_vout->p_text_renderer_data->p_face );
246 FT_Done_FreeType( p_vout->p_text_renderer_data->p_library );
247 free( p_vout->p_text_renderer_data );
250 /*****************************************************************************
251 * Render: place string in picture
252 *****************************************************************************
253 * This function merges the previously rendered freetype glyphs into a picture
254 *****************************************************************************/
255 static void Render( vout_thread_t *p_vout, picture_t *p_pic,
256 const subpicture_t *p_subpic )
258 switch( p_vout->output.i_chroma )
260 /* I420 target, no scaling */
261 case VLC_FOURCC('I','4','2','0'):
262 case VLC_FOURCC('I','Y','U','V'):
263 case VLC_FOURCC('Y','V','1','2'):
264 RenderI420( p_vout, p_pic, p_subpic );
267 /* RV16 target, scaling */
268 case VLC_FOURCC('R','V','1','6'):
269 RenderRV16( p_vout, p_pic, p_subpic );
272 /* RV32 target, scaling */
273 case VLC_FOURCC('R','V','2','4'):
274 case VLC_FOURCC('R','V','3','2'):
275 RenderRV32( p_vout, p_pic, p_subpic );
277 /* NVidia or BeOS overlay, no scaling */
278 case VLC_FOURCC('Y','U','Y','2'):
279 RenderYUY2( p_vout, p_pic, p_subpic );
283 msg_Err( p_vout, "unknown chroma, can't render SPU" );
289 * Draw a string on a i420 (or similar) picture
291 static void RenderI420( vout_thread_t *p_vout, picture_t *p_pic,
292 const subpicture_t *p_subpic )
294 subpicture_sys_t *p_string = p_subpic->p_sys;
295 int i_plane, x, y, pen_x, pen_y;
299 for( p_line = p_subpic->p_sys->p_lines; p_line != NULL; p_line = p_line->p_next )
301 for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
304 int i_pitch = p_pic->p[ i_plane ].i_pitch;
306 p_in = p_pic->p[ i_plane ].p_pixels;
310 if ( p_string->i_flags & OSD_ALIGN_BOTTOM )
312 pen_y = p_pic->p[ i_plane ].i_lines - p_string->i_height -
313 p_string->i_y_margin;
317 pen_y = p_string->i_y_margin;
319 pen_y += p_vout->p_text_renderer_data->p_face->size->metrics.ascender >> 6;
320 if ( p_string->i_flags & OSD_ALIGN_RIGHT )
322 pen_x = i_pitch - p_line->i_width
323 - p_string->i_x_margin;
325 else if ( p_string->i_flags & OSD_ALIGN_LEFT )
327 pen_x = p_string->i_x_margin;
331 pen_x = i_pitch / 2 - p_line->i_width / 2
332 + p_string->i_x_margin;
335 for( i = 0; p_line->pp_glyphs[i] != NULL; i++ )
337 FT_BitmapGlyph p_glyph = p_line->pp_glyphs[ i ];
338 #define alpha p_vout->p_text_renderer_data->pi_gamma[ p_glyph->bitmap.buffer[ x + y * p_glyph->bitmap.width ] ]
339 #define pixel p_in[ ( p_line->p_glyph_pos[ i ].y + pen_y + y - p_glyph->top ) * i_pitch + x + pen_x + p_line->p_glyph_pos[ i ].x + p_glyph->left ]
340 for(y = 0; y < p_glyph->bitmap.rows; y++ )
342 for( x = 0; x < p_glyph->bitmap.width; x++ )
345 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
347 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
349 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
351 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
355 for(y = 0; y < p_glyph->bitmap.rows; y++ )
357 for( x = 0; x < p_glyph->bitmap.width; x++ )
359 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 ) +
360 ( 255 * alpha >> 8 );
369 if ( p_string->i_flags & OSD_ALIGN_BOTTOM )
371 pen_y = p_pic->p[i_plane].i_lines - ( p_string->i_height>>1) -
372 (p_string->i_y_margin>>1);
376 pen_y = p_string->i_y_margin >> 1;
378 pen_y += p_vout->p_text_renderer_data->p_face->size->metrics.ascender >> 7;
379 if ( p_string->i_flags & OSD_ALIGN_RIGHT )
381 pen_x = i_pitch - ( p_line->i_width >> 1 )
382 - ( p_string->i_x_margin >> 1 );
384 else if ( p_string->i_flags & OSD_ALIGN_LEFT )
386 pen_x = p_string->i_x_margin >> 1;
390 pen_x = i_pitch / 2 - p_line->i_width / 4
391 + p_string->i_x_margin / 2;
394 for( i = 0; p_line->pp_glyphs[i] != NULL; i++ )
396 FT_BitmapGlyph p_glyph = p_line->pp_glyphs[ i ];
397 #define alpha p_vout->p_text_renderer_data->pi_gamma[ p_glyph->bitmap.buffer[ ( x + y * p_glyph->bitmap.width ) ] ]
398 #define pixel p_in[ ( ( p_line->p_glyph_pos[ i ].y >> 1 ) + pen_y + ( y >> 1 ) - ( p_glyph->top >> 1 ) ) * i_pitch + ( x >> 1 ) + pen_x + ( p_line->p_glyph_pos[ i ].x >> 1 ) + ( p_glyph->left >>1) ]
399 for( y = 0; y < p_glyph->bitmap.rows; y+=2 )
401 for( x = 0; x < p_glyph->bitmap.width; x+=2 )
403 pixel = ( ( pixel * ( 0xFF - alpha ) ) >> 8 ) +
404 ( 0x80 * alpha >> 8 );
416 * Draw a string on a YUY2 picture
418 static void RenderYUY2( vout_thread_t *p_vout, picture_t *p_pic,
419 const subpicture_t *p_subpic )
421 subpicture_sys_t *p_string = p_subpic->p_sys;
422 int x, y, pen_x, pen_y;
426 for( p_line = p_subpic->p_sys->p_lines; p_line != NULL;
427 p_line = p_line->p_next )
430 int i_pitch = p_pic->p[0].i_pitch;
432 p_in = p_pic->p[0].p_pixels;
434 if ( p_string->i_flags & OSD_ALIGN_BOTTOM )
436 pen_y = p_pic->p[0].i_lines - p_string->i_height -
437 p_string->i_y_margin;
441 pen_y = p_string->i_y_margin;
443 pen_y += p_vout->p_text_renderer_data->p_face->size->metrics.ascender >> 6;
444 if ( p_string->i_flags & OSD_ALIGN_RIGHT )
446 pen_x = i_pitch - p_line->i_width
447 - p_string->i_x_margin;
449 else if ( p_string->i_flags & OSD_ALIGN_LEFT )
451 pen_x = p_string->i_x_margin;
455 pen_x = i_pitch / 2 /2 - p_line->i_width / 2 + p_string->i_x_margin;
458 for( i = 0; p_line->pp_glyphs[i] != NULL; i++ )
460 FT_BitmapGlyph p_glyph = p_line->pp_glyphs[ i ];
461 #define alpha p_vout->p_text_renderer_data->pi_gamma[ p_glyph->bitmap.buffer[ x + y * p_glyph->bitmap.width ] ]
462 #define pixel p_in[ ( p_line->p_glyph_pos[ i ].y + pen_y + y - p_glyph->top ) * i_pitch + 2 * ( x + pen_x + p_line->p_glyph_pos[ i ].x + p_glyph->left ) ]
463 for(y = 0; y < p_glyph->bitmap.rows; y++ )
465 for( x = 0; x < p_glyph->bitmap.width; x++ )
468 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
470 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
472 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
474 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 );
478 for(y = 0; y < p_glyph->bitmap.rows; y++ )
480 for( x = 0; x < p_glyph->bitmap.width; x++ )
482 pixel = ( ( pixel * ( 255 - alpha ) ) >> 8 ) +
483 ( 255 * alpha >> 8 );
493 * Draw a string on a RV32 picture
495 static void RenderRV32( vout_thread_t *p_vout, picture_t *p_pic,
496 const subpicture_t *p_subpic )
498 subpicture_sys_t *p_string = p_subpic->p_sys;
499 int i_plane, x, y, pen_x, pen_y;
505 for( p_line = p_subpic->p_sys->p_lines; p_line != NULL; p_line = p_line->p_next )
508 int i_pitch = p_pic->p[ i_plane ].i_pitch;
510 p_in = p_pic->p[ i_plane ].p_pixels;
512 if ( p_string->i_flags & OSD_ALIGN_BOTTOM )
514 pen_y = p_pic->p[ i_plane ].i_lines - p_string->i_height -
515 p_string->i_y_margin;
519 pen_y = p_string->i_y_margin;
521 pen_y += p_vout->p_text_renderer_data->p_face->size->metrics.ascender >> 6;
522 if ( p_string->i_flags & OSD_ALIGN_RIGHT )
524 pen_x = i_pitch - p_line->i_width
525 - p_string->i_x_margin;
527 else if ( p_string->i_flags & OSD_ALIGN_LEFT )
529 pen_x = p_string->i_x_margin;
533 pen_x = i_pitch / 2 / 4 - p_line->i_width / 2
534 + p_string->i_x_margin;
537 for( i = 0; p_line->pp_glyphs[i] != NULL; i++ )
539 FT_BitmapGlyph p_glyph = p_line->pp_glyphs[ i ];
540 #define alpha p_vout->p_text_renderer_data->pi_gamma[ p_glyph->bitmap.buffer[ x + y * p_glyph->bitmap.width ] ]
541 #define pixel( c ) p_in[ ( p_line->p_glyph_pos[ i ].y + pen_y + y - p_glyph->top ) * i_pitch + ( x + pen_x + p_line->p_glyph_pos[ i ].x + p_glyph->left ) * 4 + c ]
542 for(y = 0; y < p_glyph->bitmap.rows; y++ )
544 for( x = 0; x < p_glyph->bitmap.width; x++ )
547 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
548 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
549 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
551 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
552 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
553 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
555 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
556 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
557 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
559 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 );
560 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 );
561 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 );
565 for(y = 0; y < p_glyph->bitmap.rows; y++ )
567 for( x = 0; x < p_glyph->bitmap.width; x++ )
569 pixel( 0 ) = ( ( pixel( 0 ) * ( 255 - alpha ) ) >> 8 ) +
570 ( 255 * alpha >> 8 );
571 pixel( 1 ) = ( ( pixel( 1 ) * ( 255 - alpha ) ) >> 8 ) +
572 ( 255 * alpha >> 8 );
573 pixel( 2 ) = ( ( pixel( 2 ) * ( 255 - alpha ) ) >> 8 ) +
574 ( 255 * alpha >> 8 );
584 * This function receives a string and creates a subpicture for it. It
585 * also calculates the size needed for this string, and renders the
586 * needed glyphs into memory. It is used as pf_add_string callback in
587 * the vout method by this module
589 static int AddText ( vout_thread_t *p_vout, byte_t *psz_string,
590 text_style_t *p_style, int i_flags, int i_hmargin,
591 int i_vmargin, mtime_t i_start, mtime_t i_stop )
593 subpicture_sys_t *p_string;
594 int i, i_pen_y, i_pen_x, i_error, i_glyph_index, i_previous, i_char;
595 subpicture_t *p_subpic;
596 line_desc_t *p_line, *p_next;
604 if ( !psz_string || !*psz_string )
620 /* Create and initialize a subpicture */
621 p_subpic = vout_CreateSubPicture( p_vout, MEMORY_SUBPICTURE );
622 if ( p_subpic == NULL )
627 p_subpic->pf_render = Render;
628 p_subpic->pf_destroy = FreeString;
629 p_subpic->i_start = i_start;
630 p_subpic->i_stop = i_stop;
633 p_subpic->b_ephemer = VLC_TRUE;
637 p_subpic->b_ephemer = VLC_FALSE;
640 /* Create and initialize private data for the subpicture */
641 p_string = malloc( sizeof(subpicture_sys_t) );
642 if ( p_string == NULL )
644 msg_Err( p_vout, "Out of memory" );
647 p_subpic->p_sys = p_string;
648 p_string->i_flags = i_flags;
649 p_string->i_x_margin = i_hmargin;
650 p_string->i_y_margin = i_vmargin;
651 p_string->p_lines = 0;
652 p_string->psz_text = strdup( psz_string );
654 /* Calculate relative glyph positions and a bounding box for the
656 p_line = NewLine( psz_string );
659 msg_Err( p_vout, "Out of memory" );
662 p_string->p_lines = p_line;
668 #define face p_vout->p_text_renderer_data->p_face
669 #define glyph face->glyph
673 i_char = GetUnicodeCharFromUTF8( &psz_string );
675 if ( i_char == '\r' ) /* ignore CR chars wherever they may be */
680 if ( i_char == '\n' )
682 p_next = NewLine( psz_string );
685 msg_Err( p_vout, "Out of memory" );
688 p_line->p_next = p_next;
689 p_line->i_width = line.xMax;
690 p_line->i_height = face->size->metrics.height >> 6;
691 p_line->pp_glyphs[ i ] = NULL;
693 result.x = __MAX( result.x, line.xMax );
694 result.y += face->size->metrics.height >> 6;
700 i_pen_y += face->size->metrics.height >> 6;
701 msg_Dbg( p_vout, "Creating new line, i is %d", i );
706 i_glyph_index = FT_Get_Char_Index( face, i_char );
707 if ( p_vout->p_text_renderer_data->i_use_kerning && i_glyph_index
711 FT_Get_Kerning( face, i_previous, i_glyph_index,
712 ft_kerning_default, &delta );
713 i_pen_x += delta.x >> 6;
716 p_line->p_glyph_pos[ i ].x = i_pen_x;
717 p_line->p_glyph_pos[ i ].y = i_pen_y;
718 i_error = FT_Load_Glyph( face, i_glyph_index, FT_LOAD_DEFAULT );
721 msg_Err( p_vout, "FT_Load_Glyph returned %d", i_error );
724 i_error = FT_Get_Glyph( glyph, &tmp_glyph );
727 msg_Err( p_vout, "FT_Get_Glyph returned %d", i_error );
730 FT_Glyph_Get_CBox( tmp_glyph, ft_glyph_bbox_pixels, &glyph_size );
731 i_error = FT_Glyph_To_Bitmap( &tmp_glyph, ft_render_mode_normal,
733 if ( i_error ) continue;
734 p_line->pp_glyphs[ i ] = (FT_BitmapGlyph)tmp_glyph;
737 line.xMax = p_line->p_glyph_pos[i].x + glyph_size.xMax - glyph_size.xMin;
738 line.yMax = __MAX( line.yMax, glyph_size.yMax );
739 line.yMin = __MIN( line.yMin, glyph_size.yMin );
741 i_previous = i_glyph_index;
742 i_pen_x += glyph->advance.x >> 6;
745 p_line->i_width = line.xMax;
746 p_line->i_height = face->size->metrics.height >> 6;
747 p_line->pp_glyphs[ i ] = NULL;
748 result.x = __MAX( result.x, line.xMax );
749 result.y += line.yMax - line.yMin;
750 p_string->i_height = result.y;
751 p_string->i_width = result.x;
752 vout_DisplaySubPicture( p_vout, p_subpic );
759 FreeString( p_subpic );
760 vout_DestroySubPicture( p_vout, p_subpic );
764 static void FreeString( subpicture_t *p_subpic )
767 subpicture_sys_t *p_string = p_subpic->p_sys;
768 line_desc_t *p_line, *p_next;
770 if( p_subpic->p_sys == NULL ) return;
772 for( p_line = p_string->p_lines; p_line != NULL; p_line = p_next )
774 p_next = p_line->p_next;
775 for( i = 0; p_line->pp_glyphs[ i ] != NULL; i++ )
777 FT_Done_Glyph( (FT_Glyph)p_line->pp_glyphs[ i ] );
779 free( p_line->pp_glyphs );
780 free( p_line->p_glyph_pos );
784 free( p_string->psz_text );
788 /* convert one or more utf8 bytes into a unicode character */
789 static int GetUnicodeCharFromUTF8( byte_t **ppsz_utf8_string )
791 int i_remaining_bytes, i_char = 0;
792 if( ( **ppsz_utf8_string & 0xFC ) == 0xFC )
794 i_char = **ppsz_utf8_string & 1;
795 i_remaining_bytes = 5;
797 else if( ( **ppsz_utf8_string & 0xF8 ) == 0xF8 )
799 i_char = **ppsz_utf8_string & 3;
800 i_remaining_bytes = 4;
802 else if( ( **ppsz_utf8_string & 0xF0 ) == 0xF0 )
804 i_char = **ppsz_utf8_string & 7;
805 i_remaining_bytes = 3;
807 else if( ( **ppsz_utf8_string & 0xE0 ) == 0xE0 )
809 i_char = **ppsz_utf8_string & 15;
810 i_remaining_bytes = 2;
812 else if( ( **ppsz_utf8_string & 0xC0 ) == 0xC0 )
814 i_char = **ppsz_utf8_string & 31;
815 i_remaining_bytes = 1;
819 i_char = **ppsz_utf8_string;
820 i_remaining_bytes = 0;
822 while( i_remaining_bytes )
824 (*ppsz_utf8_string)++;
826 i_char = ( i_char << 6 ) + ( **ppsz_utf8_string & 0x3F );
828 (*ppsz_utf8_string)++;
832 static line_desc_t *NewLine( byte_t *psz_string )
835 line_desc_t *p_line = malloc( sizeof(line_desc_t) );
840 p_line->i_height = 0;
842 p_line->p_next = NULL;
844 /* We don't use CountUtf8Characters() here because we are not acutally
845 * sure the string is utf8. Better be safe than sorry. */
846 i_count = strlen( psz_string );
848 p_line->pp_glyphs = malloc( sizeof(FT_BitmapGlyph)
850 if( p_line->pp_glyphs == NULL )
855 p_line->p_glyph_pos = malloc( sizeof( FT_Vector )
857 if( p_line->p_glyph_pos == NULL )
859 free( p_line->pp_glyphs );