Changeset ae2674440d5319f10807c854f4c30876373c2f2b

Show
Ignore:
Timestamp:
02/07/07 19:32:40 (1 year ago)
Author:
Jean-Baptiste Kempf <jb@videolan.org>
git-committer:
Jean-Baptiste Kempf <jb@videolan.org> 1183397560 +0000
git-parent:

[6e8a32cec984300f67e861dd0afb4fdfc4b46f8d]

git-author:
Jean-Baptiste Kempf <jb@videolan.org> 1183397560 +0000
Message:

Freetype:
This patch:
* try to solve the fribidi styles problems that have occured
* introduces ft_style_t, to solve the precedent problem,
* solves a few errors from precedent commits,
* split some big functions on my request to avoid many imbrications.

Patch from Bernie Purcell.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • modules/misc/freetype.c

    r5d5eb43 rae26744  
    9494                                vlc_bool_t, vlc_bool_t, int * ); 
    9595#endif 
    96 static line_desc_t *NewLine( byte_t * ); 
     96static line_desc_t *NewLine( int ); 
    9797 
    9898static int SetFontSize( filter_t *, int ); 
     
    219219}; 
    220220 
     221typedef struct 
     222{ 
     223    int         i_font_size; 
     224    uint32_t    i_font_color; /* ARGB */ 
     225    vlc_bool_t  b_italic; 
     226    vlc_bool_t  b_bold; 
     227    vlc_bool_t  b_underline; 
     228    char       *psz_fontname; 
     229} ft_style_t; 
     230 
    221231static int Render( filter_t *, subpicture_region_t *, line_desc_t *, int, int); 
    222232static void FreeLines( line_desc_t * ); 
     
    324334        goto error; 
    325335    } 
    326  
    327336    i_error = FT_New_Face( p_sys->p_library, psz_fontfile ? psz_fontfile : "", 
    328337                           0, &p_sys->p_face ); 
     
    9951004    /* Calculate relative glyph positions and a bounding box for the 
    9961005     * entire string */ 
    997     if( !(p_line = NewLine( (byte_t *)psz_string )) ) 
     1006    if( !(p_line = NewLine( strlen( psz_string ))) ) 
    9981007    { 
    9991008        msg_Err( p_filter, "out of memory" ); 
     
    10191028        { 
    10201029            psz_line_start = psz_unicode; 
    1021             if( !(p_next = NewLine( (byte_t *)psz_string )) ) 
     1030            if( !(p_next = NewLine( strlen( psz_string ))) ) 
    10221031            { 
    10231032                msg_Err( p_filter, "out of memory" ); 
     
    10881097            p_line->pp_glyphs[ i ] = NULL; 
    10891098            FreeLine( p_line ); 
    1090             p_line = NewLine( (byte_t *)psz_string ); 
     1099            p_line = NewLine( strlen( psz_string )); 
    10911100            if( p_prev ) p_prev->p_next = p_line; 
    10921101            else p_lines = p_line; 
     
    11511160 
    11521161#ifdef HAVE_FONTCONFIG 
     1162static ft_style_t *CreateStyle( char *psz_fontname, int i_font_size, 
     1163        int i_font_color, int i_font_alpha, vlc_bool_t b_bold, 
     1164        vlc_bool_t b_italic, vlc_bool_t b_uline ) 
     1165{ 
     1166    ft_style_t  *p_style = malloc( sizeof( ft_style_t )); 
     1167 
     1168    if( p_style ) 
     1169    { 
     1170        p_style->i_font_size  = i_font_size; 
     1171        p_style->i_font_color = ( i_font_color & 0x00ffffff ) 
     1172                                | (( i_font_alpha & 0xff ) << 24 ); 
     1173        p_style->b_italic     = b_italic; 
     1174        p_style->b_bold       = b_bold; 
     1175        p_style->b_underline  = b_uline; 
     1176        /* p_style has just been malloc'ed in this function - 
     1177         * it CAN'T have a previous assignment, and hence we 
     1178         * don't need to do a free() for any previous value - 
     1179         * which will in fact be undefined. */ 
     1180        p_style->psz_fontname = strdup( psz_fontname ); 
     1181    } 
     1182    return p_style; 
     1183} 
     1184 
     1185static void DeleteStyle( ft_style_t *p_style ) 
     1186{ 
     1187    if( p_style ) 
     1188    { 
     1189        if( p_style->psz_fontname ) 
     1190            free( p_style->psz_fontname ); 
     1191        free( p_style ); 
     1192    } 
     1193} 
     1194 
     1195static vlc_bool_t StyleEquals( ft_style_t *s1, ft_style_t *s2 ) 
     1196{ 
     1197    if( !s1 || !s2 ) 
     1198        return VLC_FALSE; 
     1199    if( s1 == s2 ) 
     1200        return VLC_TRUE; 
     1201 
     1202    if(( s1->i_font_size  == s2->i_font_size ) && 
     1203       ( s1->i_font_color == s2->i_font_color ) && 
     1204       ( s1->b_italic     == s2->b_italic ) && 
     1205       ( s1->b_bold       == s2->b_bold ) && 
     1206       ( s1->b_underline  == s2->b_underline ) && 
     1207       ( !strcmp( s1->psz_fontname, s2->psz_fontname ))) 
     1208    { 
     1209        return VLC_TRUE; 
     1210    } 
     1211    return VLC_FALSE; 
     1212} 
     1213 
    11531214static int PushFont( font_stack_t **p_font, const char *psz_name, int i_size, 
    11541215                     int i_color, int i_alpha ) 
     
    11601221 
    11611222    p_new = malloc( sizeof( font_stack_t ) ); 
    1162     if( !p_new ) 
     1223    if( ! p_new ) 
    11631224        return VLC_ENOMEM; 
    11641225 
     
    12391300} 
    12401301 
    1241 static uint32_t *IconvText( filter_t *p_filter, char *psz_string ) 
     1302static void IconvText( filter_t *p_filter, const char *psz_string, 
     1303                       uint32_t *i_string_length, uint32_t **ppsz_unicode ) 
    12421304{ 
    12431305    vlc_iconv_t iconv_handle = (vlc_iconv_t)(-1); 
    1244     uint32_t *psz_unicode; 
    1245     int i_string_length; 
    1246  
    1247     psz_unicode = 
    1248         malloc( ( strlen( psz_string ) + 1 ) * sizeof( uint32_t ) ); 
    1249     if( psz_unicode == NULL ) 
    1250     { 
    1251         msg_Err( p_filter, "out of memory" ); 
    1252         return NULL;; 
    1253     } 
     1306 
     1307    /* If memory hasn't been allocated for our output string, allocate it here 
     1308     * - the calling function must now be responsible for freeing it. 
     1309     */ 
     1310    if( !*ppsz_unicode ) 
     1311        *ppsz_unicode = (uint32_t *) 
     1312            malloc( (strlen( psz_string ) + 1) * sizeof( uint32_t )); 
     1313 
     1314    /* We don't need to handle a NULL pointer in *ppsz_unicode 
     1315     * if we are instead testing for a non NULL value like we are here */ 
     1316 
     1317    if( *ppsz_unicode ) 
     1318    { 
    12541319#if defined(WORDS_BIGENDIAN) 
    1255     iconv_handle = vlc_iconv_open( "UCS-4BE", "UTF-8" ); 
     1320        iconv_handle = vlc_iconv_open( "UCS-4BE", "UTF-8" ); 
    12561321#else 
    1257     iconv_handle = vlc_iconv_open( "UCS-4LE", "UTF-8" ); 
     1322        iconv_handle = vlc_iconv_open( "UCS-4LE", "UTF-8" ); 
    12581323#endif 
    1259     if( iconv_handle == (vlc_iconv_t)-1 ) 
    1260     { 
    1261         msg_Warn( p_filter, "unable to do conversion" ); 
    1262         free( psz_unicode ); 
    1263         return NULL;; 
    1264     } 
    1265  
    1266     { 
    1267         char *p_in_buffer, *p_out_buffer; 
    1268         size_t i_in_bytes, i_out_bytes, i_out_bytes_left, i_ret; 
    1269         i_in_bytes = strlen( psz_string ); 
    1270         i_out_bytes = i_in_bytes * sizeof( uint32_t ); 
    1271         i_out_bytes_left = i_out_bytes; 
    1272         p_in_buffer = psz_string; 
    1273         p_out_buffer = (char *)psz_unicode; 
    1274         i_ret = vlc_iconv( iconv_handle, (const char**)&p_in_buffer, &i_in_bytes, 
    1275                            &p_out_buffer, &i_out_bytes_left ); 
    1276  
    1277         vlc_iconv_close( iconv_handle ); 
    1278  
    1279         if( i_in_bytes ) 
    1280         { 
    1281             msg_Warn( p_filter, "failed to convert string to unicode (%s), " 
    1282                       "bytes left %d", strerror(errno), (int)i_in_bytes ); 
    1283             free( psz_unicode ); 
    1284             return NULL;; 
    1285         } 
    1286         *(uint32_t*)p_out_buffer = 0; 
    1287         i_string_length = (i_out_bytes - i_out_bytes_left) / sizeof(uint32_t); 
    1288     } 
    1289  
    1290 #if defined(HAVE_FRIBIDI) 
    1291     { 
    1292         uint32_t *p_fribidi_string; 
    1293  
    1294         p_fribidi_string = malloc( (i_string_length + 1) * sizeof(uint32_t) ); 
    1295         if( !p_fribidi_string ) 
    1296         { 
    1297             msg_Err( p_filter, "out of memory" ); 
    1298             free( psz_unicode ); 
    1299             return NULL; 
    1300         } 
    1301  
    1302         /* Do bidi conversion line-by-line */ 
    1303         FriBidiCharType base_dir = FRIBIDI_TYPE_LTR; 
    1304         fribidi_log2vis((FriBidiChar*)psz_unicode, i_string_length, 
    1305                         &base_dir, (FriBidiChar*)p_fribidi_string, 0, 0, 0); 
    1306  
    1307         free( psz_unicode ); 
    1308         psz_unicode = p_fribidi_string; 
    1309         p_fribidi_string[ i_string_length ] = 0; 
    1310     } 
    1311 #endif 
    1312     return psz_unicode; 
     1324        if( iconv_handle != (vlc_iconv_t)-1 ) 
     1325        { 
     1326            char *p_in_buffer, *p_out_buffer; 
     1327            size_t i_in_bytes, i_out_bytes, i_out_bytes_left, i_ret; 
     1328            i_in_bytes = strlen( psz_string ); 
     1329            i_out_bytes = i_in_bytes * sizeof( uint32_t ); 
     1330            i_out_bytes_left = i_out_bytes; 
     1331            p_in_buffer = (char *) psz_string; 
     1332            p_out_buffer = (char *) *ppsz_unicode; 
     1333            i_ret = vlc_iconv( iconv_handle, (const char**)&p_in_buffer, 
     1334                    &i_in_bytes, &p_out_buffer, &i_out_bytes_left ); 
     1335 
     1336            vlc_iconv_close( iconv_handle ); 
     1337 
     1338            if( i_in_bytes ) 
     1339            { 
     1340                msg_Warn( p_filter, "failed to convert string to unicode (%s), " 
     1341                          "bytes left %d", strerror(errno), (int)i_in_bytes ); 
     1342            } 
     1343            else 
     1344            { 
     1345                *(uint32_t*)p_out_buffer = 0; 
     1346                *i_string_length = 
     1347                    (i_out_bytes - i_out_bytes_left) / sizeof(uint32_t); 
     1348            } 
     1349        } 
     1350        else 
     1351        { 
     1352            msg_Warn( p_filter, "unable to do conversion" ); 
     1353        } 
     1354    } 
     1355
     1356 
     1357static ft_style_t *GetStyleFromFontStack( filter_sys_t *p_sys, 
     1358        font_stack_t **p_fonts, vlc_bool_t b_bold, vlc_bool_t b_italic,  
     1359        vlc_bool_t b_uline ) 
     1360
     1361    ft_style_t   *p_style = NULL; 
     1362 
     1363    char  *psz_fontname = NULL; 
     1364    int    i_font_color = p_sys->i_font_color; 
     1365    int    i_font_alpha = 0; 
     1366    int    i_font_size  = p_sys->i_font_size; 
     1367 
     1368    if( VLC_SUCCESS == PeekFont( p_fonts, &psz_fontname, &i_font_size, 
     1369                                 &i_font_color, &i_font_alpha ) ) 
     1370    { 
     1371        p_style = CreateStyle( psz_fontname, i_font_size, i_font_color, 
     1372                i_font_alpha, b_bold, b_italic, b_uline ); 
     1373    } 
     1374    return p_style; 
    13131375} 
    13141376 
    13151377static int RenderTag( filter_t *p_filter, FT_Face p_face, int i_font_color, 
    1316                       vlc_bool_t b_uline, line_desc_t *p_line, uint32_t *psz_unicode, 
    1317                       int *pi_pen_x, int i_pen_y, int *pi_start
    1318                       FT_Vector *p_result ) 
     1378                      vlc_bool_t b_uline, line_desc_t *p_line, 
     1379                      uint32_t *psz_unicode, int *pi_pen_x, int i_pen_y
     1380                      int *pi_start, FT_Vector *p_result ) 
    13191381{ 
    13201382    FT_BBox      line; 
    13211383    int          i_yMin, i_yMax; 
    13221384    int          i; 
     1385    vlc_bool_t   b_first_on_line = VLC_TRUE; 
    13231386 
    13241387    int          i_previous = 0; 
     
    13341397        FT_BBox glyph_size; 
    13351398 
    1336         FT_Glyph_Get_CBox( (FT_Glyph) p_line->pp_glyphs[ i ], ft_glyph_bbox_pixels, &glyph_size ); 
     1399        FT_Glyph_Get_CBox( (FT_Glyph) p_line->pp_glyphs[ i ], 
     1400                            ft_glyph_bbox_pixels, &glyph_size ); 
    13371401 
    13381402        line.xMax = p_line->p_glyph_pos[ i ].x + glyph_size.xMax - 
     
    13441408    i_yMax = line.yMax; 
    13451409 
    1346     while( *psz_unicode && ( *psz_unicode != 0xffff ) ) 
     1410    if( line.xMax > 0 ) 
     1411        b_first_on_line = VLC_FALSE; 
     1412 
     1413    while( *psz_unicode && ( *psz_unicode != '\n' ) ) 
    13471414    { 
    13481415        FT_BBox glyph_size; 
     
    13651432        if( i_error ) 
    13661433        { 
    1367             msg_Err( p_filter, "unable to render text FT_Load_Glyph returned %d", i_error ); 
     1434            msg_Err( p_filter, 
     1435                   "unable to render text FT_Load_Glyph returned %d", i_error ); 
    13681436            p_line->pp_glyphs[ i ] = NULL; 
    13691437            return VLC_EGENERIC; 
     
    13721440        if( i_error ) 
    13731441        { 
    1374             msg_Err( p_filter, "unable to render text FT_Get_Glyph returned %d", i_error ); 
     1442            msg_Err( p_filter, 
     1443                    "unable to render text FT_Get_Glyph returned %d", i_error ); 
    13751444            p_line->pp_glyphs[ i ] = NULL; 
    13761445            return VLC_EGENERIC; 
     
    13851454        if( b_uline ) 
    13861455        { 
    1387             float aOffset = FT_FLOOR(FT_MulFix(p_face->underline_position, p_face->size->metrics.y_scale)); 
    1388             float aSize = FT_CEIL(FT_MulFix(p_face->underline_thickness, p_face->size->metrics.y_scale)); 
    1389  
    1390             p_line->pi_underline_offset[ i ]  = ( aOffset < 0 ) ? -aOffset : aOffset; 
    1391             p_line->pi_underline_thickness[ i ] = ( aSize < 0 ) ? -aSize   : aSize; 
     1456            float aOffset = FT_FLOOR(FT_MulFix(p_face->underline_position, 
     1457                                               p_face->size->metrics.y_scale)); 
     1458            float aSize = FT_CEIL(FT_MulFix(p_face->underline_thickness, 
     1459                                            p_face->size->metrics.y_scale)); 
     1460 
     1461            p_line->pi_underline_offset[ i ]  = 
     1462                                       ( aOffset < 0 ) ? -aOffset : aOffset; 
     1463            p_line->pi_underline_thickness[ i ] = 
     1464                                       ( aSize < 0 ) ? -aSize   : aSize; 
    13921465        } 
    13931466        p_line->pp_glyphs[ i ] = (FT_BitmapGlyph)tmp_glyph; 
     
    13951468 
    13961469        line.xMax = p_line->p_glyph_pos[i].x + glyph_size.xMax - 
    1397             glyph_size.xMin + ((FT_BitmapGlyph)tmp_glyph)->left; 
     1470                    glyph_size.xMin + ((FT_BitmapGlyph)tmp_glyph)->left; 
    13981471        if( line.xMax > (int)p_filter->fmt_out.video.i_visible_width - 20 ) 
    13991472        { 
     
    14091482            if( psz_unicode == psz_unicode_start ) 
    14101483            { 
    1411                 msg_Warn( p_filter, "unbreakable string" ); 
     1484                if( b_first_on_line ) 
     1485                { 
     1486                    msg_Warn( p_filter, "unbreakable string" ); 
     1487                    p_line->pp_glyphs[ i ] = NULL; 
     1488                    return VLC_EGENERIC; 
     1489                } 
     1490                *pi_pen_x = i_pen_x_start; 
     1491 
     1492                p_line->i_width = line.xMax; 
     1493                p_line->i_height = __MAX( p_line->i_height, 
     1494                                          p_face->size->metrics.height >> 6 ); 
    14121495                p_line->pp_glyphs[ i ] = NULL; 
    1413                 return VLC_EGENERIC; 
     1496 
     1497                p_result->x = __MAX( p_result->x, line.xMax ); 
     1498                p_result->y = __MAX( p_result->y, __MAX( p_line->i_height, 
     1499                                                         i_yMax - i_yMin ) ); 
     1500 
     1501                *pi_start = i; 
     1502                return VLC_SUCCESS; 
    14141503            } 
    14151504            else 
    14161505            { 
    1417                 *psz_unicode = 0xffff
     1506                *psz_unicode = '\n'
    14181507            } 
    14191508            psz_unicode = psz_unicode_start; 
     
    14341523    } 
    14351524    p_line->i_width = line.xMax; 
    1436     p_line->i_height = __MAX( p_line->i_height, p_face->size->metrics.height >> 6 ); 
     1525    p_line->i_height = __MAX( p_line->i_height, 
     1526                              p_face->size->metrics.height >> 6 ); 
    14371527    p_line->pp_glyphs[ i ] = NULL; 
    14381528 
    14391529    p_result->x = __MAX( p_result->x, line.xMax ); 
    1440     p_result->y = __MAX( p_result->y, __MAX( p_line->i_height, line.yMax - line.yMin ) ); 
     1530    p_result->y = __MAX( p_result->y, __MAX( p_line->i_height, 
     1531                         line.yMax - line.yMin ) ); 
    14411532 
    14421533    *pi_start = i; 
     
    14601551} 
    14611552 
    1462 static int ProcessNodes( filter_t *p_filter, xml_reader_t *p_xml_reader, char *psz_html, text_style_t *p_font_style, line_desc_t  **p_lines, FT_Vector *p_result ) 
    1463 
    1464     filter_sys_t *p_sys = p_filter->p_sys; 
    1465  
    1466     FT_Vector tmp_result; 
    1467  
    1468     font_stack_t *p_fonts = NULL; 
     1553static int HandleFontAttributes( xml_reader_t *p_xml_reader, 
     1554                                  font_stack_t **p_fonts ) 
     1555
     1556    int   rv; 
     1557    char *psz_fontname = NULL; 
     1558    int   i_font_color = 0xffffff; 
     1559    int   i_font_alpha = 0; 
     1560    int   i_font_size  = 24; 
     1561 
     1562    /* Default all attributes to the top font in the stack -- in case not 
     1563     * all attributes are specified in the sub-font 
     1564     */ 
     1565    if( VLC_SUCCESS == PeekFont( p_fonts, 
     1566                                 &psz_fontname, 
     1567                                 &i_font_size, 
     1568                                 &i_font_color, 
     1569                                 &i_font_alpha )) 
     1570    { 
     1571        psz_fontname = strdup( psz_fontname ); 
     1572    } 
     1573 
     1574    while ( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS ) 
     1575    { 
     1576        char *psz_name = xml_ReaderName ( p_xml_reader ); 
     1577        char *psz_value = xml_ReaderValue ( p_xml_reader ); 
     1578 
     1579        if( psz_name && psz_value ) 
     1580        { 
     1581            if( !strcasecmp( "face", psz_name ) ) 
     1582            { 
     1583                if( psz_fontname ) free( psz_fontname ); 
     1584                psz_fontname = strdup( psz_value ); 
     1585            } 
     1586            else if( !strcasecmp( "size", psz_name ) ) 
     1587            { 
     1588                if( ( *psz_value == '+' ) || ( *psz_value == '-' ) ) 
     1589                { 
     1590                    int i_value = atoi( psz_value ); 
     1591 
     1592                    if( ( i_value >= -5 ) && ( i_value <= 5 ) ) 
     1593                        i_font_size += ( i_value * i_font_size ) / 10; 
     1594                    else if( i_value < -5 ) 
     1595                        i_font_size = - i_value; 
     1596                    else if( i_value > 5 ) 
     1597                        i_font_size = i_value; 
     1598                } 
     1599                else 
     1600                    i_font_size = atoi( psz_value ); 
     1601            } 
     1602            else if( !strcasecmp( "color", psz_name )  && 
     1603                     ( psz_value[0] == '#' ) ) 
     1604            { 
     1605                i_font_color = strtol( psz_value + 1, NULL, 16 ); 
     1606                i_font_color &= 0x00ffffff; 
     1607            } 
     1608            else if( !strcasecmp( "alpha", psz_name ) && 
     1609                     ( psz_value[0] == '#' ) ) 
     1610            { 
     1611                i_font_alpha = strtol( psz_value + 1, NULL, 16 ); 
     1612                i_font_alpha &= 0xff; 
     1613            } 
     1614            free( psz_name ); 
     1615            free( psz_value ); 
     1616        } 
     1617    } 
     1618    rv = PushFont( p_fonts, 
     1619                   psz_fontname, 
     1620                   i_font_size, 
     1621                   i_font_color, 
     1622                   i_font_alpha ); 
     1623 
     1624    free( psz_fontname ); 
     1625 
     1626    return rv; 
     1627
     1628 
     1629static void SetupLine( filter_t *p_filter, const char *psz_text_in, 
     1630                       uint32_t **psz_text_out, uint32_t *pi_runs, 
     1631                       uint32_t **ppi_run_lengths, ft_style_t ***ppp_styles, 
     1632                       ft_style_t *p_style ) 
     1633
     1634    uint32_t      i_string_length = 0; 
     1635 
     1636    IconvText( p_filter, psz_text_in, &i_string_length, psz_text_out ); 
     1637    *psz_text_out += i_string_length; 
     1638 
     1639    if( ppp_styles && ppi_run_lengths ) 
     1640    { 
     1641        (*pi_runs)++; 
     1642 
     1643        if( *ppp_styles ) 
     1644        { 
     1645            *ppp_styles = (ft_style_t **) 
     1646                realloc( *ppp_styles, *pi_runs * sizeof( ft_style_t * ) ); 
     1647        } 
     1648        else if( *pi_runs == 1 ) 
     1649        { 
     1650            *ppp_styles = (ft_style_t **) 
     1651                malloc( *pi_runs * sizeof( ft_style_t * ) ); 
     1652        } 
     1653 
     1654        /* We have just malloc'ed this memory successfully - 
     1655         * *pi_runs HAS to be within the memory area of *ppp_styles */ 
     1656        if( *ppp_styles ) 
     1657        { 
     1658            (*ppp_styles)[ *pi_runs - 1 ] = p_style; 
     1659            p_style = NULL; 
     1660        } 
     1661 
     1662        if( *ppi_run_lengths ) 
     1663        { 
     1664            *ppi_run_lengths = (uint32_t *) 
     1665                realloc( *ppi_run_lengths, *pi_runs * sizeof( uint32_t ) ); 
     1666        } 
     1667        else if( *pi_runs == 1 ) 
     1668        { 
     1669            *ppi_run_lengths = (uint32_t *) 
     1670                malloc( *pi_runs * sizeof( uint32_t ) ); 
     1671        } 
     1672 
     1673        /* same remarks here */ 
     1674        if( *ppi_run_lengths ) 
     1675        { 
     1676            (*ppi_run_lengths)[ *pi_runs - 1 ] = i_string_length; 
     1677        } 
     1678    } 
     1679    /* If we couldn't use the p_style argument due to memory allocation 
     1680     * problems above, release it here. 
     1681     */ 
     1682    if( p_style ) DeleteStyle( p_style ); 
     1683
     1684 
     1685static int ProcessNodes( filter_t *p_filter, xml_reader_t *p_xml_reader, 
     1686                         text_style_t *p_font_style, uint32_t *psz_text, 
     1687                         int *pi_len, uint32_t *pi_runs, 
     1688                         uint32_t **ppi_run_lengths, ft_style_t ***ppp_styles) 
     1689
     1690    int           rv             = VLC_SUCCESS; 
     1691    filter_sys_t *p_sys          = p_filter->p_sys; 
     1692    uint32_t     *psz_text_orig  = psz_text; 
     1693    font_stack_t *p_fonts        = NULL; 
     1694 
     1695    char *psz_node  = NULL; 
     1696 
    14691697    vlc_bool_t b_italic = VLC_FALSE; 
    14701698    vlc_bool_t b_bold   = VLC_FALSE; 
    14711699    vlc_bool_t b_uline  = VLC_FALSE; 
    14721700 
    1473     line_desc_t *p_line = NULL; 
    1474     line_desc_t *p_prev = NULL; 
    1475  
    1476     char *psz_node  = NULL; 
    1477  
    1478     int i_pen_x = 0; 
    1479     int i_pen_y = 0; 
    1480     int i_posn  = 0; 
    1481  
    1482     int rv = VLC_SUCCESS; 
    1483  
    1484     p_result->x = p_result->y = 0; 
    1485     tmp_result.x = tmp_result.y = 0; 
    1486  
    14871701    if( p_font_style ) 
    14881702    { 
    1489         PushFont( &p_fonts, 
    1490                   p_font_style->psz_fontname, 
    1491                   p_font_style->i_font_size, 
    1492                   p_font_style->i_font_color, 
    1493                   p_font_style->i_font_alpha ); 
     1703        rv = PushFont( &p_fonts, 
     1704                       p_font_style->psz_fontname, 
     1705                       p_font_style->i_font_size, 
     1706                       p_font_style->i_font_color, 
     1707                       p_font_style->i_font_alpha ); 
    14941708 
    14951709        if( p_font_style->i_style_flags & STYLE_BOLD ) 
     
    15021716    else 
    15031717    { 
    1504         PushFont( &p_fonts, FC_DEFAULT_FONT, p_sys->i_font_size, 0xffffff, 0 ); 
    1505     } 
    1506  
    1507     while ( ( xml_ReaderRead( p_xml_reader ) == 1 ) && ( rv == VLC_SUCCESS ) ) 
     1718        rv = PushFont( &p_fonts, 
     1719                       FC_DEFAULT_FONT, 
     1720                       p_sys->i_font_size, 
     1721                       0xffffff, 
     1722                       0 ); 
     1723    } 
     1724    if( rv != VLC_SUCCESS ) 
     1725        return rv; 
     1726 
     1727    while ( ( xml_ReaderRead( p_xml_reader ) == 1 ) ) 
    15081728    { 
    15091729        switch ( xml_ReaderNodeType( p_xml_reader ) ) 
     
    15331753                { 
    15341754                    if( !strcasecmp( "font", psz_node ) ) 
    1535                     { 
    1536                         char *psz_fontname = NULL; 
    1537                         int  i_font_color = 0xffffff; 
    1538                         int  i_font_alpha = 0; 
    1539                         int  i_font_size  = 24; 
    1540  
    1541                         /* Default all attributes to the top font in the stack -- in case not 
    1542                          * all attributes are specified in the sub-font 
    1543                          */ 
    1544                         if( VLC_SUCCESS == PeekFont( &p_fonts, &psz_fontname, &i_font_size, &i_font_color, &i_font_alpha )) 
    1545                         { 
    1546                             psz_fontname = strdup( psz_fontname ); 
    1547                         } 
    1548  
    1549                         while ( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS ) 
    1550                         { 
    1551                             char *psz_name = xml_ReaderName ( p_xml_reader ); 
    1552                             char *psz_value = xml_ReaderValue ( p_xml_reader ); 
    1553  
    1554                             if( psz_name && psz_value ) 
    1555                             { 
    1556                                 if( !strcasecmp( "face", psz_name ) ) 
    1557                                 { 
    1558                                     if( psz_fontname ) free( psz_fontname ); 
    1559                                     psz_fontname = strdup( psz_value ); 
    1560                                 } 
    1561                                 else if( !strcasecmp( "size", psz_name ) ) 
    1562                                 { 
    1563                                     i_font_size = atoi( psz_value ); 
    1564                                 } 
    1565                                 else if( !strcasecmp( "color", psz_name )  && 
    1566                                          ( psz_value[0] == '#' ) ) 
    1567                                 { 
    1568                                     i_font_color = strtol( psz_value+1, NULL, 16 ); 
    1569                                     i_font_color &= 0x00ffffff; 
    1570                                 } 
    1571                                 else if( !strcasecmp( "alpha", psz_name ) && 
    1572                                          ( psz_value[0] == '#' ) ) 
    1573                                 { 
    1574                                     i_font_alpha = strtol( psz_value+1, NULL, 16 ); 
    1575                                     i_font_alpha &= 0xff; 
    1576                                 } 
    1577                                 free( psz_name ); 
    1578                                 free( psz_value ); 
    1579                             } 
    1580                         } 
    1581                         PushFont( &p_fonts, psz_fontname, i_font_size, i_font_color, i_font_alpha ); 
    1582                         free( psz_fontname ); 
    1583                     } 
     1755                        rv = HandleFontAttributes( p_xml_reader, &p_fonts ); 
    15841756                    else if( !strcasecmp( "b", psz_node ) ) 
    1585                     { 
    15861757                        b_bold = VLC_TRUE; 
    1587                     } 
    15881758                    else if( !strcasecmp( "i", psz_node ) ) 
    1589                     { 
    15901759                        b_italic = VLC_TRUE; 
    1591                     } 
    15921760                    else if( !strcasecmp( "u", psz_node ) ) 
    1593                     { 
    15941761                        b_uline = VLC_TRUE; 
    1595                     } 
    15961762                    else if( !strcasecmp( "br", psz_node ) ) 
    15971763                    { 
    1598                         if( p_line ) 
    1599                         { 
    1600                             p_prev = p_line; 
    1601                             if( !(p_line = NewLine( (byte_t *)psz_html )) ) 
    1602                             { 
    1603                                 msg_Err( p_filter, "out of memory" ); 
    1604                                 free( psz_node ); 
    1605                                 rv = VLC_EGENERIC; 
    1606                                 break; 
    1607                             } 
    1608                             p_line->b_new_color_mode = VLC_TRUE; 
    1609                             p_result->x = __MAX( p_result->x, tmp_result.x ); 
    1610                             p_result->y += tmp_result.y; 
    1611  
    1612                             p_line->p_next = NULL; 
    1613                             i_pen_x = 0; 
    1614                             i_pen_y += tmp_result.y; 
    1615                             i_posn = 0; 
    1616                             p_prev->p_next = p_line; 
    1617                             tmp_result.x = 0; 
    1618                             tmp_result.y = 0; 
    1619                         } 
     1764                        SetupLine( p_filter, "\n", &psz_text, 
     1765                                   pi_runs, ppi_run_lengths, ppp_styles, 
     1766                                   GetStyleFromFontStack( p_sys, 
     1767                                                          &p_fonts, 
     1768                                                          b_bold, 
     1769                                                          b_italic, 
     1770                                                          b_uline ) ); 
    16201771                    } 
     1772 
    16211773                    free( psz_node ); 
    16221774                } 
     
    16261778                if( psz_node ) 
    16271779                { 
    1628                     char *psz_fontname = NULL; 
    1629                     int  i_font_color = 0xffffff; 
    1630                     int  i_font_alpha = 0; 
    1631                     int  i_font_size  = 24; 
    1632                     FT_Face p_face = NULL; 
    1633  
    1634                     if( VLC_SUCCESS == PeekFont( &p_fonts, &psz_fontname, &i_font_size, &i_font_color, &i_font_alpha ) ) 
     1780                    /* Turn any multiple-whitespaces into single spaces */ 
     1781                    char *s = strpbrk( psz_node, "\t\r\n " ); 
     1782                    while( s ) 
    16351783                    { 
    1636                         int            i_idx = 0; 
    1637                         char *psz_fontfile = FontConfig_Select( p_sys->p_fontconfig, psz_fontname, b_bold, b_italic, &i_idx ); 
    1638  
    1639                         if( psz_fontfile ) 
    1640                         { 
    1641                             if( FT_New_Face( p_sys->p_library, psz_fontfile ? psz_fontfile : "", 
    1642                                              i_idx, &p_face ) ) 
    1643                             { 
    1644                                 free( psz_fontfile ); 
    1645                                 free( psz_node ); 
    1646                                 rv = VLC_EGENERIC; 
    1647                                 break; 
    1648                             } 
    1649                             free( psz_fontfile ); 
    1650                         } 
     1784                        int i_whitespace = strspn( s, "\t\r\n " ); 
     1785 
     1786                        if( i_whitespace > 1 ) 
     1787                            memmove( s + 1, 
     1788                                     s + i_whitespace, 
     1789                                     strlen( s ) - i_whitespace + 1 ); 
     1790                        *s = ' '; 
     1791 
     1792                        s = strpbrk( s+1, "\t\r\n " ); 
    16511793                    } 
    1652  
    1653                     if( FT_Select_Charmap( p_face ? p_face : p_sys->p_face, ft_encoding_unicode ) || 
    1654                         FT_Set_Pixel_Sizes( p_face ? p_face : p_sys->p_face, 0, i_font_size ) ) 
    1655                     { 
    1656                         free( psz_node ); 
    1657                         rv = VLC_EGENERIC; 
    1658                         break; 
    1659                     } 
    1660                     p_sys->i_use_kerning = FT_HAS_KERNING( ( p_face  ? p_face : p_sys->p_face ) ); 
    1661  
    1662                     uint32_t *psz_unicode = IconvText( p_filter, psz_node ); 
    1663  
    1664                     if( !psz_unicode ) 
    1665                     { 
    1666                         free( psz_node ); 
    1667                         if( p_face ) FT_Done_Face( p_face ); 
    1668                         rv = VLC_EGENERIC; 
    1669                         break; 
    1670                     } 
    1671  
    1672                     while( *psz_unicode ) 
    1673                     { 
    1674                         if( !p_line ) 
    1675                         { 
    1676                             if( !(p_line = NewLine( (byte_t *)psz_html )) ) 
    1677                             { 
    1678                                 msg_Err( p_filter, "out of memory" ); 
    1679                                 free( psz_node ); 
    1680                                 if( p_face ) FT_Done_Face( p_face ); 
    1681                                 rv = VLC_EGENERIC; 
    1682                                 break; 
    1683                             } 
    1684                             /* New Color mode only works in YUVA rendering mode -- 
    1685                              * (RGB mode has palette constraints on it). We therefore 
    1686                              * need to populate the legacy colour fields also. 
    1687                              */ 
    1688                             p_line->b_new_color_mode = VLC_TRUE; 
    1689                             p_line->i_alpha = i_font_alpha; 
    1690                             p_line->i_red   = ( i_font_color & 0xff0000 ) >> 16; 
    1691                             p_line->i_green = ( i_font_color & 0x00ff00 ) >>  8; 
    1692                             p_line->i_blue  = ( i_font_color & 0x0000ff ); 
    1693                             p_line->p_next = NULL; 
    1694                             i_pen_x = 0; 
    1695                             i_pen_y += tmp_result.y; 
    1696                             tmp_result.x = 0; 
    1697                             tmp_result.y = 0; 
    1698                             i_posn = 0; 
    1699                             if( p_prev ) p_prev->p_next = p_line; 
    1700                             else *p_lines = p_line; 
    1701                         } 
    1702  
    1703                         if( RenderTag( p_filter, p_face, i_font_color, b_uline, p_line, psz_unicode, &i_pen_x, i_pen_y, &i_posn, &tmp_result ) != VLC_SUCCESS ) 
    1704                         { 
    1705                             free( psz_node ); 
    1706                             if( p_face ) FT_Done_Face( p_face ); 
    1707                             rv = VLC_EGENERIC; 
    1708                             break; 
    1709                         } 
    1710                         if( *psz_unicode ) 
    1711                         { 
    1712                             p_result->x = __MAX( p_result->x, tmp_result.x ); 
    1713                             p_result->y += tmp_result.y; 
    1714  
    1715                             p_prev = p_line; 
    1716                             p_line = NULL; 
    1717                         } 
    1718                     } 
    1719                     if( rv != VLC_SUCCESS ) break; 
    1720  
    1721                     if( p_face ) FT_Done_Face( p_face ); 
    1722                     free( psz_unicode ); 
     1794                    SetupLine( p_filter, psz_node, &psz_text, 
     1795                               pi_runs, ppi_run_lengths, ppp_styles, 
     1796                               GetStyleFromFontStack( p_sys, 
     1797                                                      &p_fonts, 
     1798                                                      b_bold, 
     1799                                                      b_italic, 
     1800                                                      b_uline ) ); 
    17231801                    free( psz_node ); 
    17241802                } 
    17251803                break; 
    17261804        } 
    1727     } 
     1805        if( rv != VLC_SUCCESS ) 
     1806        { 
     1807            psz_text = psz_text_orig; 
     1808            break; 
     1809        } 
     1810    } 
     1811 
     1812    *pi_len = psz_text - psz_text_orig; 
     1813 
     1814    while( VLC_SUCCESS == PopFont( &p_fonts ) ); 
     1815 
     1816    return rv; 
     1817
     1818 
     1819static int ProcessLines( filter_t *p_filter, uint32_t *psz_text, 
     1820                         int i_len, uint32_t i_runs, 
     1821                         uint32_t *pi_run_lengths, ft_style_t **pp_styles, 
     1822                         line_desc_t **pp_lines, FT_Vector *p_result ) 
     1823
     1824    filter_sys_t   *p_sys = p_filter->p_sys; 
     1825    ft_style_t     **pp_char_styles; 
     1826    uint32_t        i, j, k; 
     1827    int             i_prev; 
     1828 
     1829    /* Assign each character in the text string its style explicitly, so that 
     1830     * after the characters have been shuffled around by Fribidi, we can re-apply 
     1831     * the styles, and to simplify the calculation of runs within a line. 
     1832     */ 
     1833    pp_char_styles = (ft_style_t **) malloc( i_len * sizeof( ft_style_t * )); 
     1834    if( !pp_char_styles ) 
     1835        return VLC_ENOMEM; 
     1836 
     1837    i = 0; 
     1838    for( j = 0; j < i_runs; j++ ) 
     1839        for( k = 0; k < pi_run_lengths[ j ]; k++ ) 
     1840            pp_char_styles[ i++ ] = pp_styles[ j ]; 
     1841 
     1842#if defined(HAVE_FRIBIDI) 
     1843    { 
     1844        ft_style_t  **pp_char_styles_new; 
     1845        int         *p_positions; 
     1846        uint32_t    *p_fribidi_string; 
     1847        int start_pos, pos = 0; 
     1848 
     1849        p_fribidi_string = malloc( (i_len + 1) * sizeof(uint32_t) ); 
     1850        if(! p_fribidi_string ) 
     1851        { 
     1852            msg_Err( p_filter, "out of memory" ); 
     1853            free( pp_char_styles ); 
     1854            return VLC_ENOMEM; 
     1855        } 
     1856        pp_char_styles_new  = (ft_style_t **) 
     1857                                       malloc( i_len * sizeof( ft_style_t * )); 
     1858        if(! pp_char_styles_new ) 
     1859        { 
     1860            msg_Err( p_filter, "out of memory" ); 
     1861            free( p_fribidi_string ); 
     1862            free( pp_char_styles ); 
     1863            return VLC_ENOMEM; 
     1864        } 
     1865        p_positions = (int *) malloc( (i_len + 1) * sizeof( int ) ); 
     1866        if(! p_positions ) 
     1867        { 
     1868            msg_Err( p_filter, "out of memory" ); 
     1869            free( pp_char_styles_new ); 
     1870            free( p_fribidi_string ); 
     1871            free( pp_char_styles ); 
     1872            return VLC_ENOMEM; 
     1873