00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 typedef struct font_stack_t font_stack_t;
00026 struct font_stack_t
00027 {
00028 char *psz_name;
00029 int i_size;
00030 uint32_t i_color;
00031 uint32_t i_karaoke_bg_color;
00032
00033 font_stack_t *p_next;
00034 };
00035
00036 static void SetupLine( filter_t *p_filter, const char *psz_text_in,
00037 UCHAR **psz_text_out, uint32_t *pi_runs,
00038 uint32_t **ppi_run_lengths, TR_FONT_STYLE_PTR **ppp_styles,
00039 TR_FONT_STYLE_PTR p_style );
00040
00041 static TR_FONT_STYLE_PTR GetStyleFromFontStack( filter_sys_t *p_sys,
00042 font_stack_t **p_fonts, bool b_bold, bool b_italic,
00043 bool b_uline );
00044
00045 static int PushFont( font_stack_t **p_font, const char *psz_name, int i_size,
00046 uint32_t i_color, uint32_t i_karaoke_bg_color )
00047 {
00048 font_stack_t *p_new;
00049
00050 if( !p_font )
00051 return VLC_EGENERIC;
00052
00053 p_new = malloc( sizeof( font_stack_t ) );
00054 if( ! p_new )
00055 return VLC_ENOMEM;
00056
00057 p_new->p_next = NULL;
00058
00059 if( psz_name )
00060 p_new->psz_name = strdup( psz_name );
00061 else
00062 p_new->psz_name = NULL;
00063
00064 p_new->i_size = i_size;
00065 p_new->i_color = i_color;
00066 p_new->i_karaoke_bg_color = i_karaoke_bg_color;
00067
00068 if( !*p_font )
00069 {
00070 *p_font = p_new;
00071 }
00072 else
00073 {
00074 font_stack_t *p_last;
00075
00076 for( p_last = *p_font;
00077 p_last->p_next;
00078 p_last = p_last->p_next )
00079 ;
00080
00081 p_last->p_next = p_new;
00082 }
00083 return VLC_SUCCESS;
00084 }
00085
00086 static int PopFont( font_stack_t **p_font )
00087 {
00088 font_stack_t *p_last, *p_next_to_last;
00089
00090 if( !p_font || !*p_font )
00091 return VLC_EGENERIC;
00092
00093 p_next_to_last = NULL;
00094 for( p_last = *p_font;
00095 p_last->p_next;
00096 p_last = p_last->p_next )
00097 {
00098 p_next_to_last = p_last;
00099 }
00100
00101 if( p_next_to_last )
00102 p_next_to_last->p_next = NULL;
00103 else
00104 *p_font = NULL;
00105
00106 free( p_last->psz_name );
00107 free( p_last );
00108
00109 return VLC_SUCCESS;
00110 }
00111
00112 static int PeekFont( font_stack_t **p_font, char **psz_name, int *i_size,
00113 uint32_t *i_color, uint32_t *i_karaoke_bg_color )
00114 {
00115 font_stack_t *p_last;
00116
00117 if( !p_font || !*p_font )
00118 return VLC_EGENERIC;
00119
00120 for( p_last=*p_font;
00121 p_last->p_next;
00122 p_last=p_last->p_next )
00123 ;
00124
00125 *psz_name = p_last->psz_name;
00126 *i_size = p_last->i_size;
00127 *i_color = p_last->i_color;
00128 *i_karaoke_bg_color = p_last->i_karaoke_bg_color;
00129
00130 return VLC_SUCCESS;
00131 }
00132
00133 static const struct {
00134 const char *psz_name;
00135 uint32_t i_value;
00136 } p_html_colors[] = {
00137
00138 { "Aqua", 0x00FFFF },
00139 { "Black", 0x000000 },
00140 { "Blue", 0x0000FF },
00141 { "Fuchsia", 0xFF00FF },
00142 { "Gray", 0x808080 },
00143 { "Green", 0x008000 },
00144 { "Lime", 0x00FF00 },
00145 { "Maroon", 0x800000 },
00146 { "Navy", 0x000080 },
00147 { "Olive", 0x808000 },
00148 { "Purple", 0x800080 },
00149 { "Red", 0xFF0000 },
00150 { "Silver", 0xC0C0C0 },
00151 { "Teal", 0x008080 },
00152 { "White", 0xFFFFFF },
00153 { "Yellow", 0xFFFF00 },
00154
00155
00156 { "AliceBlue", 0xF0F8FF },
00157 { "AntiqueWhite", 0xFAEBD7 },
00158 { "Aqua", 0x00FFFF },
00159 { "Aquamarine", 0x7FFFD4 },
00160 { "Azure", 0xF0FFFF },
00161 { "Beige", 0xF5F5DC },
00162 { "Bisque", 0xFFE4C4 },
00163 { "Black", 0x000000 },
00164 { "BlanchedAlmond", 0xFFEBCD },
00165 { "Blue", 0x0000FF },
00166 { "BlueViolet", 0x8A2BE2 },
00167 { "Brown", 0xA52A2A },
00168 { "BurlyWood", 0xDEB887 },
00169 { "CadetBlue", 0x5F9EA0 },
00170 { "Chartreuse", 0x7FFF00 },
00171 { "Chocolate", 0xD2691E },
00172 { "Coral", 0xFF7F50 },
00173 { "CornflowerBlue", 0x6495ED },
00174 { "Cornsilk", 0xFFF8DC },
00175 { "Crimson", 0xDC143C },
00176 { "Cyan", 0x00FFFF },
00177 { "DarkBlue", 0x00008B },
00178 { "DarkCyan", 0x008B8B },
00179 { "DarkGoldenRod", 0xB8860B },
00180 { "DarkGray", 0xA9A9A9 },
00181 { "DarkGrey", 0xA9A9A9 },
00182 { "DarkGreen", 0x006400 },
00183 { "DarkKhaki", 0xBDB76B },
00184 { "DarkMagenta", 0x8B008B },
00185 { "DarkOliveGreen", 0x556B2F },
00186 { "Darkorange", 0xFF8C00 },
00187 { "DarkOrchid", 0x9932CC },
00188 { "DarkRed", 0x8B0000 },
00189 { "DarkSalmon", 0xE9967A },
00190 { "DarkSeaGreen", 0x8FBC8F },
00191 { "DarkSlateBlue", 0x483D8B },
00192 { "DarkSlateGray", 0x2F4F4F },
00193 { "DarkSlateGrey", 0x2F4F4F },
00194 { "DarkTurquoise", 0x00CED1 },
00195 { "DarkViolet", 0x9400D3 },
00196 { "DeepPink", 0xFF1493 },
00197 { "DeepSkyBlue", 0x00BFFF },
00198 { "DimGray", 0x696969 },
00199 { "DimGrey", 0x696969 },
00200 { "DodgerBlue", 0x1E90FF },
00201 { "FireBrick", 0xB22222 },
00202 { "FloralWhite", 0xFFFAF0 },
00203 { "ForestGreen", 0x228B22 },
00204 { "Fuchsia", 0xFF00FF },
00205 { "Gainsboro", 0xDCDCDC },
00206 { "GhostWhite", 0xF8F8FF },
00207 { "Gold", 0xFFD700 },
00208 { "GoldenRod", 0xDAA520 },
00209 { "Gray", 0x808080 },
00210 { "Grey", 0x808080 },
00211 { "Green", 0x008000 },
00212 { "GreenYellow", 0xADFF2F },
00213 { "HoneyDew", 0xF0FFF0 },
00214 { "HotPink", 0xFF69B4 },
00215 { "IndianRed", 0xCD5C5C },
00216 { "Indigo", 0x4B0082 },
00217 { "Ivory", 0xFFFFF0 },
00218 { "Khaki", 0xF0E68C },
00219 { "Lavender", 0xE6E6FA },
00220 { "LavenderBlush", 0xFFF0F5 },
00221 { "LawnGreen", 0x7CFC00 },
00222 { "LemonChiffon", 0xFFFACD },
00223 { "LightBlue", 0xADD8E6 },
00224 { "LightCoral", 0xF08080 },
00225 { "LightCyan", 0xE0FFFF },
00226 { "LightGoldenRodYellow", 0xFAFAD2 },
00227 { "LightGray", 0xD3D3D3 },
00228 { "LightGrey", 0xD3D3D3 },
00229 { "LightGreen", 0x90EE90 },
00230 { "LightPink", 0xFFB6C1 },
00231 { "LightSalmon", 0xFFA07A },
00232 { "LightSeaGreen", 0x20B2AA },
00233 { "LightSkyBlue", 0x87CEFA },
00234 { "LightSlateGray", 0x778899 },
00235 { "LightSlateGrey", 0x778899 },
00236 { "LightSteelBlue", 0xB0C4DE },
00237 { "LightYellow", 0xFFFFE0 },
00238 { "Lime", 0x00FF00 },
00239 { "LimeGreen", 0x32CD32 },
00240 { "Linen", 0xFAF0E6 },
00241 { "Magenta", 0xFF00FF },
00242 { "Maroon", 0x800000 },
00243 { "MediumAquaMarine", 0x66CDAA },
00244 { "MediumBlue", 0x0000CD },
00245 { "MediumOrchid", 0xBA55D3 },
00246 { "MediumPurple", 0x9370D8 },
00247 { "MediumSeaGreen", 0x3CB371 },
00248 { "MediumSlateBlue", 0x7B68EE },
00249 { "MediumSpringGreen", 0x00FA9A },
00250 { "MediumTurquoise", 0x48D1CC },
00251 { "MediumVioletRed", 0xC71585 },
00252 { "MidnightBlue", 0x191970 },
00253 { "MintCream", 0xF5FFFA },
00254 { "MistyRose", 0xFFE4E1 },
00255 { "Moccasin", 0xFFE4B5 },
00256 { "NavajoWhite", 0xFFDEAD },
00257 { "Navy", 0x000080 },
00258 { "OldLace", 0xFDF5E6 },
00259 { "Olive", 0x808000 },
00260 { "OliveDrab", 0x6B8E23 },
00261 { "Orange", 0xFFA500 },
00262 { "OrangeRed", 0xFF4500 },
00263 { "Orchid", 0xDA70D6 },
00264 { "PaleGoldenRod", 0xEEE8AA },
00265 { "PaleGreen", 0x98FB98 },
00266 { "PaleTurquoise", 0xAFEEEE },
00267 { "PaleVioletRed", 0xD87093 },
00268 { "PapayaWhip", 0xFFEFD5 },
00269 { "PeachPuff", 0xFFDAB9 },
00270 { "Peru", 0xCD853F },
00271 { "Pink", 0xFFC0CB },
00272 { "Plum", 0xDDA0DD },
00273 { "PowderBlue", 0xB0E0E6 },
00274 { "Purple", 0x800080 },
00275 { "Red", 0xFF0000 },
00276 { "RosyBrown", 0xBC8F8F },
00277 { "RoyalBlue", 0x4169E1 },
00278 { "SaddleBrown", 0x8B4513 },
00279 { "Salmon", 0xFA8072 },
00280 { "SandyBrown", 0xF4A460 },
00281 { "SeaGreen", 0x2E8B57 },
00282 { "SeaShell", 0xFFF5EE },
00283 { "Sienna", 0xA0522D },
00284 { "Silver", 0xC0C0C0 },
00285 { "SkyBlue", 0x87CEEB },
00286 { "SlateBlue", 0x6A5ACD },
00287 { "SlateGray", 0x708090 },
00288 { "SlateGrey", 0x708090 },
00289 { "Snow", 0xFFFAFA },
00290 { "SpringGreen", 0x00FF7F },
00291 { "SteelBlue", 0x4682B4 },
00292 { "Tan", 0xD2B48C },
00293 { "Teal", 0x008080 },
00294 { "Thistle", 0xD8BFD8 },
00295 { "Tomato", 0xFF6347 },
00296 { "Turquoise", 0x40E0D0 },
00297 { "Violet", 0xEE82EE },
00298 { "Wheat", 0xF5DEB3 },
00299 { "White", 0xFFFFFF },
00300 { "WhiteSmoke", 0xF5F5F5 },
00301 { "Yellow", 0xFFFF00 },
00302 { "YellowGreen", 0x9ACD32 },
00303
00304 { NULL, 0 }
00305 };
00306
00307 static int HandleFontAttributes( xml_reader_t *p_xml_reader,
00308 font_stack_t **p_fonts, int i_scale )
00309 {
00310 int rv;
00311 char *psz_fontname = NULL;
00312 uint32_t i_font_color = 0xffffff;
00313 int i_font_alpha = 0;
00314 uint32_t i_karaoke_bg_color = 0x00ffffff;
00315 int i_font_size = 24;
00316
00317
00318
00319
00320 if( VLC_SUCCESS == PeekFont( p_fonts,
00321 &psz_fontname,
00322 &i_font_size,
00323 &i_font_color,
00324 &i_karaoke_bg_color ))
00325 {
00326 psz_fontname = strdup( psz_fontname );
00327 i_font_size = i_font_size * 1000 / i_scale;
00328 }
00329 i_font_alpha = (i_font_color >> 24) & 0xff;
00330 i_font_color &= 0x00ffffff;
00331
00332 while ( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
00333 {
00334 char *psz_name = xml_ReaderName( p_xml_reader );
00335 char *psz_value = xml_ReaderValue( p_xml_reader );
00336
00337 if( psz_name && psz_value )
00338 {
00339 if( !strcasecmp( "face", psz_name ) )
00340 {
00341 free( psz_fontname );
00342 psz_fontname = strdup( psz_value );
00343 }
00344 else if( !strcasecmp( "size", psz_name ) )
00345 {
00346 if( ( *psz_value == '+' ) || ( *psz_value == '-' ) )
00347 {
00348 int i_value = atoi( psz_value );
00349
00350 if( ( i_value >= -5 ) && ( i_value <= 5 ) )
00351 i_font_size += ( i_value * i_font_size ) / 10;
00352 else if( i_value < -5 )
00353 i_font_size = - i_value;
00354 else if( i_value > 5 )
00355 i_font_size = i_value;
00356 }
00357 else
00358 i_font_size = atoi( psz_value );
00359 }
00360 else if( !strcasecmp( "color", psz_name ) )
00361 {
00362 if( psz_value[0] == '#' )
00363 {
00364 i_font_color = strtol( psz_value + 1, NULL, 16 );
00365 i_font_color &= 0x00ffffff;
00366 }
00367 else
00368 {
00369 for( int i = 0; p_html_colors[i].psz_name != NULL; i++ )
00370 {
00371 if( !strncasecmp( psz_value, p_html_colors[i].psz_name, strlen(p_html_colors[i].psz_name) ) )
00372 {
00373 i_font_color = p_html_colors[i].i_value;
00374 break;
00375 }
00376 }
00377 }
00378 }
00379 else if( !strcasecmp( "alpha", psz_name ) &&
00380 ( psz_value[0] == '#' ) )
00381 {
00382 i_font_alpha = strtol( psz_value + 1, NULL, 16 );
00383 i_font_alpha &= 0xff;
00384 }
00385 }
00386 free( psz_name );
00387 free( psz_value );
00388 }
00389 rv = PushFont( p_fonts,
00390 psz_fontname,
00391 i_font_size * i_scale / 1000,
00392 (i_font_color & 0xffffff) | ((i_font_alpha & 0xff) << 24),
00393 i_karaoke_bg_color );
00394
00395 free( psz_fontname );
00396
00397 return rv;
00398 }
00399
00400 static void SetKaraokeLen( uint32_t i_runs, uint32_t *pi_run_lengths,
00401 uint32_t i_k_runs, uint32_t *pi_k_run_lengths )
00402 {
00403
00404
00405
00406
00407 if( pi_k_run_lengths )
00408 {
00409 int i_chars = 0;
00410 uint32_t i;
00411
00412
00413
00414 for( i = 0; i < i_runs; i++ )
00415 i_chars += pi_run_lengths[ i ];
00416
00417
00418
00419
00420 for( i = 0; i < i_k_runs; i++ )
00421 i_chars -= pi_k_run_lengths[ i ];
00422
00423 pi_k_run_lengths[ i_k_runs - 1 ] = i_chars;
00424 }
00425 }
00426
00427 static void SetupKaraoke( xml_reader_t *p_xml_reader, uint32_t *pi_k_runs,
00428 uint32_t **ppi_k_run_lengths,
00429 uint32_t **ppi_k_durations )
00430 {
00431 while ( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
00432 {
00433 char *psz_name = xml_ReaderName( p_xml_reader );
00434 char *psz_value = xml_ReaderValue( p_xml_reader );
00435
00436 if( psz_name && psz_value &&
00437 !strcasecmp( "t", psz_name ) )
00438 {
00439 if( ppi_k_durations && ppi_k_run_lengths )
00440 {
00441 (*pi_k_runs)++;
00442
00443 if( *ppi_k_durations )
00444 {
00445 *ppi_k_durations = (uint32_t *)
00446 realloc( *ppi_k_durations,
00447 *pi_k_runs * sizeof( uint32_t ) );
00448 }
00449 else if( *pi_k_runs == 1 )
00450 {
00451 *ppi_k_durations = (uint32_t *)
00452 malloc( *pi_k_runs * sizeof( uint32_t ) );
00453 }
00454
00455 if( *ppi_k_run_lengths )
00456 {
00457 *ppi_k_run_lengths = (uint32_t *)
00458 realloc( *ppi_k_run_lengths,
00459 *pi_k_runs * sizeof( uint32_t ) );
00460 }
00461 else if( *pi_k_runs == 1 )
00462 {
00463 *ppi_k_run_lengths = (uint32_t *)
00464 malloc( *pi_k_runs * sizeof( uint32_t ) );
00465 }
00466 if( *ppi_k_durations )
00467 (*ppi_k_durations)[ *pi_k_runs - 1 ] = atoi( psz_value );
00468
00469 if( *ppi_k_run_lengths )
00470 (*ppi_k_run_lengths)[ *pi_k_runs - 1 ] = 0;
00471 }
00472 }
00473 free( psz_name );
00474 free( psz_value );
00475 }
00476 }
00477
00478
00479 static void HandleWhiteSpace( char *psz_node )
00480 {
00481 char *s = strpbrk( psz_node, "\t\r\n " );
00482 while( s )
00483 {
00484 int i_whitespace = strspn( s, "\t\r\n " );
00485
00486 if( i_whitespace > 1 )
00487 memmove( &s[1],
00488 &s[i_whitespace],
00489 strlen( s ) - i_whitespace + 1 );
00490 *s++ = ' ';
00491
00492 s = strpbrk( s, "\t\r\n " );
00493 }
00494 }
00495
00496
00497 static int ProcessNodes( filter_t *p_filter,
00498 xml_reader_t *p_xml_reader,
00499 text_style_t *p_font_style,
00500 UCHAR *psz_text,
00501 int *pi_len,
00502
00503 uint32_t *pi_runs,
00504 uint32_t **ppi_run_lengths,
00505 TR_FONT_STYLE_PTR **ppp_styles,
00506
00507 bool b_karaoke,
00508 uint32_t *pi_k_runs,
00509 uint32_t **ppi_k_run_lengths,
00510 uint32_t **ppi_k_durations )
00511 {
00512 int rv = VLC_SUCCESS;
00513 filter_sys_t *p_sys = p_filter->p_sys;
00514 UCHAR *psz_text_orig = psz_text;
00515 font_stack_t *p_fonts = NULL;
00516 vlc_value_t val;
00517 int i_scale = 1000;
00518
00519 char *psz_node = NULL;
00520
00521 bool b_italic = false;
00522 bool b_bold = false;
00523 bool b_uline = false;
00524
00525 if( VLC_SUCCESS == var_Get( p_filter, "scale", &val ))
00526 i_scale = val.i_int;
00527
00528 if( p_font_style )
00529 {
00530 rv = PushFont( &p_fonts,
00531 p_font_style->psz_fontname,
00532 p_font_style->i_font_size * i_scale / 1000,
00533 (p_font_style->i_font_color & 0xffffff) |
00534 ((p_font_style->i_font_alpha & 0xff) << 24),
00535 (p_font_style->i_karaoke_background_color & 0xffffff) |
00536 ((p_font_style->i_karaoke_background_alpha & 0xff) << 24));
00537
00538 if( p_font_style->i_style_flags & STYLE_BOLD )
00539 b_bold = true;
00540 if( p_font_style->i_style_flags & STYLE_ITALIC )
00541 b_italic = true;
00542 if( p_font_style->i_style_flags & STYLE_UNDERLINE )
00543 b_uline = true;
00544 }
00545 #ifdef HAVE_FONTCONFIG
00546 else
00547 {
00548 rv = PushFont( &p_fonts,
00549 TR_DEFAULT_FONT,
00550 p_sys->i_font_size,
00551 (p_sys->i_font_color & 0xffffff) |
00552 (((255-p_sys->i_font_opacity) & 0xff) << 24),
00553 0x00ffffff );
00554 }
00555 #endif
00556
00557 if( rv != VLC_SUCCESS )
00558 return rv;
00559
00560 while ( ( xml_ReaderRead( p_xml_reader ) == 1 ) )
00561 {
00562 switch ( xml_ReaderNodeType( p_xml_reader ) )
00563 {
00564 case XML_READER_NONE:
00565 break;
00566 case XML_READER_ENDELEM:
00567 psz_node = xml_ReaderName( p_xml_reader );
00568 if( psz_node )
00569 {
00570 if( !strcasecmp( "font", psz_node ) )
00571 PopFont( &p_fonts );
00572 else if( !strcasecmp( "b", psz_node ) )
00573 b_bold = false;
00574 else if( !strcasecmp( "i", psz_node ) )
00575 b_italic = false;
00576 else if( !strcasecmp( "u", psz_node ) )
00577 b_uline = false;
00578
00579 free( psz_node );
00580 }
00581 break;
00582 case XML_READER_STARTELEM:
00583 psz_node = xml_ReaderName( p_xml_reader );
00584 if( psz_node )
00585 {
00586 if( !strcasecmp( "font", psz_node ) )
00587 rv = HandleFontAttributes( p_xml_reader, &p_fonts, i_scale );
00588 else if( !strcasecmp( "b", psz_node ) )
00589 b_bold = true;
00590 else if( !strcasecmp( "i", psz_node ) )
00591 b_italic = true;
00592 else if( !strcasecmp( "u", psz_node ) )
00593 b_uline = true;
00594 else if( !strcasecmp( "br", psz_node ) )
00595 {
00596 SetupLine( p_filter, "\n", &psz_text,
00597 pi_runs, ppi_run_lengths, ppp_styles,
00598 GetStyleFromFontStack( p_sys,
00599 &p_fonts,
00600 b_bold,
00601 b_italic,
00602 b_uline ) );
00603 }
00604 else if( !strcasecmp( "k", psz_node ) )
00605 {
00606
00607 if( b_karaoke )
00608 {
00609 if( *pi_k_runs > 0 )
00610 {
00611 SetKaraokeLen( *pi_runs, *ppi_run_lengths,
00612 *pi_k_runs, *ppi_k_run_lengths );
00613 }
00614 SetupKaraoke( p_xml_reader, pi_k_runs,
00615 ppi_k_run_lengths, ppi_k_durations );
00616 }
00617 }
00618
00619 free( psz_node );
00620 }
00621 break;
00622 case XML_READER_TEXT:
00623 psz_node = xml_ReaderValue( p_xml_reader );
00624 if( psz_node )
00625 {
00626
00627 HandleWhiteSpace( psz_node );
00628 resolve_xml_special_chars( psz_node );
00629
00630 SetupLine( p_filter, psz_node, &psz_text,
00631 pi_runs, ppi_run_lengths, ppp_styles,
00632 GetStyleFromFontStack( p_sys,
00633 &p_fonts,
00634 b_bold,
00635 b_italic,
00636 b_uline ) );
00637 free( psz_node );
00638 }
00639 break;
00640 }
00641 if( rv != VLC_SUCCESS )
00642 {
00643 psz_text = psz_text_orig;
00644 break;
00645 }
00646 }
00647 if( b_karaoke )
00648 {
00649 SetKaraokeLen( *pi_runs, *ppi_run_lengths,
00650 *pi_k_runs, *ppi_k_run_lengths );
00651 }
00652
00653 *pi_len = psz_text - psz_text_orig;
00654
00655 while( VLC_SUCCESS == PopFont( &p_fonts ) );
00656
00657 return rv;
00658 }