X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fmisc%2Ffreetype.c;h=4e1906fd3722fb78da9b00bfea0b767251847662;hb=be378fbc80c384e2541517d6853b59411b7e67de;hp=51b3bdd7dd912dfd34fa308e2770d9bfe88fc9e8;hpb=df61d33b06e2b3cbbe746b2f5a9bea5b370c24ff;p=vlc diff --git a/modules/misc/freetype.c b/modules/misc/freetype.c index 51b3bdd7dd..4e1906fd37 100644 --- a/modules/misc/freetype.c +++ b/modules/misc/freetype.c @@ -31,7 +31,8 @@ # include "config.h" #endif -#include +#include +#include #include #include #include @@ -72,36 +73,14 @@ #include #endif -typedef struct line_desc_t line_desc_t; +#include /***************************************************************************** - * Local prototypes + * Module descriptor *****************************************************************************/ static int Create ( vlc_object_t * ); static void Destroy( vlc_object_t * ); -static int LoadFontsFromAttachments( filter_t *p_filter ); - -/* The RenderText call maps to pf_render_string, defined in vlc_filter.h */ -static int RenderText( filter_t *, subpicture_region_t *, - subpicture_region_t * ); -#ifdef HAVE_FONTCONFIG -static int RenderHtml( filter_t *, subpicture_region_t *, - subpicture_region_t * ); -static char *FontConfig_Select( FcConfig *, const char *, - bool, bool, int * ); -static int CheckIfFontBuildComplete( filter_t *p_filter ); -#endif -static line_desc_t *NewLine( int ); - -static int GetFontSize( filter_t *p_filter ); -static int SetFontSize( filter_t *, int ); -static void YUVFromRGB( uint32_t i_argb, - uint8_t *pi_y, uint8_t *pi_u, uint8_t *pi_v ); - -/***************************************************************************** - * Module descriptor - *****************************************************************************/ #define FONT_TEXT N_("Font") #define FONT_LONGTEXT N_("Filename for the font you want to use") #define FONTSIZE_TEXT N_("Font size in pixels") @@ -123,9 +102,9 @@ static void YUVFromRGB( uint32_t i_argb, "fonts that will be rendered on the video. If absolute font size is set, "\ "relative size will be overriden." ) -static int pi_sizes[] = { 20, 18, 16, 12, 6 }; -static const char *ppsz_sizes_text[] = { N_("Smaller"), N_("Small"), N_("Normal"), - N_("Large"), N_("Larger") }; +static const int pi_sizes[] = { 20, 18, 16, 12, 6 }; +static const char *const ppsz_sizes_text[] = { + N_("Smaller"), N_("Small"), N_("Normal"), N_("Large"), N_("Larger") }; #define YUVP_TEXT N_("Use YUVP renderer") #define YUVP_LONGTEXT N_("This renders the font using \"paletized YUV\". " \ "This option is only needed if you want to encode into DVB subtitles" ) @@ -137,22 +116,22 @@ static const char *ppsz_sizes_text[] = { N_("Smaller"), N_("Small"), N_("Normal" #define EFFECT_OUTLINE 2 #define EFFECT_OUTLINE_FAT 3 -static int pi_effects[] = { 1, 2, 3 }; -static const char *ppsz_effects_text[] = { N_("Background"),N_("Outline"), - N_("Fat Outline") }; -static int pi_color_values[] = { +static int const pi_effects[] = { 1, 2, 3 }; +static const char *const ppsz_effects_text[] = { + N_("Background"),N_("Outline"), N_("Fat Outline") }; +static const int pi_color_values[] = { 0x00000000, 0x00808080, 0x00C0C0C0, 0x00FFFFFF, 0x00800000, 0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x00808000, 0x00008000, 0x00008080, 0x0000FF00, 0x00800080, 0x00000080, 0x000000FF, 0x0000FFFF }; -static const char *ppsz_color_descriptions[] = { +static const char *const ppsz_color_descriptions[] = { N_("Black"), N_("Gray"), N_("Silver"), N_("White"), N_("Maroon"), N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Olive"), N_("Green"), N_("Teal"), N_("Lime"), N_("Purple"), N_("Navy"), N_("Blue"), N_("Aqua") }; vlc_module_begin(); - set_shortname( _("Text renderer")); - set_description( _("Freetype2 font renderer") ); + set_shortname( N_("Text renderer")); + set_description( N_("Freetype2 font renderer") ); set_category( CAT_VIDEO ); set_subcategory( SUBCAT_VIDEO_SUBPIC ); @@ -185,6 +164,31 @@ vlc_module_begin(); set_callbacks( Create, Destroy ); vlc_module_end(); + + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ + +/* The RenderText call maps to pf_render_string, defined in vlc_filter.h */ +static int RenderText( filter_t *, subpicture_region_t *, + subpicture_region_t * ); +#ifdef HAVE_FONTCONFIG +static int RenderHtml( filter_t *, subpicture_region_t *, + subpicture_region_t * ); +static char *FontConfig_Select( FcConfig *, const char *, + bool, bool, int * ); +#endif + + +static int LoadFontsFromAttachments( filter_t *p_filter ); + +static int GetFontSize( filter_t *p_filter ); +static int SetFontSize( filter_t *, int ); +static void YUVFromRGB( uint32_t i_argb, + uint8_t *pi_y, uint8_t *pi_u, uint8_t *pi_v ); + +typedef struct line_desc_t line_desc_t; struct line_desc_t { /** NULL-terminated list of glyphs making the string */ @@ -210,6 +214,7 @@ struct line_desc_t line_desc_t *p_next; }; +static line_desc_t *NewLine( int ); typedef struct font_stack_t font_stack_t; struct font_stack_t @@ -236,8 +241,14 @@ typedef struct static int Render( filter_t *, subpicture_region_t *, line_desc_t *, int, int); static void FreeLines( line_desc_t * ); static void FreeLine( line_desc_t * ); + #ifdef HAVE_FONTCONFIG -static void FontBuilder( vlc_object_t *p_this); +static vlc_object_t *FontBuilderAttach( filter_t *p_filter, vlc_mutex_t **pp_lock ); +static void FontBuilderDetach( filter_t *p_filter, vlc_object_t *p_fontbuilder ); +static void FontBuilderThread( vlc_object_t *p_this); +static void FontBuilderDestructor( vlc_object_t *p_this ); +static int FontBuilderDone( vlc_object_t*, const char *, vlc_value_t, vlc_value_t, + void* ); #endif /***************************************************************************** @@ -259,13 +270,15 @@ struct filter_sys_t int i_default_font_size; int i_display_height; #ifdef HAVE_FONTCONFIG + vlc_mutex_t *p_fontconfig_lock; + bool b_fontconfig_ok; FcConfig *p_fontconfig; - bool b_fontconfig_ok; - vlc_mutex_t fontconfig_lock; #endif input_attachment_t **pp_font_attachments; int i_font_attachments; + + vlc_object_t *p_fontbuilder; }; /***************************************************************************** @@ -280,16 +293,11 @@ static int Create( vlc_object_t *p_this ) char *psz_fontfile = NULL; int i_error; vlc_value_t val; - vlc_mutex_t *lock; - vlc_object_t *p_fontbuilder; /* Allocate structure */ p_filter->p_sys = p_sys = malloc( sizeof( filter_sys_t ) ); if( !p_sys ) - { - msg_Err( p_filter, "out of memory" ); return VLC_ENOMEM; - } p_sys->p_face = 0; p_sys->p_library = 0; p_sys->i_font_size = 0; @@ -321,10 +329,7 @@ static int Create( vlc_object_t *p_this ) free( psz_fontfile ); psz_fontfile = (char *)malloc( PATH_MAX + 1 ); if( !psz_fontfile ) - { - msg_Err( p_filter, "out of memory" ); goto error; - } #ifdef WIN32 GetWindowsDirectory( psz_fontfile, PATH_MAX + 1 ); strcat( psz_fontfile, "\\fonts\\arial.ttf" ); @@ -363,60 +368,9 @@ static int Create( vlc_object_t *p_this ) } #ifdef HAVE_FONTCONFIG - vlc_mutex_init( p_filter, &p_sys->fontconfig_lock ); p_sys->b_fontconfig_ok = false; p_sys->p_fontconfig = NULL; - - /* Check for an existing Fontbuilder thread */ - lock = var_AcquireMutex( "fontbuilder" ); - p_fontbuilder = vlc_object_find_name( p_filter->p_libvlc, - "fontlist builder", - FIND_CHILD ); - - if( ! p_fontbuilder ) - { - /* Create the FontBuilder thread as a child of a top-level - * object, so that it can survive the destruction of the - * freetype object - the fontlist only needs to be built once, - * and calling the fontbuild a second time while the first is - * still in progress can cause thread instabilities. - */ - - p_fontbuilder = vlc_object_create( p_filter->p_libvlc, - VLC_OBJECT_GENERIC ); - if( p_fontbuilder ) - { - p_fontbuilder->psz_object_name = "fontlist builder"; - vlc_object_attach( p_fontbuilder, p_filter->p_libvlc ); - - var_Create( p_fontbuilder, "build-done", VLC_VAR_BOOL ); - var_SetBool( p_fontbuilder, "build-done", false ); - - if( vlc_thread_create( p_fontbuilder, - "fontlist builder", - FontBuilder, - VLC_THREAD_PRIORITY_LOW, - false ) ) - { - /* Don't destroy the fontconfig object - we won't be able to do - * italics or bold or change the font face, but we will still - * be able to do underline and change the font size. - */ - msg_Warn( p_filter, "fontconfig database builder thread can't " - "be launched. Font styling support will be limited." ); - } - } - else - { - vlc_object_release( p_fontbuilder ); - } - } - else - { - vlc_object_release( p_fontbuilder ); - } - vlc_mutex_unlock( lock ); - + p_sys->p_fontbuilder = FontBuilderAttach( p_filter, &p_sys->p_fontconfig_lock ); #endif p_sys->i_use_kerning = FT_HAS_KERNING( p_sys->p_face ); @@ -464,36 +418,106 @@ static void Destroy( vlc_object_t *p_this ) int k; for( k = 0; k < p_sys->i_font_attachments; k++ ) - { vlc_input_attachment_Delete( p_sys->pp_font_attachments[k] ); - } free( p_sys->pp_font_attachments ); } #ifdef HAVE_FONTCONFIG - vlc_mutex_destroy( &p_sys->fontconfig_lock ); + FontBuilderDetach( p_filter, p_sys->p_fontbuilder ); +#endif - if( p_sys->p_fontconfig ) - { - FcConfigDestroy( p_sys->p_fontconfig ); - p_sys->p_fontconfig = NULL; - } /* FcFini asserts calling the subfunction FcCacheFini() * even if no other library functions have been made since FcInit(), * so don't call it. */ -#endif + FT_Done_Face( p_sys->p_face ); FT_Done_FreeType( p_sys->p_library ); free( p_sys ); } #ifdef HAVE_FONTCONFIG +static vlc_object_t *FontBuilderAttach( filter_t *p_filter, vlc_mutex_t **pp_lock ) +{ + /* Check for an existing Fontbuilder thread */ + vlc_mutex_t *p_lock = var_AcquireMutex( "fontbuilder" ); + vlc_object_t *p_fontbuilder = + vlc_object_find_name( p_filter->p_libvlc, + "fontlist builder", FIND_CHILD ); + + if( !p_fontbuilder ) + { + /* Create the FontBuilderThread thread as a child of a top-level + * object, so that it can survive the destruction of the + * freetype object - the fontlist only needs to be built once, + * and calling the fontbuild a second time while the first is + * still in progress can cause thread instabilities. + * + * XXX The fontbuilder will be destroy as soon as it is unused. + */ + + p_fontbuilder = vlc_object_create( p_filter->p_libvlc, + sizeof(vlc_object_t) ); + if( p_fontbuilder ) + { + p_fontbuilder->psz_object_name = strdup( "fontlist builder" ); + p_fontbuilder->p_private = NULL; + vlc_object_set_destructor( p_fontbuilder, FontBuilderDestructor ); + + vlc_object_attach( p_fontbuilder, p_filter->p_libvlc ); + + var_Create( p_fontbuilder, "build-done", VLC_VAR_BOOL ); + var_SetBool( p_fontbuilder, "build-done", false ); -static void FontBuilder( vlc_object_t *p_this ) + if( vlc_thread_create( p_fontbuilder, + "fontlist builder", + FontBuilderThread, + VLC_THREAD_PRIORITY_LOW, + false ) ) + { + msg_Warn( p_filter, "fontconfig database builder thread can't " + "be launched. Font styling support will be limited." ); + } + } + } + if( p_fontbuilder ) + { + var_AddCallback( p_fontbuilder, "build-done", FontBuilderDone, p_filter ); + var_TriggerCallback( p_fontbuilder, "build-done" ); + } + vlc_mutex_unlock( p_lock ); + *pp_lock = p_lock; + return p_fontbuilder; +} +static void FontBuilderDetach( filter_t *p_filter, vlc_object_t *p_fontbuilder ) +{ + vlc_mutex_t *lock = var_AcquireMutex( "fontbuilder" ); + if( p_fontbuilder ) + { + const bool b_alive = vlc_object_alive( p_fontbuilder ); + + var_DelCallback( p_fontbuilder, "build-done", FontBuilderDone, p_filter ); + + /* We wait for the thread on the first FontBuilderDetach */ + if( b_alive ) + { + vlc_object_kill( p_fontbuilder ); + vlc_mutex_unlock( lock ); + + /* We need to unlock otherwise we may not join (the thread waiting + * for the lock). It is safe to unlock as no one else will try a + * join and we have a reference on the object) */ + vlc_thread_join( p_fontbuilder ); + + vlc_mutex_lock( lock ); + } + vlc_object_release( p_fontbuilder ); + } + vlc_mutex_unlock( lock ); +} +static void FontBuilderThread( vlc_object_t *p_this ) { FcConfig *p_fontconfig = FcInitLoadConfig(); - vlc_mutex_t *lock; vlc_thread_ready( p_this ); @@ -501,6 +525,7 @@ static void FontBuilder( vlc_object_t *p_this ) { mtime_t t1, t2; + //msg_Dbg( p_this, "Building font database..." ); msg_Dbg( p_this, "Building font database..." ); t1 = mdate(); if(! FcConfigBuildFonts( p_fontconfig )) @@ -517,16 +542,40 @@ static void FontBuilder( vlc_object_t *p_this ) msg_Dbg( p_this, "Finished building font database." ); msg_Dbg( p_this, "Took %ld seconds", (long)((t2 - t1)/1000000) ); - lock = var_AcquireMutex( "fontbuilder" ); + vlc_mutex_t *p_lock = var_AcquireMutex( "fontbuilder" ); + p_this->p_private = p_fontconfig; + vlc_mutex_unlock( p_lock ); + var_SetBool( p_this, "build-done", true ); + } +} +static void FontBuilderDestructor( vlc_object_t *p_this ) +{ + FcConfig *p_fontconfig = p_this->p_private; + if( p_fontconfig ) FcConfigDestroy( p_fontconfig ); - vlc_mutex_unlock( lock ); - } - vlc_object_detach( p_this ); - vlc_object_release( p_this ); } +static int FontBuilderDone( vlc_object_t *p_this, const char *psz_var, + vlc_value_t oldval, vlc_value_t newval, void *param ) +{ + filter_t *p_filter = param; + filter_sys_t *p_sys = p_filter->p_sys; + + if( newval.b_bool ) + { + vlc_mutex_t *p_lock = var_AcquireMutex( "fontbuilder" ); + + p_sys->b_fontconfig_ok = true; + p_sys->p_fontconfig = p_this->p_private; + + vlc_mutex_unlock( p_lock ); + } + VLC_UNUSED(psz_var); + VLC_UNUSED(oldval); + return VLC_SUCCESS; +} #endif /***************************************************************************** @@ -1113,10 +1162,7 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out, psz_unicode = psz_unicode_orig = malloc( ( strlen(psz_string) + 1 ) * sizeof(uint32_t) ); if( psz_unicode == NULL ) - { - msg_Err( p_filter, "out of memory" ); goto error; - } #if defined(WORDS_BIGENDIAN) iconv_handle = vlc_iconv_open( "UCS-4BE", "UTF-8" ); #else @@ -1159,10 +1205,7 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out, p_fribidi_string = malloc( (i_string_length + 1) * sizeof(uint32_t) ); if( !p_fribidi_string ) - { - msg_Err( p_filter, "out of memory" ); goto error; - } /* Do bidi conversion line-by-line */ while( pos < i_string_length ) @@ -1203,10 +1246,7 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out, /* Calculate relative glyph positions and a bounding box for the * entire string */ if( !(p_line = NewLine( strlen( psz_string ))) ) - { - msg_Err( p_filter, "out of memory" ); goto error; - } p_lines = p_line; i_pen_x = i_pen_y = 0; i_previous = i = 0; @@ -1227,10 +1267,7 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out, { psz_line_start = psz_unicode; if( !(p_next = NewLine( strlen( psz_string ))) ) - { - msg_Err( p_filter, "out of memory" ); goto error; - } p_line->p_next = p_next; p_line->i_width = line.xMax; p_line->i_height = face->size->metrics.height >> 6; @@ -1293,6 +1330,7 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out, glyph_size.xMin + ((FT_BitmapGlyph)tmp_glyph)->left; if( line.xMax > (int)p_filter->fmt_out.video.i_visible_width - 20 ) { + FT_Done_Glyph( (FT_Glyph)p_line->pp_glyphs[ i ] ); p_line->pp_glyphs[ i ] = NULL; FreeLine( p_line ); p_line = NewLine( strlen( psz_string )); @@ -2187,37 +2225,6 @@ static int CheckForEmbeddedFont( filter_sys_t *p_sys, FT_Face *pp_face, ft_style return VLC_EGENERIC; } -static int CheckIfFontBuildComplete( filter_t *p_filter ) -{ - filter_sys_t *p_sys = p_filter->p_sys; - vlc_object_t *p_fb = vlc_object_find_name( p_filter->p_libvlc, - "fontlist builder", - FIND_CHILD ); - if( p_fb ) - { - vlc_mutex_t *lock = var_AcquireMutex( "fontbuilder" ); - vlc_value_t val; - - if( VLC_SUCCESS == var_Get( p_fb, "build-done", &val )) - { - p_sys->b_fontconfig_ok = val.b_bool; - - if( p_sys->b_fontconfig_ok ) - { - FcInit(); - p_sys->p_fontconfig = FcConfigGetCurrent(); - } - else - msg_Dbg( p_filter, "Font Build still not complete" ); - } - vlc_mutex_unlock( lock ); - vlc_object_release( p_fb ); - - return VLC_SUCCESS; - } - return VLC_EGENERIC; -} - static int ProcessLines( filter_t *p_filter, uint32_t *psz_text, int i_len, @@ -2289,7 +2296,6 @@ static int ProcessLines( filter_t *p_filter, ! p_new_positions || ! p_levels ) { - msg_Err( p_filter, "out of memory" ); free( p_levels ); free( p_old_positions ); free( p_new_positions ); @@ -2434,23 +2440,22 @@ static int ProcessLines( filter_t *p_filter, /* Look for a match amongst our attachments first */ CheckForEmbeddedFont( p_sys, &p_face, p_style ); - if( !p_sys->b_fontconfig_ok ) + if( ! p_face ) { - if( VLC_EGENERIC == CheckIfFontBuildComplete( p_filter )) - msg_Err( p_filter, "Can't find FontBuilder thread!" ); - } - - if( ! p_face && p_sys->b_fontconfig_ok ) - { - char *psz_fontfile; - vlc_mutex_lock( &p_sys->fontconfig_lock ); + char *psz_fontfile = NULL; - psz_fontfile = FontConfig_Select( p_sys->p_fontconfig, - p_style->psz_fontname, - p_style->b_bold, - p_style->b_italic, - &i_idx ); - vlc_mutex_unlock( &p_sys->fontconfig_lock ); + vlc_mutex_lock( p_sys->p_fontconfig_lock ); + if( p_sys->b_fontconfig_ok ) + { + /* FIXME Is there really a race condition between FontConfig_Select with default fontconfig(NULL) + * and FcConfigBuildFonts ? If not it would be better to remove the check on b_fontconfig_ok */ + psz_fontfile = FontConfig_Select( p_sys->p_fontconfig, + p_style->psz_fontname, + p_style->b_bold, + p_style->b_italic, + &i_idx ); + } + vlc_mutex_unlock( p_sys->p_fontconfig_lock ); if( psz_fontfile && ! *psz_fontfile ) { @@ -2510,7 +2515,6 @@ static int ProcessLines( filter_t *p_filter, malloc( (k - i_prev + 1) * sizeof( uint32_t )); if( !psz_unicode ) { - msg_Err( p_filter, "out of memory" ); if( p_face ) FT_Done_Face( p_face ); free( pp_char_styles ); free( psz_unicode ); @@ -2529,7 +2533,6 @@ static int ProcessLines( filter_t *p_filter, { if( !(p_line = NewLine( i_len - i_prev)) ) { - msg_Err( p_filter, "out of memory" ); if( p_face ) FT_Done_Face( p_face ); free( pp_char_styles ); free( psz_unicode ); @@ -2793,8 +2796,8 @@ static char* FontConfig_Select( FcConfig* priv, const char* family, FcPatternAddString( pat, FC_FAMILY, (const FcChar8*)family ); FcPatternAddBool( pat, FC_OUTLINE, FcTrue ); - FcPatternAddInteger( pat, FC_SLANT, b_italic ? 1000 : 0 ); - FcPatternAddInteger( pat, FC_WEIGHT, b_bold ? 1000 : 0 ); + FcPatternAddInteger( pat, FC_SLANT, b_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN ); + FcPatternAddInteger( pat, FC_WEIGHT, b_bold ? FC_WEIGHT_EXTRABOLD : FC_WEIGHT_NORMAL ); FcDefaultSubstitute( pat );