X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=modules%2Ftext_renderer%2Ffreetype.c;h=a2f292e4374b62c135ce9dc08c66c5cb2f139e6a;hb=ef8b3a7b0d07fd154fe68fecc22449bdb6781278;hp=b60b186ed9398c1143232841472dac18d3b04460;hpb=b009862bea66be3bf9d4dcdb0c4a160e514dbca4;p=vlc diff --git a/modules/text_renderer/freetype.c b/modules/text_renderer/freetype.c index b60b186ed9..a2f292e437 100644 --- a/modules/text_renderer/freetype.c +++ b/modules/text_renderer/freetype.c @@ -1,27 +1,28 @@ /***************************************************************************** * freetype.c : Put text on the video, using freetype2 ***************************************************************************** - * Copyright (C) 2002 - 2011 the VideoLAN team + * Copyright (C) 2002 - 2012 VLC authors and VideoLAN * $Id$ * * Authors: Sigmund Augdal Helberg * Gildas Bazin * Bernie Purcell * Jean-Baptiste Kempf + * Felix Paul Kühne * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** @@ -38,25 +39,52 @@ #include /* stream_MemoryNew */ #include /* vlc_input_attachment_* */ #include /* xml_reader */ -#include /* resolve_xml_special_chars */ -#include /* ToCharset */ #include /* FcCache dialog */ #include /* filter_sys_t */ #include /* text_style_t*/ /* Default fonts */ #ifdef __APPLE__ -# define DEFAULT_FONT_FILE "/Library/Fonts/Arial Black.ttf" -# define DEFAULT_FAMILY "Arial Black" -#elif defined( WIN32 ) -# define DEFAULT_FONT_FILE "arial.ttf" /* Default path font found at run-time */ -# define DEFAULT_FAMILY "Arial" -#elif defined( HAVE_MAEMO ) -# define DEFAULT_FONT_FILE "/usr/share/fonts/nokia/nosnb.ttf" -# define DEFAULT_FAMILY "Nokia Sans Bold" +# define SYSTEM_DEFAULT_FONT_FILE "/Library/Fonts/Arial Unicode.ttf" +# define SYSTEM_DEFAULT_FAMILY "Arial Unicode MS" +# define SYSTEM_DEFAULT_MONOSPACE_FONT_FILE "/System/Library/Fonts/Monaco.dfont" +# define SYSTEM_DEFAULT_MONOSPACE_FAMILY "Monaco" +#elif defined( _WIN32 ) +# define SYSTEM_DEFAULT_FONT_FILE "arial.ttf" /* Default path font found at run-time */ +# define SYSTEM_DEFAULT_FAMILY "Arial" +# define SYSTEM_DEFAULT_MONOSPACE_FONT_FILE "cour.ttf" +# define SYSTEM_DEFAULT_MONOSPACE_FAMILY "Courier New" +#elif defined( __OS2__ ) +# define SYSTEM_DEFAULT_FONT_FILE "/psfonts/tnrwt_k.ttf" +# define SYSTEM_DEFAULT_FAMILY "Times New Roman WT K" +# define SYSTEM_DEFAULT_MONOSPACE_FONT_FILE "/psfonts/mtsansdk.ttf" +# define SYSTEM_DEFAULT_MONOSPACE_FAMILY "Monotype Sans Duospace WT K" +#elif defined( __ANDROID__ ) +# define SYSTEM_DEFAULT_FONT_FILE "/system/fonts/DroidSans-Bold.ttf" +# define SYSTEM_DEFAULT_FAMILY "Droid Sans Bold" +# define SYSTEM_DEFAULT_MONOSPACE_FONT_FILE "/system/fonts/DroidSansMono.ttf" +# define SYSTEM_DEFAULT_MONOSPACE_FAMILY "Droid Sans Mono" #else -# define DEFAULT_FONT_FILE "/usr/share/fonts/truetype/freefont/FreeSerifBold.ttf" -# define DEFAULT_FAMILY "Serif Bold" +# define SYSTEM_DEFAULT_FONT_FILE "/usr/share/fonts/truetype/freefont/FreeSerifBold.ttf" +# define SYSTEM_DEFAULT_FAMILY "Serif Bold" +# define SYSTEM_DEFAULT_MONOSPACE_FONT_FILE "/usr/share/fonts/truetype/freefont/FreeMono.ttf" +# define SYSTEM_DEFAULT_MONOSPACE_FAMILY "Monospace" +#endif + +#ifndef DEFAULT_FONT_FILE +#define DEFAULT_FONT_FILE SYSTEM_DEFAULT_FONT_FILE +#endif + +#ifndef DEFAULT_FAMILY +#define DEFAULT_FAMILY SYSTEM_DEFAULT_FAMILY +#endif + +#ifndef DEFAULT_MONOSPACE_FONT_FILE +#define DEFAULT_MONOSPACE_FONT_FILE SYSTEM_DEFAULT_MONOSPACE_FONT_FILE +#endif + +#ifndef DEFAULT_MONOSPACE_FAMILY +#define DEFAULT_MONOSPACE_FAMILY SYSTEM_DEFAULT_MONOSPACE_FAMILY #endif /* Freetype */ @@ -71,17 +99,29 @@ #define FT_MulFix(v, s) (((v)*(s))>>16) #endif +/* apple stuff */ +#ifdef __APPLE__ +#include +#if !TARGET_OS_IPHONE +#include +#endif +#include /* for MAXPATHLEN */ +#undef HAVE_FONTCONFIG +#define HAVE_STYLES +#endif + /* RTL */ #if defined(HAVE_FRIBIDI) # include #endif /* Win32 GDI */ -#ifdef WIN32 +#ifdef _WIN32 # include # include # define HAVE_STYLES # undef HAVE_FONTCONFIG +# include /* FromT */ #endif /* FontConfig */ @@ -92,6 +132,8 @@ #include +#include "text_renderer.h" + /***************************************************************************** * Module descriptor *****************************************************************************/ @@ -99,6 +141,7 @@ static int Create ( vlc_object_t * ); static void Destroy( vlc_object_t * ); #define FONT_TEXT N_("Font") +#define MONOSPACE_FONT_TEXT N_("Monospace Font") #define FAMILY_LONGTEXT N_("Font family for the font you want to use") #define FONT_LONGTEXT N_("Font file for the font you want to use") @@ -168,12 +211,15 @@ vlc_module_begin () #ifdef HAVE_STYLES add_font( "freetype-font", DEFAULT_FAMILY, FONT_TEXT, FAMILY_LONGTEXT, false ) + add_font( "freetype-monofont", DEFAULT_MONOSPACE_FAMILY, MONOSPACE_FONT_TEXT, FAMILY_LONGTEXT, false ) #else add_loadfile( "freetype-font", DEFAULT_FONT_FILE, FONT_TEXT, FONT_LONGTEXT, false ) + add_loadfile( "freetype-monofont", DEFAULT_MONOSPACE_FONT_FILE, MONOSPACE_FONT_TEXT, FONT_LONGTEXT, false ) #endif add_integer( "freetype-fontsize", 0, FONTSIZE_TEXT, FONTSIZE_LONGTEXT, true ) + change_integer_range( 0, 4096) change_safe() add_integer( "freetype-rel-fontsize", 16, FONTSIZER_TEXT, @@ -259,22 +305,12 @@ struct line_desc_t line_desc_t *p_next; int i_width; + int i_height; int i_base_line; int i_character_count; line_character_t *p_character; }; -typedef struct font_stack_t font_stack_t; -struct font_stack_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 ***************************************************************************** @@ -285,36 +321,26 @@ struct filter_sys_t { FT_Library p_library; /* handle to library */ FT_Face p_face; /* handle to face object */ - FT_Stroker p_stroker; - uint8_t i_font_opacity; - int i_font_color; - int i_font_size; - bool b_font_bold; + FT_Stroker p_stroker; /* handle to path stroker object */ - uint8_t i_background_opacity; - int i_background_color; + xml_reader_t *p_xml; /* vlc xml parser */ - double f_outline_thickness; - uint8_t i_outline_opacity; - int i_outline_color; + text_style_t style; /* Current Style */ + /* More styles... */ float f_shadow_vector_x; float f_shadow_vector_y; - uint8_t i_shadow_opacity; - int i_shadow_color; - int i_default_font_size; - int i_display_height; - char* psz_fontfamily; -#ifdef HAVE_STYLES - xml_reader_t *p_xml; -#ifdef WIN32 - char* psz_win_fonts_path; -#endif -#endif + /* Attachments */ input_attachment_t **pp_font_attachments; int i_font_attachments; + + /* Cache the Win32 font folder */ +#ifdef _WIN32 + char* psz_win_fonts_path; +#endif + }; /* */ @@ -388,11 +414,10 @@ static int GetFontSize( filter_t *p_filter ) } else { - int i_ratio = var_GetInteger( p_filter, "freetype-rel-fontsize" ); + int i_ratio = var_InheritInteger( 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 ) @@ -414,7 +439,7 @@ static int SetFontSize( filter_t *p_filter, int i_size ) msg_Dbg( p_filter, "using fontsize: %i", i_size ); } - p_sys->i_font_size = i_size; + p_sys->style.i_font_size = i_size; if( FT_Set_Pixel_Sizes( p_sys->p_face, 0, i_size ) ) { @@ -434,7 +459,11 @@ static void FontConfig_BuildCache( filter_t *p_filter ) mtime_t t1, t2; t1 = mdate(); -#ifdef WIN32 +#ifdef __OS2__ + FcInit(); +#endif + +#if defined( _WIN32 ) || defined( __APPLE__ ) dialog_progress_bar_t *p_dialog = NULL; FcConfig *fcConfig = FcInitLoadConfig(); @@ -447,6 +476,15 @@ static void FontConfig_BuildCache( filter_t *p_filter ) dialog_ProgressSet( p_dialog, NULL, 0.5 ); */ FcConfigBuildFonts( fcConfig ); +#if defined( __APPLE__ ) + // By default, scan only the directory /System/Library/Fonts. + // So build the set of available fonts under another directories, + // and add the set to the current configuration. + FcConfigAppFontAddDir( NULL, "~/Library/Fonts" ); + FcConfigAppFontAddDir( NULL, "/Library/Fonts" ); + FcConfigAppFontAddDir( NULL, "/Network/Library/Fonts" ); + //FcConfigAppFontAddDir( NULL, "/System/Library/Fonts" ); +#endif if( p_dialog ) { // dialog_ProgressSet( p_dialog, NULL, 1.0 ); @@ -468,6 +506,7 @@ static char* FontConfig_Select( FcConfig* config, const char* family, FcPattern *pat, *p_pat; FcChar8* val_s; FcBool val_b; + char *ret = NULL; /* Create a pattern and fills it */ pat = FcPatternCreate(); @@ -524,60 +563,70 @@ static char* FontConfig_Select( FcConfig* config, const char* family, "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; - } + if( FcResultMatch == FcPatternGetString( p_pat, FC_FILE, 0, &val_s ) ) + ret = strdup( (const char*)val_s ); FcPatternDestroy( p_pat ); - return strdup( (const char*)val_s ); + return ret; } #endif -#ifdef WIN32 -#define UNICODE -#define FONT_DIR_NT "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts" +#ifdef _WIN32 +#define FONT_DIR_NT _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts") -static int GetFileFontByName( const char *font_name, char **psz_filename ) +static int GetFileFontByName( LPCTSTR font_name, char **psz_filename ) { HKEY hKey; - wchar_t vbuffer[MAX_PATH]; - wchar_t dbuffer[256]; - - size_t fontname_len = strlen( font_name ); + TCHAR vbuffer[MAX_PATH]; + TCHAR dbuffer[256]; if( RegOpenKeyEx(HKEY_LOCAL_MACHINE, FONT_DIR_NT, 0, KEY_READ, &hKey) != ERROR_SUCCESS ) return 1; + char *font_name_temp = FromT( font_name ); + size_t fontname_len = strlen( font_name_temp ); + for( int index = 0;; index++ ) { DWORD vbuflen = MAX_PATH - 1; DWORD dbuflen = 255; - LONG i_result = RegEnumValueW( hKey, index, vbuffer, &vbuflen, - NULL, NULL, (LPBYTE)dbuffer, &dbuflen); + LONG i_result = RegEnumValue( hKey, index, vbuffer, &vbuflen, + NULL, NULL, (LPBYTE)dbuffer, &dbuflen); if( i_result != ERROR_SUCCESS ) + { + RegCloseKey( hKey ); return i_result; + } - char *psz_value = FromWide( vbuffer ); + char *psz_value = FromT( 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 ) + if( strcasestr( psz_value, font_name_temp ) != NULL ) + { + free( psz_value ); break; + } } else { - if( strncasecmp( psz_value, font_name, fontname_len ) == 0 ) + if( strncasecmp( psz_value, font_name_temp, fontname_len ) == 0 ) + { + free( psz_value ); break; + } } + + free( psz_value ); } - *psz_filename = FromWide( dbuffer ); + *psz_filename = FromT( dbuffer ); + free( font_name_temp ); + RegCloseKey( hKey ); return 0; } @@ -589,7 +638,7 @@ static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *lpelfe, const NEWTEXTM if( (type & RASTER_FONTTYPE) ) return 1; // if( lpelfe->elfScript ) FIXME - return GetFileFontByName( (const char *)lpelfe->elfFullName, (char **)lParam ); + return GetFileFontByName( (LPCTSTR)lpelfe->elfFullName, (char **)lParam ); } static char* Win32_Select( filter_t *p_filter, const char* family, @@ -597,7 +646,7 @@ static char* Win32_Select( filter_t *p_filter, const char* family, { VLC_UNUSED( i_size ); - if( strlen( family ) < 1 ) + if( !family || strlen( family ) < 1 ) goto fail; /* */ @@ -607,7 +656,10 @@ static char* Win32_Select( filter_t *p_filter, const char* family, lf.lfItalic = true; if( b_bold ) lf.lfWeight = FW_BOLD; - strncpy( (LPSTR)&lf.lfFaceName, family, 32); + + LPTSTR psz_fbuffer = ToT( family ); + _tcsncpy( (LPTSTR)&lf.lfFaceName, psz_fbuffer, LF_FACESIZE ); + free( psz_fbuffer ); /* */ char *psz_filename = NULL; @@ -646,7 +698,90 @@ fail: return psz_tmp; } } -#endif /* HAVE_WIN32 */ +#endif /* _WIN32 */ + +#ifdef __APPLE__ +#if !TARGET_OS_IPHONE +static char* MacLegacy_Select( filter_t *p_filter, const char* psz_fontname, + bool b_bold, bool b_italic, int i_size, int *i_idx ) +{ + VLC_UNUSED( b_bold ); + VLC_UNUSED( b_italic ); + VLC_UNUSED( i_size ); + FSRef ref; + unsigned char path[MAXPATHLEN]; + char * psz_path; + + CFStringRef cf_fontName; + ATSFontRef ats_font_id; + + *i_idx = 0; + + if( psz_fontname == NULL ) + return NULL; + + msg_Dbg( p_filter, "looking for %s", psz_fontname ); + cf_fontName = CFStringCreateWithCString( kCFAllocatorDefault, psz_fontname, kCFStringEncodingUTF8 ); + + ats_font_id = ATSFontFindFromName( cf_fontName, kATSOptionFlagsIncludeDisabledMask ); + + if ( ats_font_id == 0 || ats_font_id == 0xFFFFFFFFUL ) + { + msg_Dbg( p_filter, "ATS couldn't find %s by name, checking family", psz_fontname ); + ats_font_id = ATSFontFamilyFindFromName( cf_fontName, kATSOptionFlagsDefault ); + + if ( ats_font_id == 0 || ats_font_id == 0xFFFFFFFFUL ) + { + msg_Dbg( p_filter, "ATS couldn't find either %s nor its family, checking PS name", psz_fontname ); + ats_font_id = ATSFontFindFromPostScriptName( cf_fontName, kATSOptionFlagsDefault ); + + if ( ats_font_id == 0 || ats_font_id == 0xFFFFFFFFUL ) + { + msg_Err( p_filter, "ATS couldn't find %s (no font name, family or PS name)", psz_fontname ); + CFRelease( cf_fontName ); + return NULL; + } + } + } + CFRelease( cf_fontName ); + + if ( noErr != ATSFontGetFileReference( ats_font_id, &ref ) ) + { + msg_Err( p_filter, "ATS couldn't get file ref for %s", psz_fontname ); + return NULL; + } + + /* i_idx calculation by searching preceding fontIDs */ + /* with same FSRef */ + { + ATSFontRef id2 = ats_font_id - 1; + FSRef ref2; + + while ( id2 > 0 ) + { + if ( noErr != ATSFontGetFileReference( id2, &ref2 ) ) + break; + if ( noErr != FSCompareFSRefs( &ref, &ref2 ) ) + break; + + id2 --; + } + *i_idx = ats_font_id - ( id2 + 1 ); + } + + if ( noErr != FSRefMakePath( &ref, path, sizeof(path) ) ) + { + msg_Err( p_filter, "failure when getting path from FSRef" ); + return NULL; + } + msg_Dbg( p_filter, "found %s", path ); + + psz_path = strdup( (char *)path ); + + return psz_path; +} +#endif +#endif #endif /* HAVE_STYLES */ @@ -907,6 +1042,93 @@ static inline void BlendAXYZLine( picture_t *p_picture, } } +static inline void RenderBackground( subpicture_region_t *p_region, + line_desc_t *p_line_head, + FT_BBox *p_bbox, + int i_margin, + picture_t *p_picture, + int i_text_width, + void (*ExtractComponents)( uint32_t, uint8_t *, uint8_t *, uint8_t * ), + void (*BlendPixel)(picture_t *, int, int, int, int, int, int, int) ) +{ + for( line_desc_t *p_line = p_line_head; p_line != NULL; p_line = p_line->p_next ) + { + int i_align_left = i_margin; + int i_align_top = i_margin; + int line_start = 0; + int line_end = 0; + unsigned line_top = 0; + int line_bottom = 0; + int max_height = 0; + + if( p_line->i_width < i_text_width ) + { + /* Left offset to take into account alignment */ + if( (p_region->i_align & 0x3) == SUBPICTURE_ALIGN_RIGHT ) + i_align_left += ( i_text_width - p_line->i_width ); + else if( (p_region->i_align & 0x10) == SUBPICTURE_ALIGN_LEAVETEXT) + i_align_left = i_margin; /* Keep it the way it is */ + else if( (p_region->i_align & 0x3) != SUBPICTURE_ALIGN_LEFT ) + i_align_left += ( i_text_width - p_line->i_width ) / 2; + } + + /* Find the tallest character in the line */ + for( int i = 0; i < p_line->i_character_count; i++ ) { + const line_character_t *ch = &p_line->p_character[i]; + FT_BitmapGlyph p_glyph = ch->p_outline ? ch->p_outline : ch->p_glyph; + if (p_glyph->top > max_height) + max_height = p_glyph->top; + } + + /* Compute the background for the line (identify leading/trailing space) */ + for( int i = 0; i < p_line->i_character_count; i++ ) { + const line_character_t *ch = &p_line->p_character[i]; + FT_BitmapGlyph p_glyph = ch->p_outline ? ch->p_outline : ch->p_glyph; + if (p_glyph && p_glyph->bitmap.rows > 0) { + // Found a non-whitespace character + line_start = i_align_left + p_glyph->left - p_bbox->xMin; + break; + } + } + + /* Fudge factor to make sure caption background edges are left aligned + despite variable font width */ + if (line_start < 12) + line_start = 0; + + /* Find right boundary for bounding box for background */ + for( int i = p_line->i_character_count; i > 0; i-- ) { + const line_character_t *ch = &p_line->p_character[i - 1]; + FT_BitmapGlyph p_glyph = ch->p_shadow ? ch->p_shadow : ch->p_glyph; + if (p_glyph && p_glyph->bitmap.rows > 0) { + // Found a non-whitespace character + line_end = i_align_left + p_glyph->left - p_bbox->xMin + p_glyph->bitmap.width; + break; + } + } + + /* Setup color for the background */ + uint8_t i_x, i_y, i_z; + ExtractComponents( 0x000000, &i_x, &i_y, &i_z ); + + /* Compute the upper boundary for the background */ + if ((i_align_top + p_line->i_base_line - max_height) < 0) + line_top = i_align_top + p_line->i_base_line; + else + line_top = i_align_top + p_line->i_base_line - max_height; + + /* Compute lower boundary for the background */ + line_bottom = __MIN(line_top + p_line->i_height, p_region->fmt.i_visible_height); + + /* Render the actual background */ + for( int dy = line_top; dy < line_bottom; dy++ ) + { + for( int dx = line_start; dx < line_end; dx++ ) + BlendPixel( p_picture, dx, dy, 0xff, i_x, i_y, i_z, 0xff ); + } + } +} + static inline int RenderAXYZ( filter_t *p_filter, subpicture_region_t *p_region, line_desc_t *p_line_head, @@ -935,11 +1157,22 @@ static inline int RenderAXYZ( filter_t *p_filter, p_region->fmt = fmt; /* Initialize the picture background */ - uint8_t i_a = p_sys->i_background_opacity; + uint8_t i_a = var_InheritInteger( p_filter, "freetype-background-opacity" ); + i_a = VLC_CLIP( i_a, 0, 255 ); uint8_t i_x, i_y, i_z; - ExtractComponents( p_sys->i_background_color, &i_x, &i_y, &i_z ); - FillPicture( p_picture, i_a, i_x, i_y, i_z ); + if (p_region->b_renderbg) { + /* Render the background just under the text */ + FillPicture( p_picture, 0x00, 0x00, 0x00, 0x00 ); + RenderBackground(p_region, p_line_head, p_bbox, i_margin, p_picture, i_text_width, + ExtractComponents, BlendPixel); + } else { + /* Render background under entire subpicture block */ + int i_background_color = var_InheritInteger( p_filter, "freetype-background-color" ); + i_background_color = VLC_CLIP( i_background_color, 0, 0xFFFFFF ); + ExtractComponents( i_background_color, &i_x, &i_y, &i_z ); + FillPicture( p_picture, i_a, i_x, i_y, i_z ); + } /* Render shadow then outline and then normal glyphs */ for( int g = 0; g < 3; g++ ) @@ -953,6 +1186,8 @@ static inline int RenderAXYZ( filter_t *p_filter, /* Left offset to take into account alignment */ if( (p_region->i_align & 0x3) == SUBPICTURE_ALIGN_RIGHT ) i_align_left += ( i_text_width - p_line->i_width ); + else if( (p_region->i_align & 0x10) == SUBPICTURE_ALIGN_LEAVETEXT) + i_align_left = i_margin; /* Keep it the way it is */ else if( (p_region->i_align & 0x3) != SUBPICTURE_ALIGN_LEFT ) i_align_left += ( i_text_width - p_line->i_width ) / 2; } @@ -970,12 +1205,12 @@ static inline int RenderAXYZ( filter_t *p_filter, uint32_t i_color; switch (g) { case 0: - i_a = i_a * p_sys->i_shadow_opacity / 255; - i_color = p_sys->i_shadow_color; + i_a = i_a * p_sys->style.i_shadow_alpha / 255; + i_color = p_sys->style.i_shadow_color; break; case 1: - i_a = i_a * p_sys->i_outline_opacity / 255; - i_color = p_sys->i_outline_color; + i_a = i_a * p_sys->style.i_outline_alpha / 255; + i_color = p_sys->style.i_outline_color; break; default: i_color = ch->i_color; @@ -1007,591 +1242,7 @@ static inline int RenderAXYZ( filter_t *p_filter, return VLC_SUCCESS; } -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 ) -{ - text_style_t *p_style = text_style_New(); - if( !p_style ) - return NULL; - - p_style->psz_fontname = psz_fontname ? strdup( psz_fontname ) : NULL; - 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 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 ) - { - *p_font = p_new; - } - 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 int PopFont( font_stack_t **p_font ) -{ - font_stack_t *p_last, *p_next_to_last; - - 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 = 255; - 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 - { - char *end; - uint32_t i_value = strtol( value, &end, 16 ); - if( *end == '\0' || *end == ' ' ) - i_font_color = i_value & 0x00ffffff; - - 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; -} - -/* Turn any multiple-whitespaces into single spaces */ -static void HandleWhiteSpace( char *psz_node ) -{ - char *s = strpbrk( psz_node, "\t\r\n " ); - while( s ) - { - int i_whitespace = strspn( s, "\t\r\n " ); - - if( i_whitespace > 1 ) - memmove( &s[1], - &s[i_whitespace], - strlen( s ) - i_whitespace + 1 ); - *s++ = ' '; - - s = strpbrk( s, "\t\r\n " ); - } -} - - -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; - uint32_t i_karaoke_bg_color = i_font_color; - int i_font_size = p_sys->i_font_size; - - if( PeekFont( p_fonts, &psz_fontname, &i_font_size, - &i_font_color, &i_karaoke_bg_color ) ) - return NULL; - - return CreateStyle( psz_fontname, i_font_size, i_font_color, - i_karaoke_bg_color, - i_style_flags ); -} - -static unsigned SetupText( filter_t *p_filter, - uint32_t *psz_text_out, - text_style_t **pp_styles, - uint32_t *pi_k_dates, - - const char *psz_text_in, - text_style_t *p_style, - uint32_t i_k_date ) -{ - size_t 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( i_string_length > 0 ) - { - for( unsigned i = 0; i < i_string_length; i++ ) - pp_styles[i] = p_style; - } - else - { - text_style_Delete( p_style ); - } - if( i_string_length > 0 && pi_k_dates ) - { - for( unsigned i = 0; i < i_string_length; i++ ) - pi_k_dates[i] = i_k_date; - } - return i_string_length; -} - -static int ProcessNodes( filter_t *p_filter, - uint32_t *psz_text, - text_style_t **pp_styles, - uint32_t *pi_k_dates, - int *pi_len, - xml_reader_t *p_xml_reader, - text_style_t *p_font_style ) -{ - int rv = VLC_SUCCESS; - filter_sys_t *p_sys = p_filter->p_sys; - int i_text_length = 0; - font_stack_t *p_fonts = NULL; - uint32_t i_k_date = 0; - - int i_style_flags = 0; - - if( p_font_style ) - { - rv = PushFont( &p_fonts, - p_font_style->psz_fontname, - p_font_style->i_font_size > 0 ? p_font_style->i_font_size - : p_sys->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) | - ((p_sys->i_font_opacity & 0xff) << 24), - 0x00ffffff ); - } -#endif - if( p_sys->b_font_bold ) - i_style_flags |= STYLE_BOLD; - - 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 ) ) - 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], - &pp_styles[i_text_length], - pi_k_dates ? &pi_k_dates[i_text_length] : NULL, - "\n", - GetStyleFromFontStack( p_sys, - &p_fonts, - i_style_flags ), - i_k_date ); - } - else if( !strcasecmp( "k", node ) ) - { - /* Karaoke tags */ - const char *name, *value; - while( (name = xml_ReaderNextAttr( p_xml_reader, &value )) != NULL ) - { - if( !strcasecmp( "t", name ) && value ) - i_k_date += atoi( value ); - } - } - 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], - &pp_styles[i_text_length], - pi_k_dates ? &pi_k_dates[i_text_length] : NULL, - psz_node, - GetStyleFromFontStack( p_sys, - &p_fonts, - i_style_flags ), - i_k_date ); - free( psz_node ); - break; - } - } - } - - *pi_len = i_text_length; - while( VLC_SUCCESS == PopFont( &p_fonts ) ); - - return VLC_SUCCESS; -} static void FreeLine( line_desc_t *p_line ) { @@ -1658,8 +1309,10 @@ static FT_Face LoadEmbeddedFace( filter_sys_t *p_sys, const text_style_t *p_styl { 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_ITALIC)) == i_style_received ) + if( p_face->family_name != NULL + && !strcasecmp( p_face->family_name, p_style->psz_fontname ) + && (p_style->i_style_flags & (STYLE_BOLD | STYLE_ITALIC)) + == i_style_received ) return p_face; FT_Done_Face( p_face ); @@ -1682,7 +1335,7 @@ static FT_Face LoadFace( filter_t *p_filter, if( !p_face ) { int i_idx = 0; - char *psz_fontfile; + char *psz_fontfile = NULL; #ifdef HAVE_FONTCONFIG psz_fontfile = FontConfig_Select( NULL, p_style->psz_fontname, @@ -1690,7 +1343,11 @@ static FT_Face LoadFace( filter_t *p_filter, (p_style->i_style_flags & STYLE_ITALIC) != 0, -1, &i_idx ); -#elif defined( WIN32 ) +#elif defined( __APPLE__ ) +#if !TARGET_OS_IPHONE + psz_fontfile = MacLegacy_Select( p_filter, p_style->psz_fontname, false, false, -1, &i_idx ); +#endif +#elif defined( _WIN32 ) psz_fontfile = Win32_Select( p_filter, p_style->psz_fontname, (p_style->i_style_flags & STYLE_BOLD) != 0, @@ -1734,19 +1391,6 @@ static FT_Face LoadFace( filter_t *p_filter, return p_face; } -static bool FaceStyleEquals( const text_style_t *p_style1, - const text_style_t *p_style2 ) -{ - if( !p_style1 || !p_style2 ) - return false; - if( p_style1 == p_style2 ) - return true; - - const int i_style_mask = STYLE_BOLD | STYLE_ITALIC; - return (p_style1->i_style_flags & i_style_mask) == (p_style2->i_style_flags & i_style_mask) && - !strcmp( p_style1->psz_fontname, p_style2->psz_fontname ); -} - static int GetGlyph( filter_t *p_filter, FT_Glyph *pp_glyph, FT_BBox *p_glyph_bbox, FT_Glyph *pp_outline, FT_BBox *p_outline_bbox, @@ -1790,7 +1434,7 @@ static int GetGlyph( filter_t *p_filter, } FT_Glyph shadow = NULL; - if( p_filter->p_sys->i_shadow_opacity > 0 ) + if( p_filter->p_sys->style.i_shadow_alpha > 0 ) { shadow = outline ? outline : glyph; if( FT_Glyph_To_Bitmap( &shadow, FT_RENDER_MODE_NORMAL, p_pen_shadow, 0 ) ) @@ -1856,13 +1500,13 @@ static int ProcessLines( filter_t *p_filter, FT_BBox *p_bbox, int *pi_max_face_height, - uint32_t *psz_text, + uni_char_t *psz_text, text_style_t **pp_styles, uint32_t *pi_k_dates, int i_len ) { filter_sys_t *p_sys = p_filter->p_sys; - uint32_t *p_fribidi_string = NULL; + uni_char_t *p_fribidi_string = NULL; text_style_t **pp_fribidi_styles = NULL; int *p_new_positions = NULL; @@ -2040,7 +1684,9 @@ static int ProcessLines( filter_t *p_filter, msg_Err( p_filter, "Failed to set font size to %d", p_current_style->i_font_size ); if( p_sys->p_stroker ) { - int i_radius = (p_current_style->i_font_size << 6) * p_sys->f_outline_thickness; + double f_outline_thickness = var_InheritInteger( p_filter, "freetype-outline-thickness" ) / 100.0; + f_outline_thickness = VLC_CLIP( f_outline_thickness, 0.0, 0.5 ); + int i_radius = (p_current_style->i_font_size << 6) * f_outline_thickness; FT_Stroker_Set( p_sys->p_stroker, i_radius, FT_STROKER_LINECAP_ROUND, @@ -2058,7 +1704,7 @@ static int ProcessLines( filter_t *p_filter, while( i_part_length > 0 ) { const text_style_t *p_glyph_style = pp_styles[i_index]; - uint32_t character = psz_text[i_index]; + uni_char_t character = psz_text[i_index]; int i_glyph_index = FT_Get_Char_Index( p_current_face, character ); /* Get kerning vector */ @@ -2228,6 +1874,7 @@ static int ProcessLines( filter_t *p_filter, { p_line->i_width = __MAX(line_bbox.xMax - line_bbox.xMin, 0); p_line->i_base_line = i_base_line; + p_line->i_height = __MAX(i_face_height, i_face_height_previous); if( i_ul_thickness > 0 ) { for( int i = 0; i < p_line->i_character_count; i++ ) @@ -2291,7 +1938,7 @@ static int RenderCommon( filter_t *p_filter, subpicture_region_t *p_region_out, const size_t i_text_max = strlen( b_html ? p_region_in->psz_html : p_region_in->psz_text ); - uint32_t *psz_text = calloc( i_text_max, sizeof( *psz_text ) ); + uni_char_t *psz_text = calloc( i_text_max, sizeof( *psz_text ) ); text_style_t **pp_styles = calloc( i_text_max, sizeof( *pp_styles ) ); if( !psz_text || !pp_styles ) { @@ -2301,7 +1948,7 @@ static int RenderCommon( filter_t *p_filter, subpicture_region_t *p_region_out, } /* Reset the default fontsize in case screen metrics have changed */ - p_filter->p_sys->i_font_size = GetFontSize( p_filter ); + p_filter->p_sys->style.i_font_size = GetFontSize( p_filter ); /* */ int rv = VLC_SUCCESS; @@ -2312,7 +1959,6 @@ static int RenderCommon( filter_t *p_filter, subpicture_region_t *p_region_out, uint32_t *pi_k_durations = NULL; -#ifdef HAVE_STYLES if( b_html ) { stream_t *p_sub = stream_MemoryNew( VLC_OBJECT(p_filter), @@ -2361,7 +2007,7 @@ static int RenderCommon( filter_t *p_filter, subpicture_region_t *p_region_out, { rv = ProcessNodes( p_filter, psz_text, pp_styles, pi_k_durations, &i_text_length, - p_xml_reader, p_region_in->p_style ); + p_xml_reader, p_region_in->p_style, &p_filter->p_sys->style ); } if( p_xml_reader ) @@ -2370,13 +2016,13 @@ static int RenderCommon( filter_t *p_filter, subpicture_region_t *p_region_out, stream_Delete( p_sub ); } else -#endif { text_style_t *p_style; if( p_region_in->p_style ) - p_style = CreateStyle( p_region_in->p_style->psz_fontname, + p_style = CreateStyle( p_region_in->p_style->psz_fontname ? p_region_in->p_style->psz_fontname + : p_sys->style.psz_fontname, p_region_in->p_style->i_font_size > 0 ? p_region_in->p_style->i_font_size - : p_sys->i_font_size, + : p_sys->style.i_font_size, (p_region_in->p_style->i_font_color & 0xffffff) | ((p_region_in->p_style->i_font_alpha & 0xff) << 24), 0x00ffffff, @@ -2385,12 +2031,16 @@ static int RenderCommon( filter_t *p_filter, subpicture_region_t *p_region_out, STYLE_UNDERLINE | STYLE_STRIKEOUT) ); else - p_style = CreateStyle( p_sys->psz_fontfamily, - p_sys->i_font_size, - (p_sys->i_font_color & 0xffffff) | - ((p_sys->i_font_opacity & 0xff) << 24), + { + uint32_t i_font_color = var_InheritInteger( p_filter, "freetype-color" ); + i_font_color = VLC_CLIP( i_font_color, 0, 0xFFFFFF ); + p_style = CreateStyle( p_sys->style.psz_fontname, + p_sys->style.i_font_size, + (i_font_color & 0xffffff) | + ((p_sys->style.i_font_alpha & 0xff) << 24), 0x00ffffff, 0); - if( p_sys->b_font_bold ) + } + if( p_sys->style.i_style_flags & STYLE_BOLD ) p_style->i_style_flags |= STYLE_BOLD; i_text_length = SetupText( p_filter, @@ -2422,7 +2072,9 @@ static int RenderCommon( filter_t *p_filter, subpicture_region_t *p_region_out, else if( !p_chroma_list || *p_chroma_list == 0 ) p_chroma_list = p_chroma_list_rgba; - const int i_margin = p_sys->i_background_opacity > 0 ? i_max_face_height / 4 : 0; + uint8_t i_background_opacity = var_InheritInteger( p_filter, "freetype-background-opacity" ); + i_background_opacity = VLC_CLIP( i_background_opacity, 0, 255 ); + const int i_margin = i_background_opacity > 0 ? i_max_face_height / 4 : 0; for( const vlc_fourcc_t *p_chroma = p_chroma_list; *p_chroma != 0; p_chroma++ ) { rv = VLC_EGENERIC; @@ -2472,8 +2124,6 @@ static int RenderText( filter_t *p_filter, subpicture_region_t *p_region_out, return RenderCommon( p_filter, p_region_out, p_region_in, false, p_chroma_list ); } -#ifdef HAVE_STYLES - static int RenderHtml( filter_t *p_filter, subpicture_region_t *p_region_out, subpicture_region_t *p_region_in, const vlc_fourcc_t *p_chroma_list ) @@ -2481,8 +2131,6 @@ static int RenderHtml( filter_t *p_filter, subpicture_region_t *p_region_out, return RenderCommon( p_filter, p_region_out, p_region_in, true, p_chroma_list ); } -#endif - /***************************************************************************** * Create: allocates osd-text video thread output method ***************************************************************************** @@ -2493,57 +2141,55 @@ 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; + char *psz_fontname = NULL; + char *psz_monofontfile = NULL; + char *psz_monofontfamily = NULL; + int i_error = 0, fontindex = 0, monofontindex = 0; /* Allocate structure */ p_filter->p_sys = p_sys = malloc( sizeof(*p_sys) ); if( !p_sys ) return VLC_ENOMEM; - p_sys->psz_fontfamily = NULL; -#ifdef HAVE_STYLES + p_sys->style.psz_fontname = NULL; 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; + p_sys->style.i_font_size = 0; - var_Create( p_filter, "freetype-rel-fontsize", - VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); + /* + * The following variables should not be cached, as they might be changed on-the-fly: + * freetype-rel-fontsize, freetype-background-opacity, freetype-background-color, + * freetype-outline-thickness, freetype-color + * + */ - psz_fontfamily = var_InheritString( p_filter, "freetype-font" ); + psz_fontname = var_InheritString( p_filter, "freetype-font" ); + psz_monofontfamily = var_InheritString( p_filter, "freetype-monofont" ); p_sys->i_default_font_size = var_InheritInteger( p_filter, "freetype-fontsize" ); - p_sys->i_font_opacity = var_InheritInteger( p_filter,"freetype-opacity" ); - p_sys->i_font_opacity = VLC_CLIP( p_sys->i_font_opacity, 0, 255 ); - p_sys->i_font_color = var_InheritInteger( p_filter, "freetype-color" ); - p_sys->i_font_color = VLC_CLIP( p_sys->i_font_color, 0, 0xFFFFFF ); - p_sys->b_font_bold = var_InheritBool( p_filter, "freetype-bold" ); - - p_sys->i_background_opacity = var_InheritInteger( p_filter,"freetype-background-opacity" );; - p_sys->i_background_opacity = VLC_CLIP( p_sys->i_background_opacity, 0, 255 ); - p_sys->i_background_color = var_InheritInteger( p_filter, "freetype-background-color" ); - p_sys->i_background_color = VLC_CLIP( p_sys->i_background_color, 0, 0xFFFFFF ); - - p_sys->f_outline_thickness = var_InheritInteger( p_filter, "freetype-outline-thickness" ) / 100.0; - p_sys->f_outline_thickness = VLC_CLIP( p_sys->f_outline_thickness, 0.0, 0.5 ); - p_sys->i_outline_opacity = var_InheritInteger( p_filter, "freetype-outline-opacity" ); - p_sys->i_outline_opacity = VLC_CLIP( p_sys->i_outline_opacity, 0, 255 ); - p_sys->i_outline_color = var_InheritInteger( p_filter, "freetype-outline-color" ); - p_sys->i_outline_color = VLC_CLIP( p_sys->i_outline_color, 0, 0xFFFFFF ); - - p_sys->i_shadow_opacity = var_InheritInteger( p_filter, "freetype-shadow-opacity" ); - p_sys->i_shadow_opacity = VLC_CLIP( p_sys->i_shadow_opacity, 0, 255 ); - p_sys->i_shadow_color = var_InheritInteger( p_filter, "freetype-shadow-color" ); - p_sys->i_shadow_color = VLC_CLIP( p_sys->i_shadow_color, 0, 0xFFFFFF ); + p_sys->style.i_font_alpha = var_InheritInteger( p_filter,"freetype-opacity" ); + p_sys->style.i_font_alpha = VLC_CLIP( p_sys->style.i_font_alpha, 0, 255 ); + if( var_InheritBool( p_filter, "freetype-bold" ) ) + p_sys->style.i_style_flags |= STYLE_BOLD; + + double f_outline_thickness = var_InheritInteger( p_filter, "freetype-outline-thickness" ) / 100.0; + f_outline_thickness = VLC_CLIP( f_outline_thickness, 0.0, 0.5 ); + p_sys->style.i_outline_alpha = var_InheritInteger( p_filter, "freetype-outline-opacity" ); + p_sys->style.i_outline_alpha = VLC_CLIP( p_sys->style.i_outline_alpha, 0, 255 ); + p_sys->style.i_outline_color = var_InheritInteger( p_filter, "freetype-outline-color" ); + p_sys->style.i_outline_color = VLC_CLIP( p_sys->style.i_outline_color, 0, 0xFFFFFF ); + + p_sys->style.i_shadow_alpha = var_InheritInteger( p_filter, "freetype-shadow-opacity" ); + p_sys->style.i_shadow_alpha = VLC_CLIP( p_sys->style.i_shadow_alpha, 0, 255 ); + p_sys->style.i_shadow_color = var_InheritInteger( p_filter, "freetype-shadow-color" ); + p_sys->style.i_shadow_color = VLC_CLIP( p_sys->style.i_shadow_color, 0, 0xFFFFFF ); float f_shadow_angle = var_InheritFloat( p_filter, "freetype-shadow-angle" ); float f_shadow_distance = var_InheritFloat( p_filter, "freetype-shadow-distance" ); f_shadow_distance = VLC_CLIP( f_shadow_distance, 0, 1 ); p_sys->f_shadow_vector_x = f_shadow_distance * cos(2 * M_PI * f_shadow_angle / 360); p_sys->f_shadow_vector_y = f_shadow_distance * sin(2 * M_PI * f_shadow_angle / 360); -#ifdef WIN32 +#ifdef _WIN32 /* Get Windows Font folder */ wchar_t wdir[MAX_PATH]; if( S_OK != SHGetFolderPathW( NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, wdir ) ) @@ -2554,47 +2200,60 @@ static int Create( vlc_object_t *p_this ) p_sys->psz_win_fonts_path = FromWide( wdir ); #endif - /* Set default psz_fontfamily */ - if( !psz_fontfamily || !*psz_fontfamily ) + /* Set default psz_fontname */ + if( !psz_fontname || !*psz_fontname ) { - free( psz_fontfamily ); + free( psz_fontname ); #ifdef HAVE_STYLES - psz_fontfamily = strdup( DEFAULT_FAMILY ); + psz_fontname = strdup( DEFAULT_FAMILY ); #else -# ifdef WIN32 - if( asprintf( &psz_fontfamily, "%s"DEFAULT_FONT_FILE, p_sys->psz_win_fonts_path ) == -1 ) +# ifdef _WIN32 + if( asprintf( &psz_fontname, "%s"DEFAULT_FONT_FILE, p_sys->psz_win_fonts_path ) == -1 ) + { + psz_fontname = NULL; goto error; + } # else - psz_fontfamily = strdup( DEFAULT_FONT_FILE ); + psz_fontname = strdup( DEFAULT_FONT_FILE ); # endif - msg_Err( p_filter,"User specified an empty fontfile, using %s", psz_fontfamily ); + msg_Err( p_filter,"User specified an empty fontfile, using %s", psz_fontname ); #endif } /* Set the current font file */ - p_sys->psz_fontfamily = psz_fontfamily; + p_sys->style.psz_fontname = psz_fontname; #ifdef HAVE_STYLES #ifdef HAVE_FONTCONFIG FontConfig_BuildCache( p_filter ); /* */ - psz_fontfile = FontConfig_Select( NULL, psz_fontfamily, false, false, + psz_fontfile = FontConfig_Select( NULL, psz_fontname, 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 ); + psz_monofontfile = FontConfig_Select( NULL, psz_monofontfamily, false, + false, p_sys->i_default_font_size, + &monofontindex ); +#elif defined(__APPLE__) +#if !TARGET_OS_IPHONE + psz_fontfile = MacLegacy_Select( p_filter, psz_fontname, false, false, -1, &fontindex ); +#endif +#elif defined(_WIN32) + psz_fontfile = Win32_Select( p_filter, psz_fontname, false, false, -1, &fontindex ); #endif - msg_Dbg( p_filter, "Using %s as font from file %s", psz_fontfamily, psz_fontfile ); + msg_Dbg( p_filter, "Using %s as font from file %s", psz_fontname, psz_fontfile ); /* If nothing is found, use the default family */ if( !psz_fontfile ) - psz_fontfile = strdup( psz_fontfamily ); + psz_fontfile = strdup( psz_fontname ); + if( !psz_monofontfile ) + psz_monofontfile = strdup( psz_monofontfamily ); #else /* !HAVE_STYLES */ /* Use the default file */ - psz_fontfile = psz_fontfamily; + psz_fontfile = psz_fontname; + psz_monofontfile = psz_monofontfamily; #endif + p_sys->style.psz_monofontname = psz_monofontfamily; /* */ i_error = FT_Init_FreeType( &p_sys->p_library ); @@ -2630,7 +2289,7 @@ static int Create( vlc_object_t *p_this ) if( SetFontSize( p_filter, 0 ) != VLC_SUCCESS ) goto error; p_sys->p_stroker = NULL; - if( p_sys->f_outline_thickness > 0.001 ) + if( f_outline_thickness > 0.001 ) { i_error = FT_Stroker_New( p_sys->p_library, &p_sys->p_stroker ); if( i_error ) @@ -2641,16 +2300,13 @@ static int Create( vlc_object_t *p_this ) 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 ); #ifdef HAVE_STYLES free( psz_fontfile ); + free( psz_monofontfile ); #endif return VLC_SUCCESS; @@ -2660,8 +2316,10 @@ error: if( p_sys->p_library ) FT_Done_FreeType( p_sys->p_library ); #ifdef HAVE_STYLES free( psz_fontfile ); + free( psz_monofontfile ); #endif - free( psz_fontfamily ); + free( psz_fontname ); + free( psz_monofontfamily ); free( p_sys ); return VLC_EGENERIC; } @@ -2684,10 +2342,12 @@ static void Destroy( vlc_object_t *p_this ) free( p_sys->pp_font_attachments ); } -#ifdef HAVE_STYLES if( p_sys->p_xml ) xml_ReaderDelete( p_sys->p_xml ); + free( p_sys->style.psz_fontname ); + +#ifdef _WIN32 + free( p_sys->psz_win_fonts_path ); #endif - free( p_sys->psz_fontfamily ); /* FcFini asserts calling the subfunction FcCacheFini() * even if no other library functions have been made since FcInit(), @@ -2699,5 +2359,3 @@ static void Destroy( vlc_object_t *p_this ) FT_Done_FreeType( p_sys->p_library ); free( p_sys ); } - -