diff options
Diffstat (limited to 'chromium/third_party/freetype/src/src/sfnt/ttcolr.c')
-rw-r--r-- | chromium/third_party/freetype/src/src/sfnt/ttcolr.c | 638 |
1 files changed, 593 insertions, 45 deletions
diff --git a/chromium/third_party/freetype/src/src/sfnt/ttcolr.c b/chromium/third_party/freetype/src/src/sfnt/ttcolr.c index d54231fd647..25051a49cf7 100644 --- a/chromium/third_party/freetype/src/src/sfnt/ttcolr.c +++ b/chromium/third_party/freetype/src/src/sfnt/ttcolr.c @@ -34,6 +34,16 @@ #include <freetype/ftcolor.h> #include <freetype/config/integer-types.h> +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include <freetype/internal/services/svmm.h> +#endif + + /* the next two code lines are a temporary hack, to be removed together */ + /* with `VARIABLE_COLRV1_ENABLED` and related code as soon as variable */ + /* 'COLR' support is complete and tested */ +#include "../truetype/ttobjs.h" +#include "../truetype/ttdriver.h" + #ifdef TT_CONFIG_OPTION_COLOR_LAYERS @@ -50,13 +60,33 @@ #define COLR_HEADER_SIZE 14U +#define VARIABLE_COLRV1_ENABLED \ + ( ((TT_Driver)FT_FACE_DRIVER( face ))->root.clazz == \ + &tt_driver_class && \ + ((TT_Driver)FT_FACE_DRIVER( face ))->enable_variable_colrv1 ) + + typedef enum FT_PaintFormat_Internal_ { - FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER = 18, - FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM = 20, - FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER = 22, - FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER = 26, - FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER = 30 + 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_VAR_TRANSFORM = 13, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSLATE = 15, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE = 17, + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER = 18, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER = 19, + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM = 20, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM = 21, + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER = 22, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER = 23, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE = 25, + FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER = 26, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER = 27, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW = 29, + FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER = 30, + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER = 31, } FT_PaintFormat_Internal; @@ -104,6 +134,12 @@ */ FT_Byte* paints_start_v1; +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + /* Item Variation Store for variable 'COLR' v1. */ + GX_ItemVarStoreRec var_store; + GX_DeltaSetIdxMapRec delta_set_idx_map; +#endif + /* The memory that backs up the `COLR' table. */ void* table; FT_ULong table_size; @@ -139,7 +175,9 @@ FT_ULong base_glyphs_offset_v1, num_base_glyphs_v1; FT_ULong layer_offset_v1, num_layers_v1, clip_list_offset; FT_ULong table_size; - +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + FT_ULong colr_offset_in_stream; +#endif /* `COLR' always needs `CPAL' */ if ( !face->cpal ) @@ -149,6 +187,10 @@ if ( error ) goto NoColr; +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + colr_offset_in_stream = FT_STREAM_POS(); +#endif + if ( table_size < COLR_HEADER_SIZE ) goto InvalidTable; @@ -239,6 +281,66 @@ colr->clip_list = (FT_Byte*)( table + clip_list_offset ); else colr->clip_list = 0; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + colr->var_store.dataCount = 0; + colr->var_store.varData = NULL; + colr->var_store.axisCount = 0; + colr->var_store.regionCount = 0; + colr->var_store.varRegionList = 0; + + colr->delta_set_idx_map.mapCount = 0; + colr->delta_set_idx_map.outerIndex = NULL; + colr->delta_set_idx_map.innerIndex = NULL; + + if ( face->variation_support & TT_FACE_FLAG_VAR_FVAR && + VARIABLE_COLRV1_ENABLED ) + { + FT_ULong var_idx_map_offset, var_store_offset; + + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + + var_idx_map_offset = FT_NEXT_ULONG( p ); + + if ( var_idx_map_offset >= table_size ) + goto InvalidTable; + + var_store_offset = FT_NEXT_ULONG( p ); + if ( var_store_offset >= table_size ) + goto InvalidTable; + + if ( var_store_offset ) + { + /* If variation info has not been initialized yet, try doing so, */ + /* otherwise loading the variation store will fail as it */ + /* requires access to `blend` for checking the number of axes. */ + if ( !face->blend ) + if ( mm->get_mm_var( FT_FACE( face ), NULL ) ) + goto InvalidTable; + + /* Try loading `VarIdxMap` and `VarStore`. */ + error = mm->load_item_var_store( + FT_FACE( face ), + colr_offset_in_stream + var_store_offset, + &colr->var_store ); + if ( error != FT_Err_Ok ) + goto InvalidTable; + } + + if ( colr->var_store.axisCount && var_idx_map_offset ) + { + error = mm->load_delta_set_idx_map( + FT_FACE( face ), + colr_offset_in_stream + var_idx_map_offset, + &colr->delta_set_idx_map, + &colr->var_store, + table_size ); + if ( error != FT_Err_Ok ) + goto InvalidTable; + } + } +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ } colr->base_glyphs = (FT_Byte*)( table + base_glyph_offset ); @@ -251,6 +353,19 @@ return FT_Err_Ok; InvalidTable: +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( VARIABLE_COLRV1_ENABLED ) + { + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + + mm->done_delta_set_idx_map( FT_FACE( face ), + &colr->delta_set_idx_map ); + mm->done_item_var_store( FT_FACE( face ), + &colr->var_store ); + } +#endif + error = FT_THROW( Invalid_Table ); NoColr: @@ -272,6 +387,18 @@ if ( colr ) { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( VARIABLE_COLRV1_ENABLED ) + { + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + + mm->done_delta_set_idx_map( FT_FACE( face ), + &colr->delta_set_idx_map ); + mm->done_item_var_store( FT_FACE( face ), + &colr->var_store ); + } +#endif FT_FRAME_RELEASE( colr->table ); FT_FREE( colr ); } @@ -372,8 +499,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; @@ -388,6 +516,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; } @@ -428,13 +557,83 @@ } +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + static FT_Bool - read_paint( Colr* colr, + get_deltas_for_var_index_base ( TT_Face face, + Colr* colr, + FT_ULong var_index_base, + FT_UInt num_deltas, + FT_ItemVarDelta* deltas ) + { + FT_UInt outer_index = 0; + FT_UInt inner_index = 0; + FT_ULong loop_var_index = var_index_base; + + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + FT_UInt i = 0; + + + if ( !VARIABLE_COLRV1_ENABLED ) + { + FT_ASSERT( 0 ); + return 0; + } + + if ( var_index_base == 0xFFFFFFFF ) + { + for ( i = 0; i < num_deltas; ++i ) + deltas[i] = 0; + return 1; + } + + for ( i = 0; i < num_deltas; ++i ) + { + loop_var_index = var_index_base + i; + + if ( colr->delta_set_idx_map.innerIndex ) + { + if ( loop_var_index >= colr->delta_set_idx_map.mapCount ) + loop_var_index = colr->delta_set_idx_map.mapCount - 1; + + outer_index = colr->delta_set_idx_map.outerIndex[loop_var_index]; + inner_index = colr->delta_set_idx_map.innerIndex[loop_var_index]; + } + else + { + /* TODO: Direct lookup case not implemented or tested yet. */ + FT_ASSERT( 0 ); + return 0; + } + + deltas[i] = mm->get_item_delta( FT_FACE( face ), &colr->var_store, + outer_index, inner_index ); + } + + return 1; + } + +#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ + + + static FT_Bool + read_paint( TT_Face face, + Colr* colr, FT_Byte* p, FT_COLR_Paint* apaint ) { - FT_Byte* paint_base = p; - FT_Byte* child_table_p = NULL; + FT_Byte* paint_base = p; + FT_Byte* child_table_p = NULL; + FT_Bool do_read_var = FALSE; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + 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 }; +#else + FT_UNUSED( face ); +#endif if ( !p || !colr || !colr->table ) @@ -475,11 +674,30 @@ return 1; } - else if ( apaint->format == FT_COLR_PAINTFORMAT_SOLID ) + else if ( apaint->format == FT_COLR_PAINTFORMAT_SOLID || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SOLID ) { apaint->u.solid.color.palette_index = FT_NEXT_USHORT( p ); apaint->u.solid.color.alpha = FT_NEXT_SHORT( p ); +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SOLID && + VARIABLE_COLRV1_ENABLED ) + { + var_index_base = FT_NEXT_ULONG( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 1, + item_deltas ) ) + return 0; + + apaint->u.solid.color.alpha += item_deltas[0]; + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_SOLID; + return 1; } @@ -500,10 +718,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; /* @@ -517,16 +739,40 @@ 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 ) ); +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( do_read_var && VARIABLE_COLRV1_ENABLED ) + { + var_index_base = FT_NEXT_ULONG ( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 6, + item_deltas ) ) + return 0; + + apaint->u.linear_gradient.p0.x += INT_TO_FIXED( item_deltas[0] ); + apaint->u.linear_gradient.p0.y += INT_TO_FIXED( item_deltas[1] ); + apaint->u.linear_gradient.p1.x += INT_TO_FIXED( item_deltas[2] ); + apaint->u.linear_gradient.p1.y += INT_TO_FIXED( item_deltas[3] ); + apaint->u.linear_gradient.p2.x += INT_TO_FIXED( item_deltas[4] ); + apaint->u.linear_gradient.p2.y += INT_TO_FIXED( item_deltas[5] ); + } +#endif + + 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 */ @@ -546,13 +792,41 @@ tmp = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); apaint->u.radial_gradient.r1 = tmp < 0 ? FT_INT_MAX : tmp; +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( do_read_var && VARIABLE_COLRV1_ENABLED ) + { + var_index_base = FT_NEXT_ULONG ( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 6, + item_deltas ) ) + return 0; + + apaint->u.radial_gradient.c0.x += INT_TO_FIXED( item_deltas[0] ); + apaint->u.radial_gradient.c0.y += INT_TO_FIXED( item_deltas[1] ); + + // TODO: Anything to be done about UFWORD deltas here? + apaint->u.radial_gradient.r0 += INT_TO_FIXED( item_deltas[2] ); + + apaint->u.radial_gradient.c1.x += INT_TO_FIXED( item_deltas[3] ); + apaint->u.radial_gradient.c1.y += INT_TO_FIXED( item_deltas[4] ); + + apaint->u.radial_gradient.r1 += INT_TO_FIXED( item_deltas[5] ); + } +#endif + + 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 = @@ -565,6 +839,27 @@ apaint->u.sweep_gradient.end_angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( do_read_var && VARIABLE_COLRV1_ENABLED ) + { + var_index_base = FT_NEXT_ULONG ( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 4, + item_deltas ) ) + return 0; + + // TODO: Handle overflow? + apaint->u.sweep_gradient.center.x += INT_TO_FIXED( item_deltas[0] ); + apaint->u.sweep_gradient.center.y += INT_TO_FIXED( item_deltas[1] ); + + apaint->u.sweep_gradient.start_angle += + F2DOT14_TO_FIXED( item_deltas[2] ); + apaint->u.sweep_gradient.end_angle += + F2DOT14_TO_FIXED( item_deltas[3] ); + } +#endif + apaint->format = FT_COLR_PAINTFORMAT_SWEEP_GRADIENT; + return 1; } @@ -577,7 +872,9 @@ return 1; } - else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSFORM ) + else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSFORM || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSFORM ) { apaint->u.transform.paint.p = child_table_p; apaint->u.transform.paint.insert_root_transform = 0; @@ -598,10 +895,34 @@ apaint->u.transform.affine.dx = FT_NEXT_LONG( p ); apaint->u.transform.affine.dy = FT_NEXT_LONG( p ); +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSFORM && + VARIABLE_COLRV1_ENABLED ) + { + var_index_base = FT_NEXT_ULONG( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 6, + item_deltas ) ) + return 0; + + apaint->u.transform.affine.xx += (FT_Fixed)item_deltas[0]; + apaint->u.transform.affine.yx += (FT_Fixed)item_deltas[1]; + apaint->u.transform.affine.xy += (FT_Fixed)item_deltas[2]; + apaint->u.transform.affine.yy += (FT_Fixed)item_deltas[3]; + apaint->u.transform.affine.dx += (FT_Fixed)item_deltas[4]; + apaint->u.transform.affine.dy += (FT_Fixed)item_deltas[5]; + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_TRANSFORM; + return 1; } - else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSLATE ) + else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSLATE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSLATE ) { apaint->u.translate.paint.p = child_table_p; apaint->u.translate.paint.insert_root_transform = 0; @@ -609,17 +930,30 @@ apaint->u.translate.dx = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); apaint->u.translate.dy = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSLATE && + VARIABLE_COLRV1_ENABLED ) + { + var_index_base = FT_NEXT_ULONG( p ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 2, + item_deltas ) ) + return 0; + + apaint->u.translate.dx += INT_TO_FIXED( item_deltas[0] ); + apaint->u.translate.dy += INT_TO_FIXED( item_deltas[1] ); + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_TRANSLATE; + return 1; } - else if ( apaint->format == - FT_COLR_PAINTFORMAT_SCALE || - (FT_PaintFormat_Internal)apaint->format == - FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER || - (FT_PaintFormat_Internal)apaint->format == - FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM || - (FT_PaintFormat_Internal)apaint->format == - FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER ) + else if ( apaint->format >= FT_COLR_PAINTFORMAT_SCALE && + (FT_PaintFormat_Internal)apaint->format <= + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER ) { apaint->u.scale.paint.p = child_table_p; apaint->u.scale.paint.insert_root_transform = 0; @@ -628,10 +962,13 @@ apaint->u.scale.scale_x = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); /* Non-uniform ones read an extra y value. */ - if ( apaint->format == - FT_COLR_PAINTFORMAT_SCALE || + if ( apaint->format == FT_COLR_PAINTFORMAT_SCALE || (FT_PaintFormat_Internal)apaint->format == - FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER ) + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER ) apaint->u.scale.scale_y = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); else apaint->u.scale.scale_y = apaint->u.scale.scale_x; @@ -639,9 +976,13 @@ /* Scale paints that have a center read center coordinates, */ /* otherwise the center is (0,0). */ if ( (FT_PaintFormat_Internal)apaint->format == - FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER || + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER || (FT_PaintFormat_Internal)apaint->format == - FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER ) + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER ) { apaint->u.scale.center_x = INT_TO_FIXED( FT_NEXT_SHORT ( p ) ); apaint->u.scale.center_y = INT_TO_FIXED( FT_NEXT_SHORT ( p ) ); @@ -652,6 +993,71 @@ apaint->u.scale.center_y = 0; } + /* Base values set, now handle variations. */ + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER ) && + VARIABLE_COLRV1_ENABLED ) + { + var_index_base = FT_NEXT_ULONG( p ); + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 2, + item_deltas ) ) + return 0; + + apaint->u.scale.scale_x += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.scale.scale_y += F2DOT14_TO_FIXED( item_deltas[1] ); + } + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 4, + item_deltas ) ) + return 0; + + apaint->u.scale.scale_x += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.scale.scale_y += F2DOT14_TO_FIXED( item_deltas[1] ); + apaint->u.scale.center_x += INT_TO_FIXED( item_deltas[2] ); + apaint->u.scale.center_y += INT_TO_FIXED( item_deltas[3] ); + } + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 1, + item_deltas ) ) + return 0; + + apaint->u.scale.scale_x += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.scale.scale_y += F2DOT14_TO_FIXED( item_deltas[0] ); + } + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 3, + item_deltas ) ) + return 0; + + apaint->u.scale.scale_x += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.scale.scale_y += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.scale.center_x += INT_TO_FIXED( item_deltas[1] ); + apaint->u.scale.center_y += INT_TO_FIXED( item_deltas[2] ); + } + } +#endif + /* FT 'COLR' v1 API output format always returns fully defined */ /* structs; we thus set the format to the public API value. */ apaint->format = FT_COLR_PAINTFORMAT_SCALE; @@ -659,9 +1065,13 @@ return 1; } - else if ( apaint->format == FT_COLR_PAINTFORMAT_ROTATE || + else if ( apaint->format == FT_COLR_PAINTFORMAT_ROTATE || (FT_PaintFormat_Internal)apaint->format == - FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER ) + FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER ) { apaint->u.rotate.paint.p = child_table_p; apaint->u.rotate.paint.insert_root_transform = 0; @@ -669,7 +1079,9 @@ apaint->u.rotate.angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); if ( (FT_PaintFormat_Internal)apaint->format == - FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER ) + FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER ) { apaint->u.rotate.center_x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); apaint->u.rotate.center_y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); @@ -680,14 +1092,55 @@ apaint->u.rotate.center_y = 0; } +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER ) && + VARIABLE_COLRV1_ENABLED ) + { + FT_UInt num_deltas = 0; + + + var_index_base = FT_NEXT_ULONG( p ); + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER ) + num_deltas = 3; + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE ) + num_deltas = 1; + + if ( num_deltas > 0 ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, + num_deltas, item_deltas ) ) + return 0; + + apaint->u.rotate.angle += F2DOT14_TO_FIXED( item_deltas[0] ); + + if ( num_deltas == 3 ) + { + apaint->u.rotate.center_x += INT_TO_FIXED( item_deltas[1] ); + apaint->u.rotate.center_y += INT_TO_FIXED( item_deltas[2] ); + } + } + } +#endif + apaint->format = FT_COLR_PAINTFORMAT_ROTATE; + return 1; } - else if ( apaint->format == FT_COLR_PAINTFORMAT_SKEW || + else if ( apaint->format == FT_COLR_PAINTFORMAT_SKEW || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW || (FT_PaintFormat_Internal)apaint->format == - FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER ) + FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER ) { apaint->u.skew.paint.p = child_table_p; apaint->u.skew.paint.insert_root_transform = 0; @@ -696,7 +1149,9 @@ apaint->u.skew.y_skew_angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); if ( (FT_PaintFormat_Internal)apaint->format == - FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER ) + FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER ) { apaint->u.skew.center_x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); apaint->u.skew.center_y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); @@ -707,6 +1162,42 @@ apaint->u.skew.center_y = 0; } + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER ) && + VARIABLE_COLRV1_ENABLED ) + { + var_index_base = FT_NEXT_ULONG( p ); + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 2, + item_deltas ) ) + return 0; + + apaint->u.skew.x_skew_angle += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.skew.y_skew_angle += F2DOT14_TO_FIXED( item_deltas[1] ); + } + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER ) + { + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 4, + item_deltas ) ) + return 0; + + apaint->u.skew.x_skew_angle += F2DOT14_TO_FIXED( item_deltas[0] ); + apaint->u.skew.y_skew_angle += F2DOT14_TO_FIXED( item_deltas[1] ); + apaint->u.skew.center_x += INT_TO_FIXED( item_deltas[2] ); + apaint->u.skew.center_y += INT_TO_FIXED( item_deltas[3] ); + } + } +#endif + apaint->format = FT_COLR_PAINTFORMAT_SKEW; return 1; @@ -871,7 +1362,7 @@ clip_list_format = FT_NEXT_BYTE ( p ); /* Format byte used here to be able to upgrade ClipList for >16bit */ - /* glyph ids; for now we can expect it to be 0. */ + /* glyph ids; for now we can expect it to be 1. */ if ( !( clip_list_format == 1 ) ) return 0; @@ -899,7 +1390,7 @@ format = FT_NEXT_BYTE( p1 ); - if ( format > 1 ) + if ( format > 2 ) return 0; /* Check whether we can extract four `FWORD`. */ @@ -913,11 +1404,40 @@ font_clip_box.xMin = FT_MulFix( FT_NEXT_SHORT( p1 ), face->root.size->metrics.x_scale ); font_clip_box.yMin = FT_MulFix( FT_NEXT_SHORT( p1 ), - face->root.size->metrics.x_scale ); + face->root.size->metrics.y_scale ); font_clip_box.xMax = FT_MulFix( FT_NEXT_SHORT( p1 ), face->root.size->metrics.x_scale ); font_clip_box.yMax = FT_MulFix( FT_NEXT_SHORT( p1 ), - face->root.size->metrics.x_scale ); + face->root.size->metrics.y_scale ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( VARIABLE_COLRV1_ENABLED && format == 2 ) + { + FT_ULong var_index_base = 0; + /* varIndexBase offset for clipbox is 3 at most. */ + FT_ItemVarDelta item_deltas[4] = { 0, 0, 0, 0 }; + + + /* Check whether we can extract a 32-bit VarIdxBase now. */ + if ( p1 > limit - 4 ) + return 0; + + var_index_base = FT_NEXT_ULONG( p1 ); + + if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 4, + item_deltas ) ) + return 0; + + font_clip_box.xMin += + FT_MulFix( item_deltas[0], face->root.size->metrics.x_scale ); + font_clip_box.yMin += + FT_MulFix( item_deltas[1], face->root.size->metrics.y_scale ); + font_clip_box.xMax += + FT_MulFix( item_deltas[2], face->root.size->metrics.x_scale ); + font_clip_box.yMax += + FT_MulFix( item_deltas[3], face->root.size->metrics.y_scale ); + } +#endif /* Make 4 corner points (xMin, yMin), (xMax, yMax) and transform */ /* them. If we we would only transform two corner points and */ @@ -1037,6 +1557,7 @@ Colr* colr = (Colr*)face->colr; FT_Byte* p; + FT_ULong var_index_base; if ( !colr || !colr->table ) @@ -1054,12 +1575,39 @@ /* Iterator points at first `ColorStop` of `ColorLine`. */ p = iterator->p; - color_stop->stop_offset = FT_NEXT_SHORT( p ); + color_stop->stop_offset = (FT_Fixed)FT_NEXT_SHORT( p ) << 2; color_stop->color.palette_index = FT_NEXT_USHORT( p ); 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 ) + { + FT_Int item_deltas[2]; + + + 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]; + } +#else + FT_UNUSED( var_index_base ); +#endif + } + iterator->p = p; iterator->current_color_stop++; @@ -1139,7 +1687,7 @@ return 1; } - return read_paint( colr, opaque_paint.p, paint ); + return read_paint( face, colr, opaque_paint.p, paint ); } |