diff options
Diffstat (limited to 'src/3rdparty/freetype/src/sfnt')
37 files changed, 3008 insertions, 906 deletions
diff --git a/src/3rdparty/freetype/src/sfnt/module.mk b/src/3rdparty/freetype/src/sfnt/module.mk index 0f459d8421..4491a1b22f 100644 --- a/src/3rdparty/freetype/src/sfnt/module.mk +++ b/src/3rdparty/freetype/src/sfnt/module.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2020 by +# Copyright (C) 1996-2023 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/src/3rdparty/freetype/src/sfnt/pngshim.c b/src/3rdparty/freetype/src/sfnt/pngshim.c index 1bd3a7eeb5..33712162e0 100644 --- a/src/3rdparty/freetype/src/sfnt/pngshim.c +++ b/src/3rdparty/freetype/src/sfnt/pngshim.c @@ -4,7 +4,7 @@ * * PNG Bitmap glyph support. * - * Copyright (C) 2013-2020 by + * Copyright (C) 2013-2023 by * Google, Inc. * Written by Stuart Gill and Behdad Esfahbod. * @@ -72,7 +72,6 @@ ( ( __clang_major__ >= 4 ) || \ ( ( __clang_major__ == 3 ) && ( __clang_minor__ >= 2 ) ) ) ) ) && \ defined( __OPTIMIZE__ ) && \ - !defined( __EMSCRIPTEN__ ) && \ defined( __SSE__ ) && \ __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ @@ -240,7 +239,7 @@ *e = FT_THROW( Invalid_Stream_Read ); png_error( png, NULL ); - return; + /* return; (never reached) */ } ft_memcpy( data, stream->cursor, length ); @@ -271,7 +270,10 @@ int bitdepth, color_type, interlace; FT_Int i; - png_byte* *rows = NULL; /* pacify compiler */ + + /* `rows` gets modified within a 'setjmp' scope; */ + /* we thus need the `volatile` keyword. */ + png_byte* *volatile rows = NULL; if ( x_offset < 0 || @@ -365,7 +367,7 @@ } /* transform transparency to alpha */ - if ( png_get_valid(png, info, PNG_INFO_tRNS ) ) + if ( png_get_valid( png, info, PNG_INFO_tRNS ) ) png_set_tRNS_to_alpha( png ); if ( bitdepth == 16 ) @@ -385,7 +387,7 @@ png_set_filler( png, 0xFF, PNG_FILLER_AFTER ); /* recheck header after setting EXPAND options */ - png_read_update_info(png, info ); + png_read_update_info( png, info ); png_get_IHDR( png, info, &imgWidth, &imgHeight, &bitdepth, &color_type, &interlace, @@ -404,9 +406,7 @@ switch ( color_type ) { - default: - /* Shouldn't happen, but fall through. */ - + default: /* Shouldn't happen, but ... */ case PNG_COLOR_TYPE_RGB_ALPHA: png_set_read_user_transform_fn( png, premultiply_data ); break; @@ -428,7 +428,7 @@ goto DestroyExit; } - if ( FT_NEW_ARRAY( rows, imgHeight ) ) + if ( FT_QNEW_ARRAY( rows, imgHeight ) ) { error = FT_THROW( Out_Of_Memory ); goto DestroyExit; @@ -439,11 +439,11 @@ png_read_image( png, rows ); - FT_FREE( rows ); - png_read_end( png, info ); DestroyExit: + /* even if reading fails with longjmp, rows must be freed */ + FT_FREE( rows ); png_destroy_read_struct( &png, &info, NULL ); FT_Stream_Close( &stream ); @@ -454,7 +454,7 @@ #else /* !(TT_CONFIG_OPTION_EMBEDDED_BITMAPS && FT_CONFIG_OPTION_USE_PNG) */ /* ANSI C doesn't like empty source files */ - typedef int _pngshim_dummy; + typedef int pngshim_dummy_; #endif /* !(TT_CONFIG_OPTION_EMBEDDED_BITMAPS && FT_CONFIG_OPTION_USE_PNG) */ diff --git a/src/3rdparty/freetype/src/sfnt/pngshim.h b/src/3rdparty/freetype/src/sfnt/pngshim.h index 2d6e83d69b..903bd2bc34 100644 --- a/src/3rdparty/freetype/src/sfnt/pngshim.h +++ b/src/3rdparty/freetype/src/sfnt/pngshim.h @@ -4,7 +4,7 @@ * * PNG Bitmap glyph support. * - * Copyright (C) 2013-2020 by + * Copyright (C) 2013-2023 by * Google, Inc. * Written by Stuart Gill and Behdad Esfahbod. * diff --git a/src/3rdparty/freetype/src/sfnt/rules.mk b/src/3rdparty/freetype/src/sfnt/rules.mk index f56ef060ed..4d2d7e8d84 100644 --- a/src/3rdparty/freetype/src/sfnt/rules.mk +++ b/src/3rdparty/freetype/src/sfnt/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2020 by +# Copyright (C) 1996-2023 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, @@ -36,6 +36,7 @@ SFNT_DRV_SRC := $(SFNT_DIR)/pngshim.c \ $(SFNT_DIR)/ttbdf.c \ $(SFNT_DIR)/ttcmap.c \ $(SFNT_DIR)/ttcolr.c \ + $(SFNT_DIR)/ttsvg.c \ $(SFNT_DIR)/ttcpal.c \ $(SFNT_DIR)/ttkern.c \ $(SFNT_DIR)/ttload.c \ diff --git a/src/3rdparty/freetype/src/sfnt/sfdriver.c b/src/3rdparty/freetype/src/sfnt/sfdriver.c index 0460339a74..0925940b03 100644 --- a/src/3rdparty/freetype/src/sfnt/sfdriver.c +++ b/src/3rdparty/freetype/src/sfnt/sfdriver.c @@ -4,7 +4,7 @@ * * High-level SFNT driver interface (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -36,6 +36,10 @@ #include "ttcpal.h" #endif +#ifdef FT_CONFIG_OPTION_SVG +#include "ttsvg.h" +#endif + #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES #include "ttpost.h" #endif @@ -75,41 +79,57 @@ * */ - static void* - get_sfnt_table( TT_Face face, + FT_CALLBACK_DEF( FT_Error ) + sfnt_load_table( FT_Face face, /* TT_Face */ + FT_ULong tag, + FT_Long offset, + FT_Byte* buffer, + FT_ULong* length ) + { + TT_Face ttface = (TT_Face)face; + + + return tt_face_load_any( ttface, tag, offset, buffer, length ); + } + + + FT_CALLBACK_DEF( void* ) + get_sfnt_table( FT_Face face, /* TT_Face */ FT_Sfnt_Tag tag ) { + TT_Face ttface = (TT_Face)face; + void* table; switch ( tag ) { case FT_SFNT_HEAD: - table = &face->header; + table = &ttface->header; break; case FT_SFNT_HHEA: - table = &face->horizontal; + table = &ttface->horizontal; break; case FT_SFNT_VHEA: - table = face->vertical_info ? &face->vertical : NULL; + table = ttface->vertical_info ? &ttface->vertical : NULL; break; case FT_SFNT_OS2: - table = ( face->os2.version == 0xFFFFU ) ? NULL : &face->os2; + table = ( ttface->os2.version == 0xFFFFU ) ? NULL : &ttface->os2; break; case FT_SFNT_POST: - table = &face->postscript; + table = &ttface->postscript; break; case FT_SFNT_MAXP: - table = &face->max_profile; + table = &ttface->max_profile; break; case FT_SFNT_PCLT: - table = face->pclt.Version ? &face->pclt : NULL; + table = ttface->pclt.Version ? &ttface->pclt : NULL; break; default: @@ -120,26 +140,29 @@ } - static FT_Error - sfnt_table_info( TT_Face face, + FT_CALLBACK_DEF( FT_Error ) + sfnt_table_info( FT_Face face, /* TT_Face */ FT_UInt idx, FT_ULong *tag, FT_ULong *offset, FT_ULong *length ) { + TT_Face ttface = (TT_Face)face; + + if ( !offset || !length ) return FT_THROW( Invalid_Argument ); if ( !tag ) - *length = face->num_tables; + *length = ttface->num_tables; else { - if ( idx >= face->num_tables ) + if ( idx >= ttface->num_tables ) return FT_THROW( Table_Missing ); - *tag = face->dir_tables[idx].Tag; - *offset = face->dir_tables[idx].Offset; - *length = face->dir_tables[idx].Length; + *tag = ttface->dir_tables[idx].Tag; + *offset = ttface->dir_tables[idx].Offset; + *length = ttface->dir_tables[idx].Length; } return FT_Err_Ok; @@ -149,9 +172,9 @@ FT_DEFINE_SERVICE_SFNT_TABLEREC( sfnt_service_sfnt_table, - (FT_SFNT_TableLoadFunc)tt_face_load_any, /* load_table */ - (FT_SFNT_TableGetFunc) get_sfnt_table, /* get_table */ - (FT_SFNT_TableInfoFunc)sfnt_table_info /* table_info */ + sfnt_load_table, /* FT_SFNT_TableLoadFunc load_table */ + get_sfnt_table, /* FT_SFNT_TableGetFunc get_table */ + sfnt_table_info /* FT_SFNT_TableInfoFunc table_info */ ) @@ -162,7 +185,7 @@ * */ - static FT_Error + FT_CALLBACK_DEF( FT_Error ) sfnt_get_glyph_name( FT_Face face, FT_UInt glyph_index, FT_Pointer buffer, @@ -180,7 +203,7 @@ } - static FT_UInt + FT_CALLBACK_DEF( FT_UInt ) sfnt_get_name_index( FT_Face face, const FT_String* glyph_name ) { @@ -217,8 +240,8 @@ FT_DEFINE_SERVICE_GLYPHDICTREC( sfnt_service_glyph_dict, - (FT_GlyphDict_GetNameFunc) sfnt_get_glyph_name, /* get_name */ - (FT_GlyphDict_NameIndexFunc)sfnt_get_name_index /* name_index */ + sfnt_get_glyph_name, /* FT_GlyphDict_GetNameFunc get_name */ + sfnt_get_name_index /* FT_GlyphDict_NameIndexFunc name_index */ ) #endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ @@ -374,61 +397,61 @@ { case 15: k4 ^= (FT_UInt32)tail[14] << 16; - /* fall through */ + FALL_THROUGH; case 14: k4 ^= (FT_UInt32)tail[13] << 8; - /* fall through */ + FALL_THROUGH; case 13: k4 ^= (FT_UInt32)tail[12]; k4 *= c4; k4 = ROTL32( k4, 18 ); k4 *= c1; h4 ^= k4; - /* fall through */ + FALL_THROUGH; case 12: k3 ^= (FT_UInt32)tail[11] << 24; - /* fall through */ + FALL_THROUGH; case 11: k3 ^= (FT_UInt32)tail[10] << 16; - /* fall through */ + FALL_THROUGH; case 10: k3 ^= (FT_UInt32)tail[9] << 8; - /* fall through */ + FALL_THROUGH; case 9: k3 ^= (FT_UInt32)tail[8]; k3 *= c3; k3 = ROTL32( k3, 17 ); k3 *= c4; h3 ^= k3; - /* fall through */ + FALL_THROUGH; case 8: k2 ^= (FT_UInt32)tail[7] << 24; - /* fall through */ + FALL_THROUGH; case 7: k2 ^= (FT_UInt32)tail[6] << 16; - /* fall through */ + FALL_THROUGH; case 6: k2 ^= (FT_UInt32)tail[5] << 8; - /* fall through */ + FALL_THROUGH; case 5: k2 ^= (FT_UInt32)tail[4]; k2 *= c2; k2 = ROTL32( k2, 16 ); k2 *= c3; h2 ^= k2; - /* fall through */ + FALL_THROUGH; case 4: k1 ^= (FT_UInt32)tail[3] << 24; - /* fall through */ + FALL_THROUGH; case 3: k1 ^= (FT_UInt32)tail[2] << 16; - /* fall through */ + FALL_THROUGH; case 2: k1 ^= (FT_UInt32)tail[1] << 8; - /* fall through */ + FALL_THROUGH; case 1: k1 ^= (FT_UInt32)tail[0]; k1 *= c1; @@ -491,17 +514,15 @@ char_type_func char_type, FT_Bool report_invalid_characters ) { - FT_Error error = FT_Err_Ok; + FT_Error error; char* result = NULL; FT_String* r; FT_Char* p; FT_UInt len; - FT_UNUSED( error ); - - if ( FT_ALLOC( result, entry->stringLength / 2 + 1 ) ) + if ( FT_QALLOC( result, entry->stringLength / 2 + 1 ) ) return NULL; if ( FT_STREAM_SEEK( entry->stringOffset ) || @@ -521,15 +542,14 @@ FT_TRACE0(( "get_win_string:" " Character 0x%X invalid in PS name string\n", ((unsigned)p[0])*256 + (unsigned)p[1] )); - break; + continue; } } - if ( !len ) - *r = '\0'; + *r = '\0'; FT_FRAME_EXIT(); - if ( !len ) + if ( r != result ) return result; get_win_string_error: @@ -550,17 +570,15 @@ char_type_func char_type, FT_Bool report_invalid_characters ) { - FT_Error error = FT_Err_Ok; + FT_Error error; char* result = NULL; FT_String* r; FT_Char* p; FT_UInt len; - FT_UNUSED( error ); - - if ( FT_ALLOC( result, entry->stringLength + 1 ) ) + if ( FT_QALLOC( result, entry->stringLength + 1 ) ) return NULL; if ( FT_STREAM_SEEK( entry->stringOffset ) || @@ -580,15 +598,14 @@ FT_TRACE0(( "get_apple_string:" " Character `%c' (0x%X) invalid in PS name string\n", *p, *p )); - break; + continue; } } - if ( !len ) - *r = '\0'; + *r = '\0'; FT_FRAME_EXIT(); - if ( !len ) + if ( r != result ) return result; get_apple_string_error: @@ -602,7 +619,7 @@ } - static FT_Bool + FT_CALLBACK_DEF( FT_Bool ) sfnt_get_name_id( TT_Face face, FT_UShort id, FT_Int *win, @@ -657,7 +674,7 @@ /* - * Find the shortest decimal representation of a 16.16 fixed point + * Find the shortest decimal representation of a 16.16 fixed-point * number. The function fills `buf' with the result, returning a pointer * to the position after the representation's last byte. */ @@ -733,7 +750,7 @@ an equivalent representation of `fixed'. The above FOR loop always finds the larger of the two values; I - verified this by iterating over all possible fixed point numbers. + verified this by iterating over all possible fixed-point numbers. If the remainder is 17232*10, both values are equally good, and we take the next even number (following IEEE 754's `round to nearest, @@ -741,7 +758,7 @@ If the remainder is smaller than 17232*10, the lower of the two numbers is nearer to the exact result (values 17232 and 34480 were - also found by testing all possible fixed point values). + also found by testing all possible fixed-point values). We use this to find a shorter decimal representation. If not ending with digit zero, we take the representation with less error. @@ -819,9 +836,9 @@ if ( !found ) { - /* as a last resort we try the family name; note that this is */ - /* not in the Adobe TechNote, but GX fonts (which predate the */ - /* TechNote) benefit from this behaviour */ + /* according to the 'name' documentation in the OpenType */ + /* specification the font family name is to be used if the */ + /* typographic family name is missing, so let's do that */ found = sfnt_get_name_id( face, TT_NAME_ID_FONT_FAMILY, &win, @@ -853,6 +870,10 @@ { FT_TRACE0(( "sfnt_get_var_ps_name:" " No valid PS name prefix for font instances found\n" )); + /* XXX It probably makes sense to never let this fail */ + /* since an arbitrary prefix should work, too. */ + /* On the other hand, it is very unlikely that */ + /* we ever reach this code at all. */ return NULL; } @@ -868,8 +889,8 @@ result[len] = '\0'; FT_TRACE0(( "sfnt_get_var_ps_name:" - " Shortening variation PS name prefix\n" - " " + " Shortening variation PS name prefix\n" )); + FT_TRACE0(( " " " to %d characters\n", len )); } @@ -920,16 +941,16 @@ if ( !subfamily_name ) { FT_TRACE1(( "sfnt_get_var_ps_name:" - " can't construct named instance PS name;\n" - " " + " can't construct named instance PS name;\n" )); + FT_TRACE1(( " " " trying to construct normal instance PS name\n" )); goto construct_instance_name; } /* after the prefix we have character `-' followed by the */ /* subfamily name (using only characters a-z, A-Z, and 0-9) */ - if ( FT_ALLOC( result, face->var_postscript_prefix_len + - 1 + ft_strlen( subfamily_name ) + 1 ) ) + if ( FT_QALLOC( result, face->var_postscript_prefix_len + + 1 + ft_strlen( subfamily_name ) + 1 ) ) return NULL; ft_strcpy( result, face->var_postscript_prefix ); @@ -957,9 +978,9 @@ construct_instance_name: axis = mm_var->axis; - if ( FT_ALLOC( result, - face->var_postscript_prefix_len + - num_coords * MAX_VALUE_DESCRIPTOR_LEN + 1 ) ) + if ( FT_QALLOC( result, + face->var_postscript_prefix_len + + num_coords * MAX_VALUE_DESCRIPTOR_LEN + 1 ) ) return NULL; p = result; @@ -993,6 +1014,7 @@ if ( t != ' ' && ft_isalnum( t ) ) *p++ = t; } + *p++ = '\0'; } check_length: @@ -1040,47 +1062,49 @@ #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ - static const char* - sfnt_get_ps_name( TT_Face face ) + FT_CALLBACK_DEF( const char* ) + sfnt_get_ps_name( FT_Face face ) /* TT_Face */ { + TT_Face ttface = (TT_Face)face; + FT_Int found, win, apple; const char* result = NULL; - if ( face->postscript_name ) - return face->postscript_name; + if ( ttface->postscript_name ) + return ttface->postscript_name; #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - if ( face->blend && - ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) || - FT_IS_VARIATION( FT_FACE( face ) ) ) ) + if ( ttface->blend && + ( FT_IS_NAMED_INSTANCE( face ) || + FT_IS_VARIATION( face ) ) ) { - face->postscript_name = sfnt_get_var_ps_name( face ); - return face->postscript_name; + ttface->postscript_name = sfnt_get_var_ps_name( ttface ); + return ttface->postscript_name; } #endif /* scan the name table to see whether we have a Postscript name here, */ /* either in Macintosh or Windows platform encodings */ - found = sfnt_get_name_id( face, TT_NAME_ID_PS_NAME, &win, &apple ); + found = sfnt_get_name_id( ttface, TT_NAME_ID_PS_NAME, &win, &apple ); if ( !found ) return NULL; /* prefer Windows entries over Apple */ if ( win != -1 ) - result = get_win_string( face->root.memory, - face->name_table.stream, - face->name_table.names + win, + result = get_win_string( FT_FACE_MEMORY( face ), + ttface->name_table.stream, + ttface->name_table.names + win, sfnt_is_postscript, 1 ); if ( !result && apple != -1 ) - result = get_apple_string( face->root.memory, - face->name_table.stream, - face->name_table.names + apple, + result = get_apple_string( FT_FACE_MEMORY( face ), + ttface->name_table.stream, + ttface->name_table.names + apple, sfnt_is_postscript, 1 ); - face->postscript_name = result; + ttface->postscript_name = result; return result; } @@ -1089,7 +1113,7 @@ FT_DEFINE_SERVICE_PSFONTNAMEREC( sfnt_service_ps_name, - (FT_PsName_GetFunc)sfnt_get_ps_name /* get_ps_font_name */ + sfnt_get_ps_name /* FT_PsName_GetFunc get_ps_font_name */ ) @@ -1099,14 +1123,14 @@ FT_DEFINE_SERVICE_TTCMAPSREC( tt_service_get_cmap_info, - (TT_CMap_Info_GetFunc)tt_get_cmap_info /* get_cmap_info */ + tt_get_cmap_info /* TT_CMap_Info_GetFunc get_cmap_info */ ) #ifdef TT_CONFIG_OPTION_BDF static FT_Error - sfnt_get_charset_id( TT_Face face, + sfnt_get_charset_id( FT_Face face, const char* *acharset_encoding, const char* *acharset_registry ) { @@ -1144,8 +1168,8 @@ FT_DEFINE_SERVICE_BDFRec( sfnt_service_bdf, - (FT_BDF_GetCharsetIdFunc)sfnt_get_charset_id, /* get_charset_id */ - (FT_BDF_GetPropertyFunc) tt_face_find_bdf_prop /* get_property */ + sfnt_get_charset_id, /* FT_BDF_GetCharsetIdFunc get_charset_id */ + tt_face_find_bdf_prop /* FT_BDF_GetPropertyFunc get_property */ ) @@ -1213,6 +1237,14 @@ #define PUT_COLOR_LAYERS( a ) NULL #endif +#ifdef FT_CONFIG_OPTION_SVG +#define PUT_SVG_SUPPORT( a ) a +#else +#define PUT_SVG_SUPPORT( a ) NULL +#endif + +#define PUT_COLOR_LAYERS_V1( a ) PUT_COLOR_LAYERS( a ) + #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES #define PUT_PS_NAMES( a ) a #else @@ -1271,9 +1303,9 @@ /* TT_Free_Table_Func free_eblc */ PUT_EMBEDDED_BITMAPS( tt_face_set_sbit_strike ), - /* TT_Set_SBit_Strike_Func set_sbit_strike */ + /* TT_Set_SBit_Strike_Func set_sbit_strike */ PUT_EMBEDDED_BITMAPS( tt_face_load_strike_metrics ), - /* TT_Load_Strike_Metrics_Func load_strike_metrics */ + /* TT_Load_Strike_Metrics_Func load_strike_metrics */ PUT_COLOR_LAYERS( tt_face_load_cpal ), /* TT_Load_Table_Func load_cpal */ @@ -1287,13 +1319,32 @@ /* TT_Set_Palette_Func set_palette */ PUT_COLOR_LAYERS( tt_face_get_colr_layer ), /* TT_Get_Colr_Layer_Func get_colr_layer */ + + PUT_COLOR_LAYERS_V1( tt_face_get_colr_glyph_paint ), + /* TT_Get_Color_Glyph_Paint_Func get_colr_glyph_paint */ + PUT_COLOR_LAYERS_V1( tt_face_get_color_glyph_clipbox ), + /* TT_Get_Color_Glyph_ClipBox_Func get_clipbox */ + PUT_COLOR_LAYERS_V1( tt_face_get_paint_layers ), + /* TT_Get_Paint_Layers_Func get_paint_layers */ + PUT_COLOR_LAYERS_V1( tt_face_get_colorline_stops ), + /* TT_Get_Paint get_paint */ + PUT_COLOR_LAYERS_V1( tt_face_get_paint ), + /* TT_Get_Colorline_Stops_Func get_colorline_stops */ + PUT_COLOR_LAYERS( tt_face_colr_blend_layer ), /* TT_Blend_Colr_Func colr_blend */ tt_face_get_metrics, /* TT_Get_Metrics_Func get_metrics */ tt_face_get_name, /* TT_Get_Name_Func get_name */ - sfnt_get_name_id /* TT_Get_Name_ID_Func get_name_id */ + sfnt_get_name_id, /* TT_Get_Name_ID_Func get_name_id */ + + PUT_SVG_SUPPORT( tt_face_load_svg ), + /* TT_Load_Table_Func load_svg */ + PUT_SVG_SUPPORT( tt_face_free_svg ), + /* TT_Free_Table_Func free_svg */ + PUT_SVG_SUPPORT( tt_face_load_svg_doc ) + /* TT_Load_Svg_Doc_Func load_svg_doc */ ) @@ -1309,9 +1360,9 @@ (const void*)&sfnt_interface, /* module specific interface */ - (FT_Module_Constructor)NULL, /* module_init */ - (FT_Module_Destructor) NULL, /* module_done */ - (FT_Module_Requester) sfnt_get_interface /* get_interface */ + NULL, /* FT_Module_Constructor module_init */ + NULL, /* FT_Module_Destructor module_done */ + sfnt_get_interface /* FT_Module_Requester get_interface */ ) diff --git a/src/3rdparty/freetype/src/sfnt/sfdriver.h b/src/3rdparty/freetype/src/sfnt/sfdriver.h index 1ac2706325..2445958b69 100644 --- a/src/3rdparty/freetype/src/sfnt/sfdriver.h +++ b/src/3rdparty/freetype/src/sfnt/sfdriver.h @@ -4,7 +4,7 @@ * * High-level SFNT driver interface (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/3rdparty/freetype/src/sfnt/sferrors.h b/src/3rdparty/freetype/src/sfnt/sferrors.h index 55c3e76b66..e7a8eb04bb 100644 --- a/src/3rdparty/freetype/src/sfnt/sferrors.h +++ b/src/3rdparty/freetype/src/sfnt/sferrors.h @@ -4,7 +4,7 @@ * * SFNT error codes (specification only). * - * Copyright (C) 2001-2020 by + * Copyright (C) 2001-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/3rdparty/freetype/src/sfnt/sfnt.c b/src/3rdparty/freetype/src/sfnt/sfnt.c index 471239ff0b..8e4f08a90c 100644 --- a/src/3rdparty/freetype/src/sfnt/sfnt.c +++ b/src/3rdparty/freetype/src/sfnt/sfnt.c @@ -4,7 +4,7 @@ * * Single object library component. * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -27,6 +27,7 @@ #include "ttcmap.c" #include "ttcolr.c" #include "ttcpal.c" +#include "ttsvg.c" #include "ttkern.c" #include "ttload.c" diff --git a/src/3rdparty/freetype/src/sfnt/sfobjs.c b/src/3rdparty/freetype/src/sfnt/sfobjs.c index 39460be2e6..f5d66ef840 100644 --- a/src/3rdparty/freetype/src/sfnt/sfobjs.c +++ b/src/3rdparty/freetype/src/sfnt/sfobjs.c @@ -4,7 +4,7 @@ * * SFNT object management (base). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -65,7 +65,7 @@ len = (FT_UInt)entry->stringLength / 2; - if ( FT_NEW_ARRAY( string, len + 1 ) ) + if ( FT_QNEW_ARRAY( string, len + 1 ) ) return NULL; for ( n = 0; n < len; n++ ) @@ -100,7 +100,7 @@ len = (FT_UInt)entry->stringLength; - if ( FT_NEW_ARRAY( string, len + 1 ) ) + if ( FT_QNEW_ARRAY( string, len + 1 ) ) return NULL; for ( n = 0; n < len; n++ ) @@ -360,17 +360,27 @@ FT_FRAME_END }; +#ifndef FT_CONFIG_OPTION_USE_BROTLI + FT_UNUSED( face_instance_index ); + FT_UNUSED( woff2_num_faces ); +#endif + face->ttc_header.tag = 0; face->ttc_header.version = 0; face->ttc_header.count = 0; +#if defined( FT_CONFIG_OPTION_USE_ZLIB ) || \ + defined( FT_CONFIG_OPTION_USE_BROTLI ) retry: +#endif + offset = FT_STREAM_POS(); if ( FT_READ_ULONG( tag ) ) return error; +#ifdef FT_CONFIG_OPTION_USE_ZLIB if ( tag == TTAG_wOFF ) { FT_TRACE2(( "sfnt_open_font: file is a WOFF; synthesizing SFNT\n" )); @@ -386,7 +396,9 @@ stream = face->root.stream; goto retry; } +#endif +#ifdef FT_CONFIG_OPTION_USE_BROTLI if ( tag == TTAG_wOF2 ) { FT_TRACE2(( "sfnt_open_font: file is a WOFF2; synthesizing SFNT\n" )); @@ -405,6 +417,7 @@ stream = face->root.stream; goto retry; } +#endif if ( tag != 0x00010000UL && tag != TTAG_ttcf && @@ -446,7 +459,7 @@ return FT_THROW( Array_Too_Large ); /* now read the offsets of each font in the file */ - if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ) + if ( FT_QNEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ) return error; if ( FT_FRAME_ENTER( face->ttc_header.count * 4L ) ) @@ -464,7 +477,7 @@ face->ttc_header.version = 1 << 16; face->ttc_header.count = 1; - if ( FT_NEW( face->ttc_header.offsets ) ) + if ( FT_QNEW( face->ttc_header.offsets ) ) return error; face->ttc_header.offsets[0] = offset; @@ -521,17 +534,23 @@ 0 ); } - if ( !face->var ) + if ( !face->tt_var ) { /* we want the metrics variations interface */ /* from the `truetype' module only */ FT_Module tt_module = FT_Get_Module( library, "truetype" ); - face->var = ft_module_get_service( tt_module, - FT_SERVICE_ID_METRICS_VARIATIONS, - 0 ); + face->tt_var = ft_module_get_service( tt_module, + FT_SERVICE_ID_METRICS_VARIATIONS, + 0 ); } + + if ( !face->face_var ) + face->face_var = ft_module_get_service( + &face->root.driver->root, + FT_SERVICE_ID_METRICS_VARIATIONS, + 0 ); #endif FT_TRACE2(( "SFNT driver\n" )); @@ -553,7 +572,7 @@ face_index = FT_ABS( face_instance_index ) & 0xFFFF; /* value -(N+1) requests information on index N */ - if ( face_instance_index < 0 ) + if ( face_instance_index < 0 && face_index > 0 ) face_index--; if ( face_index >= face->ttc_header.count ) @@ -643,8 +662,8 @@ */ if ( ( face->variation_support & TT_FACE_FLAG_VAR_FVAR ) && - !( FT_ALLOC( default_values, num_axes * 4 ) || - FT_ALLOC( instance_values, num_axes * 4 ) ) ) + !( FT_QALLOC( default_values, num_axes * 4 ) || + FT_QALLOC( instance_values, num_axes * 4 ) ) ) { /* the current stream position is 16 bytes after the table start */ FT_ULong array_start = FT_STREAM_POS() - 16 + offset; @@ -679,6 +698,9 @@ instance_offset += instance_size; } + /* named instance indices start with value 1 */ + face->var_default_named_instance = i + 1; + if ( i == num_instances ) { /* no default instance in named instance table; */ @@ -771,17 +793,23 @@ FT_Int num_params, FT_Parameter* params ) { - FT_Error error; + FT_Error error; #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES - FT_Error psnames_error; + FT_Error psnames_error; #endif - FT_Bool has_outline; - FT_Bool is_apple_sbit; - FT_Bool is_apple_sbix; - FT_Bool has_CBLC; - FT_Bool has_CBDT; - FT_Bool ignore_typographic_family = FALSE; - FT_Bool ignore_typographic_subfamily = FALSE; + + FT_Bool has_outline; + FT_Bool is_apple_sbit; + + FT_Bool has_CBLC; + FT_Bool has_CBDT; + FT_Bool has_EBLC; + FT_Bool has_bloc; + FT_Bool has_sbix; + + FT_Bool ignore_typographic_family = FALSE; + FT_Bool ignore_typographic_subfamily = FALSE; + FT_Bool ignore_sbix = FALSE; SFNT_Service sfnt = (SFNT_Service)face->sfnt; @@ -800,6 +828,8 @@ ignore_typographic_family = TRUE; else if ( params[i].tag == FT_PARAM_TAG_IGNORE_TYPOGRAPHIC_SUBFAMILY ) ignore_typographic_subfamily = TRUE; + else if ( params[i].tag == FT_PARAM_TAG_IGNORE_SBIX ) + ignore_sbix = TRUE; } } @@ -820,7 +850,8 @@ /* it doesn't contain outlines. */ /* */ - FT_TRACE2(( "sfnt_load_face: %p\n\n", (void *)face )); + FT_TRACE2(( "sfnt_load_face: %p\n", (void *)face )); + FT_TRACE2(( "\n" )); /* do we have outlines in there? */ #ifdef FT_CONFIG_OPTION_INCREMENTAL @@ -834,14 +865,17 @@ tt_face_lookup_table( face, TTAG_CFF2 ) ); #endif - is_apple_sbit = 0; - is_apple_sbix = !face->goto_table( face, TTAG_sbix, stream, 0 ); + /* check which sbit formats are present */ + has_CBLC = !face->goto_table( face, TTAG_CBLC, stream, 0 ); + has_CBDT = !face->goto_table( face, TTAG_CBDT, stream, 0 ); + has_EBLC = !face->goto_table( face, TTAG_EBLC, stream, 0 ); + has_bloc = !face->goto_table( face, TTAG_bloc, stream, 0 ); + has_sbix = !face->goto_table( face, TTAG_sbix, stream, 0 ); - /* Apple 'sbix' color bitmaps are rendered scaled and then the 'glyf' - * outline rendered on top. We don't support that yet, so just ignore - * the 'glyf' outline and advertise it as a bitmap-only font. */ - if ( is_apple_sbix ) - has_outline = FALSE; + is_apple_sbit = FALSE; + + if ( ignore_sbix ) + has_sbix = FALSE; /* if this font doesn't contain outlines, we try to load */ /* a `bhed' table */ @@ -853,16 +887,13 @@ /* load the font header (`head' table) if this isn't an Apple */ /* sbit font file */ - if ( !is_apple_sbit || is_apple_sbix ) + if ( !is_apple_sbit || has_sbix ) { LOAD_( head ); if ( error ) goto Exit; } - has_CBLC = !face->goto_table( face, TTAG_CBLC, stream, 0 ); - has_CBDT = !face->goto_table( face, TTAG_CBDT, stream, 0 ); - /* Ignore outlines for CBLC/CBDT fonts. */ if ( has_CBLC || has_CBDT ) has_outline = FALSE; @@ -972,7 +1003,11 @@ /* the optional tables */ /* embedded bitmap support */ - if ( sfnt->load_eblc ) + /* TODO: Replace this clumsy check for all possible sbit tables */ + /* with something better (for example, by passing a parameter */ + /* to suppress 'sbix' loading). */ + if ( sfnt->load_eblc && + ( has_CBLC || has_EBLC || has_bloc || has_sbix ) ) LOAD_( eblc ); /* colored glyph support */ @@ -982,6 +1017,10 @@ LOAD_( colr ); } + /* OpenType-SVG glyph support */ + if ( sfnt->load_svg ) + LOAD_( svg ); + /* consider the pclt, kerning, and gasp tables as optional */ LOAD_( pclt ); LOAD_( gasp ); @@ -1024,6 +1063,16 @@ GET_NAME( FONT_SUBFAMILY, &face->root.style_name ); } +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + FT_Memory memory = face->root.memory; + + + if ( FT_STRDUP( face->non_var_style_name, face->root.style_name ) ) + goto Exit; + } +#endif + /* now set up root fields */ { FT_Face root = &face->root; @@ -1036,11 +1085,19 @@ */ if ( face->sbit_table_type == TT_SBIT_TABLE_TYPE_CBLC || face->sbit_table_type == TT_SBIT_TABLE_TYPE_SBIX || - face->colr ) + face->colr || + face->svg ) flags |= FT_FACE_FLAG_COLOR; /* color glyphs */ if ( has_outline == TRUE ) - flags |= FT_FACE_FLAG_SCALABLE; /* scalable outlines */ + { + /* by default (and for backward compatibility) we handle */ + /* fonts with an 'sbix' table as bitmap-only */ + if ( has_sbix ) + flags |= FT_FACE_FLAG_SBIX; /* with 'sbix' bitmaps */ + else + flags |= FT_FACE_FLAG_SCALABLE; /* scalable outlines */ + } /* The sfnt driver only supports bitmap fonts natively, thus we */ /* don't set FT_FACE_FLAG_HINTER. */ @@ -1069,13 +1126,7 @@ /* Don't bother to load the tables unless somebody asks for them. */ /* No need to do work which will (probably) not be used. */ if ( face->variation_support & TT_FACE_FLAG_VAR_FVAR ) - { - if ( tt_face_lookup_table( face, TTAG_glyf ) != 0 && - tt_face_lookup_table( face, TTAG_gvar ) != 0 ) - flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; - if ( tt_face_lookup_table( face, TTAG_CFF2 ) != 0 ) - flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; - } + flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; #endif root->face_flags = flags; @@ -1149,9 +1200,10 @@ } /* synthesize Unicode charmap if one is missing */ - if ( !has_unicode ) + if ( !has_unicode && + root->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) { - FT_CharMapRec cmaprec; + FT_CharMapRec cmaprec; cmaprec.face = root; @@ -1188,7 +1240,7 @@ if ( count > 0 ) { - FT_Memory memory = face->root.stream->memory; + FT_Memory memory = face->root.memory; FT_UShort em_size = face->header.Units_Per_EM; FT_Short avgwidth = face->os2.xAvgCharWidth; FT_Size_Metrics metrics; @@ -1207,7 +1259,7 @@ /* of `FT_Face', we map `available_sizes' indices to strike */ /* indices */ if ( FT_NEW_ARRAY( root->available_sizes, count ) || - FT_NEW_ARRAY( sbit_strike_map, count ) ) + FT_QNEW_ARRAY( sbit_strike_map, count ) ) goto Exit; bsize_idx = 0; @@ -1236,7 +1288,7 @@ } /* reduce array size to the actually used elements */ - (void)FT_RENEW_ARRAY( sbit_strike_map, count, bsize_idx ); + FT_MEM_QRENEW_ARRAY( sbit_strike_map, count, bsize_idx ); /* from now on, all strike indices are mapped */ /* using `sbit_strike_map' */ @@ -1262,7 +1314,8 @@ * * Set up metrics. */ - if ( FT_IS_SCALABLE( root ) ) + if ( FT_IS_SCALABLE( root ) || + FT_HAS_SBIX( root ) ) { /* XXX What about if outline header is missing */ /* (e.g. sfnt wrapped bitmap)? */ @@ -1401,6 +1454,12 @@ sfnt->free_cpal( face ); sfnt->free_colr( face ); } + +#ifdef FT_CONFIG_OPTION_SVG + /* free SVG data */ + if ( sfnt->free_svg ) + sfnt->free_svg( face ); +#endif } #ifdef TT_CONFIG_OPTION_BDF @@ -1460,6 +1519,7 @@ #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT FT_FREE( face->var_postscript_prefix ); + FT_FREE( face->non_var_style_name ); #endif /* freeing glyph color palette data */ diff --git a/src/3rdparty/freetype/src/sfnt/sfobjs.h b/src/3rdparty/freetype/src/sfnt/sfobjs.h index e8e3042083..906aebbf90 100644 --- a/src/3rdparty/freetype/src/sfnt/sfobjs.h +++ b/src/3rdparty/freetype/src/sfnt/sfobjs.h @@ -4,7 +4,7 @@ * * SFNT object management (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/3rdparty/freetype/src/sfnt/sfwoff.c b/src/3rdparty/freetype/src/sfnt/sfwoff.c index f0a32e1e06..7c0ce2205e 100644 --- a/src/3rdparty/freetype/src/sfnt/sfwoff.c +++ b/src/3rdparty/freetype/src/sfnt/sfwoff.c @@ -4,7 +4,7 @@ * * WOFF format management (base). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -23,6 +23,9 @@ #include <freetype/ftgzip.h> +#ifdef FT_CONFIG_OPTION_USE_ZLIB + + /************************************************************************** * * The macro FT_COMPONENT is used in trace mode. It is an implicit @@ -61,12 +64,11 @@ FT_FREE( stream->base ); stream->size = 0; - stream->base = NULL; stream->close = NULL; } - FT_CALLBACK_DEF( int ) + FT_COMPARE_DEF( int ) compare_offsets( const void* a, const void* b ) { @@ -109,7 +111,7 @@ FT_ULong sfnt_offset; FT_Int nn; - FT_ULong old_tag = 0; + FT_Tag old_tag = 0; static const FT_Frame_Field woff_header_fields[] = { @@ -160,8 +162,7 @@ } /* Don't trust `totalSfntSize' before thorough checks. */ - if ( FT_ALLOC( sfnt, 12 + woff.num_tables * 16UL ) || - FT_NEW( sfnt_stream ) ) + if ( FT_QALLOC( sfnt, 12 ) || FT_NEW( sfnt_stream ) ) goto Exit; sfnt_header = sfnt; @@ -194,13 +195,13 @@ /* tag value, the tables themselves are not. We thus have to */ /* sort them by offset and check that they don't overlap. */ - if ( FT_NEW_ARRAY( tables, woff.num_tables ) || - FT_NEW_ARRAY( indices, woff.num_tables ) ) + if ( FT_QNEW_ARRAY( tables, woff.num_tables ) || + FT_QNEW_ARRAY( indices, woff.num_tables ) ) goto Exit; - FT_TRACE2(( "\n" - " tag offset compLen origLen checksum\n" - " -------------------------------------------\n" )); + FT_TRACE2(( "\n" )); + FT_TRACE2(( " tag offset compLen origLen checksum\n" )); + FT_TRACE2(( " -------------------------------------------\n" )); if ( FT_FRAME_ENTER( 20L * woff.num_tables ) ) goto Exit; @@ -326,9 +327,7 @@ } /* Now use `totalSfntSize'. */ - if ( FT_REALLOC( sfnt, - 12 + woff.num_tables * 16UL, - woff.totalSfntSize ) ) + if ( FT_QREALLOC( sfnt, 12, woff.totalSfntSize ) ) goto Exit; sfnt_header = sfnt + 12; @@ -360,8 +359,6 @@ } else { -#ifdef FT_CONFIG_OPTION_USE_ZLIB - /* Uncompress with zlib. */ FT_ULong output_len = table->OrigLength; @@ -377,13 +374,6 @@ error = FT_THROW( Invalid_Table ); goto Exit1; } - -#else /* !FT_CONFIG_OPTION_USE_ZLIB */ - - error = FT_THROW( Unimplemented_Feature ); - goto Exit1; - -#endif /* !FT_CONFIG_OPTION_USE_ZLIB */ } FT_FRAME_EXIT(); @@ -433,5 +423,12 @@ #undef WRITE_USHORT #undef WRITE_ULONG +#else /* !FT_CONFIG_OPTION_USE_ZLIB */ + + /* ANSI C doesn't like empty source files */ + typedef int sfwoff_dummy_; + +#endif /* !FT_CONFIG_OPTION_USE_ZLIB */ + /* END */ diff --git a/src/3rdparty/freetype/src/sfnt/sfwoff.h b/src/3rdparty/freetype/src/sfnt/sfwoff.h index d177ab1160..d438422737 100644 --- a/src/3rdparty/freetype/src/sfnt/sfwoff.h +++ b/src/3rdparty/freetype/src/sfnt/sfwoff.h @@ -4,7 +4,7 @@ * * WOFFF format management (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -26,12 +26,15 @@ FT_BEGIN_HEADER +#ifdef FT_CONFIG_OPTION_USE_ZLIB FT_LOCAL( FT_Error ) woff_open_font( FT_Stream stream, TT_Face face ); +#endif + FT_END_HEADER #endif /* SFWOFF_H_ */ diff --git a/src/3rdparty/freetype/src/sfnt/sfwoff2.c b/src/3rdparty/freetype/src/sfnt/sfwoff2.c index 5c8202f823..2be44a347a 100644 --- a/src/3rdparty/freetype/src/sfnt/sfwoff2.c +++ b/src/3rdparty/freetype/src/sfnt/sfwoff2.c @@ -4,7 +4,7 @@ * * WOFF2 format management (base). * - * Copyright (C) 2019-2020 by + * Copyright (C) 2019-2023 by * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -26,8 +26,6 @@ #include <brotli/decode.h> -#endif - /************************************************************************** * @@ -38,6 +36,8 @@ #undef FT_COMPONENT #define FT_COMPONENT sfwoff2 + /* An arbitrary, heuristic size limit (67MByte) for expanded WOFF2 data. */ +#define MAX_SFNT_SIZE ( 1 << 26 ) #define READ_255USHORT( var ) FT_SET_ERROR( Read255UShort( stream, &var ) ) @@ -86,6 +86,8 @@ #define BBOX_STREAM 5 #define INSTRUCTION_STREAM 6 +#define HAVE_OVERLAP_SIMPLE_BITMAP 0x1 + static void stream_close( FT_Stream stream ) @@ -96,20 +98,19 @@ FT_FREE( stream->base ); stream->size = 0; - stream->base = NULL; stream->close = NULL; } - FT_CALLBACK_DEF( int ) + FT_COMPARE_DEF( int ) compare_tags( const void* a, const void* b ) { WOFF2_Table table1 = *(WOFF2_Table*)a; WOFF2_Table table2 = *(WOFF2_Table*)b; - FT_ULong tag1 = table1->Tag; - FT_ULong tag2 = table2->Tag; + FT_Tag tag1 = table1->Tag; + FT_Tag tag2 = table2->Tag; if ( tag1 > tag2 ) @@ -230,9 +231,9 @@ { FT_TRACE6(( "Reallocating %lu to %lu.\n", *dst_size, (*offset + size) )); - if ( FT_REALLOC( dst, - (FT_ULong)( *dst_size ), - (FT_ULong)( *offset + size ) ) ) + if ( FT_QREALLOC( dst, + (FT_ULong)( *dst_size ), + (FT_ULong)( *offset + size ) ) ) goto Exit; *dst_size = *offset + size; @@ -316,8 +317,6 @@ const FT_Byte* src, FT_ULong src_size ) { -#ifdef FT_CONFIG_OPTION_USE_BROTLI - /* this cast is only of importance on 32bit systems; */ /* we don't validate it */ FT_Offset uncompressed_size = (FT_Offset)dst_size; @@ -338,20 +337,13 @@ FT_TRACE2(( "woff2_decompress: Brotli stream decompressed.\n" )); return FT_Err_Ok; - -#else /* !FT_CONFIG_OPTION_USE_BROTLI */ - - FT_ERROR(( "woff2_decompress: Brotli support not available.\n" )); - return FT_THROW( Unimplemented_Feature ); - -#endif /* !FT_CONFIG_OPTION_USE_BROTLI */ } static WOFF2_Table find_table( WOFF2_Table* tables, FT_UShort num_tables, - FT_ULong tag ) + FT_Tag tag ) { FT_Int i; @@ -534,6 +526,7 @@ const WOFF2_Point points, FT_UShort n_contours, FT_UShort instruction_len, + FT_Bool have_overlap, FT_Byte* dst, FT_ULong dst_size, FT_ULong* glyph_size ) @@ -561,6 +554,9 @@ FT_Int dy = point.y - last_y; + if ( i == 0 && have_overlap ) + flag |= GLYF_OVERLAP_SIMPLE; + if ( dx == 0 ) flag |= GLYF_THIS_X_IS_SAME; else if ( dx > -256 && dx < 256 ) @@ -790,7 +786,7 @@ goto Fail; loca_buf_size = loca_values_size * offset_size; - if ( FT_NEW_ARRAY( loca_buf, loca_buf_size ) ) + if ( FT_QALLOC( loca_buf, loca_buf_size ) ) goto Fail; dst = loca_buf; @@ -845,15 +841,18 @@ FT_UInt num_substreams = 7; + FT_UShort option_flags; FT_UShort num_glyphs; FT_UShort index_format; FT_ULong expected_loca_length; FT_UInt offset; FT_UInt i; FT_ULong points_size; - FT_ULong bitmap_length; FT_ULong glyph_buf_size; FT_ULong bbox_bitmap_offset; + FT_ULong bbox_bitmap_length; + FT_ULong overlap_bitmap_offset = 0; + FT_ULong overlap_bitmap_length = 0; const FT_ULong glyf_start = *out_offset; FT_ULong dest_offset = *out_offset; @@ -866,18 +865,20 @@ WOFF2_Point points = NULL; - if ( FT_NEW_ARRAY( substreams, num_substreams ) ) + if ( FT_QNEW_ARRAY( substreams, num_substreams ) ) goto Fail; - if ( FT_STREAM_SKIP( 4 ) ) + if ( FT_STREAM_SKIP( 2 ) ) + goto Fail; + if ( FT_READ_USHORT( option_flags ) ) goto Fail; if ( FT_READ_USHORT( num_glyphs ) ) goto Fail; if ( FT_READ_USHORT( index_format ) ) goto Fail; - FT_TRACE4(( "num_glyphs = %u; index_format = %u\n", - num_glyphs, index_format )); + FT_TRACE4(( "option_flags = %u; num_glyphs = %u; index_format = %u\n", + option_flags, num_glyphs, index_format )); info->num_glyphs = num_glyphs; @@ -890,7 +891,7 @@ if ( info->loca_table->dst_length != expected_loca_length ) goto Fail; - offset = ( 2 + num_substreams ) * 4; + offset = 2 + 2 + 2 + 2 + ( num_substreams * 4 ); if ( offset > info->glyf_table->TransformLength ) goto Fail; @@ -913,21 +914,36 @@ offset += substream_size; } - if ( FT_NEW_ARRAY( loca_values, num_glyphs + 1 ) ) + if ( option_flags & HAVE_OVERLAP_SIMPLE_BITMAP ) + { + /* Size of overlapBitmap = floor((numGlyphs + 7) / 8) */ + overlap_bitmap_length = ( num_glyphs + 7U ) >> 3; + if ( overlap_bitmap_length > info->glyf_table->TransformLength - offset ) + goto Fail; + + overlap_bitmap_offset = pos + offset; + + FT_TRACE5(( " Overlap bitmap: offset = %lu; size = %lu;\n", + overlap_bitmap_offset, overlap_bitmap_length )); + offset += overlap_bitmap_length; + } + + if ( FT_QNEW_ARRAY( loca_values, num_glyphs + 1 ) ) goto Fail; points_size = 0; bbox_bitmap_offset = substreams[BBOX_STREAM].offset; /* Size of bboxBitmap = 4 * floor((numGlyphs + 31) / 32) */ - bitmap_length = ( ( num_glyphs + 31U ) >> 5 ) << 2; - substreams[BBOX_STREAM].offset += bitmap_length; + bbox_bitmap_length = ( ( num_glyphs + 31U ) >> 5 ) << 2; + /* bboxStreamSize is the combined size of bboxBitmap and bboxStream. */ + substreams[BBOX_STREAM].offset += bbox_bitmap_length; glyph_buf_size = WOFF2_DEFAULT_GLYPH_BUF; - if ( FT_NEW_ARRAY( glyph_buf, glyph_buf_size ) ) + if ( FT_QALLOC( glyph_buf, glyph_buf_size ) ) goto Fail; - if ( FT_NEW_ARRAY( info->x_mins, num_glyphs ) ) + if ( FT_QNEW_ARRAY( info->x_mins, num_glyphs ) ) goto Fail; for ( i = 0; i < num_glyphs; ++i ) @@ -959,7 +975,7 @@ /* composite glyph */ FT_Bool have_instructions = FALSE; FT_UShort instruction_size = 0; - FT_ULong composite_size; + FT_ULong composite_size = 0; FT_ULong size_needed; FT_Byte* pointer = NULL; @@ -985,7 +1001,7 @@ size_needed = 12 + composite_size + instruction_size; if ( glyph_buf_size < size_needed ) { - if ( FT_RENEW_ARRAY( glyph_buf, glyph_buf_size, size_needed ) ) + if ( FT_QREALLOC( glyph_buf, glyph_buf_size, size_needed ) ) goto Fail; glyph_buf_size = size_needed; } @@ -1037,8 +1053,11 @@ FT_ULong flag_size; FT_ULong triplet_size; FT_ULong triplet_bytes_used; - FT_Byte* flags_buf = NULL; - FT_Byte* triplet_buf = NULL; + FT_Bool have_overlap = FALSE; + FT_Byte overlap_bitmap; + FT_ULong overlap_offset; + FT_Byte* flags_buf = NULL; + FT_Byte* triplet_buf = NULL; FT_UShort instruction_size; FT_ULong size_needed; FT_Int end_point; @@ -1047,7 +1066,18 @@ FT_Byte* pointer = NULL; - if ( FT_NEW_ARRAY( n_points_arr, n_contours ) ) + /* Set `have_overlap`. */ + if ( overlap_bitmap_offset ) + { + overlap_offset = overlap_bitmap_offset + ( i >> 3 ); + if ( FT_STREAM_SEEK( overlap_offset ) || + FT_READ_BYTE( overlap_bitmap ) ) + goto Fail; + if ( overlap_bitmap & ( 0x80 >> ( i & 7 ) ) ) + have_overlap = TRUE; + } + + if ( FT_QNEW_ARRAY( n_points_arr, n_contours ) ) goto Fail; if ( FT_STREAM_SEEK( substreams[N_POINTS_STREAM].offset ) ) @@ -1084,7 +1114,7 @@ /* Create array to store point information. */ points_size = total_n_points; - if ( FT_NEW_ARRAY( points, points_size ) ) + if ( FT_QNEW_ARRAY( points, points_size ) ) goto Fail; if ( triplet_decode( flags_buf, @@ -1113,7 +1143,7 @@ instruction_size; if ( glyph_buf_size < size_needed ) { - if ( FT_RENEW_ARRAY( glyph_buf, glyph_buf_size, size_needed ) ) + if ( FT_QREALLOC( glyph_buf, glyph_buf_size, size_needed ) ) goto Fail; glyph_buf_size = size_needed; } @@ -1167,6 +1197,7 @@ points, n_contours, instruction_size, + have_overlap, glyph_buf, glyph_buf_size, &glyph_size ) ) @@ -1197,8 +1228,7 @@ *glyf_checksum += compute_ULong_sum( glyph_buf, glyph_size ); /* Store x_mins, may be required to reconstruct `hmtx'. */ - if ( n_contours > 0 ) - info->x_mins[i] = (FT_Short)x_min; + info->x_mins[i] = (FT_Short)x_min; } info->glyf_table->dst_length = dest_offset - info->glyf_table->dst_offset; @@ -1315,7 +1345,7 @@ offset_size = index_format ? 4 : 2; /* Create `x_mins' array. */ - if ( FT_NEW_ARRAY( info->x_mins, num_glyphs ) ) + if ( FT_QNEW_ARRAY( info->x_mins, num_glyphs ) ) return error; loca_offset = info->loca_table->src_offset; @@ -1403,8 +1433,8 @@ if ( num_hmetrics < 1 ) goto Fail; - if ( FT_NEW_ARRAY( advance_widths, num_hmetrics ) || - FT_NEW_ARRAY( lsbs, num_glyphs ) ) + if ( FT_QNEW_ARRAY( advance_widths, num_hmetrics ) || + FT_QNEW_ARRAY( lsbs, num_glyphs ) ) goto Fail; /* Read `advanceWidth' stream. Always present. */ @@ -1455,7 +1485,7 @@ /* Build the hmtx table. */ hmtx_table_size = 2 * num_hmetrics + 2 * num_glyphs; - if ( FT_NEW_ARRAY( hmtx_table, hmtx_table_size ) ) + if ( FT_QALLOC( hmtx_table, hmtx_table_size ) ) goto Fail; dst = hmtx_table; @@ -1512,10 +1542,10 @@ { /* Memory management of `transformed_buf' is handled by the caller. */ - FT_Error error = FT_Err_Ok; - FT_Stream stream = NULL; - FT_Byte* buf_cursor = NULL; - FT_Byte* table_entry = NULL; + FT_Error error = FT_Err_Ok; + FT_Stream stream = NULL; + FT_Byte* buf_cursor = NULL; + FT_Byte table_entry[16]; /* We are reallocating memory for `sfnt', so its pointer may change. */ FT_Byte* sfnt = *sfnt_bytes; @@ -1556,10 +1586,6 @@ } } - /* Create buffer for table entries. */ - if ( FT_NEW_ARRAY( table_entry, 16 ) ) - goto Fail; - /* Create a stream for the uncompressed buffer. */ if ( FT_NEW( stream ) ) goto Fail; @@ -1722,7 +1748,6 @@ /* Set pointer of sfnt stream to its correct value. */ *sfnt_bytes = sfnt; - FT_FREE( table_entry ); FT_Stream_Close( stream ); FT_FREE( stream ); @@ -1735,7 +1760,6 @@ /* Set pointer of sfnt stream to its correct value. */ *sfnt_bytes = sfnt; - FT_FREE( table_entry ); FT_Stream_Close( stream ); FT_FREE( stream ); @@ -1848,15 +1872,14 @@ woff2.ttc_fonts = NULL; /* Read table directory. */ - if ( FT_NEW_ARRAY( tables, woff2.num_tables ) || - FT_NEW_ARRAY( indices, woff2.num_tables ) ) + if ( FT_QNEW_ARRAY( tables, woff2.num_tables ) || + FT_QNEW_ARRAY( indices, woff2.num_tables ) ) goto Exit; - FT_TRACE2(( - "\n" - " tag flags transform origLen transformLen offset\n" - " -----------------------------------------------------------\n" )); - /* " XXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX" */ + FT_TRACE2(( "\n" )); + FT_TRACE2(( " tag flags transform origLen transformLen offset\n" )); + FT_TRACE2(( " -----------------------------------------------------------\n" )); + /* " XXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX" */ for ( nn = 0; nn < woff2.num_tables; nn++ ) { @@ -1921,10 +1944,11 @@ goto Exit; } + table->flags = flags; table->src_offset = src_offset; table->src_length = table->TransformLength; src_offset += table->TransformLength; - table->flags = flags; + table->dst_offset = 0; FT_TRACE2(( " %c%c%c%c %08d %08d %08ld %08ld %08ld\n", (FT_Char)( table->Tag >> 24 ), @@ -1982,6 +2006,7 @@ FT_TRACE4(( "Number of fonts in TTC: %d\n", woff2.num_fonts )); + /* pre-zero pointers within in case of failure */ if ( FT_NEW_ARRAY( woff2.ttc_fonts, woff2.num_fonts ) ) goto Exit; @@ -1995,7 +2020,7 @@ if ( FT_READ_ULONG( ttc_font->flavor ) ) goto Exit; - if ( FT_NEW_ARRAY( ttc_font->table_indices, ttc_font->num_tables ) ) + if ( FT_QNEW_ARRAY( ttc_font->table_indices, ttc_font->num_tables ) ) goto Exit; FT_TRACE5(( "Number of tables in font %d: %d\n", @@ -2076,7 +2101,7 @@ error = FT_THROW( Invalid_Table ); goto Exit; } - file_offset = ROUND4(woff2.metaOffset + woff2.metaLength); + file_offset = ROUND4( woff2.metaOffset + woff2.metaLength ); } if ( woff2.privOffset ) @@ -2086,7 +2111,7 @@ error = FT_THROW( Invalid_Table ); goto Exit; } - file_offset = ROUND4(woff2.privOffset + woff2.privLength); + file_offset = ROUND4( woff2.privOffset + woff2.privLength ); } if ( file_offset != ( ROUND4( woff2.length ) ) ) @@ -2098,7 +2123,7 @@ /* Validate requested face index. */ *num_faces = woff2.num_fonts; /* value -(N+1) requests information on index N */ - if ( *face_instance_index < 0 ) + if ( *face_instance_index < 0 && face_index > 0 ) face_index--; if ( face_index >= woff2.num_fonts ) @@ -2119,8 +2144,8 @@ /* Create a temporary array. */ - if ( FT_NEW_ARRAY( temp_indices, - ttc_font->num_tables ) ) + if ( FT_QNEW_ARRAY( temp_indices, + ttc_font->num_tables ) ) goto Exit; FT_TRACE4(( "Storing tables for TTC face index %d.\n", face_index )); @@ -2128,9 +2153,9 @@ temp_indices[nn] = indices[ttc_font->table_indices[nn]]; /* Resize array to required size. */ - if ( FT_RENEW_ARRAY( indices, - woff2.num_tables, - ttc_font->num_tables ) ) + if ( FT_QRENEW_ARRAY( indices, + woff2.num_tables, + ttc_font->num_tables ) ) goto Exit; for ( nn = 0; nn < ttc_font->num_tables; nn++ ) @@ -2157,9 +2182,8 @@ else sfnt_size = woff2.totalSfntSize; - /* Value 1<<26 = 67108864 is heuristic. */ - if (sfnt_size >= (1 << 26)) - sfnt_size = 1 << 26; + if ( sfnt_size >= MAX_SFNT_SIZE ) + sfnt_size = MAX_SFNT_SIZE; #ifdef FT_DEBUG_LEVEL_TRACE if ( sfnt_size != woff2.totalSfntSize ) @@ -2170,8 +2194,8 @@ } /* Write sfnt header. */ - if ( FT_ALLOC( sfnt, sfnt_size ) || - FT_NEW( sfnt_stream ) ) + if ( FT_QALLOC( sfnt, sfnt_size ) || + FT_NEW( sfnt_stream ) ) goto Exit; sfnt_header = sfnt; @@ -2209,22 +2233,46 @@ sizeof ( WOFF2_Table ), compare_tags ); + /* reject fonts that have multiple tables with the same tag */ + for ( nn = 1; nn < woff2.num_tables; nn++ ) + { + FT_Tag tag = indices[nn]->Tag; + + + if ( tag == indices[nn - 1]->Tag ) + { + FT_ERROR(( "woff2_open_font:" + " multiple tables with tag `%c%c%c%c'.\n", + (FT_Char)( tag >> 24 ), + (FT_Char)( tag >> 16 ), + (FT_Char)( tag >> 8 ), + (FT_Char)( tag ) )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + } + if ( woff2.uncompressed_size < 1 ) { error = FT_THROW( Invalid_Table ); goto Exit; } - if ( woff2.uncompressed_size > sfnt_size ) + /* We must not blindly trust `uncompressed_size` since its */ + /* value might be corrupted. If it is too large, reject the */ + /* font. In other words, we don't accept a WOFF2 font that */ + /* expands to something larger than MAX_SFNT_SIZE. If ever */ + /* necessary, this limit can be easily adjusted. */ + if ( woff2.uncompressed_size > MAX_SFNT_SIZE ) { - FT_ERROR(( "woff2_open_font: SFNT table lengths are too large.\n" )); - error = FT_THROW( Invalid_Table ); + FT_ERROR(( "Uncompressed font too large.\n" )); + error = FT_THROW( Array_Too_Large ); goto Exit; } /* Allocate memory for uncompressed table data. */ - if ( FT_ALLOC( uncompressed_buf, woff2.uncompressed_size ) || - FT_FRAME_ENTER( woff2.totalCompressedSize ) ) + if ( FT_QALLOC( uncompressed_buf, woff2.uncompressed_size ) || + FT_FRAME_ENTER( woff2.totalCompressedSize ) ) goto Exit; /* Uncompress the stream. */ @@ -2255,9 +2303,9 @@ { FT_TRACE5(( "Trimming sfnt stream from %lu to %lu.\n", sfnt_size, woff2.actual_sfnt_size )); - if ( FT_REALLOC( sfnt, - (FT_ULong)( sfnt_size ), - (FT_ULong)( woff2.actual_sfnt_size ) ) ) + if ( FT_QREALLOC( sfnt, + (FT_ULong)( sfnt_size ), + (FT_ULong)( woff2.actual_sfnt_size ) ) ) goto Exit; } @@ -2333,5 +2381,12 @@ #undef BBOX_STREAM #undef INSTRUCTION_STREAM +#else /* !FT_CONFIG_OPTION_USE_BROTLI */ + + /* ANSI C doesn't like empty source files */ + typedef int sfwoff2_dummy_; + +#endif /* !FT_CONFIG_OPTION_USE_BROTLI */ + /* END */ diff --git a/src/3rdparty/freetype/src/sfnt/sfwoff2.h b/src/3rdparty/freetype/src/sfnt/sfwoff2.h index 798f66bd0a..4901286ee0 100644 --- a/src/3rdparty/freetype/src/sfnt/sfwoff2.h +++ b/src/3rdparty/freetype/src/sfnt/sfwoff2.h @@ -4,7 +4,7 @@ * * WOFFF2 format management (specification). * - * Copyright (C) 2019-2020 by + * Copyright (C) 2019-2023 by * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -26,6 +26,7 @@ FT_BEGIN_HEADER +#ifdef FT_CONFIG_OPTION_USE_BROTLI /* Leave the first byte open to store `flag_byte'. */ #define WOFF2_FLAGS_TRANSFORM 1 << 8 @@ -55,6 +56,7 @@ FT_BEGIN_HEADER #define GLYF_REPEAT 1 << 3 #define GLYF_THIS_X_IS_SAME 1 << 4 #define GLYF_THIS_Y_IS_SAME 1 << 5 +#define GLYF_OVERLAP_SIMPLE 1 << 6 /* Other constants */ #define CONTOUR_OFFSET_END_POINT 10 @@ -66,6 +68,7 @@ FT_BEGIN_HEADER FT_Int* face_index, FT_Long* num_faces ); +#endif /* FT_CONFIG_OPTION_USE_BROTLI */ FT_END_HEADER diff --git a/src/3rdparty/freetype/src/sfnt/ttbdf.c b/src/3rdparty/freetype/src/sfnt/ttbdf.c index a287d3afc4..536fa7467e 100644 --- a/src/3rdparty/freetype/src/sfnt/ttbdf.c +++ b/src/3rdparty/freetype/src/sfnt/ttbdf.c @@ -4,7 +4,7 @@ * * TrueType and OpenType embedded BDF properties (body). * - * Copyright (C) 2005-2020 by + * Copyright (C) 2005-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -136,13 +136,14 @@ FT_LOCAL_DEF( FT_Error ) - tt_face_find_bdf_prop( TT_Face face, + tt_face_find_bdf_prop( FT_Face face, /* TT_Face */ const char* property_name, BDF_PropertyRec *aprop ) { - TT_BDF bdf = &face->bdf; - FT_Size size = FT_FACE( face )->size; - FT_Error error = FT_Err_Ok; + TT_Face ttface = (TT_Face)face; + TT_BDF bdf = &ttface->bdf; + FT_Size size = FT_FACE_SIZE( face ); + FT_Error error = FT_Err_Ok; FT_Byte* p; FT_UInt count; FT_Byte* strike; @@ -153,7 +154,7 @@ if ( bdf->loaded == 0 ) { - error = tt_face_load_bdf_props( face, FT_FACE( face )->stream ); + error = tt_face_load_bdf_props( ttface, FT_FACE_STREAM( face ) ); if ( error ) goto Exit; } @@ -248,7 +249,7 @@ #else /* !TT_CONFIG_OPTION_BDF */ /* ANSI C doesn't like empty source files */ - typedef int _tt_bdf_dummy; + typedef int tt_bdf_dummy_; #endif /* !TT_CONFIG_OPTION_BDF */ diff --git a/src/3rdparty/freetype/src/sfnt/ttbdf.h b/src/3rdparty/freetype/src/sfnt/ttbdf.h index e60c01cb8b..0d7a0acecc 100644 --- a/src/3rdparty/freetype/src/sfnt/ttbdf.h +++ b/src/3rdparty/freetype/src/sfnt/ttbdf.h @@ -4,7 +4,7 @@ * * TrueType and OpenType embedded BDF properties (specification). * - * Copyright (C) 2005-2020 by + * Copyright (C) 2005-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -34,7 +34,7 @@ FT_BEGIN_HEADER FT_LOCAL( FT_Error ) - tt_face_find_bdf_prop( TT_Face face, + tt_face_find_bdf_prop( FT_Face face, const char* property_name, BDF_PropertyRec *aprop ); diff --git a/src/3rdparty/freetype/src/sfnt/ttcmap.c b/src/3rdparty/freetype/src/sfnt/ttcmap.c index 556a712199..9ba25dcbc1 100644 --- a/src/3rdparty/freetype/src/sfnt/ttcmap.c +++ b/src/3rdparty/freetype/src/sfnt/ttcmap.c @@ -4,7 +4,7 @@ * * TrueType character mapping table (cmap) support (body). * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -59,10 +59,14 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap_init( TT_CMap cmap, - FT_Byte* table ) + tt_cmap_init( FT_CMap cmap, /* TT_CMap */ + void* table_ ) { - cmap->data = table; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = (FT_Byte*)table_; + + + ttcmap->data = table; return FT_Err_Ok; } @@ -128,21 +132,23 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap0_char_index( TT_CMap cmap, + tt_cmap0_char_index( FT_CMap cmap, /* TT_CMap */ FT_UInt32 char_code ) { - FT_Byte* table = cmap->data; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; return char_code < 256 ? table[6 + char_code] : 0; } - FT_CALLBACK_DEF( FT_UInt32 ) - tt_cmap0_char_next( TT_CMap cmap, + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap0_char_next( FT_CMap cmap, /* TT_CMap */ FT_UInt32 *pchar_code ) { - FT_Byte* table = cmap->data; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; FT_UInt32 charcode = *pchar_code; FT_UInt32 result = 0; FT_UInt gindex = 0; @@ -165,10 +171,11 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap0_get_info( TT_CMap cmap, + tt_cmap0_get_info( FT_CharMap cmap, /* TT_CMap */ TT_CMapInfo *cmap_info ) { - FT_Byte* p = cmap->data + 4; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 4; cmap_info->format = 0; @@ -453,10 +460,11 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap2_char_index( TT_CMap cmap, + tt_cmap2_char_index( FT_CMap cmap, /* TT_CMap */ FT_UInt32 char_code ) { - FT_Byte* table = cmap->data; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; FT_UInt result = 0; FT_Byte* subheader; @@ -465,7 +473,7 @@ if ( subheader ) { FT_Byte* p = subheader; - FT_UInt idx = (FT_UInt)(char_code & 0xFF); + FT_UInt idx = (FT_UInt)( char_code & 0xFF ); FT_UInt start, count; FT_Int delta; FT_UInt offset; @@ -491,11 +499,12 @@ } - FT_CALLBACK_DEF( FT_UInt32 ) - tt_cmap2_char_next( TT_CMap cmap, + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap2_char_next( FT_CMap cmap, /* TT_CMap */ FT_UInt32 *pcharcode ) { - FT_Byte* table = cmap->data; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; FT_UInt gindex = 0; FT_UInt32 result = 0; FT_UInt32 charcode = *pcharcode + 1; @@ -579,10 +588,11 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap2_get_info( TT_CMap cmap, + tt_cmap2_get_info( FT_CharMap cmap, /* TT_CMap */ TT_CMapInfo *cmap_info ) { - FT_Byte* p = cmap->data + 4; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 4; cmap_info->format = 2; @@ -706,18 +716,20 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap4_init( TT_CMap4 cmap, - FT_Byte* table ) + tt_cmap4_init( FT_CMap cmap, /* TT_CMap4 */ + void* table_ ) { + TT_CMap4 ttcmap = (TT_CMap4)cmap; + FT_Byte* table = (FT_Byte*)table_; FT_Byte* p; - cmap->cmap.data = table; + ttcmap->cmap.data = table; - p = table + 6; - cmap->num_ranges = FT_PEEK_USHORT( p ) >> 1; - cmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL; - cmap->cur_gindex = 0; + p = table + 6; + ttcmap->num_ranges = FT_PEEK_USHORT( p ) >> 1; + ttcmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL; + ttcmap->cur_gindex = 0; return FT_Err_Ok; } @@ -755,7 +767,7 @@ cmap->cur_start == 0xFFFFU && cmap->cur_end == 0xFFFFU ) { - TT_Face face = (TT_Face)cmap->cmap.cmap.charmap.face; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); FT_Byte* limit = face->cmap_table + face->cmap_size; @@ -788,15 +800,12 @@ static void tt_cmap4_next( TT_CMap4 cmap ) { - TT_Face face = (TT_Face)cmap->cmap.cmap.charmap.face; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); FT_Byte* limit = face->cmap_table + face->cmap_size; FT_UInt charcode; - if ( cmap->cur_charcode >= 0xFFFFUL ) - goto Fail; - charcode = (FT_UInt)cmap->cur_charcode + 1; if ( charcode < cmap->cur_start ) @@ -882,7 +891,6 @@ charcode = cmap->cur_start; } - Fail: cmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL; cmap->cur_gindex = 0; } @@ -916,6 +924,16 @@ length = (FT_UInt)( valid->limit - table ); } + /* it also happens that the `length' field is too small; */ + /* this is easy to correct */ + if ( length < (FT_UInt)( valid->limit - table ) ) + { + if ( valid->level >= FT_VALIDATE_PARANOID ) + FT_INVALID_DATA; + + length = (FT_UInt)( valid->limit - table ); + } + if ( length < 16 ) FT_INVALID_TOO_SHORT; @@ -1087,32 +1105,26 @@ FT_UInt32* pcharcode, FT_Bool next ) { - TT_Face face = (TT_Face)cmap->cmap.charmap.face; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); FT_Byte* limit = face->cmap_table + face->cmap_size; FT_UInt num_segs2, start, end, offset; FT_Int delta; FT_UInt i, num_segs; - FT_UInt32 charcode = *pcharcode; + FT_UInt32 charcode = *pcharcode + next; FT_UInt gindex = 0; FT_Byte* p; FT_Byte* q; p = cmap->data + 6; - num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 ); - - num_segs = num_segs2 >> 1; + num_segs = TT_PEEK_USHORT( p ) >> 1; if ( !num_segs ) return 0; - if ( next ) - charcode++; - - if ( charcode > 0xFFFFU ) - return 0; + num_segs2 = num_segs << 1; /* linear search */ p = cmap->data + 14; /* ends table */ @@ -1222,37 +1234,30 @@ FT_UInt32* pcharcode, FT_Bool next ) { - TT_Face face = (TT_Face)cmap->cmap.charmap.face; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); FT_Byte* limit = face->cmap_table + face->cmap_size; FT_UInt num_segs2, start, end, offset; FT_Int delta; FT_UInt max, min, mid, num_segs; - FT_UInt charcode = (FT_UInt)*pcharcode; + FT_UInt charcode = (FT_UInt)*pcharcode + next; FT_UInt gindex = 0; FT_Byte* p; p = cmap->data + 6; - num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 ); + num_segs = TT_PEEK_USHORT( p ) >> 1; - if ( !num_segs2 ) + if ( !num_segs ) return 0; - num_segs = num_segs2 >> 1; - - /* make compiler happy */ - mid = num_segs; - end = 0xFFFFU; - - if ( next ) - charcode++; + num_segs2 = num_segs << 1; min = 0; max = num_segs; /* binary search */ - while ( min < max ) + do { mid = ( min + max ) >> 1; p = cmap->data + 14 + mid * 2; @@ -1435,6 +1440,7 @@ break; } } + while ( min < max ); if ( next ) { @@ -1444,12 +1450,8 @@ /* if `charcode' is not in any segment, then `mid' is */ /* the segment nearest to `charcode' */ - if ( charcode > end ) - { - mid++; - if ( mid == num_segs ) - return 0; - } + if ( charcode > end && ++mid == num_segs ) + return 0; if ( tt_cmap4_set_range( cmap4, mid ) ) { @@ -1464,7 +1466,6 @@ cmap4->cur_gindex = gindex; else { - cmap4->cur_charcode = charcode; tt_cmap4_next( cmap4 ); gindex = cmap4->cur_gindex; } @@ -1479,31 +1480,35 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap4_char_index( TT_CMap cmap, + tt_cmap4_char_index( FT_CMap cmap, /* TT_CMap */ FT_UInt32 char_code ) { + TT_CMap ttcmap = (TT_CMap)cmap; + + if ( char_code >= 0x10000UL ) return 0; - if ( cmap->flags & TT_CMAP_FLAG_UNSORTED ) - return tt_cmap4_char_map_linear( cmap, &char_code, 0 ); + if ( ttcmap->flags & TT_CMAP_FLAG_UNSORTED ) + return tt_cmap4_char_map_linear( ttcmap, &char_code, 0 ); else - return tt_cmap4_char_map_binary( cmap, &char_code, 0 ); + return tt_cmap4_char_map_binary( ttcmap, &char_code, 0 ); } - FT_CALLBACK_DEF( FT_UInt32 ) - tt_cmap4_char_next( TT_CMap cmap, + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap4_char_next( FT_CMap cmap, /* TT_CMap */ FT_UInt32 *pchar_code ) { + TT_CMap ttcmap = (TT_CMap)cmap; FT_UInt gindex; if ( *pchar_code >= 0xFFFFU ) return 0; - if ( cmap->flags & TT_CMAP_FLAG_UNSORTED ) - gindex = tt_cmap4_char_map_linear( cmap, pchar_code, 1 ); + if ( ttcmap->flags & TT_CMAP_FLAG_UNSORTED ) + gindex = tt_cmap4_char_map_linear( ttcmap, pchar_code, 1 ); else { TT_CMap4 cmap4 = (TT_CMap4)cmap; @@ -1518,7 +1523,7 @@ *pchar_code = cmap4->cur_charcode; } else - gindex = tt_cmap4_char_map_binary( cmap, pchar_code, 1 ); + gindex = tt_cmap4_char_map_binary( ttcmap, pchar_code, 1 ); } return gindex; @@ -1526,10 +1531,11 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap4_get_info( TT_CMap cmap, + tt_cmap4_get_info( FT_CharMap cmap, /* TT_CMap */ TT_CMapInfo *cmap_info ) { - FT_Byte* p = cmap->data + 4; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 4; cmap_info->format = 4; @@ -1630,10 +1636,11 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap6_char_index( TT_CMap cmap, + tt_cmap6_char_index( FT_CMap cmap, /* TT_CMap */ FT_UInt32 char_code ) { - FT_Byte* table = cmap->data; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; FT_UInt result = 0; FT_Byte* p = table + 6; FT_UInt start = TT_NEXT_USHORT( p ); @@ -1651,11 +1658,12 @@ } - FT_CALLBACK_DEF( FT_UInt32 ) - tt_cmap6_char_next( TT_CMap cmap, + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap6_char_next( FT_CMap cmap, /* TT_CMap */ FT_UInt32 *pchar_code ) { - FT_Byte* table = cmap->data; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; FT_UInt32 result = 0; FT_UInt32 char_code = *pchar_code + 1; FT_UInt gindex = 0; @@ -1696,10 +1704,11 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap6_get_info( TT_CMap cmap, + tt_cmap6_get_info( FT_CharMap cmap, /* TT_CMap */ TT_CMapInfo *cmap_info ) { - FT_Byte* p = cmap->data + 4; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 4; cmap_info->format = 6; @@ -1890,10 +1899,11 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap8_char_index( TT_CMap cmap, + tt_cmap8_char_index( FT_CMap cmap, /* TT_CMap */ FT_UInt32 char_code ) { - FT_Byte* table = cmap->data; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; FT_UInt result = 0; FT_Byte* p = table + 8204; FT_UInt32 num_groups = TT_NEXT_ULONG( p ); @@ -1922,15 +1932,16 @@ } - FT_CALLBACK_DEF( FT_UInt32 ) - tt_cmap8_char_next( TT_CMap cmap, + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap8_char_next( FT_CMap cmap, /* TT_CMap */ FT_UInt32 *pchar_code ) { - FT_Face face = cmap->cmap.charmap.face; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Face face = FT_CMAP_FACE( cmap ); FT_UInt32 result = 0; FT_UInt32 char_code; FT_UInt gindex = 0; - FT_Byte* table = cmap->data; + FT_Byte* table = ttcmap->data; FT_Byte* p = table + 8204; FT_UInt32 num_groups = TT_NEXT_ULONG( p ); FT_UInt32 start, end, start_id; @@ -1990,10 +2001,11 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap8_get_info( TT_CMap cmap, + tt_cmap8_get_info( FT_CharMap cmap, /* TT_CMap */ TT_CMapInfo *cmap_info ) { - FT_Byte* p = cmap->data + 8; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 8; cmap_info->format = 8; @@ -2094,10 +2106,11 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap10_char_index( TT_CMap cmap, + tt_cmap10_char_index( FT_CMap cmap, /* TT_CMap */ FT_UInt32 char_code ) { - FT_Byte* table = cmap->data; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; FT_UInt result = 0; FT_Byte* p = table + 12; FT_UInt32 start = TT_NEXT_ULONG( p ); @@ -2120,11 +2133,12 @@ } - FT_CALLBACK_DEF( FT_UInt32 ) - tt_cmap10_char_next( TT_CMap cmap, + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap10_char_next( FT_CMap cmap, /* TT_CMap */ FT_UInt32 *pchar_code ) { - FT_Byte* table = cmap->data; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* table = ttcmap->data; FT_UInt32 char_code; FT_UInt gindex = 0; FT_Byte* p = table + 12; @@ -2162,10 +2176,11 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap10_get_info( TT_CMap cmap, + tt_cmap10_get_info( FT_CharMap cmap, /* TT_CMap */ TT_CMapInfo *cmap_info ) { - FT_Byte* p = cmap->data + 8; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 8; cmap_info->format = 10; @@ -2243,15 +2258,19 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap12_init( TT_CMap12 cmap, - FT_Byte* table ) + tt_cmap12_init( FT_CMap cmap, /* TT_CMap12 */ + void* table_ ) { - cmap->cmap.data = table; + TT_CMap12 ttcmap = (TT_CMap12)cmap; + FT_Byte* table = (FT_Byte*)table_; + + + ttcmap->cmap.data = table; - table += 12; - cmap->num_groups = FT_PEEK_ULONG( table ); + table += 12; + ttcmap->num_groups = FT_PEEK_ULONG( table ); - cmap->valid = 0; + ttcmap->valid = 0; return FT_Err_Ok; } @@ -2321,23 +2340,21 @@ /* cmap->cur_group should be set up properly by caller */ /* */ static void - tt_cmap12_next( TT_CMap12 cmap ) + tt_cmap12_next( FT_CMap cmap ) /* TT_CMap12 */ { - FT_Face face = cmap->cmap.cmap.charmap.face; - FT_Byte* p; - FT_ULong start, end, start_id, char_code; - FT_ULong n; - FT_UInt gindex; - + TT_CMap12 ttcmap = (TT_CMap12)cmap; + FT_Face face = FT_CMAP_FACE( cmap ); + FT_Byte* p; + FT_ULong start, end, start_id, char_code; + FT_ULong n; + FT_UInt gindex; - if ( cmap->cur_charcode >= 0xFFFFFFFFUL ) - goto Fail; - char_code = cmap->cur_charcode + 1; + char_code = ttcmap->cur_charcode + 1; - for ( n = cmap->cur_group; n < cmap->num_groups; n++ ) + for ( n = ttcmap->cur_group; n < ttcmap->num_groups; n++ ) { - p = cmap->cmap.data + 16 + 12 * n; + p = ttcmap->cmap.data + 16 + 12 * n; start = TT_NEXT_ULONG( p ); end = TT_NEXT_ULONG( p ); start_id = TT_PEEK_ULONG( p ); @@ -2369,16 +2386,16 @@ if ( gindex >= (FT_UInt)face->num_glyphs ) continue; - cmap->cur_charcode = char_code; - cmap->cur_gindex = gindex; - cmap->cur_group = n; + ttcmap->cur_charcode = char_code; + ttcmap->cur_gindex = gindex; + ttcmap->cur_group = n; return; } } Fail: - cmap->valid = 0; + ttcmap->valid = 0; } @@ -2390,7 +2407,7 @@ FT_UInt gindex = 0; FT_Byte* p = cmap->data + 12; FT_UInt32 num_groups = TT_PEEK_ULONG( p ); - FT_UInt32 char_code = *pchar_code; + FT_UInt32 char_code = *pchar_code + next; FT_UInt32 start, end, start_id; FT_UInt32 max, min, mid; @@ -2398,23 +2415,11 @@ if ( !num_groups ) return 0; - /* make compiler happy */ - mid = num_groups; - end = 0xFFFFFFFFUL; - - if ( next ) - { - if ( char_code >= 0xFFFFFFFFUL ) - return 0; - - char_code++; - } - min = 0; max = num_groups; /* binary search */ - while ( min < max ) + do { mid = ( min + max ) >> 1; p = cmap->data + 16 + 12 * mid; @@ -2438,22 +2443,19 @@ break; } } + while ( min < max ); if ( next ) { - FT_Face face = cmap->cmap.charmap.face; + FT_Face face = FT_CMAP_FACE( cmap ); TT_CMap12 cmap12 = (TT_CMap12)cmap; /* if `char_code' is not in any group, then `mid' is */ /* the group nearest to `char_code' */ - if ( char_code > end ) - { - mid++; - if ( mid == num_groups ) - return 0; - } + if ( char_code > end && ++mid == num_groups ) + return 0; cmap12->valid = 1; cmap12->cur_charcode = char_code; @@ -2464,7 +2466,7 @@ if ( !gindex ) { - tt_cmap12_next( cmap12 ); + tt_cmap12_next( FT_CMAP( cmap12 ) ); if ( cmap12->valid ) gindex = cmap12->cur_gindex; @@ -2480,25 +2482,28 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap12_char_index( TT_CMap cmap, + tt_cmap12_char_index( FT_CMap cmap, /* TT_CMap */ FT_UInt32 char_code ) { - return tt_cmap12_char_map_binary( cmap, &char_code, 0 ); + return tt_cmap12_char_map_binary( (TT_CMap)cmap, &char_code, 0 ); } - FT_CALLBACK_DEF( FT_UInt32 ) - tt_cmap12_char_next( TT_CMap cmap, + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap12_char_next( FT_CMap cmap, /* TT_CMap12 */ FT_UInt32 *pchar_code ) { TT_CMap12 cmap12 = (TT_CMap12)cmap; FT_UInt gindex; + if ( *pchar_code >= 0xFFFFFFFFUL ) + return 0; + /* no need to search */ if ( cmap12->valid && cmap12->cur_charcode == *pchar_code ) { - tt_cmap12_next( cmap12 ); + tt_cmap12_next( FT_CMAP( cmap12 ) ); if ( cmap12->valid ) { gindex = cmap12->cur_gindex; @@ -2508,17 +2513,18 @@ gindex = 0; } else - gindex = tt_cmap12_char_map_binary( cmap, pchar_code, 1 ); + gindex = tt_cmap12_char_map_binary( (TT_CMap)cmap, pchar_code, 1 ); return gindex; } FT_CALLBACK_DEF( FT_Error ) - tt_cmap12_get_info( TT_CMap cmap, + tt_cmap12_get_info( FT_CharMap cmap, /* TT_CMap */ TT_CMapInfo *cmap_info ) { - FT_Byte* p = cmap->data + 8; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 8; cmap_info->format = 12; @@ -2596,15 +2602,19 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap13_init( TT_CMap13 cmap, - FT_Byte* table ) + tt_cmap13_init( FT_CMap cmap, /* TT_CMap13 */ + void* table_ ) { - cmap->cmap.data = table; + TT_CMap13 ttcmap = (TT_CMap13)cmap; + FT_Byte* table = (FT_Byte*)table_; - table += 12; - cmap->num_groups = FT_PEEK_ULONG( table ); - cmap->valid = 0; + ttcmap->cmap.data = table; + + table += 12; + ttcmap->num_groups = FT_PEEK_ULONG( table ); + + ttcmap->valid = 0; return FT_Err_Ok; } @@ -2669,23 +2679,21 @@ /* cmap->cur_group should be set up properly by caller */ /* */ static void - tt_cmap13_next( TT_CMap13 cmap ) + tt_cmap13_next( FT_CMap cmap ) /* TT_CMap13 */ { - FT_Face face = cmap->cmap.cmap.charmap.face; - FT_Byte* p; - FT_ULong start, end, glyph_id, char_code; - FT_ULong n; - FT_UInt gindex; - + TT_CMap13 ttcmap = (TT_CMap13)cmap; + FT_Face face = FT_CMAP_FACE( cmap ); + FT_Byte* p; + FT_ULong start, end, glyph_id, char_code; + FT_ULong n; + FT_UInt gindex; - if ( cmap->cur_charcode >= 0xFFFFFFFFUL ) - goto Fail; - char_code = cmap->cur_charcode + 1; + char_code = ttcmap->cur_charcode + 1; - for ( n = cmap->cur_group; n < cmap->num_groups; n++ ) + for ( n = ttcmap->cur_group; n < ttcmap->num_groups; n++ ) { - p = cmap->cmap.data + 16 + 12 * n; + p = ttcmap->cmap.data + 16 + 12 * n; start = TT_NEXT_ULONG( p ); end = TT_NEXT_ULONG( p ); glyph_id = TT_PEEK_ULONG( p ); @@ -2699,17 +2707,16 @@ if ( gindex && gindex < (FT_UInt)face->num_glyphs ) { - cmap->cur_charcode = char_code; - cmap->cur_gindex = gindex; - cmap->cur_group = n; + ttcmap->cur_charcode = char_code; + ttcmap->cur_gindex = gindex; + ttcmap->cur_group = n; return; } } } - Fail: - cmap->valid = 0; + ttcmap->valid = 0; } @@ -2721,7 +2728,7 @@ FT_UInt gindex = 0; FT_Byte* p = cmap->data + 12; FT_UInt32 num_groups = TT_PEEK_ULONG( p ); - FT_UInt32 char_code = *pchar_code; + FT_UInt32 char_code = *pchar_code + next; FT_UInt32 start, end; FT_UInt32 max, min, mid; @@ -2729,23 +2736,11 @@ if ( !num_groups ) return 0; - /* make compiler happy */ - mid = num_groups; - end = 0xFFFFFFFFUL; - - if ( next ) - { - if ( char_code >= 0xFFFFFFFFUL ) - return 0; - - char_code++; - } - min = 0; max = num_groups; /* binary search */ - while ( min < max ) + do { mid = ( min + max ) >> 1; p = cmap->data + 16 + 12 * mid; @@ -2764,6 +2759,7 @@ break; } } + while ( min < max ); if ( next ) { @@ -2774,12 +2770,8 @@ /* if `char_code' is not in any group, then `mid' is */ /* the group nearest to `char_code' */ - if ( char_code > end ) - { - mid++; - if ( mid == num_groups ) - return 0; - } + if ( char_code > end && ++mid == num_groups ) + return 0; cmap13->valid = 1; cmap13->cur_charcode = char_code; @@ -2790,7 +2782,7 @@ if ( !gindex ) { - tt_cmap13_next( cmap13 ); + tt_cmap13_next( FT_CMAP( cmap13 ) ); if ( cmap13->valid ) gindex = cmap13->cur_gindex; @@ -2806,25 +2798,28 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap13_char_index( TT_CMap cmap, + tt_cmap13_char_index( FT_CMap cmap, /* TT_CMap */ FT_UInt32 char_code ) { - return tt_cmap13_char_map_binary( cmap, &char_code, 0 ); + return tt_cmap13_char_map_binary( (TT_CMap)cmap, &char_code, 0 ); } - FT_CALLBACK_DEF( FT_UInt32 ) - tt_cmap13_char_next( TT_CMap cmap, + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap13_char_next( FT_CMap cmap, /* TT_CMap13 */ FT_UInt32 *pchar_code ) { TT_CMap13 cmap13 = (TT_CMap13)cmap; FT_UInt gindex; + if ( *pchar_code >= 0xFFFFFFFFUL ) + return 0; + /* no need to search */ if ( cmap13->valid && cmap13->cur_charcode == *pchar_code ) { - tt_cmap13_next( cmap13 ); + tt_cmap13_next( FT_CMAP( cmap13 ) ); if ( cmap13->valid ) { gindex = cmap13->cur_gindex; @@ -2834,17 +2829,18 @@ gindex = 0; } else - gindex = tt_cmap13_char_map_binary( cmap, pchar_code, 1 ); + gindex = tt_cmap13_char_map_binary( (TT_CMap)cmap, pchar_code, 1 ); return gindex; } FT_CALLBACK_DEF( FT_Error ) - tt_cmap13_get_info( TT_CMap cmap, + tt_cmap13_get_info( FT_CharMap cmap, /* TT_CMap */ TT_CMapInfo *cmap_info ) { - FT_Byte* p = cmap->data + 8; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = ttcmap->data + 8; cmap_info->format = 13; @@ -2959,14 +2955,15 @@ FT_CALLBACK_DEF( void ) - tt_cmap14_done( TT_CMap14 cmap ) + tt_cmap14_done( FT_CMap cmap ) /* TT_CMap14 */ { - FT_Memory memory = cmap->memory; + TT_CMap14 ttcmap = (TT_CMap14)cmap; + FT_Memory memory = ttcmap->memory; - cmap->max_results = 0; - if ( memory && cmap->results ) - FT_FREE( cmap->results ); + ttcmap->max_results = 0; + if ( memory && ttcmap->results ) + FT_FREE( ttcmap->results ); } @@ -2994,15 +2991,19 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap14_init( TT_CMap14 cmap, - FT_Byte* table ) + tt_cmap14_init( FT_CMap cmap, /* TT_CMap14 */ + void* table_ ) { - cmap->cmap.data = table; + TT_CMap14 ttcmap = (TT_CMap14)cmap; + FT_Byte* table = (FT_Byte*)table_; + + + ttcmap->cmap.data = table; - table += 6; - cmap->num_selectors = FT_PEEK_ULONG( table ); - cmap->max_results = 0; - cmap->results = NULL; + table += 6; + ttcmap->num_selectors = FT_PEEK_ULONG( table ); + ttcmap->max_results = 0; + ttcmap->results = NULL; return FT_Err_Ok; } @@ -3132,7 +3133,7 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap14_char_index( TT_CMap cmap, + tt_cmap14_char_index( FT_CMap cmap, FT_UInt32 char_code ) { FT_UNUSED( cmap ); @@ -3143,8 +3144,8 @@ } - FT_CALLBACK_DEF( FT_UInt32 ) - tt_cmap14_char_next( TT_CMap cmap, + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap14_char_next( FT_CMap cmap, FT_UInt32 *pchar_code ) { FT_UNUSED( cmap ); @@ -3156,7 +3157,7 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap14_get_info( TT_CMap cmap, + tt_cmap14_get_info( FT_CharMap cmap, TT_CMapInfo *cmap_info ) { FT_UNUSED( cmap ); @@ -3270,12 +3271,16 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap14_char_var_index( TT_CMap cmap, - TT_CMap ucmap, + tt_cmap14_char_var_index( FT_CMap cmap, /* TT_CMap */ + FT_CMap ucmap, /* TT_CMap */ FT_UInt32 charcode, FT_UInt32 variantSelector ) { - FT_Byte* p = tt_cmap14_find_variant( cmap->data + 6, variantSelector ); + TT_CMap ttcmap = (TT_CMap)cmap; + TT_CMap ttucmap = (TT_CMap)ucmap; + + FT_Byte* p = tt_cmap14_find_variant( ttcmap->data + 6, + variantSelector ); FT_ULong defOff; FT_ULong nondefOff; @@ -3286,16 +3291,16 @@ defOff = TT_NEXT_ULONG( p ); nondefOff = TT_PEEK_ULONG( p ); - if ( defOff != 0 && - tt_cmap14_char_map_def_binary( cmap->data + defOff, charcode ) ) + if ( defOff != 0 && + tt_cmap14_char_map_def_binary( ttcmap->data + defOff, charcode ) ) { /* This is the default variant of this charcode. GID not stored */ /* here; stored in the normal Unicode charmap instead. */ - return ucmap->cmap.clazz->char_index( &ucmap->cmap, charcode ); + return ttucmap->cmap.clazz->char_index( &ttucmap->cmap, charcode ); } if ( nondefOff != 0 ) - return tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff, + return tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff, charcode ); return 0; @@ -3303,11 +3308,13 @@ FT_CALLBACK_DEF( FT_Int ) - tt_cmap14_char_var_isdefault( TT_CMap cmap, + tt_cmap14_char_var_isdefault( FT_CMap cmap, /* TT_CMap */ FT_UInt32 charcode, FT_UInt32 variantSelector ) { - FT_Byte* p = tt_cmap14_find_variant( cmap->data + 6, variantSelector ); + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte* p = tt_cmap14_find_variant( ttcmap->data + 6, + variantSelector ); FT_ULong defOff; FT_ULong nondefOff; @@ -3318,13 +3325,13 @@ defOff = TT_NEXT_ULONG( p ); nondefOff = TT_NEXT_ULONG( p ); - if ( defOff != 0 && - tt_cmap14_char_map_def_binary( cmap->data + defOff, charcode ) ) + if ( defOff != 0 && + tt_cmap14_char_map_def_binary( ttcmap->data + defOff, charcode ) ) return 1; - if ( nondefOff != 0 && - tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff, - charcode ) != 0 ) + if ( nondefOff != 0 && + tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff, + charcode ) != 0 ) return 0; return -1; @@ -3332,12 +3339,13 @@ FT_CALLBACK_DEF( FT_UInt32* ) - tt_cmap14_variants( TT_CMap cmap, + tt_cmap14_variants( FT_CMap cmap, /* TT_CMap14 */ FT_Memory memory ) { + TT_CMap ttcmap = (TT_CMap)cmap; TT_CMap14 cmap14 = (TT_CMap14)cmap; FT_UInt32 count = cmap14->num_selectors; - FT_Byte* p = cmap->data + 10; + FT_Byte* p = ttcmap->data + 10; FT_UInt32* result; FT_UInt32 i; @@ -3358,13 +3366,14 @@ FT_CALLBACK_DEF( FT_UInt32 * ) - tt_cmap14_char_variants( TT_CMap cmap, + tt_cmap14_char_variants( FT_CMap cmap, /* TT_CMap14 */ FT_Memory memory, FT_UInt32 charCode ) { - TT_CMap14 cmap14 = (TT_CMap14) cmap; + TT_CMap ttcmap = (TT_CMap)cmap; + TT_CMap14 cmap14 = (TT_CMap14)cmap; FT_UInt32 count = cmap14->num_selectors; - FT_Byte* p = cmap->data + 10; + FT_Byte* p = ttcmap->data + 10; FT_UInt32* q; @@ -3378,12 +3387,12 @@ FT_ULong nondefOff = TT_NEXT_ULONG( p ); - if ( ( defOff != 0 && - tt_cmap14_char_map_def_binary( cmap->data + defOff, - charCode ) ) || - ( nondefOff != 0 && - tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff, - charCode ) != 0 ) ) + if ( ( defOff != 0 && + tt_cmap14_char_map_def_binary( ttcmap->data + defOff, + charCode ) ) || + ( nondefOff != 0 && + tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff, + charCode ) != 0 ) ) { q[0] = varSel; q++; @@ -3479,15 +3488,16 @@ FT_CALLBACK_DEF( FT_UInt32 * ) - tt_cmap14_variant_chars( TT_CMap cmap, + tt_cmap14_variant_chars( FT_CMap cmap, /* TT_CMap */ FT_Memory memory, FT_UInt32 variantSelector ) { - FT_Byte *p = tt_cmap14_find_variant( cmap->data + 6, - variantSelector ); - FT_Int i; - FT_ULong defOff; - FT_ULong nondefOff; + TT_CMap ttcmap = (TT_CMap)cmap; + FT_Byte *p = tt_cmap14_find_variant( ttcmap->data + 6, + variantSelector ); + FT_Int i; + FT_ULong defOff; + FT_ULong nondefOff; if ( !p ) @@ -3500,16 +3510,16 @@ return NULL; if ( defOff == 0 ) - return tt_cmap14_get_nondef_chars( cmap, cmap->data + nondefOff, + return tt_cmap14_get_nondef_chars( ttcmap, ttcmap->data + nondefOff, memory ); else if ( nondefOff == 0 ) - return tt_cmap14_get_def_chars( cmap, cmap->data + defOff, + return tt_cmap14_get_def_chars( ttcmap, ttcmap->data + defOff, memory ); else { /* Both a default and a non-default glyph set? That's probably not */ /* good font design, but the spec allows for it... */ - TT_CMap14 cmap14 = (TT_CMap14) cmap; + TT_CMap14 cmap14 = (TT_CMap14)cmap; FT_UInt32 numRanges; FT_UInt32 numMappings; FT_UInt32 duni; @@ -3521,18 +3531,18 @@ FT_UInt32 *ret; - p = cmap->data + nondefOff; - dp = cmap->data + defOff; + p = ttcmap->data + nondefOff; + dp = ttcmap->data + defOff; numMappings = (FT_UInt32)TT_NEXT_ULONG( p ); dcnt = tt_cmap14_def_char_count( dp ); numRanges = (FT_UInt32)TT_NEXT_ULONG( dp ); if ( numMappings == 0 ) - return tt_cmap14_get_def_chars( cmap, cmap->data + defOff, + return tt_cmap14_get_def_chars( ttcmap, ttcmap->data + defOff, memory ); if ( dcnt == 0 ) - return tt_cmap14_get_nondef_chars( cmap, cmap->data + nondefOff, + return tt_cmap14_get_nondef_chars( ttcmap, ttcmap->data + nondefOff, memory ); if ( tt_cmap14_ensure( cmap14, ( dcnt + numMappings + 1 ), memory ) ) @@ -3654,9 +3664,10 @@ #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES FT_CALLBACK_DEF( const char * ) - tt_get_glyph_name( TT_Face face, + tt_get_glyph_name( void* face_, /* TT_Face */ FT_UInt idx ) { + TT_Face face = (TT_Face)face_; FT_String* PSname = NULL; @@ -3667,12 +3678,13 @@ FT_CALLBACK_DEF( FT_Error ) - tt_cmap_unicode_init( PS_Unicodes unicodes, - FT_Pointer pointer ) + tt_cmap_unicode_init( FT_CMap cmap, /* PS_Unicodes */ + FT_Pointer pointer ) { - TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes ); - FT_Memory memory = FT_FACE_MEMORY( face ); - FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + PS_Unicodes unicodes = (PS_Unicodes)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; FT_UNUSED( pointer ); @@ -3683,17 +3695,18 @@ return psnames->unicodes_init( memory, unicodes, face->root.num_glyphs, - (PS_GetGlyphNameFunc)&tt_get_glyph_name, + &tt_get_glyph_name, (PS_FreeGlyphNameFunc)NULL, (FT_Pointer)face ); } FT_CALLBACK_DEF( void ) - tt_cmap_unicode_done( PS_Unicodes unicodes ) + tt_cmap_unicode_done( FT_CMap cmap ) /* PS_Unicodes */ { - FT_Face face = FT_CMAP_FACE( unicodes ); - FT_Memory memory = FT_FACE_MEMORY( face ); + PS_Unicodes unicodes = (PS_Unicodes)cmap; + FT_Face face = FT_CMAP_FACE( cmap ); + FT_Memory memory = FT_FACE_MEMORY( face ); FT_FREE( unicodes->maps ); @@ -3702,23 +3715,25 @@ FT_CALLBACK_DEF( FT_UInt ) - tt_cmap_unicode_char_index( PS_Unicodes unicodes, - FT_UInt32 char_code ) + tt_cmap_unicode_char_index( FT_CMap cmap, /* PS_Unicodes */ + FT_UInt32 char_code ) { - TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes ); - FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + PS_Unicodes unicodes = (PS_Unicodes)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; return psnames->unicodes_char_index( unicodes, char_code ); } - FT_CALLBACK_DEF( FT_UInt32 ) - tt_cmap_unicode_char_next( PS_Unicodes unicodes, - FT_UInt32 *pchar_code ) + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap_unicode_char_next( FT_CMap cmap, /* PS_Unicodes */ + FT_UInt32 *pchar_code ) { - TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes ); - FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; + PS_Unicodes unicodes = (PS_Unicodes)cmap; + TT_Face face = (TT_Face)FT_CMAP_FACE( cmap ); + FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames; return psnames->unicodes_char_next( unicodes, pchar_code ); @@ -3869,13 +3884,14 @@ } - FT_LOCAL( FT_Error ) + FT_LOCAL_DEF( FT_Error ) tt_get_cmap_info( FT_CharMap charmap, TT_CMapInfo *cmap_info ) { - FT_CMap cmap = (FT_CMap)charmap; + FT_CMap cmap = FT_CMAP( charmap ); TT_CMap_Class clazz = (TT_CMap_Class)cmap->clazz; + if ( clazz->get_cmap_info ) return clazz->get_cmap_info( charmap, cmap_info ); else diff --git a/src/3rdparty/freetype/src/sfnt/ttcmap.h b/src/3rdparty/freetype/src/sfnt/ttcmap.h index c7d7c21d2c..ff52917ed5 100644 --- a/src/3rdparty/freetype/src/sfnt/ttcmap.h +++ b/src/3rdparty/freetype/src/sfnt/ttcmap.h @@ -4,7 +4,7 @@ * * TrueType character mapping table (cmap) support (specification). * - * Copyright (C) 2002-2020 by + * Copyright (C) 2002-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/3rdparty/freetype/src/sfnt/ttcmapc.h b/src/3rdparty/freetype/src/sfnt/ttcmapc.h index 2e4ce5075b..0af48c2478 100644 --- a/src/3rdparty/freetype/src/sfnt/ttcmapc.h +++ b/src/3rdparty/freetype/src/sfnt/ttcmapc.h @@ -4,7 +4,7 @@ * * TT CMAP classes definitions (specification only). * - * Copyright (C) 2009-2020 by + * Copyright (C) 2009-2023 by * Oran Agra and Mickey Gabel. * * This file is part of the FreeType project, and may only be used, diff --git a/src/3rdparty/freetype/src/sfnt/ttcolr.c b/src/3rdparty/freetype/src/sfnt/ttcolr.c index 9025e356ce..281e7135ee 100644 --- a/src/3rdparty/freetype/src/sfnt/ttcolr.c +++ b/src/3rdparty/freetype/src/sfnt/ttcolr.c @@ -4,8 +4,8 @@ * * TrueType and OpenType colored glyph layer support (body). * - * Copyright (C) 2018-2020 by - * David Turner, Robert Wilhelm, and Werner Lemberg. + * Copyright (C) 2018-2023 by + * David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg. * * Originally written by Shao Yu Zhang <shaozhang@fb.com>. * @@ -27,11 +27,16 @@ */ +#include <freetype/internal/ftcalc.h> #include <freetype/internal/ftdebug.h> #include <freetype/internal/ftstream.h> #include <freetype/tttags.h> #include <freetype/ftcolor.h> +#include <freetype/config/integer-types.h> +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#include <freetype/internal/services/svmm.h> +#endif #ifdef TT_CONFIG_OPTION_COLOR_LAYERS @@ -39,12 +44,52 @@ /* NOTE: These are the table sizes calculated through the specs. */ -#define BASE_GLYPH_SIZE 6U -#define LAYER_SIZE 4U -#define COLR_HEADER_SIZE 14U - - - typedef struct BaseGlyphRecord_ +#define BASE_GLYPH_SIZE 6U +#define BASE_GLYPH_PAINT_RECORD_SIZE 6U +#define LAYER_V1_LIST_PAINT_OFFSET_SIZE 4U +#define LAYER_V1_LIST_NUM_LAYERS_SIZE 4U +#define COLOR_STOP_SIZE 6U +#define VAR_IDX_BASE_SIZE 4U +#define LAYER_SIZE 4U +/* https://docs.microsoft.com/en-us/typography/opentype/spec/colr#colr-header */ +/* 3 * uint16 + 2 * Offset32 */ +#define COLRV0_HEADER_SIZE 14U +/* COLRV0_HEADER_SIZE + 5 * Offset32 */ +#define COLRV1_HEADER_SIZE 34U + + +#define ENSURE_READ_BYTES( byte_size ) \ + if ( p < colr->paints_start_v1 || \ + p > (FT_Byte*)colr->table + colr->table_size - byte_size ) \ + return 0 + + + 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_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; + + + typedef struct BaseGlyphRecord_ { FT_UShort gid; FT_UShort first_layer_index; @@ -53,7 +98,16 @@ } BaseGlyphRecord; - typedef struct Colr_ + typedef struct BaseGlyphV1Record_ + { + FT_UShort gid; + /* Offset from start of BaseGlyphV1List, i.e., from base_glyphs_v1. */ + FT_ULong paint_offset; + + } BaseGlyphV1Record; + + + typedef struct Colr_ { FT_UShort version; FT_UShort num_base_glyphs; @@ -62,7 +116,29 @@ FT_Byte* base_glyphs; FT_Byte* layers; - /* The memory which backs up the `COLR' table. */ + FT_ULong num_base_glyphs_v1; + /* Points at beginning of BaseGlyphV1List. */ + FT_Byte* base_glyphs_v1; + + FT_ULong num_layers_v1; + FT_Byte* layers_v1; + + FT_Byte* clip_list; + + /* + * Paint tables start at the minimum of the end of the LayerList and the + * end of the BaseGlyphList. Record this location in a field here for + * safety checks when accessing paint tables. + */ + 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; @@ -88,11 +164,18 @@ FT_Byte* table = NULL; FT_Byte* p = NULL; + /* Needed for reading array lengths in referenced tables. */ + FT_Byte* p1 = NULL; Colr* colr = NULL; FT_ULong base_glyph_offset, layer_offset; + 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' */ @@ -103,8 +186,12 @@ if ( error ) goto NoColr; - if ( table_size < COLR_HEADER_SIZE ) - goto InvalidTable; +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + colr_offset_in_stream = FT_STREAM_POS(); +#endif + + if ( table_size < COLRV0_HEADER_SIZE ) + goto NoColr; if ( FT_FRAME_EXTRACT( table_size, table ) ) goto NoColr; @@ -115,7 +202,7 @@ goto NoColr; colr->version = FT_NEXT_USHORT( p ); - if ( colr->version != 0 ) + if ( colr->version != 0 && colr->version != 1 ) goto InvalidTable; colr->num_base_glyphs = FT_NEXT_USHORT( p ); @@ -135,6 +222,131 @@ if ( colr->num_layers * LAYER_SIZE > table_size - layer_offset ) goto InvalidTable; + if ( colr->version == 1 ) + { + if ( table_size < COLRV1_HEADER_SIZE ) + goto InvalidTable; + + base_glyphs_offset_v1 = FT_NEXT_ULONG( p ); + + if ( base_glyphs_offset_v1 >= table_size - 4 ) + goto InvalidTable; + + p1 = (FT_Byte*)( table + base_glyphs_offset_v1 ); + num_base_glyphs_v1 = FT_PEEK_ULONG( p1 ); + + if ( num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE > + table_size - base_glyphs_offset_v1 ) + goto InvalidTable; + + colr->num_base_glyphs_v1 = num_base_glyphs_v1; + colr->base_glyphs_v1 = p1; + + layer_offset_v1 = FT_NEXT_ULONG( p ); + + if ( layer_offset_v1 >= table_size ) + goto InvalidTable; + + if ( layer_offset_v1 ) + { + if ( layer_offset_v1 >= table_size - 4 ) + goto InvalidTable; + + p1 = (FT_Byte*)( table + layer_offset_v1 ); + num_layers_v1 = FT_PEEK_ULONG( p1 ); + + if ( num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE > + table_size - layer_offset_v1 ) + goto InvalidTable; + + colr->num_layers_v1 = num_layers_v1; + colr->layers_v1 = p1; + + colr->paints_start_v1 = + FT_MIN( colr->base_glyphs_v1 + + colr->num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE, + colr->layers_v1 + + colr->num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE ); + } + else + { + colr->num_layers_v1 = 0; + colr->layers_v1 = 0; + colr->paints_start_v1 = + colr->base_glyphs_v1 + + colr->num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE; + } + + clip_list_offset = FT_NEXT_ULONG( p ); + + if ( clip_list_offset >= table_size ) + goto InvalidTable; + + if ( clip_list_offset ) + 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 ) + { + 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 ); colr->layers = (FT_Byte*)( table + layer_offset ); colr->table = table; @@ -145,6 +357,18 @@ return FT_Err_Ok; InvalidTable: +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + 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: @@ -166,6 +390,17 @@ if ( colr ) { +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + 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 ); } @@ -174,17 +409,17 @@ static FT_Bool find_base_glyph_record( FT_Byte* base_glyph_begin, - FT_Int num_base_glyph, + FT_UInt num_base_glyph, FT_UInt glyph_id, BaseGlyphRecord* record ) { - FT_Int min = 0; - FT_Int max = num_base_glyph - 1; + FT_UInt min = 0; + FT_UInt max = num_base_glyph; - while ( min <= max ) + while ( min < max ) { - FT_Int mid = min + ( max - min ) / 2; + FT_UInt mid = min + ( max - min ) / 2; FT_Byte* p = base_glyph_begin + mid * BASE_GLYPH_SIZE; FT_UShort gid = FT_NEXT_USHORT( p ); @@ -193,7 +428,7 @@ if ( gid < glyph_id ) min = mid + 1; else if (gid > glyph_id ) - max = mid - 1; + max = mid; else { record->gid = gid; @@ -248,7 +483,9 @@ iterator->p = colr->layers + offset; } - if ( iterator->layer >= iterator->num_layers ) + if ( iterator->layer >= iterator->num_layers || + iterator->p < colr->layers || + iterator->p >= ( (FT_Byte*)colr->table + colr->table_size ) ) return 0; *aglyph_index = FT_NEXT_USHORT( iterator->p ); @@ -265,6 +502,1240 @@ } + static FT_Bool + read_color_line( Colr* colr, + FT_Byte* color_line_p, + FT_ColorLine* colorline, + FT_Bool read_variable ) + { + FT_Byte* p = color_line_p; + FT_PaintExtend paint_extend; + + + ENSURE_READ_BYTES( 3 ); + + paint_extend = (FT_PaintExtend)FT_NEXT_BYTE( p ); + if ( paint_extend > FT_COLR_PAINT_EXTEND_REFLECT ) + return 0; + + colorline->extend = paint_extend; + + 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; + } + + + /* + * Read a paint offset for `FT_Paint*` objects that have them and check + * whether it is within reasonable limits within the font and the COLR + * table. + * + * Return 1 on success, 0 on failure. + */ + static FT_Bool + get_child_table_pointer ( Colr* colr, + FT_Byte* paint_base, + FT_Byte** p, + FT_Byte** child_table_pointer ) + { + FT_UInt32 paint_offset; + FT_Byte* child_table_p; + + + if ( !child_table_pointer ) + return 0; + + if ( *p < colr->paints_start_v1 || + *p > (FT_Byte*)colr->table + colr->table_size - 1 - 3 ) + return 0; + + paint_offset = FT_NEXT_UOFF3( *p ); + if ( !paint_offset ) + return 0; + + child_table_p = (FT_Byte*)( paint_base + paint_offset ); + + if ( child_table_p < colr->paints_start_v1 || + child_table_p >= ( (FT_Byte*)colr->table + colr->table_size ) ) + return 0; + + *child_table_pointer = child_table_p; + return 1; + } + + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + + static FT_Bool + 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 ( 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 + { + outer_index = 0; + inner_index = loop_var_index; + } + + 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_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 ) + return 0; + + /* The last byte of the 'COLR' table is at 'size-1'; subtract 1 of */ + /* that to account for the expected format byte we are going to read. */ + if ( p < colr->paints_start_v1 || + p > (FT_Byte*)colr->table + colr->table_size - 2 ) + return 0; + + apaint->format = (FT_PaintFormat)FT_NEXT_BYTE( p ); + + if ( apaint->format >= FT_COLR_PAINT_FORMAT_MAX ) + return 0; + + if ( apaint->format == FT_COLR_PAINTFORMAT_COLR_LAYERS ) + { + /* Initialize layer iterator/ */ + FT_Byte num_layers; + FT_UInt32 first_layer_index; + + + num_layers = FT_NEXT_BYTE( p ); + if ( num_layers > colr->num_layers_v1 ) + return 0; + + first_layer_index = FT_NEXT_ULONG( p ); + if ( first_layer_index + num_layers > colr->num_layers_v1 ) + return 0; + + apaint->u.colr_layers.layer_iterator.num_layers = num_layers; + apaint->u.colr_layers.layer_iterator.layer = 0; + /* TODO: Check whether pointer is outside colr? */ + apaint->u.colr_layers.layer_iterator.p = + colr->layers_v1 + + LAYER_V1_LIST_NUM_LAYERS_SIZE + + LAYER_V1_LIST_PAINT_OFFSET_SIZE * first_layer_index; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_SOLID || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SOLID ) + { + ENSURE_READ_BYTES( 4 ); + 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 ) + { + ENSURE_READ_BYTES( 4 ); + 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 += (FT_F2Dot14)item_deltas[0]; + } +#endif + + apaint->format = FT_COLR_PAINTFORMAT_SOLID; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_COLR_GLYPH ) + { + ENSURE_READ_BYTES(2); + apaint->u.colr_glyph.glyphID = FT_NEXT_USHORT( p ); + + return 1; + } + + /* + * Grouped below here are all paint formats that have an offset to a + * child paint table as the first entry (for example, a color line or a + * child paint table). Retrieve that and determine whether that paint + * offset is valid first. + */ + + if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) ) + return 0; + + 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( colr, + child_table_p, + &apaint->u.linear_gradient.colorline, + do_read_var ) ) + return 0; + + /* + * In order to support variations expose these as FT_Fixed 16.16 + * values so that we can support fractional values after + * interpolation. + */ + ENSURE_READ_BYTES( 12 ); + apaint->u.linear_gradient.p0.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p0.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p1.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.linear_gradient.p1.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + 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 ) + { + ENSURE_READ_BYTES( 4 ); + 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 || + ( do_read_var = + ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_RADIAL_GRADIENT ) ) ) + { + FT_Pos tmp; + + + if ( !read_color_line( colr, + child_table_p, + &apaint->u.radial_gradient.colorline, + do_read_var ) ) + return 0; + + + /* In the OpenType specification, `r0` and `r1` are defined as */ + /* `UFWORD`. Since FreeType doesn't have a corresponding 16.16 */ + /* format we convert to `FWORD` and replace negative values with */ + /* (32bit) `FT_INT_MAX`. */ + + ENSURE_READ_BYTES( 12 ); + + apaint->u.radial_gradient.c0.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.radial_gradient.c0.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + + tmp = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.radial_gradient.r0 = tmp < 0 ? FT_INT_MAX : tmp; + + apaint->u.radial_gradient.c1.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.radial_gradient.c1.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + + 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 ) + { + ENSURE_READ_BYTES( 4 ); + 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 || + ( do_read_var = + ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SWEEP_GRADIENT ) ) ) + { + if ( !read_color_line( colr, + child_table_p, + &apaint->u.sweep_gradient.colorline, + do_read_var) ) + return 0; + + ENSURE_READ_BYTES( 8 ); + + apaint->u.sweep_gradient.center.x = + INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.sweep_gradient.center.y = + INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + + apaint->u.sweep_gradient.start_angle = + F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.sweep_gradient.end_angle = + F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( do_read_var ) + { + ENSURE_READ_BYTES( 4 ); + 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; + } + + if ( apaint->format == FT_COLR_PAINTFORMAT_GLYPH ) + { + ENSURE_READ_BYTES( 2 ); + apaint->u.glyph.paint.p = child_table_p; + apaint->u.glyph.paint.insert_root_transform = 0; + apaint->u.glyph.glyphID = FT_NEXT_USHORT( p ); + + return 1; + } + + 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; + + if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) ) + return 0; + + p = child_table_p; + + /* + * The following matrix coefficients are encoded as + * OpenType 16.16 fixed-point values. + */ + ENSURE_READ_BYTES( 24 ); + apaint->u.transform.affine.xx = FT_NEXT_LONG( p ); + apaint->u.transform.affine.yx = FT_NEXT_LONG( p ); + apaint->u.transform.affine.xy = FT_NEXT_LONG( p ); + apaint->u.transform.affine.yy = FT_NEXT_LONG( p ); + 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 ) + { + ENSURE_READ_BYTES( 4 ); + 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 || + (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; + + ENSURE_READ_BYTES( 4 ); + 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 ) + { + ENSURE_READ_BYTES( 4 ); + 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_VAR_SCALE_UNIFORM_CENTER ) + { + apaint->u.scale.paint.p = child_table_p; + apaint->u.scale.paint.insert_root_transform = 0; + + /* All scale paints get at least one scale value. */ + ENSURE_READ_BYTES( 2 ); + 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 || + (FT_PaintFormat_Internal)apaint->format == + 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 ) + { + ENSURE_READ_BYTES( 2 ); + apaint->u.scale.scale_y = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + } + else + apaint->u.scale.scale_y = apaint->u.scale.scale_x; + + /* 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_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER ) + { + ENSURE_READ_BYTES( 4 ); + apaint->u.scale.center_x = INT_TO_FIXED( FT_NEXT_SHORT ( p ) ); + apaint->u.scale.center_y = INT_TO_FIXED( FT_NEXT_SHORT ( p ) ); + } + else + { + apaint->u.scale.center_x = 0; + 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 ) + { + ENSURE_READ_BYTES( 4 ); + 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; + + return 1; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_ROTATE || + (FT_PaintFormat_Internal)apaint->format == + 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; + + ENSURE_READ_BYTES( 2 ); + apaint->u.rotate.angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + + if ( (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER ) + { + ENSURE_READ_BYTES( 4 ); + apaint->u.rotate.center_x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.rotate.center_y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + } + else + { + apaint->u.rotate.center_x = 0; + 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 ) + { + FT_UInt num_deltas = 0; + + + ENSURE_READ_BYTES( 4 ); + 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 || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW || + (FT_PaintFormat_Internal)apaint->format == + 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; + + ENSURE_READ_BYTES( 4 ); + apaint->u.skew.x_skew_angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + 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_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER ) + { + ENSURE_READ_BYTES( 4 ); + apaint->u.skew.center_x = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + apaint->u.skew.center_y = INT_TO_FIXED( FT_NEXT_SHORT( p ) ); + } + else + { + apaint->u.skew.center_x = 0; + 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 ) + { + ENSURE_READ_BYTES( 4 ); + 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; + } + + else if ( apaint->format == FT_COLR_PAINTFORMAT_COMPOSITE ) + { + FT_UInt composite_mode; + + + apaint->u.composite.source_paint.p = child_table_p; + apaint->u.composite.source_paint.insert_root_transform = 0; + + ENSURE_READ_BYTES( 1 ); + composite_mode = FT_NEXT_BYTE( p ); + if ( composite_mode >= FT_COLR_COMPOSITE_MAX ) + return 0; + + apaint->u.composite.composite_mode = (FT_Composite_Mode)composite_mode; + + if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) ) + return 0; + + apaint->u.composite.backdrop_paint.p = + child_table_p; + apaint->u.composite.backdrop_paint.insert_root_transform = + 0; + + return 1; + } + + return 0; + } + + + static FT_Bool + find_base_glyph_v1_record( FT_Byte * base_glyph_begin, + FT_UInt num_base_glyph, + FT_UInt glyph_id, + BaseGlyphV1Record *record ) + { + FT_UInt min = 0; + FT_UInt max = num_base_glyph; + + + while ( min < max ) + { + FT_UInt mid = min + ( max - min ) / 2; + + /* + * `base_glyph_begin` is the beginning of `BaseGlyphV1List`; + * skip `numBaseGlyphV1Records` by adding 4 to start binary search + * in the array of `BaseGlyphV1Record`. + */ + FT_Byte *p = base_glyph_begin + 4 + mid * BASE_GLYPH_PAINT_RECORD_SIZE; + + FT_UShort gid = FT_NEXT_USHORT( p ); + + + if ( gid < glyph_id ) + min = mid + 1; + else if (gid > glyph_id ) + max = mid; + else + { + record->gid = gid; + record->paint_offset = FT_NEXT_ULONG ( p ); + return 1; + } + } + + return 0; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_colr_glyph_paint( TT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint* opaque_paint ) + { + Colr* colr = (Colr*)face->colr; + BaseGlyphV1Record base_glyph_v1_record; + FT_Byte* p; + + if ( !colr || !colr->table ) + return 0; + + if ( colr->version < 1 || !colr->num_base_glyphs_v1 || + !colr->base_glyphs_v1 ) + return 0; + + if ( opaque_paint->p ) + return 0; + + if ( !find_base_glyph_v1_record( colr->base_glyphs_v1, + colr->num_base_glyphs_v1, + base_glyph, + &base_glyph_v1_record ) ) + return 0; + + if ( !base_glyph_v1_record.paint_offset || + base_glyph_v1_record.paint_offset > colr->table_size ) + return 0; + + p = (FT_Byte*)( colr->base_glyphs_v1 + + base_glyph_v1_record.paint_offset ); + if ( p >= ( (FT_Byte*)colr->table + colr->table_size ) ) + return 0; + + opaque_paint->p = p; + + if ( root_transform == FT_COLOR_INCLUDE_ROOT_TRANSFORM ) + opaque_paint->insert_root_transform = 1; + else + opaque_paint->insert_root_transform = 0; + + return 1; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_color_glyph_clipbox( TT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ) + { + Colr* colr; + + FT_Byte *p, *p1, *clip_base, *limit; + + FT_Byte clip_list_format; + FT_ULong num_clip_boxes, i; + FT_UShort gid_start, gid_end; + FT_UInt32 clip_box_offset; + FT_Byte format; + + const FT_Byte num_corners = 4; + FT_Vector corners[4]; + FT_Byte j; + FT_BBox font_clip_box; + + + colr = (Colr*)face->colr; + if ( !colr ) + return 0; + + if ( !colr->clip_list ) + return 0; + + p = colr->clip_list; + + /* Limit points to the first byte after the end of the color table. */ + /* Thus, in subsequent limit checks below we need to check whether the */ + /* read pointer is strictly greater than a position offset by certain */ + /* field sizes to the left of that position. */ + limit = (FT_Byte*)colr->table + colr->table_size; + + /* Check whether we can extract one `uint8` and one `uint32`. */ + if ( p > limit - ( 1 + 4 ) ) + return 0; + + clip_base = p; + 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 1. */ + if ( !( clip_list_format == 1 ) ) + return 0; + + num_clip_boxes = FT_NEXT_ULONG( p ); + + /* Check whether we can extract two `uint16` and one `Offset24`, */ + /* `num_clip_boxes` times. */ + if ( colr->table_size / ( 2 + 2 + 3 ) < num_clip_boxes || + p > limit - ( 2 + 2 + 3 ) * num_clip_boxes ) + return 0; + + for ( i = 0; i < num_clip_boxes; ++i ) + { + gid_start = FT_NEXT_USHORT( p ); + gid_end = FT_NEXT_USHORT( p ); + clip_box_offset = FT_NEXT_UOFF3( p ); + + if ( base_glyph >= gid_start && base_glyph <= gid_end ) + { + p1 = (FT_Byte*)( clip_base + clip_box_offset ); + + /* Check whether we can extract one `uint8`. */ + if ( p1 > limit - 1 ) + return 0; + + format = FT_NEXT_BYTE( p1 ); + + if ( format > 2 ) + return 0; + + /* Check whether we can extract four `FWORD`. */ + if ( p1 > limit - ( 2 + 2 + 2 + 2 ) ) + return 0; + + /* `face->root.size->metrics.x_scale` and `y_scale` are factors */ + /* that scale a font unit value in integers to a 26.6 fixed value */ + /* according to the requested size, see for example */ + /* `ft_recompute_scaled_metrics`. */ + 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.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.y_scale ); + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + if ( 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 varIndexBase 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 */ + /* span a rectangle based on those, the rectangle may become too */ + /* small to cover the glyph. */ + corners[0].x = font_clip_box.xMin; + corners[1].x = font_clip_box.xMin; + corners[2].x = font_clip_box.xMax; + corners[3].x = font_clip_box.xMax; + + corners[0].y = font_clip_box.yMin; + corners[1].y = font_clip_box.yMax; + corners[2].y = font_clip_box.yMax; + corners[3].y = font_clip_box.yMin; + + for ( j = 0; j < num_corners; ++j ) + { + if ( face->root.internal->transform_flags & 1 ) + FT_Vector_Transform( &corners[j], + &face->root.internal->transform_matrix ); + + if ( face->root.internal->transform_flags & 2 ) + { + corners[j].x += face->root.internal->transform_delta.x; + corners[j].y += face->root.internal->transform_delta.y; + } + } + + clip_box->bottom_left = corners[0]; + clip_box->top_left = corners[1]; + clip_box->top_right = corners[2]; + clip_box->bottom_right = corners[3]; + + return 1; + } + } + + return 0; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_paint_layers( TT_Face face, + FT_LayerIterator* iterator, + FT_OpaquePaint* opaque_paint ) + { + FT_Byte* p = NULL; + FT_Byte* p_first_layer = NULL; + FT_Byte* p_paint = NULL; + FT_UInt32 paint_offset; + + Colr* colr; + + + if ( iterator->layer == iterator->num_layers ) + return 0; + + colr = (Colr*)face->colr; + if ( !colr ) + return 0; + + /* + * We have an iterator pointing at a paint offset as part of the + * `paintOffset` array in `LayerV1List`. + */ + p = iterator->p; + + /* + * Do a cursor sanity check of the iterator. Counting backwards from + * where it stands, we need to end up at a position after the beginning + * of the `LayerV1List` table and not after the end of the + * `LayerV1List`. + */ + p_first_layer = p - + iterator->layer * LAYER_V1_LIST_PAINT_OFFSET_SIZE - + LAYER_V1_LIST_NUM_LAYERS_SIZE; + if ( p_first_layer < (FT_Byte*)colr->layers_v1 ) + return 0; + if ( p_first_layer >= (FT_Byte*)( + colr->layers_v1 + LAYER_V1_LIST_NUM_LAYERS_SIZE + + colr->num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE ) ) + return 0; + + /* + * Before reading, ensure that `p` is within 'COLR' v1 and we can read a + * 4-byte ULONG. + */ + if ( p < colr->layers_v1 || + p > (FT_Byte*)colr->table + colr->table_size - 4 ) + return 0; + + paint_offset = + FT_NEXT_ULONG( p ); + opaque_paint->insert_root_transform = + 0; + + p_paint = (FT_Byte*)( colr->layers_v1 + paint_offset ); + + if ( p_paint < colr->paints_start_v1 || + p_paint >= ( (FT_Byte*)colr->table + colr->table_size ) ) + return 0; + + opaque_paint->p = p_paint; + + iterator->p = p; + + iterator->layer++; + + return 1; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_colorline_stops( TT_Face face, + FT_ColorStop* color_stop, + FT_ColorStopIterator *iterator ) + { + Colr* colr = (Colr*)face->colr; + + FT_Byte* p; + FT_ULong var_index_base; + FT_Byte* last_entry_p = NULL; + FT_UInt entry_size = COLOR_STOP_SIZE; + + + if ( !colr || !colr->table || !iterator ) + return 0; + + if ( iterator->current_color_stop >= iterator->num_color_stops ) + return 0; + + if ( iterator->read_variable ) + entry_size += VAR_IDX_BASE_SIZE; + + /* Calculate the start pointer for the last to-be-read (Var)ColorStop */ + /* and check whether we can read a full (Var)ColorStop at that */ + /* position by comparing it to the position that is the size of one */ + /* (Var)ColorStop before the end of the 'COLR' table. */ + last_entry_p = + iterator->p + ( iterator->num_color_stops - 1 - + iterator->current_color_stop ) * entry_size; + if ( iterator->p < colr->paints_start_v1 || + last_entry_p > (FT_Byte*)colr->table + + colr->table_size - entry_size ) + return 0; + + /* Iterator points at first `ColorStop` of `ColorLine`. */ + p = iterator->p; + + color_stop->stop_offset = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) ); + + 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 + { + 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 += F2DOT14_TO_FIXED( item_deltas[0] ); + color_stop->color.alpha += (FT_F2Dot14)item_deltas[1]; + } +#else + FT_UNUSED( var_index_base ); +#endif + } + + iterator->p = p; + iterator->current_color_stop++; + + return 1; + } + + + FT_LOCAL_DEF( FT_Bool ) + tt_face_get_paint( TT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint* paint ) + { + Colr* colr = (Colr*)face->colr; + FT_OpaquePaint next_paint; + FT_Matrix ft_root_scale; + + if ( !colr || !colr->base_glyphs_v1 || !colr->table ) + return 0; + + if ( opaque_paint.insert_root_transform ) + { + /* 'COLR' v1 glyph information is returned in unscaled coordinates, + * i.e., `FT_Size` is not applied or multiplied into the values. When + * client applications draw color glyphs, they can request to include + * a top-level transform, which includes the active `x_scale` and + * `y_scale` information for scaling the glyph, as well the additional + * transform and translate configured through `FT_Set_Transform`. + * This allows client applications to apply this top-level transform + * to the graphics context first and only once, then have gradient and + * contour scaling applied correctly when performing the additional + * drawing operations for subsequenct paints. Prepare this initial + * transform here. + */ + paint->format = FT_COLR_PAINTFORMAT_TRANSFORM; + + next_paint.p = opaque_paint.p; + next_paint.insert_root_transform = 0; + paint->u.transform.paint = next_paint; + + /* `x_scale` and `y_scale` are in 26.6 format, representing the scale + * factor to get from font units to requested size. However, expected + * return values are in 16.16, so we shift accordingly with rounding. + */ + ft_root_scale.xx = ( face->root.size->metrics.x_scale + 32 ) >> 6; + ft_root_scale.xy = 0; + ft_root_scale.yx = 0; + ft_root_scale.yy = ( face->root.size->metrics.y_scale + 32 ) >> 6; + + if ( face->root.internal->transform_flags & 1 ) + FT_Matrix_Multiply( &face->root.internal->transform_matrix, + &ft_root_scale ); + + paint->u.transform.affine.xx = ft_root_scale.xx; + paint->u.transform.affine.xy = ft_root_scale.xy; + paint->u.transform.affine.yx = ft_root_scale.yx; + paint->u.transform.affine.yy = ft_root_scale.yy; + + /* The translation is specified in 26.6 format and, according to the + * documentation of `FT_Set_Translate`, is performed on the character + * size given in the last call to `FT_Set_Char_Size`. The + * 'PaintTransform' paint table's `FT_Affine23` format expects + * values in 16.16 format, thus we need to shift by 10 bits. + */ + if ( face->root.internal->transform_flags & 2 ) + { + paint->u.transform.affine.dx = + face->root.internal->transform_delta.x * ( 1 << 10 ); + paint->u.transform.affine.dy = + face->root.internal->transform_delta.y * ( 1 << 10 ); + } + else + { + paint->u.transform.affine.dx = 0; + paint->u.transform.affine.dy = 0; + } + + return 1; + } + + return read_paint( face, colr, opaque_paint.p, paint ); + } + + FT_LOCAL_DEF( FT_Error ) tt_face_colr_blend_layer( TT_Face face, FT_UInt color_index, @@ -443,7 +1914,7 @@ #else /* !TT_CONFIG_OPTION_COLOR_LAYERS */ /* ANSI C doesn't like empty source files */ - typedef int _tt_colr_dummy; + typedef int tt_colr_dummy_; #endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */ diff --git a/src/3rdparty/freetype/src/sfnt/ttcolr.h b/src/3rdparty/freetype/src/sfnt/ttcolr.h index 6412162669..20c85f0359 100644 --- a/src/3rdparty/freetype/src/sfnt/ttcolr.h +++ b/src/3rdparty/freetype/src/sfnt/ttcolr.h @@ -4,7 +4,7 @@ * * TrueType and OpenType colored glyph layer support (specification). * - * Copyright (C) 2018-2020 by + * Copyright (C) 2018-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Originally written by Shao Yu Zhang <shaozhang@fb.com>. @@ -42,6 +42,32 @@ FT_BEGIN_HEADER FT_UInt *acolor_index, FT_LayerIterator* iterator ); + FT_LOCAL( FT_Bool ) + tt_face_get_colr_glyph_paint( TT_Face face, + FT_UInt base_glyph, + FT_Color_Root_Transform root_transform, + FT_OpaquePaint* paint ); + + FT_LOCAL( FT_Bool ) + tt_face_get_color_glyph_clipbox( TT_Face face, + FT_UInt base_glyph, + FT_ClipBox* clip_box ); + + FT_LOCAL( FT_Bool ) + tt_face_get_paint_layers( TT_Face face, + FT_LayerIterator* iterator, + FT_OpaquePaint* paint ); + + FT_LOCAL( FT_Bool ) + tt_face_get_colorline_stops( TT_Face face, + FT_ColorStop* color_stop, + FT_ColorStopIterator* iterator ); + + FT_LOCAL( FT_Bool ) + tt_face_get_paint( TT_Face face, + FT_OpaquePaint opaque_paint, + FT_COLR_Paint* paint ); + FT_LOCAL( FT_Error ) tt_face_colr_blend_layer( TT_Face face, FT_UInt color_index, diff --git a/src/3rdparty/freetype/src/sfnt/ttcpal.c b/src/3rdparty/freetype/src/sfnt/ttcpal.c index 9c514bafe5..46ae08596f 100644 --- a/src/3rdparty/freetype/src/sfnt/ttcpal.c +++ b/src/3rdparty/freetype/src/sfnt/ttcpal.c @@ -4,7 +4,7 @@ * * TrueType and OpenType color palette support (body). * - * Copyright (C) 2018-2020 by + * Copyright (C) 2018-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Originally written by Shao Yu Zhang <shaozhang@fb.com>. @@ -303,7 +303,7 @@ #else /* !TT_CONFIG_OPTION_COLOR_LAYERS */ /* ANSI C doesn't like empty source files */ - typedef int _tt_cpal_dummy; + typedef int tt_cpal_dummy_; #endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */ diff --git a/src/3rdparty/freetype/src/sfnt/ttcpal.h b/src/3rdparty/freetype/src/sfnt/ttcpal.h index b544be696a..8e9913f0cc 100644 --- a/src/3rdparty/freetype/src/sfnt/ttcpal.h +++ b/src/3rdparty/freetype/src/sfnt/ttcpal.h @@ -4,7 +4,7 @@ * * TrueType and OpenType color palette support (specification). * - * Copyright (C) 2018-2020 by + * Copyright (C) 2018-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Originally written by Shao Yu Zhang <shaozhang@fb.com>. diff --git a/src/3rdparty/freetype/src/sfnt/ttkern.c b/src/3rdparty/freetype/src/sfnt/ttkern.c index d4a70c7855..a47d08bd6d 100644 --- a/src/3rdparty/freetype/src/sfnt/ttkern.c +++ b/src/3rdparty/freetype/src/sfnt/ttkern.c @@ -5,7 +5,7 @@ * Load the basic TrueType kerning table. This doesn't handle * kerning data within the GPOS table at the moment. * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -94,7 +94,7 @@ p_next = p; - p += 2; /* skip version */ + p += 2; /* skip version */ length = FT_NEXT_USHORT( p ); coverage = FT_NEXT_USHORT( p ); @@ -144,7 +144,7 @@ cur_pair = FT_NEXT_ULONG( p ); - if ( cur_pair <= old_pair ) + if ( cur_pair < old_pair ) break; p += 2; @@ -187,11 +187,18 @@ FT_UInt left_glyph, FT_UInt right_glyph ) { - FT_Int result = 0; - FT_UInt count, mask; - FT_Byte* p = face->kern_table; - FT_Byte* p_limit = p + face->kern_table_size; + FT_Int result = 0; + FT_UInt count, mask; + FT_Byte* p; + FT_Byte* p_limit; + + + if ( !face->kern_table ) + return result; + + p = face->kern_table; + p_limit = p + face->kern_table_size; p += 4; mask = 0x0001; diff --git a/src/3rdparty/freetype/src/sfnt/ttkern.h b/src/3rdparty/freetype/src/sfnt/ttkern.h index f44b5bdeb0..960c7da494 100644 --- a/src/3rdparty/freetype/src/sfnt/ttkern.h +++ b/src/3rdparty/freetype/src/sfnt/ttkern.h @@ -5,7 +5,7 @@ * Load the basic TrueType kerning table. This doesn't handle * kerning data within the GPOS table at the moment. * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/3rdparty/freetype/src/sfnt/ttload.c b/src/3rdparty/freetype/src/sfnt/ttload.c index 4b46f41357..7b44e9cd2e 100644 --- a/src/3rdparty/freetype/src/sfnt/ttload.c +++ b/src/3rdparty/freetype/src/sfnt/ttload.c @@ -5,7 +5,7 @@ * Load the basic TrueType tables, i.e., tables that can be either in * TTF or OTF fonts (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -205,9 +205,8 @@ if ( FT_STREAM_READ_FIELDS( table_dir_entry_fields, &table ) ) { - nn--; FT_TRACE2(( "check_table_dir:" - " can read only %d table%s in font (instead of %d)\n", + " can read only %hu table%s in font (instead of %hu)\n", nn, nn == 1 ? "" : "s", sfnt->num_tables )); sfnt->num_tables = nn; break; @@ -217,7 +216,7 @@ if ( table.Offset > stream->size ) { - FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn )); + FT_TRACE2(( "check_table_dir: table entry %hu invalid\n", nn )); continue; } else if ( table.Length > stream->size - table.Offset ) @@ -232,7 +231,7 @@ valid_entries++; else { - FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn )); + FT_TRACE2(( "check_table_dir: table entry %hu invalid\n", nn )); continue; } } @@ -381,7 +380,7 @@ /* load the table directory */ - FT_TRACE2(( "-- Number of tables: %10u\n", sfnt.num_tables )); + FT_TRACE2(( "-- Number of tables: %10hu\n", sfnt.num_tables )); FT_TRACE2(( "-- Format version: 0x%08lx\n", sfnt.format_tag )); if ( sfnt.format_tag != TTAG_OTTO ) @@ -416,9 +415,9 @@ FT_FRAME_ENTER( sfnt.num_tables * 16L ) ) goto Exit; - FT_TRACE2(( "\n" - " tag offset length checksum\n" - " ----------------------------------\n" )); + FT_TRACE2(( "\n" )); + FT_TRACE2(( " tag offset length checksum\n" )); + FT_TRACE2(( " ----------------------------------\n" )); valid_entries = 0; for ( nn = 0; nn < sfnt.num_tables; nn++ ) @@ -505,7 +504,15 @@ FT_FRAME_EXIT(); - FT_TRACE2(( "table directory loaded\n\n" )); + if ( !valid_entries ) + { + FT_TRACE2(( "tt_face_load_font_dir: no valid tables found\n" )); + error = FT_THROW( Unknown_File_Format ); + goto Exit; + } + + FT_TRACE2(( "table directory loaded\n" )); + FT_TRACE2(( "\n" )); Exit: return error; @@ -671,8 +678,8 @@ if ( FT_STREAM_READ_FIELDS( header_fields, header ) ) goto Exit; - FT_TRACE3(( "Units per EM: %4u\n", header->Units_Per_EM )); - FT_TRACE3(( "IndexToLoc: %4d\n", header->Index_To_Loc_Format )); + FT_TRACE3(( "Units per EM: %4hu\n", header->Units_Per_EM )); + FT_TRACE3(( "IndexToLoc: %4hd\n", header->Index_To_Loc_Format )); Exit: return error; @@ -794,15 +801,15 @@ if ( maxProfile->maxTwilightPoints > ( 0xFFFFU - 4 ) ) { FT_TRACE0(( "tt_face_load_maxp:" - " too much twilight points in `maxp' table;\n" - " " + " too much twilight points in `maxp' table;\n" )); + FT_TRACE0(( " " " some glyphs might be rendered incorrectly\n" )); maxProfile->maxTwilightPoints = 0xFFFFU - 4; } } - FT_TRACE3(( "numGlyphs: %u\n", maxProfile->numGlyphs )); + FT_TRACE3(( "numGlyphs: %hu\n", maxProfile->numGlyphs )); Exit: return error; @@ -836,6 +843,8 @@ FT_ULong table_pos, table_len; FT_ULong storage_start, storage_limit; TT_NameTable table; + TT_Name names = NULL; + TT_LangTag langTags = NULL; static const FT_Frame_Field name_table_fields[] = { @@ -916,13 +925,13 @@ storage_start += 2 + 4 * table->numLangTagRecords; /* allocate language tag records array */ - if ( FT_NEW_ARRAY( table->langTags, table->numLangTagRecords ) || - FT_FRAME_ENTER( table->numLangTagRecords * 4 ) ) + if ( FT_QNEW_ARRAY( langTags, table->numLangTagRecords ) || + FT_FRAME_ENTER( table->numLangTagRecords * 4 ) ) goto Exit; /* load language tags */ { - TT_LangTag entry = table->langTags; + TT_LangTag entry = langTags; TT_LangTag limit = FT_OFFSET( entry, table->numLangTagRecords ); @@ -938,7 +947,13 @@ /* invalid entry; ignore it */ entry->stringLength = 0; } + + /* mark the string as not yet loaded */ + entry->string = NULL; } + + table->langTags = langTags; + langTags = NULL; } FT_FRAME_EXIT(); @@ -947,14 +962,15 @@ } /* allocate name records array */ - if ( FT_NEW_ARRAY( table->names, table->numNameRecords ) || - FT_FRAME_ENTER( table->numNameRecords * 12 ) ) + if ( FT_QNEW_ARRAY( names, table->numNameRecords ) || + FT_FRAME_ENTER( table->numNameRecords * 12 ) ) goto Exit; /* load name records */ { - TT_Name entry = table->names; + TT_Name entry = names; FT_UInt count = table->numNameRecords; + FT_UInt valid = 0; for ( ; count > 0; count-- ) @@ -987,15 +1003,20 @@ } } + /* mark the string as not yet converted */ + entry->string = NULL; + + valid++; entry++; } /* reduce array size to the actually used elements */ - count = (FT_UInt)( entry - table->names ); - (void)FT_RENEW_ARRAY( table->names, - table->numNameRecords, - count ); - table->numNameRecords = count; + FT_MEM_QRENEW_ARRAY( names, + table->numNameRecords, + valid ); + table->names = names; + names = NULL; + table->numNameRecords = valid; } FT_FRAME_EXIT(); @@ -1004,6 +1025,8 @@ face->num_names = (FT_UShort)table->numNameRecords; Exit: + FT_FREE( names ); + FT_FREE( langTags ); return error; } @@ -1249,11 +1272,11 @@ } } - FT_TRACE3(( "sTypoAscender: %4d\n", os2->sTypoAscender )); - FT_TRACE3(( "sTypoDescender: %4d\n", os2->sTypoDescender )); - FT_TRACE3(( "usWinAscent: %4u\n", os2->usWinAscent )); - FT_TRACE3(( "usWinDescent: %4u\n", os2->usWinDescent )); - FT_TRACE3(( "fsSelection: 0x%2x\n", os2->fsSelection )); + FT_TRACE3(( "sTypoAscender: %4hd\n", os2->sTypoAscender )); + FT_TRACE3(( "sTypoDescender: %4hd\n", os2->sTypoDescender )); + FT_TRACE3(( "usWinAscent: %4hu\n", os2->usWinAscent )); + FT_TRACE3(( "usWinDescent: %4hu\n", os2->usWinDescent )); + FT_TRACE3(( "fsSelection: 0x%2hx\n", os2->fsSelection )); Exit: return error; @@ -1311,6 +1334,12 @@ if ( FT_STREAM_READ_FIELDS( post_fields, post ) ) return error; + if ( post->FormatType != 0x00030000L && + post->FormatType != 0x00025000L && + post->FormatType != 0x00020000L && + post->FormatType != 0x00010000L ) + return FT_THROW( Invalid_Post_Table_Format ); + /* we don't load the glyph names, we do that in another */ /* module (ttpost). */ @@ -1410,8 +1439,8 @@ FT_Error error; FT_Memory memory = stream->memory; - FT_UInt j,num_ranges; - TT_GaspRange gaspranges = NULL; + FT_UShort j, num_ranges; + TT_GaspRange gasp_ranges = NULL; /* the gasp table is optional */ @@ -1422,8 +1451,8 @@ if ( FT_FRAME_ENTER( 4L ) ) goto Exit; - face->gasp.version = FT_GET_USHORT(); - face->gasp.numRanges = FT_GET_USHORT(); + face->gasp.version = FT_GET_USHORT(); + num_ranges = FT_GET_USHORT(); FT_FRAME_EXIT(); @@ -1435,29 +1464,31 @@ goto Exit; } - num_ranges = face->gasp.numRanges; - FT_TRACE3(( "numRanges: %u\n", num_ranges )); + FT_TRACE3(( "numRanges: %hu\n", num_ranges )); - if ( FT_QNEW_ARRAY( face->gasp.gaspRanges, num_ranges ) || - FT_FRAME_ENTER( num_ranges * 4L ) ) + if ( FT_QNEW_ARRAY( gasp_ranges, num_ranges ) || + FT_FRAME_ENTER( num_ranges * 4L ) ) goto Exit; - gaspranges = face->gasp.gaspRanges; - for ( j = 0; j < num_ranges; j++ ) { - gaspranges[j].maxPPEM = FT_GET_USHORT(); - gaspranges[j].gaspFlag = FT_GET_USHORT(); + gasp_ranges[j].maxPPEM = FT_GET_USHORT(); + gasp_ranges[j].gaspFlag = FT_GET_USHORT(); - FT_TRACE3(( "gaspRange %d: rangeMaxPPEM %5d, rangeGaspBehavior 0x%x\n", + FT_TRACE3(( "gaspRange %hu: rangeMaxPPEM %5hu, rangeGaspBehavior 0x%hx\n", j, - gaspranges[j].maxPPEM, - gaspranges[j].gaspFlag )); + gasp_ranges[j].maxPPEM, + gasp_ranges[j].gaspFlag )); } + face->gasp.gaspRanges = gasp_ranges; + gasp_ranges = NULL; + face->gasp.numRanges = num_ranges; + FT_FRAME_EXIT(); Exit: + FT_FREE( gasp_ranges ); return error; } diff --git a/src/3rdparty/freetype/src/sfnt/ttload.h b/src/3rdparty/freetype/src/sfnt/ttload.h index 4e53d8b782..1499dd5735 100644 --- a/src/3rdparty/freetype/src/sfnt/ttload.h +++ b/src/3rdparty/freetype/src/sfnt/ttload.h @@ -5,7 +5,7 @@ * Load the basic TrueType tables, i.e., tables that can be either in * TTF or OTF fonts (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/3rdparty/freetype/src/sfnt/ttmtx.c b/src/3rdparty/freetype/src/sfnt/ttmtx.c index 021123336e..38ee9ae728 100644 --- a/src/3rdparty/freetype/src/sfnt/ttmtx.c +++ b/src/3rdparty/freetype/src/sfnt/ttmtx.c @@ -4,7 +4,7 @@ * * Load the metrics tables common to TTF and OTF fonts (body). * - * Copyright (C) 2006-2020 by + * Copyright (C) 2006-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -239,7 +239,7 @@ #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT FT_Service_MetricsVariations var = - (FT_Service_MetricsVariations)face->var; + (FT_Service_MetricsVariations)face->tt_var; #endif @@ -306,7 +306,7 @@ } #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - if ( var ) + if ( var && face->blend ) { FT_Face f = FT_FACE( face ); FT_Int a = (FT_Int)*aadvance; diff --git a/src/3rdparty/freetype/src/sfnt/ttmtx.h b/src/3rdparty/freetype/src/sfnt/ttmtx.h index dba65ca9ba..56d2b62766 100644 --- a/src/3rdparty/freetype/src/sfnt/ttmtx.h +++ b/src/3rdparty/freetype/src/sfnt/ttmtx.h @@ -4,7 +4,7 @@ * * Load the metrics tables common to TTF and OTF fonts (specification). * - * Copyright (C) 2006-2020 by + * Copyright (C) 2006-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/3rdparty/freetype/src/sfnt/ttpost.c b/src/3rdparty/freetype/src/sfnt/ttpost.c index e93a4bf1b1..1dfad4298b 100644 --- a/src/3rdparty/freetype/src/sfnt/ttpost.c +++ b/src/3rdparty/freetype/src/sfnt/ttpost.c @@ -5,7 +5,7 @@ * PostScript name table processing for TrueType and OpenType fonts * (body). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -58,7 +58,7 @@ #define MAC_NAME( x ) (FT_String*)psnames->macintosh_name( (FT_UInt)(x) ) -#else /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ +#else /* !FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ /* Otherwise, we ignore the `psnames' module, and provide our own */ @@ -152,155 +152,109 @@ }; -#endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ +#endif /* !FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ static FT_Error - load_format_20( TT_Face face, - FT_Stream stream, - FT_ULong post_limit ) + load_format_20( TT_Post_Names names, + FT_Stream stream, + FT_UShort num_glyphs, + FT_ULong post_len ) { FT_Memory memory = stream->memory; FT_Error error; - FT_Int num_glyphs; - FT_UShort num_names; + FT_UShort n; + FT_UShort num_names = 0; FT_UShort* glyph_indices = NULL; - FT_Char** name_strings = NULL; + FT_Byte** name_strings = NULL; + FT_Byte* q; - if ( FT_READ_USHORT( num_glyphs ) ) - goto Exit; - - /* UNDOCUMENTED! The number of glyphs in this table can be smaller */ - /* than the value in the maxp table (cf. cyberbit.ttf). */ - - /* There already exist fonts which have more than 32768 glyph names */ - /* in this table, so the test for this threshold has been dropped. */ - - if ( num_glyphs > face->max_profile.numGlyphs ) + if ( (FT_ULong)num_glyphs * 2 > post_len ) { error = FT_THROW( Invalid_File_Format ); goto Exit; } - /* load the indices */ - { - FT_Int n; - - - if ( FT_NEW_ARRAY ( glyph_indices, num_glyphs ) || - FT_FRAME_ENTER( num_glyphs * 2L ) ) - goto Fail; - - for ( n = 0; n < num_glyphs; n++ ) - glyph_indices[n] = FT_GET_USHORT(); + /* load the indices and note their maximum */ + if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) || + FT_FRAME_ENTER( num_glyphs * 2 ) ) + goto Fail; - FT_FRAME_EXIT(); - } + q = (FT_Byte*)stream->cursor; - /* compute number of names stored in table */ + for ( n = 0; n < num_glyphs; n++ ) { - FT_Int n; + FT_UShort idx = FT_NEXT_USHORT( q ); - num_names = 0; + if ( idx > num_names ) + num_names = idx; - for ( n = 0; n < num_glyphs; n++ ) - { - FT_Int idx; + glyph_indices[n] = idx; + } + FT_FRAME_EXIT(); - idx = glyph_indices[n]; - if ( idx >= 258 ) - { - idx -= 257; - if ( idx > num_names ) - num_names = (FT_UShort)idx; - } - } - } + /* compute number of names stored in the table */ + num_names = num_names > 257 ? num_names - 257 : 0; /* now load the name strings */ + if ( num_names ) { - FT_UShort n; + FT_ULong p; + FT_Byte* strings; - if ( FT_NEW_ARRAY( name_strings, num_names ) ) - goto Fail; + post_len -= (FT_ULong)num_glyphs * 2; - for ( n = 0; n < num_names; n++ ) - { - FT_UInt len; + if ( FT_QALLOC( name_strings, num_names * sizeof ( FT_Byte* ) + + post_len + 1 ) ) + goto Fail; + strings = (FT_Byte*)( name_strings + num_names ); + if ( FT_STREAM_READ( strings, post_len ) ) + goto Fail; - if ( FT_STREAM_POS() >= post_limit ) - break; - else - { - FT_TRACE6(( "load_format_20: %ld byte left in post table\n", - post_limit - FT_STREAM_POS() )); + /* convert from Pascal- to C-strings and set pointers */ + for ( p = 0, n = 0; p < post_len && n < num_names; n++ ) + { + FT_UInt len = strings[p]; - if ( FT_READ_BYTE( len ) ) - goto Fail1; - } - if ( len > post_limit || - FT_STREAM_POS() > post_limit - len ) + if ( len > 63U ) { - FT_Int d = (FT_Int)post_limit - (FT_Int)FT_STREAM_POS(); - - - FT_ERROR(( "load_format_20:" - " exceeding string length (%d)," - " truncating at end of post table (%d byte left)\n", - len, d )); - len = (FT_UInt)FT_MAX( 0, d ); + error = FT_THROW( Invalid_File_Format ); + goto Fail; } - if ( FT_NEW_ARRAY( name_strings[n], len + 1 ) || - FT_STREAM_READ( name_strings[n], len ) ) - goto Fail1; - - name_strings[n][len] = '\0'; + strings[p] = 0; + name_strings[n] = strings + p + 1; + p += len + 1; } + strings[post_len] = 0; + /* deal with missing or insufficient string data */ if ( n < num_names ) { - FT_ERROR(( "load_format_20:" - " all entries in post table are already parsed," - " using NULL names for gid %d - %d\n", - n, num_names - 1 )); + FT_TRACE4(( "load_format_20: %hu PostScript names are truncated\n", + num_names - n )); + for ( ; n < num_names; n++ ) - if ( FT_NEW_ARRAY( name_strings[n], 1 ) ) - goto Fail1; - else - name_strings[n][0] = '\0'; + name_strings[n] = strings + post_len; } } /* all right, set table fields and exit successfully */ - { - TT_Post_20 table = &face->postscript_names.names.format_20; + names->num_glyphs = num_glyphs; + names->num_names = num_names; + names->glyph_indices = glyph_indices; + names->glyph_names = name_strings; - - table->num_glyphs = (FT_UShort)num_glyphs; - table->num_names = (FT_UShort)num_names; - table->glyph_indices = glyph_indices; - table->glyph_names = name_strings; - } return FT_Err_Ok; - Fail1: - { - FT_UShort n; - - - for ( n = 0; n < num_names; n++ ) - FT_FREE( name_strings[n] ); - } - Fail: FT_FREE( name_strings ); FT_FREE( glyph_indices ); @@ -311,66 +265,55 @@ static FT_Error - load_format_25( TT_Face face, - FT_Stream stream, - FT_ULong post_limit ) + load_format_25( TT_Post_Names names, + FT_Stream stream, + FT_UShort num_glyphs, + FT_ULong post_len ) { FT_Memory memory = stream->memory; FT_Error error; - FT_Int num_glyphs; - FT_Char* offset_table = NULL; - - FT_UNUSED( post_limit ); - + FT_UShort n; + FT_UShort* glyph_indices = NULL; + FT_Byte* q; - if ( FT_READ_USHORT( num_glyphs ) ) - goto Exit; - /* check the number of glyphs */ - if ( num_glyphs > face->max_profile.numGlyphs || - num_glyphs > 258 || - num_glyphs < 1 ) + /* check the number of glyphs, including the theoretical limit */ + if ( num_glyphs > post_len || + num_glyphs > 258 + 128 ) { error = FT_THROW( Invalid_File_Format ); goto Exit; } - if ( FT_NEW_ARRAY( offset_table, num_glyphs ) || - FT_STREAM_READ( offset_table, num_glyphs ) ) + /* load the indices and check their Mac range */ + if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) || + FT_FRAME_ENTER( num_glyphs ) ) goto Fail; - /* now check the offset table */ - { - FT_Int n; + q = (FT_Byte*)stream->cursor; + for ( n = 0; n < num_glyphs; n++ ) + { + FT_Int idx = n + FT_NEXT_CHAR( q ); - for ( n = 0; n < num_glyphs; n++ ) - { - FT_Long idx = (FT_Long)n + offset_table[n]; + if ( idx < 0 || idx > 257 ) + idx = 0; - if ( idx < 0 || idx > num_glyphs ) - { - error = FT_THROW( Invalid_File_Format ); - goto Fail; - } - } + glyph_indices[n] = (FT_UShort)idx; } - /* OK, set table fields and exit successfully */ - { - TT_Post_25 table = &face->postscript_names.names.format_25; - + FT_FRAME_EXIT(); - table->num_glyphs = (FT_UShort)num_glyphs; - table->offsets = offset_table; - } + /* OK, set table fields and exit successfully */ + names->num_glyphs = num_glyphs; + names->glyph_indices = glyph_indices; return FT_Err_Ok; Fail: - FT_FREE( offset_table ); + FT_FREE( glyph_indices ); Exit: return error; @@ -380,40 +323,37 @@ static FT_Error load_post_names( TT_Face face ) { - FT_Stream stream; - FT_Error error; - FT_Fixed format; + FT_Error error = FT_Err_Ok; + FT_Stream stream = face->root.stream; + FT_Fixed format = face->postscript.FormatType; FT_ULong post_len; - FT_ULong post_limit; + FT_UShort num_glyphs; - /* get a stream for the face's resource */ - stream = face->root.stream; - /* seek to the beginning of the PS names table */ error = face->goto_table( face, TTAG_post, stream, &post_len ); if ( error ) goto Exit; - post_limit = FT_STREAM_POS() + post_len; - - format = face->postscript.FormatType; - - /* go to beginning of subtable */ - if ( FT_STREAM_SKIP( 32 ) ) + /* UNDOCUMENTED! The number of glyphs in this table can be smaller */ + /* than the value in the maxp table (cf. cyberbit.ttf). */ + if ( post_len < 34 || + FT_STREAM_SKIP( 32 ) || + FT_READ_USHORT( num_glyphs ) || + num_glyphs > face->max_profile.numGlyphs || + num_glyphs == 0 ) goto Exit; - /* now read postscript table */ + /* now read postscript names data */ if ( format == 0x00020000L ) - error = load_format_20( face, stream, post_limit ); + error = load_format_20( &face->postscript_names, stream, + num_glyphs, post_len - 34 ); else if ( format == 0x00025000L ) - error = load_format_25( face, stream, post_limit ); - else - error = FT_THROW( Invalid_File_Format ); - - face->postscript_names.loaded = 1; + error = load_format_25( &face->postscript_names, stream, + num_glyphs, post_len - 34 ); Exit: + face->postscript_names.loaded = 1; /* even if failed */ return error; } @@ -423,37 +363,20 @@ { FT_Memory memory = face->root.memory; TT_Post_Names names = &face->postscript_names; - FT_Fixed format; - if ( names->loaded ) + if ( names->num_glyphs ) { - format = face->postscript.FormatType; - - if ( format == 0x00020000L ) - { - TT_Post_20 table = &names->names.format_20; - FT_UShort n; - - - FT_FREE( table->glyph_indices ); - table->num_glyphs = 0; - - for ( n = 0; n < table->num_names; n++ ) - FT_FREE( table->glyph_names[n] ); - - FT_FREE( table->glyph_names ); - table->num_names = 0; - } - else if ( format == 0x00025000L ) - { - TT_Post_25 table = &names->names.format_25; - + FT_FREE( names->glyph_indices ); + names->num_glyphs = 0; + } - FT_FREE( table->offsets ); - table->num_glyphs = 0; - } + if ( names->num_names ) + { + FT_FREE( names->glyph_names ); + names->num_names = 0; } + names->loaded = 0; } @@ -489,7 +412,6 @@ FT_String** PSname ) { FT_Error error; - TT_Post_Names names; FT_Fixed format; #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES @@ -509,8 +431,6 @@ return FT_THROW( Unimplemented_Feature ); #endif - names = &face->postscript_names; - /* `.notdef' by default */ *PSname = MAC_NAME( 0 ); @@ -521,9 +441,10 @@ if ( idx < 258 ) /* paranoid checking */ *PSname = MAC_NAME( idx ); } - else if ( format == 0x00020000L ) + else if ( format == 0x00020000L || + format == 0x00025000L ) { - TT_Post_20 table = &names->names.format_20; + TT_Post_Names names = &face->postscript_names; if ( !names->loaded ) @@ -533,43 +454,29 @@ goto End; } - if ( idx < (FT_UInt)table->num_glyphs ) + if ( idx < (FT_UInt)names->num_glyphs ) { - FT_UShort name_index = table->glyph_indices[idx]; + FT_UShort name_index = names->glyph_indices[idx]; if ( name_index < 258 ) *PSname = MAC_NAME( name_index ); - else - *PSname = (FT_String*)table->glyph_names[name_index - 258]; + else /* only for version 2.0 */ + *PSname = (FT_String*)names->glyph_names[name_index - 258]; } } - else if ( format == 0x00025000L ) - { - TT_Post_25 table = &names->names.format_25; - - - if ( !names->loaded ) - { - error = load_post_names( face ); - if ( error ) - goto End; - } - - if ( idx < (FT_UInt)table->num_glyphs ) /* paranoid checking */ - *PSname = MAC_NAME( (FT_Int)idx + table->offsets[idx] ); - } /* nothing to do for format == 0x00030000L */ End: + /* post format errors ignored */ return FT_Err_Ok; } #else /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ /* ANSI C doesn't like empty source files */ - typedef int _tt_post_dummy; + typedef int tt_post_dummy_; #endif /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ diff --git a/src/3rdparty/freetype/src/sfnt/ttpost.h b/src/3rdparty/freetype/src/sfnt/ttpost.h index 94c7d16800..528f1c5f2f 100644 --- a/src/3rdparty/freetype/src/sfnt/ttpost.h +++ b/src/3rdparty/freetype/src/sfnt/ttpost.h @@ -5,7 +5,7 @@ * PostScript name table processing for TrueType and OpenType fonts * (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/3rdparty/freetype/src/sfnt/ttsbit.c b/src/3rdparty/freetype/src/sfnt/ttsbit.c index 9dd4419710..03f90a628d 100644 --- a/src/3rdparty/freetype/src/sfnt/ttsbit.c +++ b/src/3rdparty/freetype/src/sfnt/ttsbit.c @@ -4,7 +4,7 @@ * * TrueType and OpenType embedded bitmap support (body). * - * Copyright (C) 2005-2020 by + * Copyright (C) 2005-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Copyright 2013 by Google, Inc. @@ -172,13 +172,8 @@ goto Exit; } - /* we currently don't support bit 1; however, it is better to */ - /* draw at least something... */ if ( flags == 3 ) - FT_TRACE1(( "tt_face_load_sbit_strikes:" - " sbix overlay not supported yet\n" - " " - " expect bad rendering results\n" )); + face->root.face_flags |= FT_FACE_FLAG_SBIX_OVERLAY; /* * Count the number of strikes available in the table. We are a bit @@ -240,8 +235,8 @@ if ( !face->ebdt_size ) { FT_TRACE2(( "tt_face_load_sbit_strikes:" - " no embedded bitmap data table found;\n" - " " + " no embedded bitmap data table found;\n" )); + FT_TRACE2(( " " " resetting number of strikes to zero\n" )); face->sbit_num_strikes = 0; } @@ -345,8 +340,8 @@ if ( metrics->ascender == 0 ) { FT_TRACE2(( "tt_face_load_strike_metrics:" - " sanitizing invalid ascender and descender\n" - " " + " sanitizing invalid ascender and descender\n" )); + FT_TRACE2(( " " " values for strike %ld (%dppem, %dppem)\n", strike_index, metrics->x_ppem, metrics->y_ppem )); @@ -374,8 +369,8 @@ if ( metrics->height == 0 ) { FT_TRACE2(( "tt_face_load_strike_metrics:" - " sanitizing invalid height value\n" - " " + " sanitizing invalid height value\n" )); + FT_TRACE2(( " " " for strike (%d, %d)\n", metrics->x_ppem, metrics->y_ppem )); metrics->height = metrics->y_ppem * 64; @@ -390,11 +385,9 @@ /* set the scale values (in 16.16 units) so advances */ /* from the hmtx and vmtx table are scaled correctly */ - metrics->x_scale = FT_MulDiv( metrics->x_ppem, - 64 * 0x10000, + metrics->x_scale = FT_DivFix( metrics->x_ppem * 64, face->header.Units_Per_EM ); - metrics->y_scale = FT_MulDiv( metrics->y_ppem, - 64 * 0x10000, + metrics->y_scale = FT_DivFix( metrics->y_ppem * 64, face->header.Units_Per_EM ); return FT_Err_Ok; @@ -404,9 +397,9 @@ { FT_Stream stream = face->root.stream; FT_UInt offset; - FT_UShort upem, ppem, resolution; + FT_UShort ppem, resolution; TT_HoriHeader *hori; - FT_Pos ppem_; /* to reduce casts */ + FT_Fixed scale; FT_Error error; FT_Byte* p; @@ -429,32 +422,23 @@ FT_FRAME_EXIT(); - upem = face->header.Units_Per_EM; - hori = &face->horizontal; - metrics->x_ppem = ppem; metrics->y_ppem = ppem; - ppem_ = (FT_Pos)ppem; + scale = FT_DivFix( ppem * 64, face->header.Units_Per_EM ); + hori = &face->horizontal; - metrics->ascender = - FT_MulDiv( hori->Ascender, ppem_ * 64, upem ); - metrics->descender = - FT_MulDiv( hori->Descender, ppem_ * 64, upem ); - metrics->height = - FT_MulDiv( hori->Ascender - hori->Descender + hori->Line_Gap, - ppem_ * 64, upem ); - metrics->max_advance = - FT_MulDiv( hori->advance_Width_Max, ppem_ * 64, upem ); + metrics->ascender = FT_MulFix( hori->Ascender, scale ); + metrics->descender = FT_MulFix( hori->Descender, scale ); + metrics->height = + FT_MulFix( hori->Ascender - hori->Descender + hori->Line_Gap, + scale ); + metrics->max_advance = FT_MulFix( hori->advance_Width_Max, scale ); /* set the scale values (in 16.16 units) so advances */ /* from the hmtx and vmtx table are scaled correctly */ - metrics->x_scale = FT_MulDiv( metrics->x_ppem, - 64 * 0x10000, - face->header.Units_Per_EM ); - metrics->y_scale = FT_MulDiv( metrics->y_ppem, - 64 * 0x10000, - face->header.Units_Per_EM ); + metrics->x_scale = scale; + metrics->y_scale = scale; return error; } @@ -726,6 +710,9 @@ pitch = bitmap->pitch; line = bitmap->buffer; + if ( !line ) + goto Exit; + width = decoder->metrics->width; height = decoder->metrics->height; @@ -1206,7 +1193,7 @@ goto Fail; p += 1; /* skip padding */ - /* fall-through */ + FALL_THROUGH; case 9: loader = tt_sbit_decoder_load_compound; @@ -1573,23 +1560,40 @@ if ( !error ) { - FT_Short abearing; + FT_Short abearing; /* not used here */ FT_UShort aadvance; tt_face_get_metrics( face, FALSE, glyph_index, &abearing, &aadvance ); metrics->horiBearingX = (FT_Short)originOffsetX; - metrics->horiBearingY = (FT_Short)( -originOffsetY + metrics->height ); + metrics->vertBearingX = (FT_Short)originOffsetX; + + metrics->horiBearingY = (FT_Short)( originOffsetY + metrics->height ); + metrics->vertBearingY = (FT_Short)originOffsetY; + metrics->horiAdvance = (FT_UShort)( aadvance * face->root.size->metrics.x_ppem / face->header.Units_Per_EM ); + + if ( face->vertical_info ) + tt_face_get_metrics( face, TRUE, glyph_index, &abearing, &aadvance ); + else if ( face->os2.version != 0xFFFFU ) + aadvance = (FT_UShort)FT_ABS( face->os2.sTypoAscender - + face->os2.sTypoDescender ); + else + aadvance = (FT_UShort)FT_ABS( face->horizontal.Ascender - + face->horizontal.Descender ); + + metrics->vertAdvance = (FT_UShort)( aadvance * + face->root.size->metrics.x_ppem / + face->header.Units_Per_EM ); } return error; } - FT_LOCAL( FT_Error ) + FT_LOCAL_DEF( FT_Error ) tt_face_load_sbit_image( TT_Face face, FT_ULong strike_index, FT_UInt glyph_index, @@ -1673,7 +1677,7 @@ #else /* !TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ /* ANSI C doesn't like empty source files */ - typedef int _tt_sbit_dummy; + typedef int tt_sbit_dummy_; #endif /* !TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ diff --git a/src/3rdparty/freetype/src/sfnt/ttsbit.h b/src/3rdparty/freetype/src/sfnt/ttsbit.h index b867e43a61..07e2db461a 100644 --- a/src/3rdparty/freetype/src/sfnt/ttsbit.h +++ b/src/3rdparty/freetype/src/sfnt/ttsbit.h @@ -4,7 +4,7 @@ * * TrueType and OpenType embedded bitmap support (specification). * - * Copyright (C) 1996-2020 by + * Copyright (C) 1996-2023 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/src/3rdparty/freetype/src/sfnt/ttsvg.c b/src/3rdparty/freetype/src/sfnt/ttsvg.c new file mode 100644 index 0000000000..4461d483b0 --- /dev/null +++ b/src/3rdparty/freetype/src/sfnt/ttsvg.c @@ -0,0 +1,413 @@ +/**************************************************************************** + * + * ttsvg.c + * + * OpenType SVG Color (specification). + * + * Copyright (C) 2022-2023 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * 'SVG' table specification: + * + * https://docs.microsoft.com/en-us/typography/opentype/spec/svg + * + */ + +#include <ft2build.h> +#include <freetype/internal/ftstream.h> +#include <freetype/internal/ftobjs.h> +#include <freetype/internal/ftdebug.h> +#include <freetype/tttags.h> +#include <freetype/ftgzip.h> +#include <freetype/otsvg.h> + + +#ifdef FT_CONFIG_OPTION_SVG + +#include "ttsvg.h" + + + /* NOTE: These table sizes are given by the specification. */ +#define SVG_TABLE_HEADER_SIZE (10U) +#define SVG_DOCUMENT_RECORD_SIZE (12U) +#define SVG_DOCUMENT_LIST_MINIMUM_SIZE (2U + SVG_DOCUMENT_RECORD_SIZE) +#define SVG_MINIMUM_SIZE (SVG_TABLE_HEADER_SIZE + \ + SVG_DOCUMENT_LIST_MINIMUM_SIZE) + + + typedef struct Svg_ + { + FT_UShort version; /* table version (starting at 0) */ + FT_UShort num_entries; /* number of SVG document records */ + + FT_Byte* svg_doc_list; /* pointer to the start of SVG Document List */ + + void* table; /* memory that backs up SVG */ + FT_ULong table_size; + + } Svg; + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, usued to print/log + * messages during execution. + */ +#undef FT_COMPONENT +#define FT_COMPONENT ttsvg + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_svg( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = face->root.memory; + + FT_ULong table_size; + FT_Byte* table = NULL; + FT_Byte* p = NULL; + Svg* svg = NULL; + FT_ULong offsetToSVGDocumentList; + + + error = face->goto_table( face, TTAG_SVG, stream, &table_size ); + if ( error ) + goto NoSVG; + + if ( table_size < SVG_MINIMUM_SIZE ) + goto InvalidTable; + + if ( FT_FRAME_EXTRACT( table_size, table ) ) + goto NoSVG; + + /* Allocate memory for the SVG object */ + if ( FT_NEW( svg ) ) + goto NoSVG; + + p = table; + svg->version = FT_NEXT_USHORT( p ); + offsetToSVGDocumentList = FT_NEXT_ULONG( p ); + + if ( offsetToSVGDocumentList < SVG_TABLE_HEADER_SIZE || + offsetToSVGDocumentList > table_size - + SVG_DOCUMENT_LIST_MINIMUM_SIZE ) + goto InvalidTable; + + svg->svg_doc_list = (FT_Byte*)( table + offsetToSVGDocumentList ); + + p = svg->svg_doc_list; + svg->num_entries = FT_NEXT_USHORT( p ); + + FT_TRACE3(( "version: %d\n", svg->version )); + FT_TRACE3(( "number of entries: %d\n", svg->num_entries )); + + if ( offsetToSVGDocumentList + 2U + + svg->num_entries * SVG_DOCUMENT_RECORD_SIZE > table_size ) + goto InvalidTable; + + svg->table = table; + svg->table_size = table_size; + + face->svg = svg; + face->root.face_flags |= FT_FACE_FLAG_SVG; + + return FT_Err_Ok; + + InvalidTable: + error = FT_THROW( Invalid_Table ); + + NoSVG: + FT_FRAME_RELEASE( table ); + FT_FREE( svg ); + face->svg = NULL; + + return error; + } + + + FT_LOCAL_DEF( void ) + tt_face_free_svg( TT_Face face ) + { + FT_Memory memory = face->root.memory; + FT_Stream stream = face->root.stream; + + Svg* svg = (Svg*)face->svg; + + + if ( svg ) + { + FT_FRAME_RELEASE( svg->table ); + FT_FREE( svg ); + } + } + + + typedef struct Svg_doc_ + { + FT_UShort start_glyph_id; + FT_UShort end_glyph_id; + + FT_ULong offset; + FT_ULong length; + + } Svg_doc; + + + static Svg_doc + extract_svg_doc( FT_Byte* stream ) + { + Svg_doc doc; + + + doc.start_glyph_id = FT_NEXT_USHORT( stream ); + doc.end_glyph_id = FT_NEXT_USHORT( stream ); + + doc.offset = FT_NEXT_ULONG( stream ); + doc.length = FT_NEXT_ULONG( stream ); + + return doc; + } + + + static FT_Int + compare_svg_doc( Svg_doc doc, + FT_UInt glyph_index ) + { + if ( glyph_index < doc.start_glyph_id ) + return -1; + else if ( glyph_index > doc.end_glyph_id ) + return 1; + else + return 0; + } + + + static FT_Error + find_doc( FT_Byte* document_records, + FT_UShort num_entries, + FT_UInt glyph_index, + FT_ULong *doc_offset, + FT_ULong *doc_length, + FT_UShort *start_glyph, + FT_UShort *end_glyph ) + { + FT_Error error; + + Svg_doc start_doc; + Svg_doc mid_doc = { 0, 0, 0, 0 }; /* pacify compiler */ + Svg_doc end_doc; + + FT_Bool found = FALSE; + FT_UInt i = 0; + + FT_UInt start_index = 0; + FT_UInt end_index = num_entries - 1; + FT_Int comp_res; + + + /* search algorithm */ + if ( num_entries == 0 ) + { + error = FT_THROW( Invalid_Table ); + return error; + } + + start_doc = extract_svg_doc( document_records + start_index * 12 ); + end_doc = extract_svg_doc( document_records + end_index * 12 ); + + if ( ( compare_svg_doc( start_doc, glyph_index ) == -1 ) || + ( compare_svg_doc( end_doc, glyph_index ) == 1 ) ) + { + error = FT_THROW( Invalid_Glyph_Index ); + return error; + } + + while ( start_index <= end_index ) + { + i = ( start_index + end_index ) / 2; + mid_doc = extract_svg_doc( document_records + i * 12 ); + comp_res = compare_svg_doc( mid_doc, glyph_index ); + + if ( comp_res == 1 ) + { + start_index = i + 1; + start_doc = extract_svg_doc( document_records + start_index * 4 ); + } + else if ( comp_res == -1 ) + { + end_index = i - 1; + end_doc = extract_svg_doc( document_records + end_index * 4 ); + } + else + { + found = TRUE; + break; + } + } + /* search algorithm end */ + + if ( found != TRUE ) + { + FT_TRACE5(( "SVG glyph not found\n" )); + error = FT_THROW( Invalid_Glyph_Index ); + } + else + { + *doc_offset = mid_doc.offset; + *doc_length = mid_doc.length; + + *start_glyph = mid_doc.start_glyph_id; + *end_glyph = mid_doc.end_glyph_id; + + error = FT_Err_Ok; + } + + return error; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_svg_doc( FT_GlyphSlot glyph, + FT_UInt glyph_index ) + { + FT_Error error = FT_Err_Ok; + TT_Face face = (TT_Face)glyph->face; + FT_Memory memory = face->root.memory; + Svg* svg = (Svg*)face->svg; + + FT_Byte* doc_list; + FT_ULong doc_limit; + + FT_Byte* doc; + FT_ULong doc_offset; + FT_ULong doc_length; + FT_UShort doc_start_glyph_id; + FT_UShort doc_end_glyph_id; + + FT_SVG_Document svg_document = (FT_SVG_Document)glyph->other; + + + FT_ASSERT( !( svg == NULL ) ); + + doc_list = svg->svg_doc_list; + + error = find_doc( doc_list + 2, svg->num_entries, glyph_index, + &doc_offset, &doc_length, + &doc_start_glyph_id, &doc_end_glyph_id ); + if ( error != FT_Err_Ok ) + goto Exit; + + doc_limit = svg->table_size - + (FT_ULong)( doc_list - (FT_Byte*)svg->table ); + if ( doc_offset > doc_limit || + doc_length > doc_limit - doc_offset ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + doc = doc_list + doc_offset; + + if ( doc_length > 6 && + doc[0] == 0x1F && + doc[1] == 0x8B && + doc[2] == 0x08 ) + { +#ifdef FT_CONFIG_OPTION_USE_ZLIB + + FT_ULong uncomp_size; + FT_Byte* uncomp_buffer = NULL; + + + /* + * Get the size of the original document. This helps in allotting the + * buffer to accommodate the uncompressed version. The last 4 bytes + * of the compressed document are equal to the original size modulo + * 2^32. Since the size of SVG documents is less than 2^32 bytes we + * can use this accurately. The four bytes are stored in + * little-endian format. + */ + FT_TRACE4(( "SVG document is GZIP compressed\n" )); + uncomp_size = (FT_ULong)doc[doc_length - 1] << 24 | + (FT_ULong)doc[doc_length - 2] << 16 | + (FT_ULong)doc[doc_length - 3] << 8 | + (FT_ULong)doc[doc_length - 4]; + + if ( FT_QALLOC( uncomp_buffer, uncomp_size ) ) + goto Exit; + + error = FT_Gzip_Uncompress( memory, + uncomp_buffer, + &uncomp_size, + doc, + doc_length ); + if ( error ) + { + FT_FREE( uncomp_buffer ); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + + glyph->internal->flags |= FT_GLYPH_OWN_GZIP_SVG; + + doc = uncomp_buffer; + doc_length = uncomp_size; + +#else /* !FT_CONFIG_OPTION_USE_ZLIB */ + + error = FT_THROW( Unimplemented_Feature ); + goto Exit; + +#endif /* !FT_CONFIG_OPTION_USE_ZLIB */ + } + + svg_document->svg_document = doc; + svg_document->svg_document_length = doc_length; + + svg_document->metrics = glyph->face->size->metrics; + svg_document->units_per_EM = glyph->face->units_per_EM; + + svg_document->start_glyph_id = doc_start_glyph_id; + svg_document->end_glyph_id = doc_end_glyph_id; + + svg_document->transform.xx = 0x10000; + svg_document->transform.xy = 0; + svg_document->transform.yx = 0; + svg_document->transform.yy = 0x10000; + + svg_document->delta.x = 0; + svg_document->delta.y = 0; + + FT_TRACE5(( "start_glyph_id: %d\n", doc_start_glyph_id )); + FT_TRACE5(( "end_glyph_id: %d\n", doc_end_glyph_id )); + FT_TRACE5(( "svg_document:\n" )); + FT_TRACE5(( " %.*s\n", (FT_UInt)doc_length, doc )); + + glyph->other = svg_document; + + Exit: + return error; + } + +#else /* !FT_CONFIG_OPTION_SVG */ + + /* ANSI C doesn't like empty source files */ + typedef int tt_svg_dummy_; + +#endif /* !FT_CONFIG_OPTION_SVG */ + + +/* END */ diff --git a/src/3rdparty/freetype/src/sfnt/ttsvg.h b/src/3rdparty/freetype/src/sfnt/ttsvg.h new file mode 100644 index 0000000000..3f32321ded --- /dev/null +++ b/src/3rdparty/freetype/src/sfnt/ttsvg.h @@ -0,0 +1,43 @@ +/**************************************************************************** + * + * ttsvg.h + * + * OpenType SVG Color (specification). + * + * Copyright (C) 2022-2023 by + * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#ifndef TTSVG_H_ +#define TTSVG_H_ + +#include <freetype/internal/ftstream.h> +#include <freetype/internal/tttypes.h> + + +FT_BEGIN_HEADER + + FT_LOCAL( FT_Error ) + tt_face_load_svg( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + tt_face_free_svg( TT_Face face ); + + FT_LOCAL( FT_Error ) + tt_face_load_svg_doc( FT_GlyphSlot glyph, + FT_UInt glyph_index ); + +FT_END_HEADER + +#endif /* TTSVG_H_ */ + + +/* END */ diff --git a/src/3rdparty/freetype/src/sfnt/woff2tags.c b/src/3rdparty/freetype/src/sfnt/woff2tags.c index fd9f2e6c5d..eeedd9906b 100644 --- a/src/3rdparty/freetype/src/sfnt/woff2tags.c +++ b/src/3rdparty/freetype/src/sfnt/woff2tags.c @@ -4,7 +4,7 @@ * * WOFF2 Font table tags (base). * - * Copyright (C) 2019-2020 by + * Copyright (C) 2019-2023 by * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -17,6 +17,9 @@ #include <freetype/tttags.h> + +#ifdef FT_CONFIG_OPTION_USE_BROTLI + #include "woff2tags.h" /* @@ -28,10 +31,10 @@ * * for details. */ - FT_LOCAL_DEF( FT_ULong ) + FT_LOCAL_DEF( FT_Tag ) woff2_known_tags( FT_Byte index ) { - const FT_ULong known_tags[63] = + static const FT_Tag known_tags[63] = { FT_MAKE_TAG('c', 'm', 'a', 'p'), /* 0 */ FT_MAKE_TAG('h', 'e', 'a', 'd'), /* 1 */ @@ -105,5 +108,12 @@ return known_tags[index]; } +#else /* !FT_CONFIG_OPTION_USE_BROTLI */ + + /* ANSI C doesn't like empty source files */ + typedef int woff2tags_dummy_; + +#endif /* !FT_CONFIG_OPTION_USE_BROTLI */ + /* END */ diff --git a/src/3rdparty/freetype/src/sfnt/woff2tags.h b/src/3rdparty/freetype/src/sfnt/woff2tags.h index c437c77aa1..1201848e5e 100644 --- a/src/3rdparty/freetype/src/sfnt/woff2tags.h +++ b/src/3rdparty/freetype/src/sfnt/woff2tags.h @@ -2,9 +2,9 @@ * * woff2tags.h * - * WOFFF2 Font table tags (specification). + * WOFF2 Font table tags (specification). * - * Copyright (C) 2019-2020 by + * Copyright (C) 2019-2023 by * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -26,10 +26,12 @@ FT_BEGIN_HEADER +#ifdef FT_CONFIG_OPTION_USE_BROTLI - FT_LOCAL( FT_ULong ) + FT_LOCAL( FT_Tag ) woff2_known_tags( FT_Byte index ); +#endif FT_END_HEADER |