#include <vlc_strings.h> /* resolve_xml_special_chars */
#include <vlc_charset.h> /* ToCharset */
#include <vlc_dialog.h> /* FcCache dialog */
+#include <vlc_filter.h> /* filter_sys_t */
+#include <vlc_text_style.h> /* text_style_t*/
+#include <vlc_memory.h> /* realloc_or_free */
/* Default fonts */
#ifdef __APPLE__
* Local prototypes
*****************************************************************************/
-/* The RenderText call maps to pf_render_string, defined in vlc_filter.h */
-static int RenderText( filter_t *, subpicture_region_t *,
- subpicture_region_t * );
-
-#ifdef HAVE_STYLES
-static int RenderHtml( filter_t *, subpicture_region_t *,
- subpicture_region_t * );
-#endif
-#ifdef HAVE_FONTCONFIG
-static void FontConfig_BuildCache( filter_t * );
-static char* FontConfig_Select( FcConfig *, const char *,
- bool, bool, int, int * );
-#endif
-#ifdef WIN32
-static char* Win32_Select( filter_t *, const char *,
- bool, bool, int, int * );
-#endif
-
-static int LoadFontsFromAttachments( filter_t *p_filter );
-
-static int GetFontSize( filter_t *p_filter );
-static int SetFontSize( filter_t *, int );
-static void YUVFromRGB( uint32_t i_argb,
- uint8_t *pi_y, uint8_t *pi_u, uint8_t *pi_v );
-
typedef struct line_desc_t line_desc_t;
struct line_desc_t
{
FT_BitmapGlyph *pp_glyphs;
/** list of relative positions for the glyphs */
FT_Vector *p_glyph_pos;
- /** list of RGB information for styled text
- * -- if the rendering mode supports it (RenderYUVA) and
- * b_new_color_mode is set, then it becomes possible to
- * have multicoloured text within the subtitles. */
+ /** list of RGB information for styled text */
uint32_t *p_fg_rgb;
uint32_t *p_bg_rgb;
uint8_t *p_fg_bg_ratio; /* 0x00=100% FG --> 0x7F=100% BG */
- bool b_new_color_mode;
/** underline information -- only supplied if text should be underlined */
int *pi_underline_offset;
uint16_t *pi_underline_thickness;
- int i_height;
int i_width;
- int i_red, i_green, i_blue;
+ int i_height;
+
int i_alpha;
line_desc_t *p_next;
};
-static line_desc_t *NewLine( int );
-typedef struct
+typedef struct font_stack_t font_stack_t;
+struct font_stack_t
{
- int i_font_size;
- uint32_t i_font_color; /* ARGB */
- uint32_t i_karaoke_bg_color; /* ARGB */
- bool b_italic;
- bool b_bold;
- bool b_underline;
- bool b_through;
- char *psz_fontname;
-} ft_style_t;
-
-static int RenderYUVP( filter_t *, subpicture_region_t *, line_desc_t *, int, int);
-static void FreeLines( line_desc_t * );
-static void FreeLine( line_desc_t * );
+ char *psz_name;
+ int i_size;
+ uint32_t i_color; /* ARGB */
+ uint32_t i_karaoke_bg_color; /* ARGB */
+
+ font_stack_t *p_next;
+};
/*****************************************************************************
* filter_sys_t: freetype local data
int i_font_attachments;
};
-#define UCHAR uint32_t
-#define TR_DEFAULT_FONT p_sys->psz_fontfamily
-#define TR_FONT_STYLE_PTR ft_style_t *
-
-#include "text_renderer.h"
-
-/*****************************************************************************
- * Create: allocates osd-text video thread output method
- *****************************************************************************
- * This function allocates and initializes a Clone vout method.
- *****************************************************************************/
-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;
- char *psz_fontfamily = NULL;
- int i_error = 0, fontindex = 0;
-
- /* Allocate structure */
- p_filter->p_sys = p_sys = malloc( sizeof( filter_sys_t ) );
- if( !p_sys )
- return VLC_ENOMEM;
-
- p_sys->psz_fontfamily = NULL;
-#ifdef HAVE_STYLES
- p_sys->p_xml = NULL;
-#endif
- p_sys->p_face = 0;
- p_sys->p_library = 0;
- p_sys->i_font_size = 0;
- p_sys->i_display_height = 0;
-
- var_Create( p_filter, "freetype-rel-fontsize",
- VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
-
- psz_fontfamily = var_InheritString( p_filter, "freetype-font" );
- p_sys->i_default_font_size = var_InheritInteger( p_filter, "freetype-fontsize" );
- p_sys->i_effect = var_InheritInteger( p_filter, "freetype-effect" );
- p_sys->i_font_opacity = var_InheritInteger( p_filter,"freetype-opacity" );
- p_sys->i_font_opacity = __MAX( __MIN( p_sys->i_font_opacity, 255 ), 0 );
- p_sys->i_font_color = var_InheritInteger( p_filter, "freetype-color" );
- p_sys->i_font_color = __MAX( __MIN( p_sys->i_font_color , 0xFFFFFF ), 0 );
-
-#ifdef WIN32
- /* Get Windows Font folder */
- wchar_t wdir[MAX_PATH];
- if( S_OK != SHGetFolderPathW( NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, wdir ) )
- {
- GetWindowsDirectoryW( wdir, MAX_PATH );
- wcscat( wdir, L"\\fonts" );
- }
- p_sys->psz_win_fonts_path = FromWide( wdir );
-#endif
-
- /* Set default psz_fontfamily */
- if( !psz_fontfamily || !*psz_fontfamily )
- {
- free( psz_fontfamily );
-#ifdef HAVE_STYLES
- psz_fontfamily = strdup( DEFAULT_FAMILY );
-#else
-# ifdef WIN32
- if( asprintf( &psz_fontfamily, "%s"DEFAULT_FONT_FILE, p_sys->psz_win_fonts_path ) == -1 )
- goto error;
-# else
- psz_fontfamily = strdup( DEFAULT_FONT_FILE );
-# endif
- msg_Err( p_filter,"User specified an empty fontfile, using %s", psz_fontfamily );
-#endif
- }
-
- /* Set the current font file */
- p_sys->psz_fontfamily = psz_fontfamily;
-#ifdef HAVE_STYLES
-#ifdef HAVE_FONTCONFIG
- FontConfig_BuildCache( p_filter );
-
- /* */
- psz_fontfile = FontConfig_Select( NULL, psz_fontfamily, false, false,
- p_sys->i_default_font_size, &fontindex );
-#elif defined(WIN32)
- psz_fontfile = Win32_Select( p_filter, psz_fontfamily, false, false,
- p_sys->i_default_font_size, &fontindex );
-
-#endif
- msg_Dbg( p_filter, "Using %s as font from file %s", psz_fontfamily, psz_fontfile );
-
- /* If nothing is found, use the default family */
- if( !psz_fontfile )
- psz_fontfile = strdup( psz_fontfamily );
-
-#else /* !HAVE_STYLES */
- /* Use the default file */
- psz_fontfile = psz_fontfamily;
-#endif
-
- /* */
- i_error = FT_Init_FreeType( &p_sys->p_library );
- if( i_error )
- {
- msg_Err( p_filter, "couldn't initialize freetype" );
- goto error;
- }
-
- i_error = FT_New_Face( p_sys->p_library, psz_fontfile ? psz_fontfile : "",
- fontindex, &p_sys->p_face );
-
- if( i_error == FT_Err_Unknown_File_Format )
- {
- msg_Err( p_filter, "file %s have unknown format",
- psz_fontfile ? psz_fontfile : "(null)" );
- goto error;
- }
- else if( i_error )
- {
- msg_Err( p_filter, "failed to load font file %s",
- psz_fontfile ? psz_fontfile : "(null)" );
- goto error;
- }
-#ifdef HAVE_STYLES
- free( psz_fontfile );
-#endif
-
- i_error = FT_Select_Charmap( p_sys->p_face, ft_encoding_unicode );
- if( i_error )
- {
- msg_Err( p_filter, "font has no unicode translation table" );
- goto error;
- }
-
- p_sys->i_use_kerning = FT_HAS_KERNING( p_sys->p_face );
-
- if( SetFontSize( p_filter, 0 ) != VLC_SUCCESS ) goto error;
-
-
- p_sys->pp_font_attachments = NULL;
- p_sys->i_font_attachments = 0;
-
- p_filter->pf_render_text = RenderText;
-#ifdef HAVE_STYLES
- p_filter->pf_render_html = RenderHtml;
-#else
- p_filter->pf_render_html = NULL;
-#endif
-
- LoadFontsFromAttachments( p_filter );
-
- return VLC_SUCCESS;
-
-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 );
-#ifdef HAVE_STYLES
- free( psz_fontfile );
-#endif
- free( psz_fontfamily );
- free( p_sys );
- return VLC_EGENERIC;
-}
-
-/*****************************************************************************
- * Destroy: destroy Clone video thread output method
- *****************************************************************************
- * Clean up all data and library connections
- *****************************************************************************/
-static void Destroy( vlc_object_t *p_this )
+/* */
+static void YUVFromRGB( uint32_t i_argb,
+ uint8_t *pi_y, uint8_t *pi_u, uint8_t *pi_v )
{
- filter_t *p_filter = (filter_t *)p_this;
- filter_sys_t *p_sys = p_filter->p_sys;
-
- if( p_sys->pp_font_attachments )
- {
- for( int k = 0; k < p_sys->i_font_attachments; k++ )
- vlc_input_attachment_Delete( p_sys->pp_font_attachments[k] );
-
- free( p_sys->pp_font_attachments );
- }
-
-#ifdef HAVE_STYLES
- if( p_sys->p_xml ) xml_ReaderDelete( p_sys->p_xml );
-#endif
- free( p_sys->psz_fontfamily );
-
- /* FcFini asserts calling the subfunction FcCacheFini()
- * even if no other library functions have been made since FcInit(),
- * so don't call it. */
+ int i_red = ( i_argb & 0x00ff0000 ) >> 16;
+ int i_green = ( i_argb & 0x0000ff00 ) >> 8;
+ int i_blue = ( i_argb & 0x000000ff );
- FT_Done_Face( p_sys->p_face );
- FT_Done_FreeType( p_sys->p_library );
- free( p_sys );
+ *pi_y = (uint8_t)__MIN(abs( 2104 * i_red + 4130 * i_green +
+ 802 * i_blue + 4096 + 131072 ) >> 13, 235);
+ *pi_u = (uint8_t)__MIN(abs( -1214 * i_red + -2384 * i_green +
+ 3598 * i_blue + 4096 + 1048576) >> 13, 240);
+ *pi_v = (uint8_t)__MIN(abs( 3598 * i_red + -3013 * i_green +
+ -585 * i_blue + 4096 + 1048576) >> 13, 240);
}
/*****************************************************************************
return VLC_EGENERIC;
p_sys->i_font_attachments = 0;
- p_sys->pp_font_attachments = malloc( i_attachments_cnt * sizeof( input_attachment_t * ));
+ p_sys->pp_font_attachments = malloc( i_attachments_cnt * sizeof(*p_sys->pp_font_attachments));
if( !p_sys->pp_font_attachments )
return VLC_ENOMEM;
return VLC_SUCCESS;
}
-/*****************************************************************************
- * RenderYUVP: place string in picture
- *****************************************************************************
- * This function merges the previously rendered freetype glyphs into a picture
- *****************************************************************************/
-static int RenderYUVP( filter_t *p_filter, subpicture_region_t *p_region,
- line_desc_t *p_line, int i_width, int i_height )
+static int GetFontSize( filter_t *p_filter )
{
- VLC_UNUSED(p_filter);
- static const uint8_t pi_gamma[16] =
- {0x00, 0x52, 0x84, 0x96, 0xb8, 0xca, 0xdc, 0xee, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-
- uint8_t *p_dst;
- video_format_t fmt;
- int i, x, y, i_pitch;
- uint8_t i_y, i_u, i_v; /* YUV values, derived from incoming RGB */
-
- /* Create a new subpicture region */
- memset( &fmt, 0, sizeof(video_format_t) );
- fmt.i_chroma = VLC_CODEC_YUVP;
- fmt.i_width = fmt.i_visible_width = i_width + 4;
- fmt.i_height = fmt.i_visible_height = i_height + 4;
- if( p_region->fmt.i_visible_width > 0 )
- fmt.i_visible_width = p_region->fmt.i_visible_width;
- if( p_region->fmt.i_visible_height > 0 )
- fmt.i_visible_height = p_region->fmt.i_visible_height;
- fmt.i_x_offset = fmt.i_y_offset = 0;
- fmt.i_sar_num = 1;
- fmt.i_sar_den = 1;
-
- assert( !p_region->p_picture );
- p_region->p_picture = picture_NewFromFormat( &fmt );
- if( !p_region->p_picture )
- return VLC_EGENERIC;
- fmt.p_palette = p_region->fmt.p_palette ? p_region->fmt.p_palette : malloc(sizeof(*fmt.p_palette));
- p_region->fmt = fmt;
-
- /* Calculate text color components */
- YUVFromRGB( (p_line->i_red << 16) |
- (p_line->i_green << 8) |
- (p_line->i_blue ),
- &i_y, &i_u, &i_v);
+ filter_sys_t *p_sys = p_filter->p_sys;
+ int i_size = 0;
- /* Build palette */
- fmt.p_palette->i_entries = 16;
- for( i = 0; i < 8; i++ )
+ if( p_sys->i_default_font_size )
{
- fmt.p_palette->palette[i][0] = 0;
+ i_size = p_sys->i_default_font_size;
+ }
+ else
+ {
+ int i_ratio = var_GetInteger( p_filter, "freetype-rel-fontsize" );
+ if( i_ratio > 0 )
+ {
+ i_size = (int)p_filter->fmt_out.video.i_height / i_ratio;
+ p_filter->p_sys->i_display_height = p_filter->fmt_out.video.i_height;
+ }
+ }
+ if( i_size <= 0 )
+ {
+ msg_Warn( p_filter, "invalid fontsize, using 12" );
+ i_size = 12;
+ }
+ return i_size;
+}
+
+static int SetFontSize( filter_t *p_filter, int i_size )
+{
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ if( !i_size )
+ {
+ i_size = GetFontSize( p_filter );
+
+ msg_Dbg( p_filter, "using fontsize: %i", i_size );
+ }
+
+ p_sys->i_font_size = i_size;
+
+ if( FT_Set_Pixel_Sizes( p_sys->p_face, 0, i_size ) )
+ {
+ msg_Err( p_filter, "couldn't set font size to %d", i_size );
+ return VLC_EGENERIC;
+ }
+
+ return VLC_SUCCESS;
+}
+
+#ifdef HAVE_STYLES
+#ifdef HAVE_FONTCONFIG
+static void FontConfig_BuildCache( filter_t *p_filter )
+{
+ /* */
+ msg_Dbg( p_filter, "Building font databases.");
+ mtime_t t1, t2;
+ t1 = mdate();
+
+#ifdef WIN32
+ dialog_progress_bar_t *p_dialog = NULL;
+ FcConfig *fcConfig = FcInitLoadConfig();
+
+ p_dialog = dialog_ProgressCreate( p_filter,
+ _("Building font cache"),
+ _("Please wait while your font cache is rebuilt.\n"
+ "This should take less than a few minutes."), NULL );
+
+/* if( p_dialog )
+ dialog_ProgressSet( p_dialog, NULL, 0.5 ); */
+
+ FcConfigBuildFonts( fcConfig );
+ if( p_dialog )
+ {
+// dialog_ProgressSet( p_dialog, NULL, 1.0 );
+ dialog_ProgressDestroy( p_dialog );
+ p_dialog = NULL;
+ }
+#endif
+ t2 = mdate();
+ msg_Dbg( p_filter, "Took %ld microseconds", (long)((t2 - t1)) );
+}
+
+/***
+ * \brief Selects a font matching family, bold, italic provided
+ ***/
+static char* FontConfig_Select( FcConfig* config, const char* family,
+ bool b_bold, bool b_italic, int i_size, int *i_idx )
+{
+ FcResult result = FcResultMatch;
+ FcPattern *pat, *p_pat;
+ FcChar8* val_s;
+ FcBool val_b;
+
+ /* Create a pattern and fills it */
+ pat = FcPatternCreate();
+ if (!pat) return NULL;
+
+ /* */
+ FcPatternAddString( pat, FC_FAMILY, (const FcChar8*)family );
+ FcPatternAddBool( pat, FC_OUTLINE, FcTrue );
+ FcPatternAddInteger( pat, FC_SLANT, b_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
+ FcPatternAddInteger( pat, FC_WEIGHT, b_bold ? FC_WEIGHT_EXTRABOLD : FC_WEIGHT_NORMAL );
+ if( i_size != -1 )
+ {
+ char *psz_fontsize;
+ if( asprintf( &psz_fontsize, "%d", i_size ) != -1 )
+ {
+ FcPatternAddString( pat, FC_SIZE, (const FcChar8 *)psz_fontsize );
+ free( psz_fontsize );
+ }
+ }
+
+ /* */
+ FcDefaultSubstitute( pat );
+ if( !FcConfigSubstitute( config, pat, FcMatchPattern ) )
+ {
+ FcPatternDestroy( pat );
+ return NULL;
+ }
+
+ /* Find the best font for the pattern, destroy the pattern */
+ p_pat = FcFontMatch( config, pat, &result );
+ FcPatternDestroy( pat );
+ if( !p_pat || result == FcResultNoMatch ) return NULL;
+
+ /* Check the new pattern */
+ if( ( FcResultMatch != FcPatternGetBool( p_pat, FC_OUTLINE, 0, &val_b ) )
+ || ( val_b != FcTrue ) )
+ {
+ FcPatternDestroy( p_pat );
+ return NULL;
+ }
+ if( FcResultMatch != FcPatternGetInteger( p_pat, FC_INDEX, 0, i_idx ) )
+ {
+ *i_idx = 0;
+ }
+
+ if( FcResultMatch != FcPatternGetString( p_pat, FC_FAMILY, 0, &val_s ) )
+ {
+ FcPatternDestroy( p_pat );
+ return NULL;
+ }
+
+ /* if( strcasecmp((const char*)val_s, family ) != 0 )
+ msg_Warn( p_filter, "fontconfig: selected font family is not"
+ "the requested one: '%s' != '%s'\n",
+ (const char*)val_s, family ); */
+
+ if( FcResultMatch != FcPatternGetString( p_pat, FC_FILE, 0, &val_s ) )
+ {
+ FcPatternDestroy( p_pat );
+ return NULL;
+ }
+
+ FcPatternDestroy( p_pat );
+ return strdup( (const char*)val_s );
+}
+#endif
+
+#ifdef WIN32
+#define UNICODE
+#define FONT_DIR_NT "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"
+
+static int GetFileFontByName( const char *font_name, char **psz_filename )
+{
+ HKEY hKey;
+ wchar_t vbuffer[MAX_PATH];
+ wchar_t dbuffer[256];
+
+ if( RegOpenKeyEx(HKEY_LOCAL_MACHINE, FONT_DIR_NT, 0, KEY_READ, &hKey) != ERROR_SUCCESS )
+ return 1;
+
+ for( int index = 0;; index++ )
+ {
+ DWORD vbuflen = MAX_PATH - 1;
+ DWORD dbuflen = 255;
+
+ if( RegEnumValueW( hKey, index, vbuffer, &vbuflen,
+ NULL, NULL, (LPBYTE)dbuffer, &dbuflen) != ERROR_SUCCESS )
+ return 2;
+
+ char *psz_value = FromWide( vbuffer );
+
+ char *s = strchr( psz_value,'(' );
+ if( s != NULL && s != psz_value ) s[-1] = '\0';
+
+ /* Manage concatenated font names */
+ if( strchr( psz_value, '&') ) {
+ if( strcasestr( psz_value, font_name ) != NULL )
+ break;
+ }
+ else {
+ if( strcasecmp( psz_value, font_name ) == 0 )
+ break;
+ }
+ }
+
+ *psz_filename = FromWide( dbuffer );
+ return 0;
+}
+
+
+static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *lpelfe, const NEWTEXTMETRICEX *metric,
+ DWORD type, LPARAM lParam)
+{
+ VLC_UNUSED( metric );
+ if( (type & RASTER_FONTTYPE) ) return 1;
+ // if( lpelfe->elfScript ) FIXME
+
+ return GetFileFontByName( (const char *)lpelfe->elfFullName, (char **)lParam );
+}
+
+static char* Win32_Select( filter_t *p_filter, const char* family,
+ bool b_bold, bool b_italic, int i_size, int *i_idx )
+{
+ VLC_UNUSED( i_size );
+ // msg_Dbg( p_filter, "Here in Win32_Select, asking for %s", family );
+
+ /* */
+ LOGFONT lf;
+ lf.lfCharSet = DEFAULT_CHARSET;
+ if( b_italic )
+ lf.lfItalic = true;
+ if( b_bold )
+ lf.lfWeight = FW_BOLD;
+ strncpy( (LPSTR)&lf.lfFaceName, family, 32);
+
+ /* */
+ char *psz_filename = NULL;
+ HDC hDC = GetDC( NULL );
+ EnumFontFamiliesEx(hDC, &lf, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&psz_filename, 0);
+ ReleaseDC(NULL, hDC);
+
+ if( psz_filename == NULL )
+ return NULL;
+
+ /* FIXME: increase i_idx, when concatenated strings */
+ i_idx = 0;
+
+ /* */
+ char *psz_tmp;
+ if( asprintf( &psz_tmp, "%s\\%s", p_filter->p_sys->psz_win_fonts_path, psz_filename ) == -1 )
+ return NULL;
+ return psz_tmp;
+}
+#endif
+
+#endif
+
+
+/*****************************************************************************
+ * RenderYUVP: place string in picture
+ *****************************************************************************
+ * This function merges the previously rendered freetype glyphs into a picture
+ *****************************************************************************/
+static int RenderYUVP( filter_t *p_filter, subpicture_region_t *p_region,
+ line_desc_t *p_line, int i_width, int i_height )
+{
+ VLC_UNUSED(p_filter);
+ static const uint8_t pi_gamma[16] =
+ {0x00, 0x52, 0x84, 0x96, 0xb8, 0xca, 0xdc, 0xee, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+ uint8_t *p_dst;
+ video_format_t fmt;
+ int i, x, y, i_pitch;
+ uint8_t i_y, i_u, i_v; /* YUV values, derived from incoming RGB */
+
+ /* Create a new subpicture region */
+ memset( &fmt, 0, sizeof(video_format_t) );
+ fmt.i_chroma = VLC_CODEC_YUVP;
+ fmt.i_width = fmt.i_visible_width = i_width + 4;
+ fmt.i_height = fmt.i_visible_height = i_height + 4;
+ if( p_region->fmt.i_visible_width > 0 )
+ fmt.i_visible_width = p_region->fmt.i_visible_width;
+ if( p_region->fmt.i_visible_height > 0 )
+ fmt.i_visible_height = p_region->fmt.i_visible_height;
+ fmt.i_x_offset = fmt.i_y_offset = 0;
+ fmt.i_sar_num = 1;
+ fmt.i_sar_den = 1;
+
+ assert( !p_region->p_picture );
+ p_region->p_picture = picture_NewFromFormat( &fmt );
+ if( !p_region->p_picture )
+ return VLC_EGENERIC;
+ fmt.p_palette = p_region->fmt.p_palette ? p_region->fmt.p_palette : malloc(sizeof(*fmt.p_palette));
+ p_region->fmt = fmt;
+
+ /* Calculate text color components
+ * Only use the first color */
+ YUVFromRGB( p_line->p_fg_rgb[ 0 ], &i_y, &i_u, &i_v );
+
+ /* Build palette */
+ fmt.p_palette->i_entries = 16;
+ for( i = 0; i < 8; i++ )
+ {
+ fmt.p_palette->palette[i][0] = 0;
fmt.p_palette->palette[i][1] = 0x80;
fmt.p_palette->palette[i][2] = 0x80;
fmt.p_palette->palette[i][3] = pi_gamma[i];
uint8_t *p_dst_y,*p_dst_u,*p_dst_v,*p_dst_a;
video_format_t fmt;
int i, y, i_pitch, i_alpha;
- uint8_t i_y, i_u, i_v; /* YUV values, derived from incoming RGB */
if( i_width == 0 || i_height == 0 )
return VLC_SUCCESS;
return VLC_EGENERIC;
p_region->fmt = fmt;
- /* Calculate text color components */
- YUVFromRGB( (p_line->i_red << 16) |
- (p_line->i_green << 8) |
- (p_line->i_blue ),
- &i_y, &i_u, &i_v);
+ /* Save the alpha value */
i_alpha = p_line->i_alpha;
p_dst_y = p_region->p_picture->Y_PIXELS;
i_pitch = p_region->p_picture->A_PITCH;
/* Initialize the region pixels */
+ memset( p_dst_y, 0x00, i_pitch * p_region->fmt.i_height );
+ memset( p_dst_u, 0x80, i_pitch * p_region->fmt.i_height );
+ memset( p_dst_v, 0x80, i_pitch * p_region->fmt.i_height );
+
if( p_filter->p_sys->i_effect != EFFECT_BACKGROUND )
- {
- memset( p_dst_y, 0x00, i_pitch * p_region->fmt.i_height );
- memset( p_dst_u, 0x80, i_pitch * p_region->fmt.i_height );
- memset( p_dst_v, 0x80, i_pitch * p_region->fmt.i_height );
- memset( p_dst_a, 0, i_pitch * p_region->fmt.i_height );
- }
+ memset( p_dst_a, 0x00, i_pitch * p_region->fmt.i_height );
else
- {
- memset( p_dst_y, 0x0, i_pitch * p_region->fmt.i_height );
- memset( p_dst_u, 0x80, i_pitch * p_region->fmt.i_height );
- memset( p_dst_v, 0x80, i_pitch * p_region->fmt.i_height );
memset( p_dst_a, 0x80, i_pitch * p_region->fmt.i_height );
- }
+
if( p_filter->p_sys->i_effect == EFFECT_OUTLINE ||
p_filter->p_sys->i_effect == EFFECT_OUTLINE_FAT )
{
i_pitch + p_line->p_glyph_pos[ i ].x + p_glyph->left + 3 +
i_align_offset;
- if( p_line->b_new_color_mode )
- {
- /* Every glyph can (and in fact must) have its own color */
- YUVFromRGB( p_line->p_fg_rgb[ i ], &i_y, &i_u, &i_v );
- }
+ /* Every glyph can (and in fact must) have its own color */
+ uint8_t i_y, i_u, i_v;
+ YUVFromRGB( p_line->p_fg_rgb[ i ], &i_y, &i_u, &i_v );
for( y = 0, i_bitmap_offset = 0; y < p_glyph->bitmap.rows; y++ )
{
return VLC_SUCCESS;
}
-static ft_style_t *CreateStyle( char *psz_fontname, int i_font_size,
- uint32_t i_font_color, uint32_t i_karaoke_bg_color, bool b_bold,
- bool b_italic, bool b_uline, bool b_through )
+static text_style_t *CreateStyle( char *psz_fontname, int i_font_size,
+ uint32_t i_font_color, uint32_t i_karaoke_bg_color,
+ int i_style_flags )
{
- ft_style_t *p_style = malloc( sizeof( *p_style ));
+ text_style_t *p_style = text_style_New();
if( !p_style )
return NULL;
- p_style->i_font_size = i_font_size;
- p_style->i_font_color = i_font_color;
- p_style->i_karaoke_bg_color = i_karaoke_bg_color;
- p_style->b_italic = b_italic;
- p_style->b_bold = b_bold;
- p_style->b_underline = b_uline;
- p_style->b_through = b_through;
-
p_style->psz_fontname = strdup( psz_fontname );
-
+ p_style->i_font_size = i_font_size;
+ p_style->i_font_color = (i_font_color & 0x00ffffff) >> 0;
+ p_style->i_font_alpha = (i_font_color & 0xff000000) >> 24;
+ p_style->i_karaoke_background_color = (i_karaoke_bg_color & 0x00ffffff) >> 0;
+ p_style->i_karaoke_background_alpha = (i_karaoke_bg_color & 0xff000000) >> 24;
+ p_style->i_style_flags |= i_style_flags;
return p_style;
}
-static void DeleteStyle( ft_style_t *p_style )
-{
- if( !p_style )
- return;
-
- free( p_style->psz_fontname );
- free( p_style );
-}
-
-static bool StyleEquals( ft_style_t *s1, ft_style_t *s2 )
+static bool StyleEquals( text_style_t *s1, text_style_t *s2 )
{
if( !s1 || !s2 )
return false;
if( s1 == s2 )
return true;
- if(( s1->i_font_size == s2->i_font_size ) &&
- ( s1->i_font_color == s2->i_font_color ) &&
- ( s1->b_italic == s2->b_italic ) &&
- ( s1->b_through == s2->b_through ) &&
- ( s1->b_bold == s2->b_bold ) &&
- ( s1->b_underline == s2->b_underline ) &&
- ( !strcmp( s1->psz_fontname, s2->psz_fontname )))
+ return s1->i_font_size == s2->i_font_size &&
+ s1->i_font_color == s2->i_font_color &&
+ s1->i_font_alpha == s2->i_font_alpha &&
+ s1->i_style_flags == s2->i_style_flags &&
+ !strcmp( s1->psz_fontname, s2->psz_fontname );
+}
+
+static int PushFont( font_stack_t **p_font, const char *psz_name, int i_size,
+ uint32_t i_color, uint32_t i_karaoke_bg_color )
+{
+ if( !p_font )
+ return VLC_EGENERIC;
+
+ font_stack_t *p_new = malloc( sizeof(*p_new) );
+ if( !p_new )
+ return VLC_ENOMEM;
+
+ p_new->p_next = NULL;
+
+ if( psz_name )
+ p_new->psz_name = strdup( psz_name );
+ else
+ p_new->psz_name = NULL;
+
+ p_new->i_size = i_size;
+ p_new->i_color = i_color;
+ p_new->i_karaoke_bg_color = i_karaoke_bg_color;
+
+ if( !*p_font )
{
- return true;
+ *p_font = p_new;
}
- return false;
+ else
+ {
+ font_stack_t *p_last;
+
+ for( p_last = *p_font;
+ p_last->p_next;
+ p_last = p_last->p_next )
+ ;
+
+ p_last->p_next = p_new;
+ }
+ return VLC_SUCCESS;
}
-static void IconvText( filter_t *p_filter, const char *psz_string,
- size_t *i_string_length, uint32_t *psz_unicode )
+static int PopFont( font_stack_t **p_font )
{
- *i_string_length = 0;
- if( psz_unicode == NULL )
- return;
+ font_stack_t *p_last, *p_next_to_last;
- size_t i_length;
- uint32_t *psz_tmp =
-#if defined(WORDS_BIGENDIAN)
- ToCharset( "UCS-4BE", psz_string, &i_length );
-#else
- ToCharset( "UCS-4LE", psz_string, &i_length );
-#endif
- if( !psz_tmp )
+ if( !p_font || !*p_font )
+ return VLC_EGENERIC;
+
+ p_next_to_last = NULL;
+ for( p_last = *p_font;
+ p_last->p_next;
+ p_last = p_last->p_next )
+ {
+ p_next_to_last = p_last;
+ }
+
+ if( p_next_to_last )
+ p_next_to_last->p_next = NULL;
+ else
+ *p_font = NULL;
+
+ free( p_last->psz_name );
+ free( p_last );
+
+ return VLC_SUCCESS;
+}
+
+static int PeekFont( font_stack_t **p_font, char **psz_name, int *i_size,
+ uint32_t *i_color, uint32_t *i_karaoke_bg_color )
+{
+ font_stack_t *p_last;
+
+ if( !p_font || !*p_font )
+ return VLC_EGENERIC;
+
+ for( p_last=*p_font;
+ p_last->p_next;
+ p_last=p_last->p_next )
+ ;
+
+ *psz_name = p_last->psz_name;
+ *i_size = p_last->i_size;
+ *i_color = p_last->i_color;
+ *i_karaoke_bg_color = p_last->i_karaoke_bg_color;
+
+ return VLC_SUCCESS;
+}
+
+static const struct {
+ const char *psz_name;
+ uint32_t i_value;
+} p_html_colors[] = {
+ /* Official html colors */
+ { "Aqua", 0x00FFFF },
+ { "Black", 0x000000 },
+ { "Blue", 0x0000FF },
+ { "Fuchsia", 0xFF00FF },
+ { "Gray", 0x808080 },
+ { "Green", 0x008000 },
+ { "Lime", 0x00FF00 },
+ { "Maroon", 0x800000 },
+ { "Navy", 0x000080 },
+ { "Olive", 0x808000 },
+ { "Purple", 0x800080 },
+ { "Red", 0xFF0000 },
+ { "Silver", 0xC0C0C0 },
+ { "Teal", 0x008080 },
+ { "White", 0xFFFFFF },
+ { "Yellow", 0xFFFF00 },
+
+ /* Common ones */
+ { "AliceBlue", 0xF0F8FF },
+ { "AntiqueWhite", 0xFAEBD7 },
+ { "Aqua", 0x00FFFF },
+ { "Aquamarine", 0x7FFFD4 },
+ { "Azure", 0xF0FFFF },
+ { "Beige", 0xF5F5DC },
+ { "Bisque", 0xFFE4C4 },
+ { "Black", 0x000000 },
+ { "BlanchedAlmond", 0xFFEBCD },
+ { "Blue", 0x0000FF },
+ { "BlueViolet", 0x8A2BE2 },
+ { "Brown", 0xA52A2A },
+ { "BurlyWood", 0xDEB887 },
+ { "CadetBlue", 0x5F9EA0 },
+ { "Chartreuse", 0x7FFF00 },
+ { "Chocolate", 0xD2691E },
+ { "Coral", 0xFF7F50 },
+ { "CornflowerBlue", 0x6495ED },
+ { "Cornsilk", 0xFFF8DC },
+ { "Crimson", 0xDC143C },
+ { "Cyan", 0x00FFFF },
+ { "DarkBlue", 0x00008B },
+ { "DarkCyan", 0x008B8B },
+ { "DarkGoldenRod", 0xB8860B },
+ { "DarkGray", 0xA9A9A9 },
+ { "DarkGrey", 0xA9A9A9 },
+ { "DarkGreen", 0x006400 },
+ { "DarkKhaki", 0xBDB76B },
+ { "DarkMagenta", 0x8B008B },
+ { "DarkOliveGreen", 0x556B2F },
+ { "Darkorange", 0xFF8C00 },
+ { "DarkOrchid", 0x9932CC },
+ { "DarkRed", 0x8B0000 },
+ { "DarkSalmon", 0xE9967A },
+ { "DarkSeaGreen", 0x8FBC8F },
+ { "DarkSlateBlue", 0x483D8B },
+ { "DarkSlateGray", 0x2F4F4F },
+ { "DarkSlateGrey", 0x2F4F4F },
+ { "DarkTurquoise", 0x00CED1 },
+ { "DarkViolet", 0x9400D3 },
+ { "DeepPink", 0xFF1493 },
+ { "DeepSkyBlue", 0x00BFFF },
+ { "DimGray", 0x696969 },
+ { "DimGrey", 0x696969 },
+ { "DodgerBlue", 0x1E90FF },
+ { "FireBrick", 0xB22222 },
+ { "FloralWhite", 0xFFFAF0 },
+ { "ForestGreen", 0x228B22 },
+ { "Fuchsia", 0xFF00FF },
+ { "Gainsboro", 0xDCDCDC },
+ { "GhostWhite", 0xF8F8FF },
+ { "Gold", 0xFFD700 },
+ { "GoldenRod", 0xDAA520 },
+ { "Gray", 0x808080 },
+ { "Grey", 0x808080 },
+ { "Green", 0x008000 },
+ { "GreenYellow", 0xADFF2F },
+ { "HoneyDew", 0xF0FFF0 },
+ { "HotPink", 0xFF69B4 },
+ { "IndianRed", 0xCD5C5C },
+ { "Indigo", 0x4B0082 },
+ { "Ivory", 0xFFFFF0 },
+ { "Khaki", 0xF0E68C },
+ { "Lavender", 0xE6E6FA },
+ { "LavenderBlush", 0xFFF0F5 },
+ { "LawnGreen", 0x7CFC00 },
+ { "LemonChiffon", 0xFFFACD },
+ { "LightBlue", 0xADD8E6 },
+ { "LightCoral", 0xF08080 },
+ { "LightCyan", 0xE0FFFF },
+ { "LightGoldenRodYellow", 0xFAFAD2 },
+ { "LightGray", 0xD3D3D3 },
+ { "LightGrey", 0xD3D3D3 },
+ { "LightGreen", 0x90EE90 },
+ { "LightPink", 0xFFB6C1 },
+ { "LightSalmon", 0xFFA07A },
+ { "LightSeaGreen", 0x20B2AA },
+ { "LightSkyBlue", 0x87CEFA },
+ { "LightSlateGray", 0x778899 },
+ { "LightSlateGrey", 0x778899 },
+ { "LightSteelBlue", 0xB0C4DE },
+ { "LightYellow", 0xFFFFE0 },
+ { "Lime", 0x00FF00 },
+ { "LimeGreen", 0x32CD32 },
+ { "Linen", 0xFAF0E6 },
+ { "Magenta", 0xFF00FF },
+ { "Maroon", 0x800000 },
+ { "MediumAquaMarine", 0x66CDAA },
+ { "MediumBlue", 0x0000CD },
+ { "MediumOrchid", 0xBA55D3 },
+ { "MediumPurple", 0x9370D8 },
+ { "MediumSeaGreen", 0x3CB371 },
+ { "MediumSlateBlue", 0x7B68EE },
+ { "MediumSpringGreen", 0x00FA9A },
+ { "MediumTurquoise", 0x48D1CC },
+ { "MediumVioletRed", 0xC71585 },
+ { "MidnightBlue", 0x191970 },
+ { "MintCream", 0xF5FFFA },
+ { "MistyRose", 0xFFE4E1 },
+ { "Moccasin", 0xFFE4B5 },
+ { "NavajoWhite", 0xFFDEAD },
+ { "Navy", 0x000080 },
+ { "OldLace", 0xFDF5E6 },
+ { "Olive", 0x808000 },
+ { "OliveDrab", 0x6B8E23 },
+ { "Orange", 0xFFA500 },
+ { "OrangeRed", 0xFF4500 },
+ { "Orchid", 0xDA70D6 },
+ { "PaleGoldenRod", 0xEEE8AA },
+ { "PaleGreen", 0x98FB98 },
+ { "PaleTurquoise", 0xAFEEEE },
+ { "PaleVioletRed", 0xD87093 },
+ { "PapayaWhip", 0xFFEFD5 },
+ { "PeachPuff", 0xFFDAB9 },
+ { "Peru", 0xCD853F },
+ { "Pink", 0xFFC0CB },
+ { "Plum", 0xDDA0DD },
+ { "PowderBlue", 0xB0E0E6 },
+ { "Purple", 0x800080 },
+ { "Red", 0xFF0000 },
+ { "RosyBrown", 0xBC8F8F },
+ { "RoyalBlue", 0x4169E1 },
+ { "SaddleBrown", 0x8B4513 },
+ { "Salmon", 0xFA8072 },
+ { "SandyBrown", 0xF4A460 },
+ { "SeaGreen", 0x2E8B57 },
+ { "SeaShell", 0xFFF5EE },
+ { "Sienna", 0xA0522D },
+ { "Silver", 0xC0C0C0 },
+ { "SkyBlue", 0x87CEEB },
+ { "SlateBlue", 0x6A5ACD },
+ { "SlateGray", 0x708090 },
+ { "SlateGrey", 0x708090 },
+ { "Snow", 0xFFFAFA },
+ { "SpringGreen", 0x00FF7F },
+ { "SteelBlue", 0x4682B4 },
+ { "Tan", 0xD2B48C },
+ { "Teal", 0x008080 },
+ { "Thistle", 0xD8BFD8 },
+ { "Tomato", 0xFF6347 },
+ { "Turquoise", 0x40E0D0 },
+ { "Violet", 0xEE82EE },
+ { "Wheat", 0xF5DEB3 },
+ { "White", 0xFFFFFF },
+ { "WhiteSmoke", 0xF5F5F5 },
+ { "Yellow", 0xFFFF00 },
+ { "YellowGreen", 0x9ACD32 },
+
+ { NULL, 0 }
+};
+
+static int HandleFontAttributes( xml_reader_t *p_xml_reader,
+ font_stack_t **p_fonts )
+{
+ int rv;
+ char *psz_fontname = NULL;
+ uint32_t i_font_color = 0xffffff;
+ int i_font_alpha = 0;
+ uint32_t i_karaoke_bg_color = 0x00ffffff;
+ int i_font_size = 24;
+
+ /* Default all attributes to the top font in the stack -- in case not
+ * all attributes are specified in the sub-font
+ */
+ if( VLC_SUCCESS == PeekFont( p_fonts,
+ &psz_fontname,
+ &i_font_size,
+ &i_font_color,
+ &i_karaoke_bg_color ))
+ {
+ psz_fontname = strdup( psz_fontname );
+ i_font_size = i_font_size;
+ }
+ i_font_alpha = (i_font_color >> 24) & 0xff;
+ i_font_color &= 0x00ffffff;
+
+ const char *name, *value;
+ while( (name = xml_ReaderNextAttr( p_xml_reader, &value )) != NULL )
+ {
+ if( !strcasecmp( "face", name ) )
+ {
+ free( psz_fontname );
+ psz_fontname = strdup( value );
+ }
+ else if( !strcasecmp( "size", name ) )
+ {
+ if( ( *value == '+' ) || ( *value == '-' ) )
+ {
+ int i_value = atoi( value );
+
+ if( ( i_value >= -5 ) && ( i_value <= 5 ) )
+ i_font_size += ( i_value * i_font_size ) / 10;
+ else if( i_value < -5 )
+ i_font_size = - i_value;
+ else if( i_value > 5 )
+ i_font_size = i_value;
+ }
+ else
+ i_font_size = atoi( value );
+ }
+ else if( !strcasecmp( "color", name ) )
+ {
+ if( value[0] == '#' )
+ {
+ i_font_color = strtol( value + 1, NULL, 16 );
+ i_font_color &= 0x00ffffff;
+ }
+ else
+ {
+ for( int i = 0; p_html_colors[i].psz_name != NULL; i++ )
+ {
+ if( !strncasecmp( value, p_html_colors[i].psz_name, strlen(p_html_colors[i].psz_name) ) )
+ {
+ i_font_color = p_html_colors[i].i_value;
+ break;
+ }
+ }
+ }
+ }
+ else if( !strcasecmp( "alpha", name ) && ( value[0] == '#' ) )
+ {
+ i_font_alpha = strtol( value + 1, NULL, 16 );
+ i_font_alpha &= 0xff;
+ }
+ }
+ rv = PushFont( p_fonts,
+ psz_fontname,
+ i_font_size,
+ (i_font_color & 0xffffff) | ((i_font_alpha & 0xff) << 24),
+ i_karaoke_bg_color );
+
+ free( psz_fontname );
+
+ return rv;
+}
+
+static void SetKaraokeLen( uint32_t i_runs, uint32_t *pi_run_lengths,
+ uint32_t i_k_runs, uint32_t *pi_k_run_lengths )
+{
+ /* Karaoke tags _PRECEDE_ the text they specify a duration
+ * for, therefore we are working out the length for the
+ * previous tag, and first time through we have nothing
+ */
+ if( pi_k_run_lengths )
+ {
+ int i_chars = 0;
+ uint32_t i;
+
+ /* Work out how many characters are presently in the string
+ */
+ for( i = 0; i < i_runs; i++ )
+ i_chars += pi_run_lengths[ i ];
+
+ /* Subtract away those we've already allocated to other
+ * karaoke tags
+ */
+ for( i = 0; i < i_k_runs; i++ )
+ i_chars -= pi_k_run_lengths[ i ];
+
+ pi_k_run_lengths[ i_k_runs - 1 ] = i_chars;
+ }
+}
+
+static void SetupKaraoke( xml_reader_t *p_xml_reader, uint32_t *pi_k_runs,
+ uint32_t **ppi_k_run_lengths,
+ uint32_t **ppi_k_durations )
+{
+ const char *name, *value;
+
+ while( (name = xml_ReaderNextAttr( p_xml_reader, &value )) != NULL )
+ {
+ if( !strcasecmp( "t", name ) )
+ {
+ if( ppi_k_durations && ppi_k_run_lengths )
+ {
+ (*pi_k_runs)++;
+
+ if( *ppi_k_durations )
+ {
+ *ppi_k_durations = realloc_or_free( *ppi_k_durations,
+ *pi_k_runs * sizeof(**ppi_k_durations) );
+ }
+ else if( *pi_k_runs == 1 )
+ {
+ *ppi_k_durations = malloc( *pi_k_runs * sizeof(**ppi_k_durations) );
+ }
+
+ if( *ppi_k_run_lengths )
+ {
+ *ppi_k_run_lengths = realloc_or_free( *ppi_k_run_lengths,
+ *pi_k_runs * sizeof(**ppi_k_run_lengths) );
+ }
+ else if( *pi_k_runs == 1 )
+ {
+ *ppi_k_run_lengths = malloc( *pi_k_runs * sizeof(**ppi_k_run_lengths) );
+ }
+ if( *ppi_k_durations )
+ (*ppi_k_durations)[ *pi_k_runs - 1 ] = atoi( value );
+
+ if( *ppi_k_run_lengths )
+ (*ppi_k_run_lengths)[ *pi_k_runs - 1 ] = 0;
+ }
+ }
+ }
+}
+
+/* Turn any multiple-whitespaces into single spaces */
+static void HandleWhiteSpace( char *psz_node )
+{
+ char *s = strpbrk( psz_node, "\t\r\n " );
+ while( s )
{
- msg_Warn( p_filter, "failed to convert string to unicode (%m)" );
- return;
- }
- memcpy( psz_unicode, psz_tmp, i_length );
- *i_string_length = i_length / 4;
+ int i_whitespace = strspn( s, "\t\r\n " );
- free( psz_tmp );
+ if( i_whitespace > 1 )
+ memmove( &s[1],
+ &s[i_whitespace],
+ strlen( s ) - i_whitespace + 1 );
+ *s++ = ' ';
+
+ s = strpbrk( s, "\t\r\n " );
+ }
}
-static ft_style_t *GetStyleFromFontStack( filter_sys_t *p_sys,
- font_stack_t **p_fonts,
- bool b_bold, bool b_italic,
- bool b_uline, bool b_through )
+
+static text_style_t *GetStyleFromFontStack( filter_sys_t *p_sys,
+ font_stack_t **p_fonts,
+ int i_style_flags )
{
char *psz_fontname = NULL;
uint32_t i_font_color = p_sys->i_font_color & 0x00ffffff;
return NULL;
return CreateStyle( psz_fontname, i_font_size, i_font_color,
- i_karaoke_bg_color, b_bold, b_italic, b_uline, b_through );
+ i_karaoke_bg_color,
+ i_style_flags );
}
-static int RenderTag( filter_t *p_filter, FT_Face p_face, int i_font_color,
- bool b_uline, bool b_through, bool b_bold,
- bool b_italic, int i_karaoke_bgcolor,
+static int RenderTag( filter_t *p_filter, FT_Face p_face,
+ const text_style_t *p_style,
line_desc_t *p_line, uint32_t *psz_unicode,
int *pi_pen_x, int i_pen_y, int *pi_start,
FT_Vector *p_result )
* ie. if the font we have loaded is NOT already in the
* style that the tags want, then switch it on; if they
* are then don't. */
- if (b_bold && !( p_face->style_flags & FT_STYLE_FLAG_BOLD ))
+ if ((p_style->i_style_flags & STYLE_BOLD) && !(p_face->style_flags & FT_STYLE_FLAG_BOLD))
FT_GlyphSlot_Embolden( p_face->glyph );
- if (b_italic && !( p_face->style_flags & FT_STYLE_FLAG_ITALIC ))
+ if ((p_style->i_style_flags & STYLE_ITALIC) && !(p_face->style_flags & FT_STYLE_FLAG_ITALIC))
FT_GlyphSlot_Oblique( p_face->glyph );
i_error = FT_Get_Glyph( p_face->glyph, &tmp_glyph );
FT_Done_Glyph( tmp_glyph );
continue;
}
- if( b_uline || b_through )
+ if( p_style->i_style_flags & (STYLE_UNDERLINE | STYLE_STRIKEOUT) )
{
float aOffset = FT_FLOOR(FT_MulFix(p_face->underline_position,
p_face->size->metrics.y_scale));
( aOffset < 0 ) ? -aOffset : aOffset;
p_line->pi_underline_thickness[ i ] =
( aSize < 0 ) ? -aSize : aSize;
- if (b_through)
+ if( p_style->i_style_flags & STYLE_STRIKEOUT )
{
/* Move the baseline to make it strikethrough instead of
* underline. That means that strikethrough takes precedence
}
p_line->pp_glyphs[ i ] = (FT_BitmapGlyph)tmp_glyph;
- p_line->p_fg_rgb[ i ] = i_font_color & 0x00ffffff;
- p_line->p_bg_rgb[ i ] = i_karaoke_bgcolor & 0x00ffffff;
+ p_line->p_fg_rgb[ i ] = p_style->i_font_color;
+ p_line->p_bg_rgb[ i ] = p_style->i_karaoke_background_color;
p_line->p_fg_bg_ratio[ i ] = 0x00;
line.xMax = p_line->p_glyph_pos[i].x + glyph_size.xMax -
return VLC_SUCCESS;
}
-static void SetupLine( filter_t *p_filter, const char *psz_text_in,
- uint32_t **ppsz_text_out, uint32_t *pi_runs,
- uint32_t **ppi_run_lengths, ft_style_t ***ppp_styles,
- ft_style_t *p_style )
+static unsigned SetupText( filter_t *p_filter,
+ uint32_t *psz_text_out,
+ uint32_t *pi_runs,
+ uint32_t **ppi_run_lengths,
+ text_style_t ***ppp_styles,
+
+ const char *psz_text_in,
+ text_style_t *p_style )
{
size_t i_string_length;
- IconvText( p_filter, psz_text_in, &i_string_length, *ppsz_text_out );
- *ppsz_text_out += i_string_length;
+ size_t i_string_bytes;
+#if defined(WORDS_BIGENDIAN)
+ uint32_t *psz_tmp = ToCharset( "UCS-4BE", psz_text_in, &i_string_bytes );
+#else
+ uint32_t *psz_tmp = ToCharset( "UCS-4LE", psz_text_in, &i_string_bytes );
+#endif
+ if( psz_tmp )
+ {
+ memcpy( psz_text_out, psz_tmp, i_string_bytes );
+ i_string_length = i_string_bytes / 4;
+ free( psz_tmp );
+ }
+ else
+ {
+ msg_Warn( p_filter, "failed to convert string to unicode (%m)" );
+ i_string_length = 0;
+ }
- if( ppp_styles && ppi_run_lengths )
+ if( i_string_length > 0 && ppp_styles && ppi_run_lengths )
{
(*pi_runs)++;
if( *ppp_styles )
{
*ppp_styles = realloc_or_free( *ppp_styles,
- *pi_runs * sizeof( ft_style_t * ) );
+ *pi_runs * sizeof(**ppp_styles) );
}
else if( *pi_runs == 1 )
{
- *ppp_styles = malloc( *pi_runs * sizeof( ft_style_t * ) );
+ *ppp_styles = malloc( *pi_runs * sizeof(**ppp_styles) );
}
/* We have just malloc'ed this memory successfully -
if( *ppi_run_lengths )
{
*ppi_run_lengths = realloc_or_free( *ppi_run_lengths,
- *pi_runs * sizeof( uint32_t ) );
+ *pi_runs * sizeof(**ppi_run_lengths) );
}
else if( *pi_runs == 1 )
{
- *ppi_run_lengths = (uint32_t *)
- malloc( *pi_runs * sizeof( uint32_t ) );
+ *ppi_run_lengths = malloc( *pi_runs * sizeof(**ppi_run_lengths) );
}
/* same remarks here */
/* If we couldn't use the p_style argument due to memory allocation
* problems above, release it here.
*/
- DeleteStyle( p_style );
+ text_style_Delete( p_style );
+ return i_string_length;
}
-static int CheckForEmbeddedFont( filter_sys_t *p_sys, FT_Face *pp_face, ft_style_t *p_style )
+static int CheckForEmbeddedFont( filter_sys_t *p_sys, FT_Face *pp_face, text_style_t *p_style )
{
for( int k = 0; k < p_sys->i_font_attachments; k++ )
{
{
if( p_face )
{
- bool match = !strcasecmp( p_face->family_name,
- p_style->psz_fontname );
-
- if( p_face->style_flags & FT_STYLE_FLAG_BOLD )
- match = match && p_style->b_bold;
- else
- match = match && !p_style->b_bold;
-
- if( p_face->style_flags & FT_STYLE_FLAG_ITALIC )
- match = match && p_style->b_italic;
- else
- match = match && !p_style->b_italic;
-
- if( match )
+ int i_style_received = ((p_face->style_flags & FT_STYLE_FLAG_BOLD) ? STYLE_BOLD : 0) |
+ ((p_face->style_flags & FT_STYLE_FLAG_ITALIC ) ? STYLE_ITALIC : 0);
+ if( !strcasecmp( p_face->family_name, p_style->psz_fontname ) &&
+ (p_style->i_style_flags & (STYLE_BOLD | STYLE_BOLD)) == i_style_received )
{
*pp_face = p_face;
return VLC_SUCCESS;
}
-
FT_Done_Face( p_face );
}
i_font_idx++;
return VLC_EGENERIC;
}
+static int ProcessNodes( filter_t *p_filter,
+ xml_reader_t *p_xml_reader,
+ text_style_t *p_font_style,
+ uint32_t *psz_text,
+ int *pi_len,
+
+ uint32_t *pi_runs,
+ uint32_t **ppi_run_lengths,
+ text_style_t * **ppp_styles,
+
+ bool b_karaoke,
+ uint32_t *pi_k_runs,
+ uint32_t **ppi_k_run_lengths,
+ uint32_t **ppi_k_durations )
+{
+ int rv = VLC_SUCCESS;
+ filter_sys_t *p_sys = p_filter->p_sys;
+ int i_text_length = 0;
+ font_stack_t *p_fonts = NULL;
+
+ int i_style_flags = 0;
+
+ if( p_font_style )
+ {
+ rv = PushFont( &p_fonts,
+ p_font_style->psz_fontname,
+ p_font_style->i_font_size,
+ (p_font_style->i_font_color & 0xffffff) |
+ ((p_font_style->i_font_alpha & 0xff) << 24),
+ (p_font_style->i_karaoke_background_color & 0xffffff) |
+ ((p_font_style->i_karaoke_background_alpha & 0xff) << 24));
+
+ i_style_flags = p_font_style->i_style_flags & (STYLE_BOLD |
+ STYLE_ITALIC |
+ STYLE_UNDERLINE |
+ STYLE_STRIKEOUT);
+ }
+#ifdef HAVE_STYLES
+ else
+ {
+ rv = PushFont( &p_fonts,
+ p_sys->psz_fontfamily,
+ p_sys->i_font_size,
+ (p_sys->i_font_color & 0xffffff) |
+ (((255-p_sys->i_font_opacity) & 0xff) << 24),
+ 0x00ffffff );
+ }
+#endif
+
+ if( rv != VLC_SUCCESS )
+ return rv;
+
+ const char *node;
+ int type;
+
+ while ( (type = xml_ReaderNextNode( p_xml_reader, &node )) > 0 )
+ {
+ switch ( type )
+ {
+ case XML_READER_ENDELEM:
+ if( !strcasecmp( "font", node ) )
+ PopFont( &p_fonts );
+ else if( !strcasecmp( "b", node ) )
+ i_style_flags &= ~STYLE_BOLD;
+ else if( !strcasecmp( "i", node ) )
+ i_style_flags &= ~STYLE_ITALIC;
+ else if( !strcasecmp( "u", node ) )
+ i_style_flags &= ~STYLE_UNDERLINE;
+ else if( !strcasecmp( "s", node ) )
+ i_style_flags &= ~STYLE_STRIKEOUT;
+ break;
+
+ case XML_READER_STARTELEM:
+ if( !strcasecmp( "font", node ) )
+ rv = HandleFontAttributes( p_xml_reader, &p_fonts );
+ else if( !strcasecmp( "b", node ) )
+ i_style_flags |= STYLE_BOLD;
+ else if( !strcasecmp( "i", node ) )
+ i_style_flags |= STYLE_ITALIC;
+ else if( !strcasecmp( "u", node ) )
+ i_style_flags |= STYLE_UNDERLINE;
+ else if( !strcasecmp( "s", node ) )
+ i_style_flags |= STYLE_STRIKEOUT;
+ else if( !strcasecmp( "br", node ) )
+ {
+ i_text_length += SetupText( p_filter,
+ &psz_text[i_text_length],
+ pi_runs, ppi_run_lengths, ppp_styles,
+ "\n",
+ GetStyleFromFontStack( p_sys,
+ &p_fonts,
+ i_style_flags ) );
+ }
+ else if( !strcasecmp( "k", node ) )
+ {
+ /* Only valid in karaoke */
+ if( b_karaoke )
+ {
+ if( *pi_k_runs > 0 )
+ SetKaraokeLen( *pi_runs, *ppi_run_lengths,
+ *pi_k_runs, *ppi_k_run_lengths );
+ SetupKaraoke( p_xml_reader, pi_k_runs,
+ ppi_k_run_lengths, ppi_k_durations );
+ }
+ }
+ break;
+
+ case XML_READER_TEXT:
+ {
+ char *psz_node = strdup( node );
+ if( unlikely(!psz_node) )
+ break;
+
+ HandleWhiteSpace( psz_node );
+ resolve_xml_special_chars( psz_node );
+
+ i_text_length += SetupText( p_filter,
+ &psz_text[i_text_length],
+ pi_runs, ppi_run_lengths, ppp_styles,
+ psz_node,
+ GetStyleFromFontStack( p_sys,
+ &p_fonts,
+ i_style_flags ) );
+ free( psz_node );
+ break;
+ }
+ }
+ if( rv != VLC_SUCCESS )
+ {
+ i_text_length = 0;
+ break;
+ }
+ }
+ if( b_karaoke )
+ {
+ SetKaraokeLen( *pi_runs, *ppi_run_lengths,
+ *pi_k_runs, *ppi_k_run_lengths );
+ }
+
+ *pi_len = i_text_length;
+
+ while( VLC_SUCCESS == PopFont( &p_fonts ) );
+
+ return rv;
+}
+
+static void FreeLine( line_desc_t *p_line )
+{
+ for( int i = 0; p_line->pp_glyphs && p_line->pp_glyphs[i] != NULL; i++ )
+ FT_Done_Glyph( (FT_Glyph)p_line->pp_glyphs[i] );
+
+ free( p_line->pp_glyphs );
+ free( p_line->p_glyph_pos );
+ free( p_line->p_fg_rgb );
+ free( p_line->p_bg_rgb );
+ free( p_line->p_fg_bg_ratio );
+ free( p_line->pi_underline_offset );
+ free( p_line->pi_underline_thickness );
+ free( p_line );
+}
+
+static void FreeLines( line_desc_t *p_lines )
+{
+ for( line_desc_t *p_line = p_lines; p_line != NULL; )
+ {
+ line_desc_t *p_next = p_line->p_next;
+ FreeLine( p_line );
+ p_line = p_next;
+ }
+}
+
+static line_desc_t *NewLine( int i_count )
+{
+ line_desc_t *p_line = malloc( sizeof(*p_line) );
+
+ if( !p_line )
+ return NULL;
+
+ p_line->i_width = 0;
+ p_line->i_height = 0;
+ p_line->i_alpha = 0xff;
+
+ p_line->p_next = NULL;
+
+ p_line->pp_glyphs = calloc( i_count + 1, sizeof(*p_line->pp_glyphs) );
+ p_line->p_glyph_pos = calloc( i_count + 1, sizeof(*p_line->p_glyph_pos) );
+ p_line->p_fg_rgb = calloc( i_count + 1, sizeof(*p_line->p_fg_rgb) );
+ p_line->p_bg_rgb = calloc( i_count + 1, sizeof(*p_line->p_bg_rgb) );
+ p_line->p_fg_bg_ratio = calloc( i_count + 1, sizeof(*p_line->p_fg_bg_ratio) );
+ p_line->pi_underline_offset = calloc( i_count + 1, sizeof(*p_line->pi_underline_offset) );
+ p_line->pi_underline_thickness = calloc( i_count + 1, sizeof(*p_line->pi_underline_thickness) );
+
+ if( !p_line->pp_glyphs || !p_line->p_glyph_pos ||
+ !p_line->p_fg_rgb || !p_line->p_bg_rgb || !p_line->p_fg_bg_ratio ||
+ !p_line->pi_underline_offset || !p_line->pi_underline_thickness )
+ {
+ FreeLine( p_line );
+ return NULL;
+ }
+ p_line->pp_glyphs[0] = NULL;
+ return p_line;
+}
+
+
static int ProcessLines( filter_t *p_filter,
uint32_t *psz_text,
int i_len,
uint32_t i_runs,
uint32_t *pi_run_lengths,
- ft_style_t **pp_styles,
+ text_style_t **pp_styles,
line_desc_t **pp_lines,
FT_Vector *p_result,
uint32_t *pi_k_durations )
{
filter_sys_t *p_sys = p_filter->p_sys;
- ft_style_t **pp_char_styles;
+ text_style_t **pp_char_styles;
int *p_new_positions = NULL;
int8_t *p_levels = NULL;
uint8_t *pi_karaoke_bar = NULL;
* after the characters have been shuffled around by Fribidi, we can re-apply
* the styles, and to simplify the calculation of runs within a line.
*/
- pp_char_styles = (ft_style_t **) malloc( i_len * sizeof( ft_style_t * ));
+ pp_char_styles = malloc( i_len * sizeof(*pp_char_styles));
if( !pp_char_styles )
return VLC_ENOMEM;
if( b_karaoke )
{
- pi_karaoke_bar = (uint8_t *) malloc( i_len * sizeof( uint8_t ));
+ pi_karaoke_bar = malloc( i_len * sizeof(*pi_karaoke_bar));
/* If we can't allocate sufficient memory for karaoke, continue anyway -
* we just won't be able to display the progress bar; at least we'll
* get the text.
#if defined(HAVE_FRIBIDI)
{
- ft_style_t **pp_char_styles_new;
+ text_style_t **pp_char_styles_new;
int *p_old_positions;
uint32_t *p_fribidi_string;
int start_pos, pos = 0;
- pp_char_styles_new = (ft_style_t **)
- malloc( i_len * sizeof( ft_style_t * ));
+ pp_char_styles_new = malloc( i_len * sizeof(*pp_char_styles_new));
- p_fribidi_string = (uint32_t *)
- malloc( (i_len + 1) * sizeof(uint32_t) );
- p_old_positions = (int *)
- malloc( (i_len + 1) * sizeof( int ) );
- p_new_positions = (int *)
- malloc( (i_len + 1) * sizeof( int ) );
- p_levels = (int8_t *)
- malloc( (i_len + 1) * sizeof( int8_t ) );
+ p_fribidi_string = malloc( (i_len + 1) * sizeof(*p_fribidi_string) );
+ p_old_positions = malloc( (i_len + 1) * sizeof(*p_old_positions) );
+ p_new_positions = malloc( (i_len + 1) * sizeof(*p_new_positions) );
+ p_levels = malloc( (i_len + 1) * sizeof(*p_levels) );
if( ! pp_char_styles_new ||
! p_fribidi_string ||
( ( k > 0 ) &&
!StyleEquals( pp_char_styles[ k ], pp_char_styles[ k - 1] ) ) )
{
- ft_style_t *p_style = pp_char_styles[ k - 1 ];
+ text_style_t *p_style = pp_char_styles[ k - 1 ];
/* End of the current style run */
FT_Face p_face = NULL;
#ifdef HAVE_FONTCONFIG
psz_fontfile = FontConfig_Select( NULL,
p_style->psz_fontname,
- p_style->b_bold,
- p_style->b_italic,
+ (p_style->i_style_flags & STYLE_BOLD) != 0,
+ (p_style->i_style_flags & STYLE_ITALIC) != 0,
-1,
&i_idx );
#elif defined( WIN32 )
psz_fontfile = Win32_Select( p_filter,
p_style->psz_fontname,
- p_style->b_bold,
- p_style->b_italic,
+ (p_style->i_style_flags & STYLE_BOLD) != 0,
+ (p_style->i_style_flags & STYLE_ITALIC) != 0,
-1,
&i_idx );
#else
#endif
if( psz_fontfile && ! *psz_fontfile )
{
- msg_Warn( p_filter, "We were not able to find a matching 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)" : ""))) );
+ msg_Warn( p_filter,
+ "We were not able to find a matching font: \"%s\" (%s %s),"
+ " so using default font",
+ p_style->psz_fontname,
+ (p_style->i_style_flags & STYLE_BOLD) ? "Bold" : "",
+ (p_style->i_style_flags & STYLE_ITALIC) ? "Italic" : "" );
free( psz_fontfile );
psz_fontfile = NULL;
}
FT_HAS_KERNING( ( p_face ? p_face : p_sys->p_face ) );
- uint32_t *psz_unicode = (uint32_t *)
- malloc( (k - i_prev + 1) * sizeof( uint32_t ));
+ uint32_t *psz_unicode = malloc( (k - i_prev + 1) * sizeof(*psz_unicode) );
if( !psz_unicode )
{
if( p_face ) FT_Done_Face( p_face );
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 = 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;
- p_line->i_blue = ( p_style->i_font_color & 0x000000ff );
- p_line->p_next = NULL;
+ p_line->i_alpha = p_style->i_font_alpha & 0xff;
i_pen_x = 0;
i_pen_y += tmp_result.y;
tmp_result.x = 0;
}
if( RenderTag( p_filter, p_face ? p_face : p_sys->p_face,
- p_style->i_font_color, p_style->b_underline,
- p_style->b_through,
- p_style->b_bold,
- p_style->b_italic,
- p_style->i_karaoke_bg_color,
+ p_style,
p_line, psz_unicode, &i_pen_x, i_pen_y, &i_posn,
&tmp_result ) != VLC_SUCCESS )
{
FT_Vector result = {0, 0};
line_desc_t *p_lines = NULL;
+ uint32_t i_runs = 0;
+ uint32_t i_k_runs = 0;
+ uint32_t *pi_run_lengths = NULL;
+ uint32_t *pi_k_run_lengths = NULL;
+ uint32_t *pi_k_durations = NULL;
+ text_style_t **pp_styles = NULL;
+ bool b_karaoke = false;
+
#ifdef HAVE_STYLES
if( b_html )
{
if( !p_xml_reader )
rv = VLC_EGENERIC;
- bool b_karaoke = false;
if( !rv )
{
/* Look for Root Node */
{
if( !strcasecmp( "karaoke", node ) )
{
- /* 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", true );
b_karaoke = true;
}
else if( !strcasecmp( "text", node ) )
}
if( !rv )
{
- uint32_t i_runs = 0;
- uint32_t i_k_runs = 0;
- uint32_t *pi_run_lengths = NULL;
- uint32_t *pi_k_run_lengths = NULL;
- uint32_t *pi_k_durations = NULL;
- ft_style_t **pp_styles = NULL;
-
rv = ProcessNodes( p_filter, p_xml_reader,
p_region_in->p_style, psz_text, &i_text_length,
&i_runs, &pi_run_lengths, &pp_styles,
b_karaoke, &i_k_runs, &pi_k_run_lengths,
&pi_k_durations );
-
- if( !rv && i_text_length > 0 )
- {
- rv = ProcessLines( p_filter, psz_text, i_text_length, i_runs,
- pi_run_lengths, pp_styles, &p_lines,
- &result, b_karaoke, i_k_runs,
- pi_k_run_lengths, pi_k_durations );
- }
-
- for( uint32_t k = 0; k < i_runs; k++ )
- DeleteStyle( pp_styles[k] );
- free( pp_styles );
- free( pi_run_lengths );
-
}
if( p_xml_reader )
else
#endif
{
-
- size_t i_iconv_length;
- IconvText( p_filter, p_region_in->psz_text, &i_iconv_length, psz_text );
- i_text_length = i_iconv_length;
-
- int i_scale = 1000;
- vlc_value_t val;
- if( VLC_SUCCESS == var_Get( p_filter, "scale", &val ) )
- i_scale = val.i_int;
-
- ft_style_t *p_style;
+ text_style_t *p_style;
if( p_region_in->p_style )
p_style = CreateStyle( p_region_in->p_style->psz_fontname,
- p_region_in->p_style->i_font_size * i_scale / 1000,
+ p_region_in->p_style->i_font_size,
(p_region_in->p_style->i_font_color & 0xffffff) |
((p_region_in->p_style->i_font_alpha & 0xff) << 24),
0x00ffffff,
- p_region_in->p_style->i_style_flags & STYLE_BOLD,
- p_region_in->p_style->i_style_flags & STYLE_ITALIC,
- p_region_in->p_style->i_style_flags & STYLE_UNDERLINE,
- p_region_in->p_style->i_style_flags & STYLE_STRIKEOUT);
+ p_region_in->p_style->i_style_flags & (STYLE_BOLD |
+ STYLE_ITALIC |
+ STYLE_UNDERLINE |
+ STYLE_STRIKEOUT) );
else
p_style = CreateStyle( p_sys->psz_fontfamily,
- p_sys->i_font_size * i_scale / 1000,
+ p_sys->i_font_size,
(p_sys->i_font_color & 0xffffff) |
(((255-p_sys->i_font_opacity) & 0xff) << 24),
- 0x00ffffff,
- false, false, false, false );
- uint32_t i_run_length = i_text_length;
-
- rv = ProcessLines( p_filter, psz_text, i_text_length,
- 1, &i_run_length, &p_style,
- &p_lines, &result,
- false, 0, NULL, NULL );
- DeleteStyle( p_style );
+ 0x00ffffff, 0);
+
+ i_text_length = SetupText( p_filter,
+ psz_text,
+ &i_runs, &pi_run_lengths, &pp_styles,
+ p_region_in->psz_text, p_style );
+ }
+
+ if( !rv && i_text_length > 0 )
+ {
+ rv = ProcessLines( p_filter, psz_text, i_text_length, i_runs,
+ pi_run_lengths, pp_styles, &p_lines,
+ &result, b_karaoke, i_k_runs,
+ pi_k_run_lengths, pi_k_durations );
}
+
free( psz_text );
+ for( uint32_t k = 0; k < i_runs; k++ )
+ text_style_Delete( pp_styles[k] );
+ free( pp_styles );
+ free( pi_run_lengths );
+ free( pi_k_run_lengths );
+ free( pi_k_durations );
+
+
p_region_out->i_x = p_region_in->i_x;
p_region_out->i_y = p_region_in->i_y;
else
RenderYUVA( p_filter, p_region_out, p_lines,
result.x, result.y );
+
+
+ /* With karaoke, we're going to have to render the text a number
+ * of times to show the progress marker on the text.
+ */
+ if( b_karaoke )
+ var_SetBool( p_filter, "text-rerender", true );
}
FreeLines( p_lines );
return RenderCommon( p_filter, p_region_out, p_region_in, true );
}
-#ifdef WIN32
-#define UNICODE
-#define FONT_DIR_NT "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"
-
-static int GetFileFontByName( const char *font_name, char **psz_filename )
-{
- HKEY hKey;
- wchar_t vbuffer[MAX_PATH];
- wchar_t dbuffer[256];
-
- if( RegOpenKeyEx(HKEY_LOCAL_MACHINE, FONT_DIR_NT, 0, KEY_READ, &hKey) != ERROR_SUCCESS )
- return 1;
-
- for( int index = 0;; index++ )
- {
- DWORD vbuflen = MAX_PATH - 1;
- DWORD dbuflen = 255;
-
- if( RegEnumValueW( hKey, index, vbuffer, &vbuflen,
- NULL, NULL, (LPBYTE)dbuffer, &dbuflen) != ERROR_SUCCESS )
- return 2;
-
- char *psz_value = FromWide( vbuffer );
-
- char *s = strchr( psz_value,'(' );
- if( s != NULL && s != psz_value ) s[-1] = '\0';
-
- /* Manage concatenated font names */
- if( strchr( psz_value, '&') ) {
- if( strcasestr( psz_value, font_name ) != NULL )
- break;
- }
- else {
- if( strcasecmp( psz_value, font_name ) == 0 )
- break;
- }
- }
-
- *psz_filename = FromWide( dbuffer );
- return 0;
-}
-
-
-static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *lpelfe, const NEWTEXTMETRICEX *metric,
- DWORD type, LPARAM lParam)
-{
- VLC_UNUSED( metric );
- if( (type & RASTER_FONTTYPE) ) return 1;
- // if( lpelfe->elfScript ) FIXME
-
- return GetFileFontByName( (const char *)lpelfe->elfFullName, (char **)lParam );
-}
+#endif
-static char* Win32_Select( filter_t *p_filter, const char* family,
- bool b_bold, bool b_italic, int i_size, int *i_idx )
+/*****************************************************************************
+ * Create: allocates osd-text video thread output method
+ *****************************************************************************
+ * This function allocates and initializes a Clone vout method.
+ *****************************************************************************/
+static int Create( vlc_object_t *p_this )
{
- VLC_UNUSED( i_size );
- // msg_Dbg( p_filter, "Here in Win32_Select, asking for %s", family );
-
- /* */
- LOGFONT lf;
- lf.lfCharSet = DEFAULT_CHARSET;
- if( b_italic )
- lf.lfItalic = true;
- if( b_bold )
- lf.lfWeight = FW_BOLD;
- strncpy( (LPSTR)&lf.lfFaceName, family, 32);
-
- /* */
- char *psz_filename = NULL;
- HDC hDC = GetDC( NULL );
- EnumFontFamiliesEx(hDC, &lf, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&psz_filename, 0);
- ReleaseDC(NULL, hDC);
-
- if( psz_filename == NULL )
- return NULL;
+ filter_t *p_filter = (filter_t *)p_this;
+ filter_sys_t *p_sys;
+ char *psz_fontfile = NULL;
+ char *psz_fontfamily = NULL;
+ int i_error = 0, fontindex = 0;
- /* FIXME: increase i_idx, when concatenated strings */
- i_idx = 0;
+ /* Allocate structure */
+ p_filter->p_sys = p_sys = malloc( sizeof(*p_sys) );
+ if( !p_sys )
+ return VLC_ENOMEM;
- /* */
- char *psz_tmp;
- if( asprintf( &psz_tmp, "%s\\%s", p_filter->p_sys->psz_win_fonts_path, psz_filename ) == -1 )
- return NULL;
- return psz_tmp;
-}
+ p_sys->psz_fontfamily = NULL;
+#ifdef HAVE_STYLES
+ p_sys->p_xml = NULL;
#endif
+ p_sys->p_face = 0;
+ p_sys->p_library = 0;
+ p_sys->i_font_size = 0;
+ p_sys->i_display_height = 0;
-#ifdef HAVE_FONTCONFIG
-static void FontConfig_BuildCache( filter_t *p_filter )
-{
- /* */
- msg_Dbg( p_filter, "Building font databases.");
- mtime_t t1, t2;
- t1 = mdate();
-
-#ifdef WIN32
- dialog_progress_bar_t *p_dialog = NULL;
- FcConfig *fcConfig = FcInitLoadConfig();
-
- p_dialog = dialog_ProgressCreate( p_filter,
- _("Building font cache"),
- _("Please wait while your font cache is rebuilt.\n"
- "This should take less than a few minutes."), NULL );
+ var_Create( p_filter, "freetype-rel-fontsize",
+ VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
-/* if( p_dialog )
- dialog_ProgressSet( p_dialog, NULL, 0.5 ); */
+ psz_fontfamily = var_InheritString( p_filter, "freetype-font" );
+ p_sys->i_default_font_size = var_InheritInteger( p_filter, "freetype-fontsize" );
+ p_sys->i_effect = var_InheritInteger( p_filter, "freetype-effect" );
+ p_sys->i_font_opacity = var_InheritInteger( p_filter,"freetype-opacity" );
+ p_sys->i_font_opacity = __MAX( __MIN( p_sys->i_font_opacity, 255 ), 0 );
+ p_sys->i_font_color = var_InheritInteger( p_filter, "freetype-color" );
+ p_sys->i_font_color = __MAX( __MIN( p_sys->i_font_color , 0xFFFFFF ), 0 );
- FcConfigBuildFonts( fcConfig );
- if( p_dialog )
+#ifdef WIN32
+ /* Get Windows Font folder */
+ wchar_t wdir[MAX_PATH];
+ if( S_OK != SHGetFolderPathW( NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, wdir ) )
{
-// dialog_ProgressSet( p_dialog, NULL, 1.0 );
- dialog_ProgressDestroy( p_dialog );
- p_dialog = NULL;
+ GetWindowsDirectoryW( wdir, MAX_PATH );
+ wcscat( wdir, L"\\fonts" );
}
+ p_sys->psz_win_fonts_path = FromWide( wdir );
#endif
- t2 = mdate();
- msg_Dbg( p_filter, "Took %ld microseconds", (long)((t2 - t1)) );
-}
-
-/***
- * \brief Selects a font matching family, bold, italic provided
- ***/
-static char* FontConfig_Select( FcConfig* config, const char* family,
- bool b_bold, bool b_italic, int i_size, int *i_idx )
-{
- FcResult result = FcResultMatch;
- FcPattern *pat, *p_pat;
- FcChar8* val_s;
- FcBool val_b;
- /* Create a pattern and fills it */
- pat = FcPatternCreate();
- if (!pat) return NULL;
-
- /* */
- FcPatternAddString( pat, FC_FAMILY, (const FcChar8*)family );
- FcPatternAddBool( pat, FC_OUTLINE, FcTrue );
- FcPatternAddInteger( pat, FC_SLANT, b_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN );
- FcPatternAddInteger( pat, FC_WEIGHT, b_bold ? FC_WEIGHT_EXTRABOLD : FC_WEIGHT_NORMAL );
- if( i_size != -1 )
+ /* Set default psz_fontfamily */
+ if( !psz_fontfamily || !*psz_fontfamily )
{
- char *psz_fontsize;
- if( asprintf( &psz_fontsize, "%d", i_size ) != -1 )
- {
- FcPatternAddString( pat, FC_SIZE, (const FcChar8 *)psz_fontsize );
- free( psz_fontsize );
- }
+ free( psz_fontfamily );
+#ifdef HAVE_STYLES
+ psz_fontfamily = strdup( DEFAULT_FAMILY );
+#else
+# ifdef WIN32
+ if( asprintf( &psz_fontfamily, "%s"DEFAULT_FONT_FILE, p_sys->psz_win_fonts_path ) == -1 )
+ goto error;
+# else
+ psz_fontfamily = strdup( DEFAULT_FONT_FILE );
+# endif
+ msg_Err( p_filter,"User specified an empty fontfile, using %s", psz_fontfamily );
+#endif
}
+ /* Set the current font file */
+ p_sys->psz_fontfamily = psz_fontfamily;
+#ifdef HAVE_STYLES
+#ifdef HAVE_FONTCONFIG
+ FontConfig_BuildCache( p_filter );
+
/* */
- FcDefaultSubstitute( pat );
- if( !FcConfigSubstitute( config, pat, FcMatchPattern ) )
- {
- FcPatternDestroy( pat );
- return NULL;
- }
+ psz_fontfile = FontConfig_Select( NULL, psz_fontfamily, false, false,
+ p_sys->i_default_font_size, &fontindex );
+#elif defined(WIN32)
+ psz_fontfile = Win32_Select( p_filter, psz_fontfamily, false, false,
+ p_sys->i_default_font_size, &fontindex );
- /* Find the best font for the pattern, destroy the pattern */
- p_pat = FcFontMatch( config, pat, &result );
- FcPatternDestroy( pat );
- if( !p_pat || result == FcResultNoMatch ) return NULL;
+#endif
+ msg_Dbg( p_filter, "Using %s as font from file %s", psz_fontfamily, psz_fontfile );
- /* Check the new pattern */
- if( ( FcResultMatch != FcPatternGetBool( p_pat, FC_OUTLINE, 0, &val_b ) )
- || ( val_b != FcTrue ) )
- {
- FcPatternDestroy( p_pat );
- return NULL;
- }
- if( FcResultMatch != FcPatternGetInteger( p_pat, FC_INDEX, 0, i_idx ) )
- {
- *i_idx = 0;
- }
+ /* If nothing is found, use the default family */
+ if( !psz_fontfile )
+ psz_fontfile = strdup( psz_fontfamily );
- if( FcResultMatch != FcPatternGetString( p_pat, FC_FAMILY, 0, &val_s ) )
+#else /* !HAVE_STYLES */
+ /* Use the default file */
+ psz_fontfile = psz_fontfamily;
+#endif
+
+ /* */
+ i_error = FT_Init_FreeType( &p_sys->p_library );
+ if( i_error )
{
- FcPatternDestroy( p_pat );
- return NULL;
+ msg_Err( p_filter, "couldn't initialize freetype" );
+ goto error;
}
- /* if( strcasecmp((const char*)val_s, family ) != 0 )
- msg_Warn( p_filter, "fontconfig: selected font family is not"
- "the requested one: '%s' != '%s'\n",
- (const char*)val_s, family ); */
+ i_error = FT_New_Face( p_sys->p_library, psz_fontfile ? psz_fontfile : "",
+ fontindex, &p_sys->p_face );
- if( FcResultMatch != FcPatternGetString( p_pat, FC_FILE, 0, &val_s ) )
+ if( i_error == FT_Err_Unknown_File_Format )
{
- FcPatternDestroy( p_pat );
- return NULL;
+ msg_Err( p_filter, "file %s have unknown format",
+ psz_fontfile ? psz_fontfile : "(null)" );
+ goto error;
}
-
- FcPatternDestroy( p_pat );
- return strdup( (const char*)val_s );
-}
-#endif
+ else if( i_error )
+ {
+ msg_Err( p_filter, "failed to load font file %s",
+ psz_fontfile ? psz_fontfile : "(null)" );
+ goto error;
+ }
+#ifdef HAVE_STYLES
+ free( psz_fontfile );
#endif
-static void FreeLine( line_desc_t *p_line )
-{
- unsigned int i;
- for( i = 0; p_line->pp_glyphs[ i ] != NULL; i++ )
+ i_error = FT_Select_Charmap( p_sys->p_face, ft_encoding_unicode );
+ if( i_error )
{
- FT_Done_Glyph( (FT_Glyph)p_line->pp_glyphs[ i ] );
+ msg_Err( p_filter, "font has no unicode translation table" );
+ goto error;
}
- free( p_line->pp_glyphs );
- free( p_line->p_glyph_pos );
- free( p_line->p_fg_rgb );
- free( p_line->p_bg_rgb );
- free( p_line->p_fg_bg_ratio );
- free( p_line->pi_underline_offset );
- free( p_line->pi_underline_thickness );
- free( p_line );
-}
-
-static void FreeLines( line_desc_t *p_lines )
-{
- line_desc_t *p_line, *p_next;
- if( !p_lines ) return;
+ p_sys->i_use_kerning = FT_HAS_KERNING( p_sys->p_face );
- for( p_line = p_lines; p_line != NULL; p_line = p_next )
- {
- p_next = p_line->p_next;
- FreeLine( p_line );
- }
-}
+ if( SetFontSize( p_filter, 0 ) != VLC_SUCCESS ) goto error;
-static line_desc_t *NewLine( int i_count )
-{
- line_desc_t *p_line = malloc( sizeof(line_desc_t) );
- if( !p_line ) return NULL;
- p_line->i_height = 0;
- p_line->i_width = 0;
- p_line->p_next = NULL;
+ p_sys->pp_font_attachments = NULL;
+ p_sys->i_font_attachments = 0;
- p_line->pp_glyphs = malloc( sizeof(FT_BitmapGlyph) * ( i_count + 1 ) );
- p_line->p_glyph_pos = malloc( sizeof( FT_Vector ) * ( i_count + 1 ) );
- p_line->p_fg_rgb = malloc( sizeof( uint32_t ) * ( i_count + 1 ) );
- p_line->p_bg_rgb = malloc( sizeof( uint32_t ) * ( i_count + 1 ) );
- p_line->p_fg_bg_ratio = calloc( i_count + 1, sizeof( uint8_t ) );
- p_line->pi_underline_offset = calloc( i_count + 1, sizeof( int ) );
- p_line->pi_underline_thickness = calloc( i_count + 1, sizeof( uint16_t ) );
- if( ( p_line->pp_glyphs == NULL ) ||
- ( p_line->p_glyph_pos == NULL ) ||
- ( p_line->p_fg_rgb == NULL ) ||
- ( p_line->p_bg_rgb == NULL ) ||
- ( p_line->p_fg_bg_ratio == NULL ) ||
- ( p_line->pi_underline_offset == NULL ) ||
- ( p_line->pi_underline_thickness == NULL ) )
- {
- 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 = false;
+ p_filter->pf_render_text = RenderText;
+#ifdef HAVE_STYLES
+ p_filter->pf_render_html = RenderHtml;
+#else
+ p_filter->pf_render_html = NULL;
+#endif
- return p_line;
-}
+ LoadFontsFromAttachments( p_filter );
-static int GetFontSize( filter_t *p_filter )
-{
- filter_sys_t *p_sys = p_filter->p_sys;
- vlc_value_t val;
- int i_size = 0;
+ return VLC_SUCCESS;
- if( p_sys->i_default_font_size )
- {
- if( VLC_SUCCESS == var_Get( p_filter, "scale", &val ))
- i_size = p_sys->i_default_font_size * val.i_int / 1000;
- else
- i_size = p_sys->i_default_font_size;
- }
- else
- {
- var_Get( p_filter, "freetype-rel-fontsize", &val );
- if( val.i_int > 0 )
- {
- i_size = (int)p_filter->fmt_out.video.i_height / val.i_int;
- p_filter->p_sys->i_display_height =
- p_filter->fmt_out.video.i_height;
- }
- }
- if( i_size <= 0 )
- {
- msg_Warn( p_filter, "invalid fontsize, using 12" );
- if( VLC_SUCCESS == var_Get( p_filter, "scale", &val ))
- i_size = 12 * val.i_int / 1000;
- else
- i_size = 12;
- }
- return i_size;
+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 );
+#ifdef HAVE_STYLES
+ free( psz_fontfile );
+#endif
+ free( psz_fontfamily );
+ free( p_sys );
+ return VLC_EGENERIC;
}
-static int SetFontSize( filter_t *p_filter, int i_size )
+/*****************************************************************************
+ * Destroy: destroy Clone video thread output method
+ *****************************************************************************
+ * Clean up all data and library connections
+ *****************************************************************************/
+static void Destroy( vlc_object_t *p_this )
{
+ filter_t *p_filter = (filter_t *)p_this;
filter_sys_t *p_sys = p_filter->p_sys;
- if( !i_size )
+ if( p_sys->pp_font_attachments )
{
- i_size = GetFontSize( p_filter );
+ for( int k = 0; k < p_sys->i_font_attachments; k++ )
+ vlc_input_attachment_Delete( p_sys->pp_font_attachments[k] );
- msg_Dbg( p_filter, "using fontsize: %i", i_size );
+ free( p_sys->pp_font_attachments );
}
- p_sys->i_font_size = i_size;
+#ifdef HAVE_STYLES
+ if( p_sys->p_xml ) xml_ReaderDelete( p_sys->p_xml );
+#endif
+ free( p_sys->psz_fontfamily );
- if( FT_Set_Pixel_Sizes( p_sys->p_face, 0, i_size ) )
- {
- msg_Err( p_filter, "couldn't set font size to %d", i_size );
- return VLC_EGENERIC;
- }
+ /* FcFini asserts calling the subfunction FcCacheFini()
+ * even if no other library functions have been made since FcInit(),
+ * so don't call it. */
- return VLC_SUCCESS;
+ FT_Done_Face( p_sys->p_face );
+ FT_Done_FreeType( p_sys->p_library );
+ free( p_sys );
}
-static void YUVFromRGB( uint32_t i_argb,
- uint8_t *pi_y, uint8_t *pi_u, uint8_t *pi_v )
-{
- int i_red = ( i_argb & 0x00ff0000 ) >> 16;
- int i_green = ( i_argb & 0x0000ff00 ) >> 8;
- int i_blue = ( i_argb & 0x000000ff );
- *pi_y = (uint8_t)__MIN(abs( 2104 * i_red + 4130 * i_green +
- 802 * i_blue + 4096 + 131072 ) >> 13, 235);
- *pi_u = (uint8_t)__MIN(abs( -1214 * i_red + -2384 * i_green +
- 3598 * i_blue + 4096 + 1048576) >> 13, 240);
- *pi_v = (uint8_t)__MIN(abs( 3598 * i_red + -3013 * i_green +
- -585 * i_blue + 4096 + 1048576) >> 13, 240);
-}