Commit aa11155a authored by François Cartegnie's avatar François Cartegnie 🤞

text_renderer: freetype add support for ruby

parent 65b4b3a7
...@@ -841,6 +841,17 @@ static void RenderCharAXYZ( filter_t *p_filter, ...@@ -841,6 +841,17 @@ static void RenderCharAXYZ( filter_t *p_filter,
break; break;
} }
if(ch->p_ruby && ch->p_ruby->p_laid)
{
RenderCharAXYZ( p_filter,
p_picture,
ch->p_ruby->p_laid,
i_offset_x, i_offset_y,
2,
ExtractComponents,
BlendPixel );
}
/* Don't render if invisible or not wanted */ /* Don't render if invisible or not wanted */
if( i_a == STYLE_ALPHA_TRANSPARENT || if( i_a == STYLE_ALPHA_TRANSPARENT ||
(g == 0 && 0 == (ch->p_style->i_style_flags & STYLE_SHADOW) ) || (g == 0 && 0 == (ch->p_style->i_style_flags & STYLE_SHADOW) ) ||
...@@ -1001,6 +1012,27 @@ static void FillDefaultStyles( filter_t *p_filter ) ...@@ -1001,6 +1012,27 @@ static void FillDefaultStyles( filter_t *p_filter )
text_style_Merge( p_sys->p_default_style, p_sys->p_forced_style, true ); text_style_Merge( p_sys->p_default_style, p_sys->p_forced_style, true );
} }
static void FreeRubyBlockArray( ruby_block_t **pp_array, size_t i_array )
{
ruby_block_t *p_lyt = NULL;
for( size_t i = 0; i< i_array; i++ )
{
if( p_lyt != pp_array[i] )
{
p_lyt = pp_array[i];
if( p_lyt )
{
free( p_lyt->p_uchars );
text_style_Delete( p_lyt->p_style );
if( p_lyt->p_laid )
FreeLines( p_lyt->p_laid );
free( p_lyt );
}
}
}
free( pp_array );
}
static void FreeStylesArray( text_style_t **pp_styles, size_t i_styles ) static void FreeStylesArray( text_style_t **pp_styles, size_t i_styles )
{ {
text_style_t *p_style = NULL; text_style_t *p_style = NULL;
...@@ -1016,7 +1048,8 @@ static void FreeStylesArray( text_style_t **pp_styles, size_t i_styles ) ...@@ -1016,7 +1048,8 @@ static void FreeStylesArray( text_style_t **pp_styles, size_t i_styles )
} }
static size_t AddTextAndStyles( filter_sys_t *p_sys, static size_t AddTextAndStyles( filter_sys_t *p_sys,
const char *psz_text, const text_style_t *p_style, const char *psz_text, const char *psz_rt,
const text_style_t *p_style,
layout_text_block_t *p_text_block ) layout_text_block_t *p_text_block )
{ {
/* Convert chars to unicode */ /* Convert chars to unicode */
...@@ -1046,6 +1079,15 @@ static size_t AddTextAndStyles( filter_sys_t *p_sys, ...@@ -1046,6 +1079,15 @@ static size_t AddTextAndStyles( filter_sys_t *p_sys,
return 0; return 0;
p_text_block->pp_styles = p_realloc; p_text_block->pp_styles = p_realloc;
/* Same for ruby text */
if( SIZE_MAX / sizeof(text_segment_ruby_t *) < p_text_block->i_count + i_newchars )
return 0;
i_realloc = (p_text_block->i_count + i_newchars) * sizeof(text_segment_ruby_t *);
p_realloc = realloc( p_text_block->pp_ruby, i_realloc );
if ( unlikely(!p_realloc) )
return 0;
p_text_block->pp_ruby = p_realloc;
/* Copy data */ /* Copy data */
memcpy( &p_text_block->p_uchars[p_text_block->i_count], p_ucs4, i_newchars * 4 ); memcpy( &p_text_block->p_uchars[p_text_block->i_count], p_ucs4, i_newchars * 4 );
free( p_ucs4 ); free( p_ucs4 );
...@@ -1065,6 +1107,33 @@ static size_t AddTextAndStyles( filter_sys_t *p_sys, ...@@ -1065,6 +1107,33 @@ static size_t AddTextAndStyles( filter_sys_t *p_sys,
for ( size_t i = 0; i < i_newchars; ++i ) for ( size_t i = 0; i < i_newchars; ++i )
p_text_block->pp_styles[p_text_block->i_count + i] = p_mgstyle; p_text_block->pp_styles[p_text_block->i_count + i] = p_mgstyle;
ruby_block_t *p_rubyblock = NULL;
if( psz_rt )
{
p_ucs4 = ToCharset( FREETYPE_TO_UCS, psz_rt, &i_bytes );
if( !p_ucs4 )
return 0;
p_rubyblock = malloc(sizeof(ruby_block_t));
if( p_rubyblock )
{
p_rubyblock->p_style = text_style_Duplicate( p_mgstyle );
if( !p_rubyblock->p_style )
{
free( p_ucs4 );
free( p_rubyblock );
return 0;
}
p_rubyblock->p_style->i_font_size *= 0.4;
p_rubyblock->p_style->f_font_relsize *= 0.4;
p_rubyblock->p_uchars = p_ucs4;
p_rubyblock->i_count = i_bytes / 4;
p_rubyblock->p_laid = NULL;
}
else free( p_ucs4 );
}
for ( size_t i = 0; i < i_newchars; ++i )
p_text_block->pp_ruby[p_text_block->i_count + i] = p_rubyblock;
/* now safe to update total nb */ /* now safe to update total nb */
p_text_block->i_count += i_newchars; p_text_block->i_count += i_newchars;
...@@ -1081,8 +1150,22 @@ static size_t SegmentsToTextAndStyles( filter_t *p_filter, const text_segment_t ...@@ -1081,8 +1150,22 @@ static size_t SegmentsToTextAndStyles( filter_t *p_filter, const text_segment_t
if( !s->psz_text || !s->psz_text[0] ) if( !s->psz_text || !s->psz_text[0] )
continue; continue;
i_nb_char += AddTextAndStyles( p_filter->p_sys, s->psz_text, if( s->p_ruby )
s->style, p_text_block ); {
for( const text_segment_ruby_t *p_ruby = s->p_ruby;
p_ruby; p_ruby = p_ruby->p_next )
{
i_nb_char += AddTextAndStyles( p_filter->p_sys,
p_ruby->psz_base, p_ruby->psz_rt,
s->style, p_text_block );
}
}
else
{
i_nb_char += AddTextAndStyles( p_filter->p_sys,
s->psz_text, NULL,
s->style, p_text_block );
}
} }
return i_nb_char; return i_nb_char;
...@@ -1283,6 +1366,8 @@ static int Render( filter_t *p_filter, subpicture_region_t *p_region_out, ...@@ -1283,6 +1366,8 @@ static int Render( filter_t *p_filter, subpicture_region_t *p_region_out,
free( text_block.p_uchars ); free( text_block.p_uchars );
FreeStylesArray( text_block.pp_styles, text_block.i_count ); FreeStylesArray( text_block.pp_styles, text_block.i_count );
if( text_block.pp_ruby )
FreeRubyBlockArray( text_block.pp_ruby, text_block.i_count );
free( text_block.pi_k_durations ); free( text_block.pi_k_durations );
return rv; return rv;
......
...@@ -137,6 +137,7 @@ typedef struct paragraph_t ...@@ -137,6 +137,7 @@ typedef struct paragraph_t
uni_char_t *p_code_points; /**< Unicode code points */ uni_char_t *p_code_points; /**< Unicode code points */
int *pi_glyph_indices; /**< Glyph index values within the run's font face */ int *pi_glyph_indices; /**< Glyph index values within the run's font face */
text_style_t **pp_styles; text_style_t **pp_styles;
ruby_block_t **pp_ruby;
FT_Face *pp_faces; /**< Used to determine run boundaries when performing font fallback */ FT_Face *pp_faces; /**< Used to determine run boundaries when performing font fallback */
int *pi_run_ids; /**< The run to which each glyph belongs */ int *pi_run_ids; /**< The run to which each glyph belongs */
glyph_bitmaps_t *p_glyph_bitmaps; glyph_bitmaps_t *p_glyph_bitmaps;
...@@ -171,6 +172,9 @@ static void FreeLine( line_desc_t *p_line ) ...@@ -171,6 +172,9 @@ static void FreeLine( line_desc_t *p_line )
FT_Done_Glyph( (FT_Glyph)ch->p_shadow ); FT_Done_Glyph( (FT_Glyph)ch->p_shadow );
} }
// if( p_line->p_ruby )
// FreeLine( p_line->p_ruby );
free( p_line->p_character ); free( p_line->p_character );
free( p_line ); free( p_line );
} }
...@@ -210,6 +214,67 @@ line_desc_t *NewLine( int i_count ) ...@@ -210,6 +214,67 @@ line_desc_t *NewLine( int i_count )
return p_line; return p_line;
} }
static void ShiftGlyph( FT_BitmapGlyph g, int x, int y )
{
if( g )
{
g->left += x;
g->top += y;
}
}
static void ShiftChar( line_character_t *c, int x, int y )
{
ShiftGlyph( c->p_glyph, x, y );
ShiftGlyph( c->p_shadow, x, y );
ShiftGlyph( c->p_outline, x, y );
c->bbox.yMin += y;
c->bbox.yMax += y;
c->bbox.xMin += x;
c->bbox.xMax += x;
}
static void ShiftLine( line_desc_t *p_line, int x, int y )
{
for( int i=0; i<p_line->i_character_count; i++ )
ShiftChar( &p_line->p_character[i], x, y );
p_line->i_base_line += y;
p_line->bbox.yMin += y;
p_line->bbox.yMax += y;
p_line->bbox.xMin += x;
p_line->bbox.xMax += x;
}
static void MoveLineTo( line_desc_t *p_line, int x, int y )
{
ShiftLine( p_line, x - p_line->bbox.xMin,
y - p_line->bbox.yMax );
}
static void IndentCharsFrom( line_desc_t *p_line, int i_start, int i_count, int w, int h )
{
for( int i=0; i<i_count; i++ )
{
line_character_t *p_ch = &p_line->p_character[i_start + i];
ShiftChar( p_ch, w, h );
BBoxEnlarge( &p_line->bbox, &p_ch->bbox );
}
}
static int RubyBaseAdvance( const line_desc_t *p_line, int i_start, int *pi_count )
{
int i_total = 0;
*pi_count = 0;
for( int i = i_start; i < p_line->i_character_count; i++ )
{
if( p_line->p_character[i].p_ruby != p_line->p_character[i_start].p_ruby )
break;
(*pi_count)++;
i_total += (p_line->p_character[i].bbox.xMax - p_line->p_character[i].bbox.xMin);
}
return i_total;
}
static void FixGlyph( FT_Glyph glyph, FT_BBox *p_bbox, static void FixGlyph( FT_Glyph glyph, FT_BBox *p_bbox,
FT_Pos i_x_advance, FT_Pos i_y_advance, FT_Pos i_x_advance, FT_Pos i_y_advance,
const FT_Vector *p_pen ) const FT_Vector *p_pen )
...@@ -233,6 +298,7 @@ static paragraph_t *NewParagraph( filter_t *p_filter, ...@@ -233,6 +298,7 @@ static paragraph_t *NewParagraph( filter_t *p_filter,
int i_size, int i_size,
const uni_char_t *p_code_points, const uni_char_t *p_code_points,
text_style_t **pp_styles, text_style_t **pp_styles,
ruby_block_t **pp_ruby,
uint32_t *pi_k_dates, uint32_t *pi_k_dates,
int i_runs_size ) int i_runs_size )
{ {
...@@ -255,6 +321,8 @@ static paragraph_t *NewParagraph( filter_t *p_filter, ...@@ -255,6 +321,8 @@ static paragraph_t *NewParagraph( filter_t *p_filter,
calloc( i_size, sizeof( *p_paragraph->p_glyph_bitmaps ) ); calloc( i_size, sizeof( *p_paragraph->p_glyph_bitmaps ) );
p_paragraph->pi_karaoke_bar = p_paragraph->pi_karaoke_bar =
calloc( i_size, sizeof( *p_paragraph->pi_karaoke_bar ) ); calloc( i_size, sizeof( *p_paragraph->pi_karaoke_bar ) );
if( pp_ruby )
p_paragraph->pp_ruby = calloc( i_size, sizeof( *p_paragraph->pp_ruby ) );
p_paragraph->p_runs = calloc( i_runs_size, sizeof( run_desc_t ) ); p_paragraph->p_runs = calloc( i_runs_size, sizeof( run_desc_t ) );
p_paragraph->i_runs_size = i_runs_size; p_paragraph->i_runs_size = i_runs_size;
...@@ -272,6 +340,9 @@ static paragraph_t *NewParagraph( filter_t *p_filter, ...@@ -272,6 +340,9 @@ static paragraph_t *NewParagraph( filter_t *p_filter,
if( pp_styles ) if( pp_styles )
memcpy( p_paragraph->pp_styles, pp_styles, memcpy( p_paragraph->pp_styles, pp_styles,
i_size * sizeof( *pp_styles ) ); i_size * sizeof( *pp_styles ) );
if( p_paragraph->pp_ruby )
memcpy( p_paragraph->pp_ruby, pp_ruby, i_size * sizeof( *pp_ruby ) );
if( pi_k_dates ) if( pi_k_dates )
{ {
int64_t i_elapsed = var_GetInteger( p_filter, "spu-elapsed" ) / 1000; int64_t i_elapsed = var_GetInteger( p_filter, "spu-elapsed" ) / 1000;
...@@ -315,6 +386,7 @@ error: ...@@ -315,6 +386,7 @@ error:
if( p_paragraph->p_code_points ) free( p_paragraph->p_code_points ); if( p_paragraph->p_code_points ) free( p_paragraph->p_code_points );
if( p_paragraph->pi_glyph_indices ) free( p_paragraph->pi_glyph_indices ); if( p_paragraph->pi_glyph_indices ) free( p_paragraph->pi_glyph_indices );
if( p_paragraph->pp_styles ) free( p_paragraph->pp_styles ); if( p_paragraph->pp_styles ) free( p_paragraph->pp_styles );
if( p_paragraph->pp_ruby ) free( p_paragraph->pp_ruby );
if( p_paragraph->pp_faces ) free( p_paragraph->pp_faces ); if( p_paragraph->pp_faces ) free( p_paragraph->pp_faces );
if( p_paragraph->pi_run_ids ) free( p_paragraph->pi_run_ids ); if( p_paragraph->pi_run_ids ) free( p_paragraph->pi_run_ids );
if( p_paragraph->p_glyph_bitmaps ) free( p_paragraph->p_glyph_bitmaps ); if( p_paragraph->p_glyph_bitmaps ) free( p_paragraph->p_glyph_bitmaps );
...@@ -341,6 +413,7 @@ static void FreeParagraph( paragraph_t *p_paragraph ) ...@@ -341,6 +413,7 @@ static void FreeParagraph( paragraph_t *p_paragraph )
free( p_paragraph->pi_karaoke_bar ); free( p_paragraph->pi_karaoke_bar );
free( p_paragraph->pi_run_ids ); free( p_paragraph->pi_run_ids );
free( p_paragraph->pp_faces ); free( p_paragraph->pp_faces );
free( p_paragraph->pp_ruby );
free( p_paragraph->pp_styles ); free( p_paragraph->pp_styles );
free( p_paragraph->p_code_points ); free( p_paragraph->p_code_points );
...@@ -732,13 +805,20 @@ static int ShapeParagraphHarfBuzz( filter_t *p_filter, ...@@ -732,13 +805,20 @@ static int ShapeParagraphHarfBuzz( filter_t *p_filter,
i_total_glyphs += p_run->i_glyph_count; i_total_glyphs += p_run->i_glyph_count;
} }
p_new_paragraph = NewParagraph( p_filter, i_total_glyphs, 0, 0, 0, p_new_paragraph = NewParagraph( p_filter, i_total_glyphs,
NULL, NULL, NULL, NULL,
p_paragraph->i_runs_size ); p_paragraph->i_runs_size );
if( !p_new_paragraph ) if( !p_new_paragraph )
{ {
i_ret = VLC_ENOMEM; i_ret = VLC_ENOMEM;
goto error; goto error;
} }
if( p_paragraph->pp_ruby )
{
p_new_paragraph->pp_ruby = calloc(p_new_paragraph->i_size,
sizeof(ruby_block_t *));
}
p_new_paragraph->paragraph_type = p_paragraph->paragraph_type; p_new_paragraph->paragraph_type = p_paragraph->paragraph_type;
int i_index = 0; int i_index = 0;
...@@ -772,6 +852,9 @@ static int ShapeParagraphHarfBuzz( filter_t *p_filter, ...@@ -772,6 +852,9 @@ static int ShapeParagraphHarfBuzz( filter_t *p_filter,
p_paragraph->p_levels[ i_source_index ]; p_paragraph->p_levels[ i_source_index ];
p_new_paragraph->pp_styles[ i_index ] = p_new_paragraph->pp_styles[ i_index ] =
p_paragraph->pp_styles[ i_source_index ]; p_paragraph->pp_styles[ i_source_index ];
if( p_new_paragraph->pp_ruby )
p_new_paragraph->pp_ruby[ i_index ] =
p_paragraph->pp_ruby[ i_source_index ];
p_new_paragraph->pi_karaoke_bar[ i_index ] = p_new_paragraph->pi_karaoke_bar[ i_index ] =
p_paragraph->pi_karaoke_bar[ i_source_index ]; p_paragraph->pi_karaoke_bar[ i_source_index ];
p_new_paragraph->p_glyph_bitmaps[ i_index ].i_x_offset = p_new_paragraph->p_glyph_bitmaps[ i_index ].i_x_offset =
...@@ -1056,7 +1139,8 @@ static int LoadGlyphs( filter_t *p_filter, paragraph_t *p_paragraph, ...@@ -1056,7 +1139,8 @@ static int LoadGlyphs( filter_t *p_filter, paragraph_t *p_paragraph,
static int LayoutLine( filter_t *p_filter, static int LayoutLine( filter_t *p_filter,
paragraph_t *p_paragraph, paragraph_t *p_paragraph,
int i_first_char, int i_last_char, int i_first_char, int i_last_char,
line_desc_t **pp_line, bool b_grid ) bool b_grid,
line_desc_t **pp_line )
{ {
if( p_paragraph->i_size <= 0 || p_paragraph->i_runs_count <= 0 if( p_paragraph->i_size <= 0 || p_paragraph->i_runs_count <= 0
|| i_first_char < 0 || i_last_char < 0 || i_first_char < 0 || i_last_char < 0
...@@ -1111,6 +1195,9 @@ static int LayoutLine( filter_t *p_filter, ...@@ -1111,6 +1195,9 @@ static int LayoutLine( filter_t *p_filter,
line_character_t *p_ch = &p_line->p_character[p_line->i_character_count]; line_character_t *p_ch = &p_line->p_character[p_line->i_character_count];
p_ch->p_style = p_paragraph->pp_styles[ i_paragraph_index ]; p_ch->p_style = p_paragraph->pp_styles[ i_paragraph_index ];
if( p_paragraph->pp_ruby )
p_ch->p_ruby = p_paragraph->pp_ruby[ i ];
glyph_bitmaps_t *p_bitmaps = glyph_bitmaps_t *p_bitmaps =
p_paragraph->p_glyph_bitmaps + i_paragraph_index; p_paragraph->p_glyph_bitmaps + i_paragraph_index;
...@@ -1273,6 +1360,44 @@ static int LayoutLine( filter_t *p_filter, ...@@ -1273,6 +1360,44 @@ static int LayoutLine( filter_t *p_filter,
p_line->i_character_count++; p_line->i_character_count++;
} }
/* Second pass for ruby layout */
if( p_paragraph->pp_ruby )
{
const int i_ruby_baseline = p_line->bbox.yMax;
const ruby_block_t *p_prevruby = NULL;
for( int i = 0; i < p_line->i_character_count; ++i )
{
line_character_t *p_ch = &p_line->p_character[i];
if( p_ch->p_ruby == p_prevruby || !p_ch->p_glyph )
continue;
p_prevruby = p_ch->p_ruby;
if( !p_ch->p_ruby )
continue;
line_desc_t *p_rubyline = p_ch->p_ruby->p_laid;
if( !p_rubyline )
continue;
int i_rubyadvance = (p_rubyline->bbox.xMax - p_rubyline->bbox.xMin);
int i_rubyheight = (p_rubyline->bbox.yMax - p_rubyline->bbox.yMin);
MoveLineTo( p_rubyline, p_ch->bbox.xMin, i_ruby_baseline + i_rubyheight );
BBoxEnlarge( &p_line->bbox, &p_rubyline->bbox );
int i_count;
int i_baseadvance = RubyBaseAdvance( p_line, i, &i_count );
if( i_baseadvance < i_rubyadvance )
{
IndentCharsFrom( p_line, i, i_count, (i_rubyadvance - i_baseadvance) / 2, 0 );
IndentCharsFrom( p_line, i + i_count, p_line->i_character_count - (i + i_count),
(i_rubyadvance - i_baseadvance + 1), 0 );
}
else if( i_baseadvance > i_rubyadvance + 1 )
{
ShiftLine( p_rubyline, (i_baseadvance - i_rubyadvance) / 2, 0 );
BBoxEnlarge( &p_line->bbox, &p_rubyline->bbox ); /* shouldn't be needed */
}
}
}
p_line->i_width = __MAX( 0, p_line->bbox.xMax - p_line->bbox.xMin ); p_line->i_width = __MAX( 0, p_line->bbox.xMax - p_line->bbox.xMin );
if( b_grid ) if( b_grid )
...@@ -1316,7 +1441,8 @@ static inline bool IsWhitespaceAt( paragraph_t *p_paragraph, size_t i ) ...@@ -1316,7 +1441,8 @@ static inline bool IsWhitespaceAt( paragraph_t *p_paragraph, size_t i )
static int LayoutParagraph( filter_t *p_filter, paragraph_t *p_paragraph, static int LayoutParagraph( filter_t *p_filter, paragraph_t *p_paragraph,
unsigned i_max_width, unsigned i_max_advance_x, unsigned i_max_width, unsigned i_max_advance_x,
line_desc_t **pp_lines, bool b_grid, bool b_balance ) bool b_grid, bool b_balance,
line_desc_t **pp_lines )
{ {
if( p_paragraph->i_size <= 0 || p_paragraph->i_runs_count <= 0 ) if( p_paragraph->i_size <= 0 || p_paragraph->i_runs_count <= 0 )
{ {
...@@ -1376,12 +1502,27 @@ static int LayoutParagraph( filter_t *p_filter, paragraph_t *p_paragraph, ...@@ -1376,12 +1502,27 @@ static int LayoutParagraph( filter_t *p_filter, paragraph_t *p_paragraph,
{ {
if( i_line_start < i ) if( i_line_start < i )
if( LayoutLine( p_filter, p_paragraph, if( LayoutLine( p_filter, p_paragraph,
i_line_start, i - 1, pp_line, b_grid ) ) i_line_start, i - 1, b_grid, pp_line ) )
goto error; goto error;
break; break;
} }
if( p_paragraph->pp_ruby &&
p_paragraph->pp_ruby[i] &&
p_paragraph->pp_ruby[i]->p_laid )
{
/* Just forward as non breakable */
const ruby_block_t *p_rubyseq = p_paragraph->pp_ruby[i];
int i_advance = 0;
int i_advanceruby = p_rubyseq->p_laid->i_width;
while( i < p_paragraph->i_size && p_rubyseq == p_paragraph->pp_ruby[i] )
i_advance += p_paragraph->p_glyph_bitmaps[ i++ ].i_x_advance;
/* Just forward as non breakable */
i_width += (i_advance < i_advanceruby) ? i_advanceruby : i_advance;
continue;
}
if( IsWhitespaceAt( p_paragraph, i ) ) if( IsWhitespaceAt( p_paragraph, i ) )
{ {
if( i_line_start == i ) if( i_line_start == i )
...@@ -1431,7 +1572,7 @@ static int LayoutParagraph( filter_t *p_filter, paragraph_t *p_paragraph, ...@@ -1431,7 +1572,7 @@ static int LayoutParagraph( filter_t *p_filter, paragraph_t *p_paragraph,
i_newline_start = i; /* we break line on last char */ i_newline_start = i; /* we break line on last char */
if( LayoutLine( p_filter, p_paragraph, i_line_start, if( LayoutLine( p_filter, p_paragraph, i_line_start,
i_newline_start - 1, pp_line, b_grid ) ) i_newline_start - 1, b_grid, pp_line ) )
goto error; goto error;
/* Handle early end of renderable content; /* Handle early end of renderable content;
...@@ -1480,6 +1621,7 @@ static paragraph_t * BuildParagraph( filter_t *p_filter, ...@@ -1480,6 +1621,7 @@ static paragraph_t * BuildParagraph( filter_t *p_filter,
int i_size, int i_size,
const uni_char_t *p_uchars, const uni_char_t *p_uchars,
text_style_t **pp_styles, text_style_t **pp_styles,
ruby_block_t **pp_ruby,
uint32_t *pi_k_dates, uint32_t *pi_k_dates,
int i_runs_size, int i_runs_size,
unsigned *pi_max_advance_x ) unsigned *pi_max_advance_x )
...@@ -1487,6 +1629,7 @@ static paragraph_t * BuildParagraph( filter_t *p_filter, ...@@ -1487,6 +1629,7 @@ static paragraph_t * BuildParagraph( filter_t *p_filter,
paragraph_t *p_paragraph = NewParagraph( p_filter, i_size, paragraph_t *p_paragraph = NewParagraph( p_filter, i_size,
p_uchars, p_uchars,
pp_styles, pp_styles,
pp_ruby,
pi_k_dates, pi_k_dates,
i_runs_size ); i_runs_size );
if( !p_paragraph ) if( !p_paragraph )
...@@ -1520,6 +1663,7 @@ static paragraph_t * BuildParagraph( filter_t *p_filter, ...@@ -1520,6 +1663,7 @@ static paragraph_t * BuildParagraph( filter_t *p_filter,
if( LoadGlyphs( p_filter, p_paragraph, false, true, pi_max_advance_x ) ) if( LoadGlyphs( p_filter, p_paragraph, false, true, pi_max_advance_x ) )
goto error; goto error;
#endif #endif
return p_paragraph; return p_paragraph;
error: error:
...@@ -1529,6 +1673,43 @@ error: ...@@ -1529,6 +1673,43 @@ error:
return NULL; return NULL;
} }
static int LayoutRubyText( filter_t *p_filter,
const uni_char_t *p_uchars,
int i_uchars,
text_style_t *p_style,
line_desc_t **pp_line )
{
unsigned int i_max_advance_x;
text_style_t **pp_styles = malloc(sizeof(*pp_styles) * i_uchars);
for(int i=0;i<i_uchars;i++)
pp_styles[i] = p_style;
paragraph_t *p_paragraph = BuildParagraph( p_filter, i_uchars,
p_uchars, pp_styles,
NULL, NULL, 1,
&i_max_advance_x );
if( !p_paragraph )
{
free( pp_styles );
return VLC_EGENERIC;
}
if( LayoutLine( p_filter, p_paragraph,
0, i_uchars - 1,
false, pp_line ) )
{
free( pp_styles );
FreeParagraph( p_paragraph );
return VLC_EGENERIC;
}
FreeParagraph( p_paragraph );
free( pp_styles );
return VLC_SUCCESS;
}
int LayoutTextBlock( filter_t *p_filter, int LayoutTextBlock( filter_t *p_filter,
const layout_text_block_t *p_textblock, const layout_text_block_t *p_textblock,
line_desc_t **pp_lines, FT_BBox *p_bbox, line_desc_t **pp_lines, FT_BBox *p_bbox,
...@@ -1541,6 +1722,22 @@ int LayoutTextBlock( filter_t *p_filter, ...@@ -1541,6 +1722,22 @@ int LayoutTextBlock( filter_t *p_filter,
unsigned i_max_advance_x = 0; unsigned i_max_advance_x = 0;
int i_max_face_height = 0; int i_max_face_height = 0;
/* Prepare ruby content */
if( p_textblock->pp_ruby )
{
ruby_block_t *p_prev = NULL;
for( size_t i=0; i<p_textblock->i_count; i++ )
{
if( p_textblock->pp_ruby[i] == p_prev )
continue;
p_prev = p_textblock->pp_ruby[i];
if( p_prev )
LayoutRubyText( p_filter, p_prev->p_uchars, p_prev->i_count,
p_prev->p_style, &p_prev->p_laid );
}
}
/* !Prepare ruby content */
for( size_t i = 0; i <= p_textblock->i_count; ++i ) for( size_t i = 0; i <= p_textblock->i_count; ++i )
{ {
if( i == p_textblock->i_count || p_textblock->p_uchars[ i ] == '\n' ) if( i == p_textblock->i_count || p_textblock->p_uchars[ i ] == '\n' )
...@@ -1556,6 +1753,8 @@ int LayoutTextBlock( filter_t *p_filter, ...@@ -1556,6 +1753,8 @@ int LayoutTextBlock( filter_t *p_filter,
i - i_paragraph_start, i - i_paragraph_start,
&p_textblock->p_uchars[i_paragraph_start], &p_textblock->p_uchars[i_paragraph_start],
&p_textblock->pp_styles[i_paragraph_start], &p_textblock->pp_styles[i_paragraph_start],
p_textblock->pp_ruby ?
&p_textblock->pp_ruby[i_paragraph_start] : NULL,
p_textblock->pi_k_durations ? p_textblock->pi_k_durations ?
&p_textblock->pi_k_durations[i_paragraph_start] : NULL, &p_textblock->pi_k_durations[i_paragraph_start] : NULL,
20, &i_max_advance_x ); 20, &i_max_advance_x );
...@@ -1567,8 +1766,9 @@ int LayoutTextBlock( filter_t *p_filter, ...@@ -1567,8 +1766,9 @@ int LayoutTextBlock( filter_t *p_filter,
if( LayoutParagraph( p_filter, p_paragraph, if( LayoutParagraph( p_filter, p_paragraph,
p_textblock->i_max_width, p_textblock->i_max_width,
i_max_advance_x, pp_line, i_max_advance_x,
p_textblock->b_grid, p_textblock->b_balanced ) ) p_textblock->b_grid, p_textblock->b_balanced,
pp_line ) )
{ {
FreeParagraph( p_paragraph ); FreeParagraph( p_paragraph );
if( p_first_line ) FreeLines( p_first_line ); if( p_first_line ) FreeLines( p_first_line );
......
...@@ -33,6 +33,9 @@ ...@@ -33,6 +33,9 @@
#include "freetype.h" #include "freetype.h"
typedef struct ruby_block_t ruby_block_t;
typedef struct line_desc_t line_desc_t;
typedef struct typedef struct
{ {
FT_BitmapGlyph p_glyph; FT_BitmapGlyph p_glyph;
...@@ -40,16 +43,15 @@ typedef struct ...@@ -40,16 +43,15 @@ typedef struct
FT_BitmapGlyph p_shadow; FT_BitmapGlyph p_shadow;
FT_BBox bbox; FT_BBox bbox;
const text_style_t *p_style; const text_style_t *p_style;
const ruby_block_t *p_ruby;
int i_line_offset; /* underline/strikethrough offset */ int i_line_offset; /* underline/strikethrough offset */
int i_line_thickness; /* underline/strikethrough thickness */ int i_line_thickness; /* underline/strikethrough thickness */
bool b_in_karaoke; bool b_in_karaoke;
} line_character_t; } line_character_t;
typedef struct line_desc_t line_desc_t;
struct line_desc_t struct line_desc_t
{ {
line_desc_t *p_next; line_desc_t *p_next;
int i_width; int i_width;
int i_height; int i_height;
int i_base_line; int i_base_line;
...@@ -63,6 +65,18 @@ struct line_desc_t ...@@ -63,6 +65,18 @@ struct line_desc_t
void FreeLines( line_desc_t *p_lines ); void FreeLines( line_desc_t *p_lines );