From 3414fef74f9dd1858aca521f93ebadca9ab36f96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20R=C3=B6ttsches?= Date: Mon, 4 Jul 2022 16:29:31 +0300 Subject: [PATCH] [sfnt] Support variable 'COLR' v1 color lines. * include/freetype/ftcolor.h (FT_ColorStopIterator): Add field `read_variable` to indicate whether a variation index base should be read. * src/sfnt/ttcolr.c: (FT_PaintFormat_Internal): New enumerations `FT_COLR_PAINTFORMAT_INTERNAL_VAR_LINEAR_GRADIENT` `FT_COLR_PAINTFORMAT_INTERNAL_VAR_RADIAL_GRADIENT`, and `FT_COLR_PAINTFORMAT_INTERNAL_VAR_SWEEP_GRADIENT`. (read_color_line): New parameter `read_variable`; update callers. (read_paint): Handle new enumerations. --- include/freetype/ftcolor.h | 13 ++++++-- src/sfnt/ttcolr.c | 64 +++++++++++++++++++++++++++++++++----- 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/include/freetype/ftcolor.h b/include/freetype/ftcolor.h index 13285683f..17f1dd89c 100644 --- a/include/freetype/ftcolor.h +++ b/include/freetype/ftcolor.h @@ -521,9 +521,10 @@ FT_BEGIN_HEADER * * @description: * This iterator object is needed for @FT_Get_Colorline_Stops. It keeps - * state while iterating over the stops of an @FT_ColorLine, - * representing the `ColorLine` struct of the v1 extensions to 'COLR', - * see 'https://github.com/googlefonts/colr-gradients-spec'. + * state while iterating over the stops of an @FT_ColorLine, representing + * the `ColorLine` struct of the v1 extensions to 'COLR', see + * 'https://github.com/googlefonts/colr-gradients-spec'. Do not manually + * modify fields of this iterator. * * @fields: * num_color_stops :: @@ -537,6 +538,10 @@ FT_BEGIN_HEADER * An opaque pointer into 'COLR' table data. Set by @FT_Get_Paint. * Updated by @FT_Get_Colorline_Stops. * + * read_variable :: + * A boolean keeping track of whether variable color lines are to be + * read. Set by @FT_Get_Paint. + * * @since: * 2.11 -- **currently experimental only!** There might be changes * without retaining backward compatibility of both the API and ABI. @@ -549,6 +554,8 @@ FT_BEGIN_HEADER FT_Byte* p; + FT_Bool read_variable; + } FT_ColorStopIterator; diff --git a/src/sfnt/ttcolr.c b/src/sfnt/ttcolr.c index f10113eb2..e8a3d65ac 100644 --- a/src/sfnt/ttcolr.c +++ b/src/sfnt/ttcolr.c @@ -66,6 +66,9 @@ typedef enum FT_PaintFormat_Internal_ { FT_COLR_PAINTFORMAT_INTERNAL_VAR_SOLID = 3, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_LINEAR_GRADIENT = 5, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_RADIAL_GRADIENT = 7, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SWEEP_GRADIENT = 9, FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER = 18, FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM = 20, FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER = 22, @@ -477,8 +480,9 @@ static FT_Bool - read_color_line( FT_Byte* color_line_p, - FT_ColorLine *colorline ) + read_color_line( FT_Byte* color_line_p, + FT_ColorLine* colorline, + FT_Bool read_variable ) { FT_Byte* p = color_line_p; FT_PaintExtend paint_extend; @@ -493,6 +497,7 @@ colorline->color_stop_iterator.num_color_stops = FT_NEXT_USHORT( p ); colorline->color_stop_iterator.p = p; colorline->color_stop_iterator.current_color_stop = 0; + colorline->color_stop_iterator.read_variable = read_variable; return 1; } @@ -604,6 +609,7 @@ { FT_Byte* paint_base = p; FT_Byte* child_table_p = NULL; + FT_Bool do_read_var = FALSE; FT_ULong var_index_base = 0; /* Longest varIndexBase offset is 5 in the spec. */ FT_ItemVarDelta item_deltas[6] = { 0, 0, 0, 0, 0, 0 }; @@ -691,10 +697,14 @@ if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) ) return 0; - if ( apaint->format == FT_COLR_PAINTFORMAT_LINEAR_GRADIENT ) + if ( apaint->format == FT_COLR_PAINTFORMAT_LINEAR_GRADIENT || + ( do_read_var = + ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_LINEAR_GRADIENT ) ) ) { if ( !read_color_line( child_table_p, - &apaint->u.linear_gradient.colorline ) ) + &apaint->u.linear_gradient.colorline, + do_read_var ) ) return 0; /* @@ -708,16 +718,22 @@ apaint->u.linear_gradient.p2.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); apaint->u.linear_gradient.p2.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->format = FT_COLR_PAINTFORMAT_LINEAR_GRADIENT; + return 1; } - else if ( apaint->format == FT_COLR_PAINTFORMAT_RADIAL_GRADIENT ) + else if ( apaint->format == FT_COLR_PAINTFORMAT_RADIAL_GRADIENT || + ( do_read_var = + ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_RADIAL_GRADIENT ) ) ) { FT_Pos tmp; if ( !read_color_line( child_table_p, - &apaint->u.radial_gradient.colorline ) ) + &apaint->u.radial_gradient.colorline, + do_read_var ) ) return 0; /* In the OpenType specification, `r0` and `r1` are defined as */ @@ -737,13 +753,19 @@ tmp = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); apaint->u.radial_gradient.r1 = tmp < 0 ? FT_INT_MAX : tmp; + apaint->format = FT_COLR_PAINTFORMAT_RADIAL_GRADIENT; + return 1; } - else if ( apaint->format == FT_COLR_PAINTFORMAT_SWEEP_GRADIENT ) + else if ( apaint->format == FT_COLR_PAINTFORMAT_SWEEP_GRADIENT || + ( do_read_var = + ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SWEEP_GRADIENT ) ) ) { if ( !read_color_line( child_table_p, - &apaint->u.sweep_gradient.colorline ) ) + &apaint->u.sweep_gradient.colorline, + do_read_var) ) return 0; apaint->u.sweep_gradient.center.x = @@ -756,6 +778,8 @@ apaint->u.sweep_gradient.end_angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->format = FT_COLR_PAINTFORMAT_SWEEP_GRADIENT; + return 1; } @@ -1228,6 +1252,8 @@ Colr* colr = (Colr*)face->colr; FT_Byte* p; + FT_Long var_index_base; + FT_Int item_deltas[2]; if ( !colr || !colr->table ) @@ -1251,6 +1277,28 @@ color_stop->color.alpha = FT_NEXT_SHORT( p ); + if ( iterator->read_variable ) + { + /* Pointer p needs to be advanced independently of whether we intend */ + /* to take variable deltas into account or not. Otherwise iteration */ + /* would fail due to wrong offsets. */ + var_index_base = FT_NEXT_ULONG( p ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( VARIABLE_COLRV1_ENABLED ) + { + if ( !get_deltas_for_var_index_base( face, colr, + var_index_base, + 2, + item_deltas ) ) + return 0; + + color_stop->stop_offset += (FT_Fixed)item_deltas[0] << 2; + color_stop->color.alpha += item_deltas[1]; + } +#endif + } + iterator->p = p; iterator->current_color_stop++;