]> git.sesse.net Git - vlc/blobdiff - modules/misc/freetype.c
Qt4 - Getting rid of useless setCheckState( Qt::Checked ) when setChecked is enough...
[vlc] / modules / misc / freetype.c
index 38d0cb30552e0d4d94637069e62864471dd6e95e..8a2233b3114287bf6f8888ad538a5c2fc441f5b9 100644 (file)
@@ -1,4 +1,3 @@
-#include <time.h>
 /*****************************************************************************
  * freetype.c : Put text on the video, using freetype2
  *****************************************************************************
  * Preamble
  *****************************************************************************/
 
-#ifdef HAVE_LINUX_LIMITS_H
-#   include <linux/limits.h>
-#endif
-
 #include <vlc/vlc.h>
 #include <vlc_vout.h>
 #include <vlc_osd.h>
 #include <vlc_xml.h>
 #include <vlc_input.h>
 
-#include <math.h>
-
-#ifdef HAVE_ERRNO_H
-#   include <errno.h>
+#ifdef HAVE_LINUX_LIMITS_H
+#   include <linux/limits.h>
 #endif
 
+#include <time.h>
+#include <math.h>
+#include <errno.h>
+
 #include <ft2build.h>
 #include FT_FREETYPE_H
 #include FT_GLYPH_H
@@ -63,9 +60,6 @@
 #elif defined( WIN32 )
 #define DEFAULT_FONT "" /* Default font found at run-time */
 #define FC_DEFAULT_FONT "Arial"
-#elif defined(GENTOO_LINUX)
-#define DEFAULT_FONT "/usr/share/fonts/ttf-bitstream-vera/Vera.ttf"
-#define FC_DEFAULT_FONT "Vera"
 #else
 #define DEFAULT_FONT "/usr/share/fonts/truetype/freefont/FreeSerifBold.ttf"
 #define FC_DEFAULT_FONT "Serif Bold"
@@ -97,6 +91,7 @@ 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 * );
+static int CheckIfFontBuildComplete( filter_t *p_filter );
 #endif
 static line_desc_t *NewLine( int );
 
@@ -281,11 +276,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 ) );
@@ -340,38 +337,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 )
     {
@@ -398,6 +363,63 @@ 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 = VLC_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", VLC_FALSE );
+
+            if( vlc_thread_create( p_fontbuilder,
+                                   "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
+        {
+            vlc_object_destroy( 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 );
@@ -411,11 +433,10 @@ static int Create( vlc_object_t *p_this )
 
     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 );
 
@@ -470,36 +491,40 @@ 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);
+        time_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..." );
+        time( &t1 );
+        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" );
+        }
+        time( &t2 );
+
+        msg_Dbg( p_this, "Finished building font database." );
+        if( t1 > 0 && t2 > 0 )
+            msg_Dbg( p_this, "Took %ld seconds", t2 - t1 );
 
-    FcConfigSetCurrent( p_sys->p_fontconfig );
-    p_sys->b_fontconfig_ok = VLC_TRUE;
+        lock = var_AcquireMutex( "fontbuilder" );
+        var_SetBool( p_this, "build-done", VLC_TRUE );
 
-    vlc_mutex_unlock( &p_sys->fontconfig_lock );
+        FcConfigDestroy( p_fontconfig );
+        vlc_mutex_unlock( lock );
+    }
 }
 
 #endif
@@ -1118,8 +1143,8 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out,
 
         if( i_in_bytes )
         {
-            msg_Warn( p_filter, "failed to convert string to unicode (%s), "
-                      "bytes left %d", strerror(errno), (int)i_in_bytes );
+            msg_Warn( p_filter, "failed to convert string to unicode (%m), "
+                      "bytes left %u", (unsigned)i_in_bytes );
             goto error;
         }
         *(uint32_t*)p_out_buffer = 0;
@@ -1268,11 +1293,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;
@@ -1502,8 +1538,8 @@ static void IconvText( filter_t *p_filter, const char *psz_string,
 
             if( i_in_bytes )
             {
-                msg_Warn( p_filter, "failed to convert string to unicode (%s), "
-                          "bytes left %d", strerror(errno), (int)i_in_bytes );
+                msg_Warn( p_filter, "failed to convert string to unicode (%m), "
+                          "bytes left %u", (unsigned)i_in_bytes );
             }
             else
             {
@@ -1707,9 +1743,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';
@@ -2147,6 +2182,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,
@@ -2363,10 +2429,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,
@@ -2374,9 +2445,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,
@@ -2500,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 );
@@ -2608,6 +2699,7 @@ static int RenderHtml( filter_t *p_filter, subpicture_region_t *p_region_out,
                     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;
@@ -2620,7 +2712,7 @@ static int RenderHtml( filter_t *p_filter, subpicture_region_t *p_region_out,
             if( p_xml_reader )
             {
                 uint32_t   *psz_text;
-                int         i_len;
+                int         i_len = 0;
                 uint32_t    i_runs = 0;
                 uint32_t    i_k_runs = 0;
                 uint32_t   *pi_run_lengths = NULL;