📄 freetype.c
字号:
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 void IconvText( filter_t *p_filter, const char *psz_string, uint32_t *i_string_length, uint32_t **ppsz_unicode ){ vlc_iconv_t iconv_handle = (vlc_iconv_t)(-1); /* If memory hasn't been allocated for our output string, allocate it here * - the calling function must now be responsible for freeing it. */ if( !*ppsz_unicode ) *ppsz_unicode = (uint32_t *) malloc( (strlen( psz_string ) + 1) * sizeof( uint32_t )); /* We don't need to handle a NULL pointer in *ppsz_unicode * if we are instead testing for a non NULL value like we are here */ if( *ppsz_unicode ) {#if defined(WORDS_BIGENDIAN) iconv_handle = vlc_iconv_open( "UCS-4BE", "UTF-8" );#else iconv_handle = vlc_iconv_open( "UCS-4LE", "UTF-8" );#endif if( iconv_handle != (vlc_iconv_t)-1 ) { char *p_in_buffer, *p_out_buffer; size_t i_in_bytes, i_out_bytes, i_out_bytes_left, i_ret; i_in_bytes = strlen( psz_string ); i_out_bytes = i_in_bytes * sizeof( uint32_t ); i_out_bytes_left = i_out_bytes; p_in_buffer = (char *) psz_string; p_out_buffer = (char *) *ppsz_unicode; i_ret = vlc_iconv( iconv_handle, (const char**)&p_in_buffer, &i_in_bytes, &p_out_buffer, &i_out_bytes_left ); vlc_iconv_close( iconv_handle ); if( i_in_bytes ) { msg_Warn( p_filter, "failed to convert string to unicode (%m), " "bytes left %u", (unsigned)i_in_bytes ); } else { *(uint32_t*)p_out_buffer = 0; *i_string_length = (i_out_bytes - i_out_bytes_left) / sizeof(uint32_t); } } else { msg_Warn( p_filter, "unable to do conversion" ); } }}static ft_style_t *GetStyleFromFontStack( filter_sys_t *p_sys, font_stack_t **p_fonts, bool b_bold, bool b_italic, bool b_uline ){ ft_style_t *p_style = NULL; 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( VLC_SUCCESS == PeekFont( p_fonts, &psz_fontname, &i_font_size, &i_font_color, &i_karaoke_bg_color )) { p_style = CreateStyle( psz_fontname, i_font_size, i_font_color, i_karaoke_bg_color, b_bold, b_italic, b_uline ); } return p_style;}static int RenderTag( filter_t *p_filter, FT_Face p_face, int i_font_color, bool b_uline, int i_karaoke_bgcolor, line_desc_t *p_line, uint32_t *psz_unicode, int *pi_pen_x, int i_pen_y, int *pi_start, FT_Vector *p_result ){ FT_BBox line; int i_yMin, i_yMax; int i; bool b_first_on_line = true; int i_previous = 0; int i_pen_x_start = *pi_pen_x; uint32_t *psz_unicode_start = psz_unicode; line.xMin = line.xMax = line.yMin = line.yMax = 0; /* Account for part of line already in position */ for( i=0; i<*pi_start; i++ ) { FT_BBox glyph_size; FT_Glyph_Get_CBox( (FT_Glyph) p_line->pp_glyphs[ i ], ft_glyph_bbox_pixels, &glyph_size ); line.xMax = p_line->p_glyph_pos[ i ].x + glyph_size.xMax - glyph_size.xMin + p_line->pp_glyphs[ i ]->left; line.yMax = __MAX( line.yMax, glyph_size.yMax ); line.yMin = __MIN( line.yMin, glyph_size.yMin ); } i_yMin = line.yMin; i_yMax = line.yMax; if( line.xMax > 0 ) b_first_on_line = false; while( *psz_unicode && ( *psz_unicode != '\n' ) ) { FT_BBox glyph_size; FT_Glyph tmp_glyph; int i_error; int i_glyph_index = FT_Get_Char_Index( p_face, *psz_unicode++ ); if( FT_HAS_KERNING( p_face ) && i_glyph_index && i_previous ) { FT_Vector delta; FT_Get_Kerning( p_face, i_previous, i_glyph_index, ft_kerning_default, &delta ); *pi_pen_x += delta.x >> 6; } p_line->p_glyph_pos[ i ].x = *pi_pen_x; p_line->p_glyph_pos[ i ].y = i_pen_y; i_error = FT_Load_Glyph( p_face, i_glyph_index, FT_LOAD_DEFAULT ); if( i_error ) { msg_Err( p_filter, "unable to render text FT_Load_Glyph returned %d", i_error ); p_line->pp_glyphs[ i ] = NULL; return VLC_EGENERIC; } i_error = FT_Get_Glyph( p_face->glyph, &tmp_glyph ); if( i_error ) { msg_Err( p_filter, "unable to render text FT_Get_Glyph returned %d", i_error ); p_line->pp_glyphs[ i ] = NULL; return VLC_EGENERIC; } FT_Glyph_Get_CBox( tmp_glyph, ft_glyph_bbox_pixels, &glyph_size ); i_error = FT_Glyph_To_Bitmap( &tmp_glyph, FT_RENDER_MODE_NORMAL, 0, 1); if( i_error ) { FT_Done_Glyph( tmp_glyph ); continue; } if( b_uline ) { float aOffset = FT_FLOOR(FT_MulFix(p_face->underline_position, p_face->size->metrics.y_scale)); float aSize = FT_CEIL(FT_MulFix(p_face->underline_thickness, p_face->size->metrics.y_scale)); p_line->pi_underline_offset[ i ] = ( aOffset < 0 ) ? -aOffset : aOffset; p_line->pi_underline_thickness[ i ] = ( aSize < 0 ) ? -aSize : aSize; } 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_bg_ratio[ i ] = 0x00; line.xMax = p_line->p_glyph_pos[i].x + glyph_size.xMax - glyph_size.xMin + ((FT_BitmapGlyph)tmp_glyph)->left; if( line.xMax > (int)p_filter->fmt_out.video.i_visible_width - 20 ) { while( --i > *pi_start ) { FT_Done_Glyph( (FT_Glyph)p_line->pp_glyphs[ i ] ); } while( psz_unicode > psz_unicode_start && *psz_unicode != ' ' ) { psz_unicode--; } if( psz_unicode == psz_unicode_start ) { if( b_first_on_line ) { msg_Warn( p_filter, "unbreakable string" ); p_line->pp_glyphs[ i ] = NULL; return VLC_EGENERIC; } *pi_pen_x = i_pen_x_start; p_line->i_width = line.xMax; p_line->i_height = __MAX( p_line->i_height, p_face->size->metrics.height >> 6 ); p_line->pp_glyphs[ i ] = NULL; p_result->x = __MAX( p_result->x, line.xMax ); p_result->y = __MAX( p_result->y, __MAX( p_line->i_height, i_yMax - i_yMin ) ); *pi_start = i; return VLC_SUCCESS; } else { *psz_unicode = '\n'; } psz_unicode = psz_unicode_start; *pi_pen_x = i_pen_x_start; i_previous = 0; line.yMax = i_yMax; line.yMin = i_yMin; continue; } line.yMax = __MAX( line.yMax, glyph_size.yMax ); line.yMin = __MIN( line.yMin, glyph_size.yMin ); i_previous = i_glyph_index; *pi_pen_x += p_face->glyph->advance.x >> 6; i++; } p_line->i_width = line.xMax; p_line->i_height = __MAX( p_line->i_height, p_face->size->metrics.height >> 6 ); p_line->pp_glyphs[ i ] = NULL; p_result->x = __MAX( p_result->x, line.xMax ); p_result->y = __MAX( p_result->y, __MAX( p_line->i_height, line.yMax - line.yMin ) ); *pi_start = i; /* Get rid of any text processed - if necessary repositioning * at the start of a new line of text */ if( !*psz_unicode ) { *psz_unicode_start = '\0'; } else if( psz_unicode > psz_unicode_start ) { for( i=0; psz_unicode[ i ]; i++ ) psz_unicode_start[ i ] = psz_unicode[ i ]; psz_unicode_start[ i ] = '\0'; } return VLC_SUCCESS;}static int HandleFontAttributes( xml_reader_t *p_xml_reader, font_stack_t **p_fonts, int i_scale ){ 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 * 1000 / i_scale; } i_font_alpha = (i_font_color >> 24) & 0xff; i_font_color &= 0x00ffffff; while ( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS ) { char *psz_name = xml_ReaderName( p_xml_reader ); char *psz_value = xml_ReaderValue( p_xml_reader ); if( psz_name && psz_value ) { if( !strcasecmp( "face", psz_name ) ) { free( psz_fontname ); psz_fontname = strdup( psz_value ); } else if( !strcasecmp( "size", psz_name ) ) { if( ( *psz_value == '+' ) || ( *psz_value == '-' ) ) { int i_value = atoi( psz_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( psz_value ); } else if( !strcasecmp( "color", psz_name ) && ( psz_value[0] == '#' ) ) { i_font_color = strtol( psz_value + 1, NULL, 16 ); i_font_color &= 0x00ffffff; } else if( !strcasecmp( "alpha", psz_name ) && ( psz_value[0] == '#' ) ) { i_font_alpha = strtol( psz_value + 1, NULL, 16 ); i_font_alpha &= 0xff; } } free( psz_name ); free( psz_value ); } rv = PushFont( p_fonts, psz_fontname, i_font_size * i_scale / 100
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -