]> git.sesse.net Git - vlc/blobdiff - modules/misc/freetype.c
Merge branch 'master' of git@git.videolan.org:vlc
[vlc] / modules / misc / freetype.c
index 3b1c7f92ebc406dd3883e9888ae4fbb775377419..51b3bdd7dd912dfd34fa308e2770d9bfe88fc9e8 100644 (file)
  * Preamble
  *****************************************************************************/
 
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
 #include <vlc/vlc.h>
 #include <vlc_vout.h>
 #include <vlc_osd.h>
 #include <vlc_xml.h>
 #include <vlc_input.h>
 
-#ifdef HAVE_LINUX_LIMITS_H
-#   include <linux/limits.h>
-#endif
-
-#include <time.h>
 #include <math.h>
 #include <errno.h>
 
@@ -90,7 +89,8 @@ static int RenderText( filter_t *, subpicture_region_t *,
 static int RenderHtml( filter_t *, subpicture_region_t *,
                        subpicture_region_t * );
 static char *FontConfig_Select( FcConfig *, const char *,
-                                vlc_bool_t, vlc_bool_t, int * );
+                                bool, bool, int * );
+static int CheckIfFontBuildComplete( filter_t *p_filter );
 #endif
 static line_desc_t *NewLine( int );
 
@@ -157,29 +157,29 @@ vlc_module_begin();
     set_subcategory( SUBCAT_VIDEO_SUBPIC );
 
     add_file( "freetype-font", DEFAULT_FONT, NULL, FONT_TEXT, FONT_LONGTEXT,
-              VLC_FALSE );
+              false );
 
     add_integer( "freetype-fontsize", 0, NULL, FONTSIZE_TEXT,
-                 FONTSIZE_LONGTEXT, VLC_TRUE );
+                 FONTSIZE_LONGTEXT, true );
 
     /* opacity valid on 0..255, with default 255 = fully opaque */
     add_integer_with_range( "freetype-opacity", 255, 0, 255, NULL,
-        OPACITY_TEXT, OPACITY_LONGTEXT, VLC_TRUE );
+        OPACITY_TEXT, OPACITY_LONGTEXT, true );
 
     /* hook to the color values list, with default 0x00ffffff = white */
     add_integer( "freetype-color", 0x00FFFFFF, NULL, COLOR_TEXT,
-                 COLOR_LONGTEXT, VLC_FALSE );
+                 COLOR_LONGTEXT, false );
         change_integer_list( pi_color_values, ppsz_color_descriptions, 0 );
 
     add_integer( "freetype-rel-fontsize", 16, NULL, FONTSIZER_TEXT,
-                 FONTSIZER_LONGTEXT, VLC_FALSE );
+                 FONTSIZER_LONGTEXT, false );
         change_integer_list( pi_sizes, ppsz_sizes_text, 0 );
     add_integer( "freetype-effect", 2, NULL, EFFECT_TEXT,
-                 EFFECT_LONGTEXT, VLC_FALSE );
+                 EFFECT_LONGTEXT, false );
         change_integer_list( pi_effects, ppsz_effects_text, 0 );
 
     add_bool( "freetype-yuvp", 0, NULL, YUVP_TEXT,
-              YUVP_LONGTEXT, VLC_TRUE );
+              YUVP_LONGTEXT, true );
     set_capability( "text renderer", 100 );
     add_shortcut( "text" );
     set_callbacks( Create, Destroy );
@@ -198,7 +198,7 @@ struct line_desc_t
     uint32_t       *p_fg_rgb;
     uint32_t       *p_bg_rgb;
     uint8_t        *p_fg_bg_ratio; /* 0x00=100% FG --> 0x7F=100% BG */
-    vlc_bool_t      b_new_color_mode;
+    bool      b_new_color_mode;
     /** underline information -- only supplied if text should be underlined */
     uint16_t       *pi_underline_offset;
     uint16_t       *pi_underline_thickness;
@@ -227,9 +227,9 @@ typedef struct
     int         i_font_size;
     uint32_t    i_font_color;         /* ARGB */
     uint32_t    i_karaoke_bg_color;   /* ARGB */
-    vlc_bool_t  b_italic;
-    vlc_bool_t  b_bold;
-    vlc_bool_t  b_underline;
+    bool  b_italic;
+    bool  b_bold;
+    bool  b_underline;
     char       *psz_fontname;
 } ft_style_t;
 
@@ -250,7 +250,7 @@ struct filter_sys_t
 {
     FT_Library     p_library;   /* handle to library     */
     FT_Face        p_face;      /* handle to face object */
-    vlc_bool_t     i_use_kerning;
+    bool     i_use_kerning;
     uint8_t        i_font_opacity;
     int            i_font_color;
     int            i_font_size;
@@ -260,7 +260,7 @@ struct filter_sys_t
     int            i_display_height;
 #ifdef HAVE_FONTCONFIG
     FcConfig      *p_fontconfig;
-    vlc_bool_t     b_fontconfig_ok;
+    bool     b_fontconfig_ok;
     vlc_mutex_t    fontconfig_lock;
 #endif
 
@@ -275,11 +275,13 @@ struct filter_sys_t
  *****************************************************************************/
 static int Create( vlc_object_t *p_this )
 {
-    filter_t *p_filter = (filter_t *)p_this;
-    filter_sys_t *p_sys;
-    char *psz_fontfile = NULL;
-    int i_error;
-    vlc_value_t val;
+    filter_t      *p_filter = (filter_t *)p_this;
+    filter_sys_t  *p_sys;
+    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 ) );
@@ -316,7 +318,7 @@ static int Create( vlc_object_t *p_this )
     psz_fontfile = val.psz_string;
     if( !psz_fontfile || !*psz_fontfile )
     {
-        if( psz_fontfile ) free( psz_fontfile );
+        free( psz_fontfile );
         psz_fontfile = (char *)malloc( PATH_MAX + 1 );
         if( !psz_fontfile )
         {
@@ -334,38 +336,6 @@ static int Create( vlc_object_t *p_this )
 #endif
     }
 
-#ifdef HAVE_FONTCONFIG
-    vlc_mutex_init( p_filter, &p_sys->fontconfig_lock );
-    p_sys->b_fontconfig_ok = VLC_FALSE;
-
-    p_sys->p_fontconfig = FcInitLoadConfig();
-
-    if( p_sys->p_fontconfig )
-    {
-        /* Normally this doesn't take very long, but an initial build of
-         * the fontconfig database or the addition of a lot of new fonts
-         * can cause it to take several minutes for a large number of fonts.
-         * Even a small number can take several seconds - much longer than
-         * we can afford to block, so we build the list in the background
-         * and if it succeeds we allow fontconfig to be used.
-         */
-        if( vlc_thread_create( p_filter, "fontlist builder", FontBuilder,
-                       VLC_THREAD_PRIORITY_LOW, VLC_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
-    {
-        msg_Warn( p_filter, "Couldn't initialise Fontconfig. "
-                            "Font styling won't be available." );
-    }
-#endif
     i_error = FT_Init_FreeType( &p_sys->p_library );
     if( i_error )
     {
@@ -392,24 +362,80 @@ static int Create( vlc_object_t *p_this )
         goto error;
     }
 
+#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 );
+
+#endif
+
     p_sys->i_use_kerning = FT_HAS_KERNING( p_sys->p_face );
 
     var_Get( p_filter, "freetype-fontsize", &val );
     p_sys->i_default_font_size = val.i_int;
     if( SetFontSize( p_filter, 0 ) != VLC_SUCCESS ) goto error;
 
-    if( psz_fontfile ) free( psz_fontfile );
+    free( psz_fontfile );
 
     p_sys->pp_font_attachments = NULL;
     p_sys->i_font_attachments = 0;
 
     p_filter->pf_render_text = RenderText;
 #ifdef HAVE_FONTCONFIG
-    if( p_sys->p_fontconfig )
-        p_filter->pf_render_html = RenderHtml;
-    else
+    p_filter->pf_render_html = RenderHtml;
+#else
+    p_filter->pf_render_html = NULL;
 #endif
-        p_filter->pf_render_html = NULL;
 
     LoadFontsFromAttachments( p_filter );
 
@@ -418,7 +444,7 @@ static int Create( vlc_object_t *p_this )
  error:
     if( p_sys->p_face ) FT_Done_Face( p_sys->p_face );
     if( p_sys->p_library ) FT_Done_FreeType( p_sys->p_library );
-    if( psz_fontfile ) free( psz_fontfile );
+    free( psz_fontfile );
     free( p_sys );
     return VLC_EGENERIC;
 }
@@ -464,36 +490,41 @@ static void Destroy( vlc_object_t *p_this )
 
 #ifdef HAVE_FONTCONFIG
 
-static void FontBuilder( vlc_object_t *p_this)
+static void FontBuilder( vlc_object_t *p_this )
 {
-    filter_t *p_filter = (filter_t*)p_this;
-    filter_sys_t *p_sys = p_filter->p_sys;
-    time_t    t1, t2;
+    FcConfig      *p_fontconfig = FcInitLoadConfig();
+    vlc_mutex_t   *lock;
 
-    /* Find the session to announce */
-    vlc_mutex_lock( &p_sys->fontconfig_lock );
+    vlc_thread_ready( p_this );
 
-    msg_Dbg( p_filter, "Building font database..." );
-    time(&t1);
-    if(! FcConfigBuildFonts( p_sys->p_fontconfig ))
+    if( p_fontconfig )
     {
-        /* 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_Err( p_filter, "fontconfig database can't be built. "
-                                "Font styling won't be available" );
-    }
-    time(&t2);
+        mtime_t    t1, t2;
 
-    msg_Dbg( p_filter, "Finished building font database." );
-    if( t1 > 0 && t2 > 0 )
-        msg_Dbg( p_filter, "Took %ld seconds", t2 - t1 );
+        msg_Dbg( p_this, "Building font database..." );
+        t1 = mdate();
+        if(! FcConfigBuildFonts( p_fontconfig ))
+        {
+            /* 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_Err( p_this, "fontconfig database can't be built. "
+                                    "Font styling won't be available" );
+        }
+        t2 = mdate();
 
-    FcConfigSetCurrent( p_sys->p_fontconfig );
-    p_sys->b_fontconfig_ok = VLC_TRUE;
+        msg_Dbg( p_this, "Finished building font database." );
+        msg_Dbg( p_this, "Took %ld seconds", (long)((t2 - t1)/1000000) );
 
-    vlc_mutex_unlock( &p_sys->fontconfig_lock );
+        lock = var_AcquireMutex( "fontbuilder" );
+        var_SetBool( p_this, "build-done", true );
+
+        FcConfigDestroy( p_fontconfig );
+        vlc_mutex_unlock( lock );
+    }
+    vlc_object_detach( p_this );
+    vlc_object_release( p_this );
 }
 
 #endif
@@ -703,11 +734,11 @@ static int Render( filter_t *p_filter, subpicture_region_t *p_region,
     return VLC_SUCCESS;
 }
 
-static void UnderlineGlyphYUVA( int i_line_thickness, int i_line_offset, vlc_bool_t b_ul_next_char,
+static void UnderlineGlyphYUVA( int i_line_thickness, int i_line_offset, bool b_ul_next_char,
                                 FT_BitmapGlyph  p_this_glyph, FT_Vector *p_this_glyph_pos,
                                 FT_BitmapGlyph  p_next_glyph, FT_Vector *p_next_glyph_pos,
                                 int i_glyph_tmax, int i_align_offset,
-                                uint8_t i_y, uint8_t i_u, uint8_t i_v, uint8_t i_alpha,
+                                uint8_t i_y, uint8_t i_u, uint8_t i_v,
                                 subpicture_region_t *p_region)
 {
     int y, x, z;
@@ -734,7 +765,7 @@ static void UnderlineGlyphYUVA( int i_line_thickness, int i_line_offset, vlc_boo
         }
         for( x = 0; x < i_extra; x++ )
         {
-            vlc_bool_t b_ok = VLC_TRUE;
+            bool b_ok = true;
 
             /* break the underline around the tails of any glyphs which cross it */
             for( z = x - i_line_thickness;
@@ -748,7 +779,7 @@ static void UnderlineGlyphYUVA( int i_line_thickness, int i_line_offset, vlc_boo
                     if( ( p_next_glyph->bitmap.rows > i_row ) &&
                         p_next_glyph->bitmap.buffer[p_next_glyph->bitmap.width * i_row + z-i_extra] )
                     {
-                        b_ok = VLC_FALSE;
+                        b_ok = false;
                     }
                 }
                 else if ((z > 0 ) && (z < p_this_glyph->bitmap.width))
@@ -758,7 +789,7 @@ static void UnderlineGlyphYUVA( int i_line_thickness, int i_line_offset, vlc_boo
                     if( ( p_this_glyph->bitmap.rows > i_row ) &&
                         p_this_glyph->bitmap.buffer[p_this_glyph->bitmap.width * i_row + z] )
                     {
-                        b_ok = VLC_FALSE;
+                        b_ok = false;
                     }
                 }
             }
@@ -1009,7 +1040,7 @@ static int RenderYUVA( filter_t *p_filter, subpicture_region_t *p_region,
                                     p_line->pp_glyphs[i], &(p_line->p_glyph_pos[i]),
                                     p_line->pp_glyphs[i+1], &(p_line->p_glyph_pos[i+1]),
                                     i_glyph_tmax, i_align_offset,
-                                    i_y, i_u, i_v, i_alpha,
+                                    i_y, i_u, i_v,
                                     p_region);
             }
         }
@@ -1105,7 +1136,8 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
         i_out_bytes = i_in_bytes * sizeof( uint32_t );
         i_out_bytes_left = i_out_bytes;
         p_out_buffer = (char *)psz_unicode;
-        i_ret = vlc_iconv( iconv_handle, (const char**)&p_in_buffer, &i_in_bytes,
+        i_ret = vlc_iconv( iconv_handle, (const char**)&p_in_buffer,
+                           &i_in_bytes,
                            &p_out_buffer, &i_out_bytes_left );
 
         vlc_iconv_close( iconv_handle );
@@ -1123,7 +1155,7 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
 #if defined(HAVE_FRIBIDI)
     {
         uint32_t *p_fribidi_string;
-        int start_pos, pos = 0;
+        int32_t start_pos, pos = 0;
 
         p_fribidi_string = malloc( (i_string_length + 1) * sizeof(uint32_t) );
         if( !p_fribidi_string )
@@ -1133,9 +1165,10 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
         }
 
         /* Do bidi conversion line-by-line */
-        while(pos < i_string_length)
+        while( pos < i_string_length )
         {
-            while(pos < i_string_length) {
+            while( pos < i_string_length ) 
+            {
                 i_char = psz_unicode[pos];
                 if (i_char != '\r' && i_char != '\n')
                     break;
@@ -1143,7 +1176,8 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
                 ++pos;
             }
             start_pos = pos;
-            while(pos < i_string_length) {
+            while( pos < i_string_length )
+            {
                 i_char = psz_unicode[pos];
                 if (i_char == '\r' || i_char == '\n')
                     break;
@@ -1152,8 +1186,11 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
             if (pos > start_pos)
             {
                 FriBidiCharType base_dir = FRIBIDI_TYPE_LTR;
-                fribidi_log2vis((FriBidiChar*)psz_unicode + start_pos, pos - start_pos,
-                                &base_dir, (FriBidiChar*)p_fribidi_string + start_pos, 0, 0, 0);
+                fribidi_log2vis((FriBidiChar*)psz_unicode + start_pos,
+                                pos - start_pos,
+                                &base_dir,
+                                (FriBidiChar*)p_fribidi_string + start_pos,
+                                0, 0, 0);
             }
         }
 
@@ -1262,11 +1299,22 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
             if( p_prev ) p_prev->p_next = p_line;
             else p_lines = p_line;
 
+            uint32_t *psz_unicode_saved = psz_unicode;
             while( psz_unicode > psz_line_start && *psz_unicode != ' ' )
             {
                 psz_unicode--;
             }
             if( psz_unicode == psz_line_start )
+            {   /* try harder to break that line */
+                psz_unicode = psz_unicode_saved;
+                while( psz_unicode > psz_line_start &&
+                    *psz_unicode != '_'  && *psz_unicode != '/' &&
+                    *psz_unicode != '\\' && *psz_unicode != '.' )
+                {
+                    psz_unicode--;
+                }
+            }
+            if( psz_unicode == psz_line_start )
             {
                 msg_Warn( p_filter, "unbreakable string" );
                 goto error;
@@ -1310,20 +1358,20 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
     else
         RenderYUVA( p_filter, p_region_out, p_lines, result.x, result.y );
 
-    if( psz_unicode_orig ) free( psz_unicode_orig );
+    free( psz_unicode_orig );
     FreeLines( p_lines );
     return VLC_SUCCESS;
 
  error:
-    if( psz_unicode_orig ) free( psz_unicode_orig );
+    free( psz_unicode_orig );
     FreeLines( p_lines );
     return VLC_EGENERIC;
 }
 
 #ifdef HAVE_FONTCONFIG
 static ft_style_t *CreateStyle( char *psz_fontname, int i_font_size,
-        uint32_t i_font_color, uint32_t i_karaoke_bg_color, vlc_bool_t b_bold,
-        vlc_bool_t b_italic, vlc_bool_t b_uline )
+        uint32_t i_font_color, uint32_t i_karaoke_bg_color, bool b_bold,
+        bool b_italic, bool b_uline )
 {
     ft_style_t  *p_style = malloc( sizeof( ft_style_t ));
 
@@ -1345,18 +1393,17 @@ static void DeleteStyle( ft_style_t *p_style )
 {
     if( p_style )
     {
-        if( p_style->psz_fontname )
-            free( p_style->psz_fontname );
+        free( p_style->psz_fontname );
         free( p_style );
     }
 }
 
-static vlc_bool_t StyleEquals( ft_style_t *s1, ft_style_t *s2 )
+static bool StyleEquals( ft_style_t *s1, ft_style_t *s2 )
 {
     if( !s1 || !s2 )
-        return VLC_FALSE;
+        return false;
     if( s1 == s2 )
-        return VLC_TRUE;
+        return true;
 
     if(( s1->i_font_size  == s2->i_font_size ) &&
        ( s1->i_font_color == s2->i_font_color ) &&
@@ -1365,9 +1412,9 @@ static vlc_bool_t StyleEquals( ft_style_t *s1, ft_style_t *s2 )
        ( s1->b_underline  == s2->b_underline ) &&
        ( !strcmp( s1->psz_fontname, s2->psz_fontname )))
     {
-        return VLC_TRUE;
+        return true;
     }
-    return VLC_FALSE;
+    return false;
 }
 
 static int PushFont( font_stack_t **p_font, const char *psz_name, int i_size,
@@ -1514,8 +1561,8 @@ static void IconvText( filter_t *p_filter, const char *psz_string,
 }
 
 static ft_style_t *GetStyleFromFontStack( filter_sys_t *p_sys,
-        font_stack_t **p_fonts, vlc_bool_t b_bold, vlc_bool_t b_italic,
-        vlc_bool_t b_uline )
+        font_stack_t **p_fonts, bool b_bold, bool b_italic,
+        bool b_uline )
 {
     ft_style_t   *p_style = NULL;
 
@@ -1534,7 +1581,7 @@ static ft_style_t *GetStyleFromFontStack( filter_sys_t *p_sys,
 }
 
 static int RenderTag( filter_t *p_filter, FT_Face p_face, int i_font_color,
-                      vlc_bool_t b_uline, int i_karaoke_bgcolor,
+                      bool b_uline, int i_karaoke_bgcolor,
                       line_desc_t *p_line, uint32_t *psz_unicode,
                       int *pi_pen_x, int i_pen_y, int *pi_start,
                       FT_Vector *p_result )
@@ -1542,7 +1589,7 @@ static int RenderTag( filter_t *p_filter, FT_Face p_face, int i_font_color,
     FT_BBox      line;
     int          i_yMin, i_yMax;
     int          i;
-    vlc_bool_t   b_first_on_line = VLC_TRUE;
+    bool   b_first_on_line = true;
 
     int          i_previous = 0;
     int          i_pen_x_start = *pi_pen_x;
@@ -1568,7 +1615,7 @@ static int RenderTag( filter_t *p_filter, FT_Face p_face, int i_font_color,
     i_yMax = line.yMax;
 
     if( line.xMax > 0 )
-        b_first_on_line = VLC_FALSE;
+        b_first_on_line = false;
 
     while( *psz_unicode && ( *psz_unicode != '\n' ) )
     {
@@ -1701,9 +1748,8 @@ static int RenderTag( filter_t *p_filter, FT_Face p_face, int i_font_color,
     {
         *psz_unicode_start = '\0';
     }
-    else
+    else if( psz_unicode > psz_unicode_start )
     {
-        psz_unicode++;
         for( i=0; psz_unicode[ i ]; i++ )
             psz_unicode_start[ i ] = psz_unicode[ i ];
         psz_unicode_start[ i ] = '\0';
@@ -1746,7 +1792,7 @@ static int HandleFontAttributes( xml_reader_t *p_xml_reader,
         {
             if( !strcasecmp( "face", psz_name ) )
             {
-                if( psz_fontname ) free( psz_fontname );
+                free( psz_fontname );
                 psz_fontname = strdup( psz_value );
             }
             else if( !strcasecmp( "size", psz_name ) )
@@ -1921,8 +1967,8 @@ static void SetupKaraoke( xml_reader_t *p_xml_reader, uint32_t *pi_k_runs,
                     (*ppi_k_run_lengths)[ *pi_k_runs - 1 ] = 0;
             }
         }
-        if( psz_name )  free( psz_name );
-        if( psz_value ) free( psz_value );
+        free( psz_name );
+        free( psz_value );
     }
 }
 
@@ -1936,7 +1982,7 @@ static int ProcessNodes( filter_t *p_filter,
                          uint32_t **ppi_run_lengths,
                          ft_style_t ***ppp_styles,
 
-                         vlc_bool_t b_karaoke,
+                         bool b_karaoke,
                          uint32_t *pi_k_runs,
                          uint32_t **ppi_k_run_lengths,
                          uint32_t **ppi_k_durations )
@@ -1950,9 +1996,9 @@ static int ProcessNodes( filter_t *p_filter,
 
     char *psz_node  = NULL;
 
-    vlc_bool_t b_italic = VLC_FALSE;
-    vlc_bool_t b_bold   = VLC_FALSE;
-    vlc_bool_t b_uline  = VLC_FALSE;
+    bool b_italic = false;
+    bool b_bold   = false;
+    bool b_uline  = false;
 
     if( VLC_SUCCESS == var_Get( p_filter, "scale", &val ))
         i_scale = val.i_int;
@@ -1968,11 +2014,11 @@ static int ProcessNodes( filter_t *p_filter,
                    ((p_font_style->i_karaoke_background_alpha & 0xff) << 24));
 
         if( p_font_style->i_style_flags & STYLE_BOLD )
-            b_bold = VLC_TRUE;
+            b_bold = true;
         if( p_font_style->i_style_flags & STYLE_ITALIC )
-            b_italic = VLC_TRUE;
+            b_italic = true;
         if( p_font_style->i_style_flags & STYLE_UNDERLINE )
-            b_uline = VLC_TRUE;
+            b_uline = true;
     }
     else
     {
@@ -1999,11 +2045,11 @@ static int ProcessNodes( filter_t *p_filter,
                     if( !strcasecmp( "font", psz_node ) )
                         PopFont( &p_fonts );
                     else if( !strcasecmp( "b", psz_node ) )
-                        b_bold   = VLC_FALSE;
+                        b_bold   = false;
                     else if( !strcasecmp( "i", psz_node ) )
-                        b_italic = VLC_FALSE;
+                        b_italic = false;
                     else if( !strcasecmp( "u", psz_node ) )
-                        b_uline  = VLC_FALSE;
+                        b_uline  = false;
 
                     free( psz_node );
                 }
@@ -2015,11 +2061,11 @@ static int ProcessNodes( filter_t *p_filter,
                     if( !strcasecmp( "font", psz_node ) )
                         rv = HandleFontAttributes( p_xml_reader, &p_fonts, i_scale );
                     else if( !strcasecmp( "b", psz_node ) )
-                        b_bold = VLC_TRUE;
+                        b_bold = true;
                     else if( !strcasecmp( "i", psz_node ) )
-                        b_italic = VLC_TRUE;
+                        b_italic = true;
                     else if( !strcasecmp( "u", psz_node ) )
-                        b_uline = VLC_TRUE;
+                        b_uline = true;
                     else if( !strcasecmp( "br", psz_node ) )
                     {
                         SetupLine( p_filter, "\n", &psz_text,
@@ -2114,7 +2160,7 @@ static int CheckForEmbeddedFont( filter_sys_t *p_sys, FT_Face *pp_face, ft_style
         {
             if( p_face )
             {
-                vlc_bool_t match = !strcasecmp( p_face->family_name,
+                bool match = !strcasecmp( p_face->family_name,
                                                 p_style->psz_fontname );
 
                 if( p_face->style_flags & FT_STYLE_FLAG_BOLD )
@@ -2141,6 +2187,37 @@ 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,
@@ -2152,7 +2229,7 @@ static int ProcessLines( filter_t *p_filter,
 
                          FT_Vector *p_result,
 
-                         vlc_bool_t b_karaoke,
+                         bool b_karaoke,
                          uint32_t i_k_runs,
                          uint32_t *pi_k_run_lengths,
                          uint32_t *pi_k_durations )
@@ -2213,12 +2290,12 @@ static int ProcessLines( filter_t *p_filter,
             ! p_levels )
         {
             msg_Err( p_filter, "out of memory" );
-            if( p_levels )           free( p_levels );
-            if( p_old_positions )    free( p_old_positions );
-            if( p_new_positions )    free( p_new_positions );
-            if( p_fribidi_string )   free( p_fribidi_string );
-            if( pp_char_styles_new ) free( pp_char_styles_new );
-            if( pi_karaoke_bar )     free( pi_karaoke_bar );
+            free( p_levels );
+            free( p_old_positions );
+            free( p_new_positions );
+            free( p_fribidi_string );
+            free( pp_char_styles_new );
+            free( pi_karaoke_bar );
 
             free( pp_char_styles );
             return VLC_ENOMEM;
@@ -2326,8 +2403,8 @@ static int ProcessLines( filter_t *p_filter,
              i_start_pos += pi_k_run_lengths[ k ];
         }
     }
-    if( p_levels )         free( p_levels );
-    if( p_new_positions )  free( p_new_positions );
+    free( p_levels );
+    free( p_new_positions );
 
     FT_Vector tmp_result;
 
@@ -2357,10 +2434,15 @@ 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( 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 );
 
                 psz_fontfile = FontConfig_Select( p_sys->p_fontconfig,
@@ -2368,9 +2450,19 @@ static int ProcessLines( filter_t *p_filter,
                                                   p_style->b_bold,
                                                   p_style->b_italic,
                                                   &i_idx );
-
                 vlc_mutex_unlock( &p_sys->fontconfig_lock );
 
+                if( psz_fontfile && ! *psz_fontfile )
+                {
+                    msg_Warn( p_filter, "Fontconfig was unable to find a font: \"%s\" %s"
+                        " so using default font", p_style->psz_fontname,
+                        ((p_style->b_bold && p_style->b_italic) ? "(Bold,Italic)" :
+                                               (p_style->b_bold ? "(Bold)" :
+                                             (p_style->b_italic ? "(Italic)" : ""))) );
+                    free( psz_fontfile );
+                    psz_fontfile = NULL;
+                }
+
                 if( psz_fontfile )
                 {
                     if( FT_New_Face( p_sys->p_library,
@@ -2381,8 +2473,7 @@ static int ProcessLines( filter_t *p_filter,
 #if defined(HAVE_FRIBIDI)
                         free( psz_text );
 #endif
-                        if( pi_karaoke_bar )
-                            free( pi_karaoke_bar );
+                        free( pi_karaoke_bar );
                         return VLC_EGENERIC;
                     }
                     free( psz_fontfile );
@@ -2408,8 +2499,7 @@ static int ProcessLines( filter_t *p_filter,
 #if defined(HAVE_FRIBIDI)
                 free( psz_text );
 #endif
-                if( pi_karaoke_bar )
-                    free( pi_karaoke_bar );
+                free( pi_karaoke_bar );
                 return VLC_EGENERIC;
             }
             p_sys->i_use_kerning =
@@ -2427,8 +2517,7 @@ static int ProcessLines( filter_t *p_filter,
 #if defined(HAVE_FRIBIDI)
                 free( psz_text );
 #endif
-                if( pi_karaoke_bar )
-                    free( pi_karaoke_bar );
+                free( pi_karaoke_bar );
                 return VLC_ENOMEM;
             }
             memcpy( psz_unicode, psz_text + i_prev,
@@ -2447,15 +2536,14 @@ static int ProcessLines( filter_t *p_filter,
 #if defined(HAVE_FRIBIDI)
                         free( psz_text );
 #endif
-                        if( pi_karaoke_bar )
-                            free( pi_karaoke_bar );
+                        free( pi_karaoke_bar );
                         return VLC_ENOMEM;
                     }
                     /* New Color mode only works in YUVA rendering mode --
                      * (RGB mode has palette constraints on it). We therefore
                      * need to populate the legacy colour fields also.
                      */
-                    p_line->b_new_color_mode = VLC_TRUE;
+                    p_line->b_new_color_mode = true;
                     p_line->i_alpha = ( p_style->i_font_color & 0xff000000 ) >> 24;
                     p_line->i_red   = ( p_style->i_font_color & 0x00ff0000 ) >> 16;
                     p_line->i_green = ( p_style->i_font_color & 0x0000ff00 ) >>  8;
@@ -2482,8 +2570,7 @@ static int ProcessLines( filter_t *p_filter,
 #if defined(HAVE_FRIBIDI)
                     free( psz_text );
 #endif
-                    if( pi_karaoke_bar )
-                        free( pi_karaoke_bar );
+                    free( pi_karaoke_bar );
                     return VLC_EGENERIC;
                 }
 
@@ -2494,6 +2581,16 @@ static int ProcessLines( filter_t *p_filter,
 
                     p_prev = p_line;
                     p_line = NULL;
+
+                    if( *psz_unicode == '\n')
+                    {
+                        uint32_t *c_ptr;
+
+                        for( c_ptr = psz_unicode; *c_ptr; c_ptr++ )
+                        {
+                            *c_ptr = *(c_ptr+1);
+                        }
+                    }
                 }
             }
             free( psz_unicode );
@@ -2571,13 +2668,13 @@ static int RenderHtml( filter_t *p_filter, subpicture_region_t *p_region_out,
     p_sub = stream_MemoryNew( VLC_OBJECT(p_filter),
                               (uint8_t *) p_region_in->psz_html,
                               strlen( p_region_in->psz_html ),
-                              VLC_TRUE );
+                              true );
     if( p_sub )
     {
         p_xml = xml_Create( p_filter );
         if( p_xml )
         {
-            vlc_bool_t b_karaoke = VLC_FALSE;
+            bool b_karaoke = false;
 
             p_xml_reader = xml_ReaderCreate( p_xml, p_sub );
             if( p_xml_reader )
@@ -2592,16 +2689,17 @@ static int RenderHtml( filter_t *p_filter, subpicture_region_t *p_region_out,
                         /* We're going to have to render the text a number
                          * of times to show the progress marker on the text.
                          */
-                        var_SetBool( p_filter, "text-rerender", VLC_TRUE );
-                        b_karaoke = VLC_TRUE;
+                        var_SetBool( p_filter, "text-rerender", true );
+                        b_karaoke = true;
                     }
                     else if( !strcasecmp( "text", psz_node ) )
                     {
-                        b_karaoke = VLC_FALSE;
+                        b_karaoke = false;
                     }
                     else
                     {
                         /* Only text and karaoke tags are supported */
+                        msg_Dbg( p_filter, "Unsupported top-level tag '%s' ignored.", psz_node );
                         xml_ReaderDelete( p_xml, p_xml_reader );
                         p_xml_reader = NULL;
                         rv = VLC_EGENERIC;
@@ -2683,7 +2781,7 @@ static int RenderHtml( filter_t *p_filter, subpicture_region_t *p_region_out,
 }
 
 static char* FontConfig_Select( FcConfig* priv, const char* family,
-                          vlc_bool_t b_bold, vlc_bool_t b_italic, int *i_idx )
+                          bool b_bold, bool b_italic, int *i_idx )
 {
     FcResult result;
     FcPattern *pat, *p_pat;
@@ -2799,19 +2897,18 @@ static line_desc_t *NewLine( int i_count )
         ( p_line->pi_underline_offset == NULL ) ||
         ( p_line->pi_underline_thickness == NULL ) )
     {
-        if( p_line->pi_underline_thickness )
-            free( p_line->pi_underline_thickness );
-        if( p_line->pi_underline_offset ) free( p_line->pi_underline_offset );
-        if( p_line->p_fg_rgb ) free( p_line->p_fg_rgb );
-        if( p_line->p_bg_rgb ) free( p_line->p_bg_rgb );
-        if( p_line->p_fg_bg_ratio ) free( p_line->p_fg_bg_ratio );
-        if( p_line->p_glyph_pos ) free( p_line->p_glyph_pos );
-        if( p_line->pp_glyphs ) free( p_line->pp_glyphs );
+        free( p_line->pi_underline_thickness );
+        free( p_line->pi_underline_offset );
+        free( p_line->p_fg_rgb );
+        free( p_line->p_bg_rgb );
+        free( p_line->p_fg_bg_ratio );
+        free( p_line->p_glyph_pos );
+        free( p_line->pp_glyphs );
         free( p_line );
         return NULL;
     }
     p_line->pp_glyphs[0] = NULL;
-    p_line->b_new_color_mode = VLC_FALSE;
+    p_line->b_new_color_mode = false;
 
     return p_line;
 }