From c412de52fb909dcdf6e60c574d1f991a4f43cb3b Mon Sep 17 00:00:00 2001 From: Werner Lemberg Date: Sat, 9 Jun 2018 23:56:21 +0200 Subject: [PATCH] [sfnt] Read `CPAL' version 1 tables. * include/freetype/internal.tttypes.h: Include FT_COLOR_H. (TT_FaceRec): Add `palette' field. * src/sfnt/ttcolr.c: Include FT_COLOR_H. (Cpal): Remove all data covered by the new `palette' field in `TT_FaceRec'. (tt_face_load_colr): Updated. Read `CPAL' version 1 data. (tt_face_load_colr_layers, tt_face_find_color): Updated. * src/sfnt/sfobjs.c (sfnt_done_face): Free glyph color palette data. --- ChangeLog | 16 ++++ include/freetype/internal/tttypes.h | 8 +- src/sfnt/sfobjs.c | 5 ++ src/sfnt/ttcolr.c | 135 +++++++++++++++++++++------- 4 files changed, 131 insertions(+), 33 deletions(-) diff --git a/ChangeLog b/ChangeLog index 93c1d518a..c7ccdfc52 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2018-06-09 Werner Lemberg + + [sfnt] Read `CPAL' version 1 tables. + + * include/freetype/internal.tttypes.h: Include FT_COLOR_H. + (TT_FaceRec): Add `palette' field. + + * src/sfnt/ttcolr.c: Include FT_COLOR_H. + (Cpal): Remove all data covered by the new `palette' field in + `TT_FaceRec'. + (tt_face_load_colr): Updated. + Read `CPAL' version 1 data. + (tt_face_load_colr_layers, tt_face_find_color): Updated. + + * src/sfnt/sfobjs.c (sfnt_done_face): Free glyph color palette data. + 2018-06-07 Alexei Podtelezhnikov [base] API for Harmony LCD rendering. diff --git a/include/freetype/internal/tttypes.h b/include/freetype/internal/tttypes.h index c02d76dc6..2d5ee0aac 100644 --- a/include/freetype/internal/tttypes.h +++ b/include/freetype/internal/tttypes.h @@ -24,6 +24,7 @@ #include #include FT_TRUETYPE_TABLES_H #include FT_INTERNAL_OBJECTS_H +#include FT_COLOR_H #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT #include FT_MULTIPLE_MASTERS_H @@ -1657,6 +1658,9 @@ FT_BEGIN_HEADER /* postscript names table */ TT_Post_NamesRec postscript_names; + /* glyph colors */ + FT_Palette palette; /* since 2.10 */ + /************************************************************************ * @@ -1728,7 +1732,6 @@ FT_BEGIN_HEADER FT_UInt sbit_num_strikes; FT_UInt* sbit_strike_map; - void* colr_and_cpal; FT_Byte* kern_table; FT_ULong kern_table_size; FT_UInt num_kern_tables; @@ -1756,6 +1759,9 @@ FT_BEGIN_HEADER FT_ULong ebdt_size; #endif + /* since 2.10 */ + void* colr_and_cpal; + } TT_FaceRec; diff --git a/src/sfnt/sfobjs.c b/src/sfnt/sfobjs.c index 0c0e020f9..87749cae4 100644 --- a/src/sfnt/sfobjs.c +++ b/src/sfnt/sfobjs.c @@ -1808,6 +1808,11 @@ FT_FREE( face->var_postscript_prefix ); #endif + /* freeing glyph color palette data */ + FT_FREE( face->palette.palette_name_ids ); + FT_FREE( face->palette.palette_types ); + FT_FREE( face->palette.palette_entry_name_ids ); + face->sfnt = NULL; } diff --git a/src/sfnt/ttcolr.c b/src/sfnt/ttcolr.c index bfe8a39a7..ecadcddb9 100644 --- a/src/sfnt/ttcolr.c +++ b/src/sfnt/ttcolr.c @@ -32,6 +32,7 @@ #include FT_INTERNAL_DEBUG_H #include FT_INTERNAL_STREAM_H #include FT_TRUETYPE_TAGS_H +#include FT_COLOR_H #ifdef TT_CONFIG_OPTION_COLOR_LAYERS @@ -68,22 +69,16 @@ } Colr; + /* all data from `CPAL' not covered in FT_Palette */ typedef struct Cpal_ { FT_UShort version; /* Table version number (0 or 1 supported). */ - FT_UShort num_palettes_entries; /* # of entries in each palette. */ - FT_UShort num_palettes; /* # of palettes in the table. */ FT_UShort num_colors; /* Total number of color records, */ /* combined for all palettes. */ FT_Byte* colors; /* RGBA array of colors */ FT_Byte* color_indices; /* Index of each palette's first color record */ /* in the combined color record array. */ - /* version 1 fields */ - FT_ULong* palette_types; - FT_UShort* palette_labels; - FT_UShort* palette_entry_labels; - } Cpal; @@ -126,11 +121,13 @@ ColrCpal* cc = NULL; FT_ULong base_glyph_begin, base_glyph_end, layer_begin, layer_end; - FT_ULong colors_begin, colors_end; + FT_ULong colors_offset; FT_ULong table_size; - face->colr_and_cpal = NULL; + /* + * COLR + */ error = face->goto_table( face, TTAG_COLR, stream, &table_size ); if ( error ) @@ -173,6 +170,10 @@ if ( colr.base_glyphs < colr_table || colr.layers < colr_table ) goto InvalidTable; + /* + * CPAL + */ + error = face->goto_table( face, TTAG_CPAL, stream, &table_size ); if ( error ) goto NoColor; @@ -186,28 +187,99 @@ p = cpal_table; FT_ZERO( &cpal ); - cpal.version = FT_NEXT_USHORT( p ); - cpal.num_palettes_entries = FT_NEXT_USHORT( p ); - cpal.num_palettes = FT_NEXT_USHORT( p ); - cpal.num_colors = FT_NEXT_USHORT( p ); + cpal.version = FT_NEXT_USHORT( p ); + if ( cpal.version > 1 ) + goto InvalidTable; - colors_begin = FT_NEXT_ULONG( p ); + face->palette.num_palette_entries = FT_NEXT_USHORT( p ); + face->palette.num_palettes = FT_NEXT_USHORT( p ); + + cpal.num_colors = FT_NEXT_USHORT( p ); + colors_offset = FT_NEXT_ULONG( p ); + + if ( colors_offset >= table_size ) + goto InvalidTable; + if ( cpal.num_colors * COLOR_SIZE > table_size - colors_offset ) + goto InvalidTable; cpal.color_indices = p; - cpal.colors = (FT_Byte*)cpal_table + colors_begin; + cpal.colors = (FT_Byte*)cpal_table + colors_offset; - if ( cpal.version != 0 && cpal.version != 1 ) - goto InvalidTable; + if ( cpal.version == 1 ) + { + FT_ULong type_offset, label_offset, entry_label_offset; + FT_UShort* array; + FT_UShort* limit; + FT_UShort* q; - colors_end = colors_begin + cpal.num_colors * COLOR_SIZE; - /* Ensure variable length tables lies within the COLR table. */ - /* We wrap around FT_ULong at most once since count is FT_UShort. */ - if ( colors_end < colors_begin || colors_end > table_size ) - goto InvalidTable; + p += face->palette.num_palettes * 2; - if ( cpal.colors < cpal_table ) - goto InvalidTable; + type_offset = FT_NEXT_ULONG( p ); + label_offset = FT_NEXT_ULONG( p ); + entry_label_offset = FT_NEXT_ULONG( p ); + + if ( type_offset ) + { + if ( type_offset >= table_size ) + goto InvalidTable; + if ( face->palette.num_palettes * 2 > table_size - type_offset ) + goto InvalidTable; + + if ( FT_QNEW_ARRAY( array, face->palette.num_palettes ) ) + goto NoColor; + + p = cpal_table + type_offset; + q = array; + limit = q + face->palette.num_palettes * sizeof ( FT_UShort ); + + while ( q < limit ) + *q++ = FT_NEXT_USHORT( p ); + + face->palette.palette_types = array; + } + + if ( label_offset ) + { + if ( label_offset >= table_size ) + goto InvalidTable; + if ( face->palette.num_palettes * 2 > table_size - label_offset ) + goto InvalidTable; + + if ( FT_QNEW_ARRAY( array, face->palette.num_palettes ) ) + goto NoColor; + + p = cpal_table + label_offset; + q = array; + limit = q + face->palette.num_palettes * sizeof ( FT_UShort ); + + while ( q < limit ) + *q++ = FT_NEXT_USHORT( p ); + + face->palette.palette_name_ids = array; + } + + if ( entry_label_offset ) + { + if ( entry_label_offset >= table_size ) + goto InvalidTable; + if ( face->palette.num_palette_entries * 2 > + table_size - entry_label_offset ) + goto InvalidTable; + + if ( FT_QNEW_ARRAY( array, face->palette.num_palette_entries ) ) + goto NoColor; + + p = cpal_table + entry_label_offset; + q = array; + limit = q + face->palette.num_palette_entries * sizeof ( FT_UShort ); + + while ( q < limit ) + *q++ = FT_NEXT_USHORT( p ); + + face->palette.palette_entry_name_ids = array; + } + } if ( FT_NEW( cc ) ) goto NoColor; @@ -225,10 +297,10 @@ error = FT_THROW( Invalid_File_Format ); NoColor: - if ( colr_table ) - FT_FRAME_RELEASE( colr_table ); - if ( cpal_table ) - FT_FRAME_RELEASE( cpal_table ); + FT_FRAME_RELEASE( colr_table ); + FT_FRAME_RELEASE( cpal_table ); + + /* arrays in `face->palette' are freed in `sfnt_face_done' */ return error; } @@ -300,7 +372,6 @@ ColrCpal* colr_and_cpal = (ColrCpal *)face->colr_and_cpal; Colr* colr = &colr_and_cpal->colr; - Cpal* cpal = &colr_and_cpal->cpal; BaseGlyphRecord glyph_record; FT_Glyph_Layer layers; @@ -335,8 +406,8 @@ FT_UShort palette_index = FT_NEXT_USHORT( layer_record_ptr ); - if ( palette_index != 0xFFFF && - palette_index >= cpal->num_palettes_entries ) + if ( palette_index != 0xFFFF && + palette_index >= face->palette.num_palette_entries ) { error = FT_THROW( Invalid_File_Format ); goto Error; @@ -375,7 +446,7 @@ FT_Int color_offset; - if ( color_index >= cpal->num_palettes_entries ) + if ( color_index >= face->palette.num_palette_entries ) return 0; p = cpal->color_indices + palette_index * (int)sizeof ( FT_UShort );