From 9d86c63f4a315738646138c57d85b49249efde86 Mon Sep 17 00:00:00 2001 From: Werner Lemberg Date: Mon, 7 Mar 2022 14:57:53 +0100 Subject: [PATCH] Improve handling of color palettes. This commit adds new functions to streamline palette access: FT_Palette_Set: Set a user-defined palette. FT_Palette_Get: Get palette and palette index. FT_Palette_Get_Foreground_Color: Get foreground color. Fixes issue #1134. * include/freetype/internal/tttypes.h (TT_FaceRec): Change type of `palette_index` to `FT_Int`. Negative values now represent user-defined palettes. * src/base/ftcolor.c (FT_Palette_Set, FT_Palette_Get, FT_Palette_Get_Foreground_Color): New functions. * include/freetype/ftcolor.h: Updated. --- include/freetype/ftcolor.h | 172 ++++++++++++++++++++++++---- include/freetype/internal/tttypes.h | 2 +- src/base/ftcolor.c | 131 ++++++++++++++++++++- 3 files changed, 283 insertions(+), 22 deletions(-) diff --git a/include/freetype/ftcolor.h b/include/freetype/ftcolor.h index 777fa8b8c..22030b5d7 100644 --- a/include/freetype/ftcolor.h +++ b/include/freetype/ftcolor.h @@ -45,6 +45,12 @@ FT_BEGIN_HEADER * @description: * The functions described here allow access and manipulation of color * palette entries in OpenType's 'CPAL' tables. + * + * FreeType maintains a 'working palette' (together with a corresponding + * 'working palette index'), which can be set either to a palette stored + * in the font (function @FT_Palette_Select) or to a user-defined palette + * (function @FT_Palette_Set). For user-defined palettes, the working + * palette index is negative, and positive otherwise. */ @@ -218,18 +224,13 @@ FT_BEGIN_HEADER * FT_Palette_Select * * @description: - * This function has two purposes. + * This function copies a palette entry in the font's 'CPAL' table into a + * 'working palette', which is a read-write array managed by FreeType. + * It also sets the 'working palette index' to the index value given as + * an argument. * - * (1) It activates a palette for rendering color glyphs, and - * - * (2) it retrieves all (unmodified) color entries of this palette. This - * function returns a read-write array, which means that a calling - * application can modify the palette entries on demand. - * - * A corollary of (2) is that calling the function, then modifying some - * values, then calling the function again with the same arguments resets - * all color entries to the original 'CPAL' values; all user modifications - * are lost. + * The current working palette and palette index can be retrieved with + * @FT_Palette_Get. * * @input: * face :: @@ -240,10 +241,10 @@ FT_BEGIN_HEADER * * @output: * apalette :: - * An array of color entries for a palette with index `palette_index`, - * having `num_palette_entries` elements (as found in the - * `FT_Palette_Data` structure). If `apalette` is set to `NULL`, no - * array gets returned (and no color entries can be modified). + * A pointer to the 'working palette', which is an array of color + * entries for a palette with index `palette_index`, having + * `num_palette_entries` elements (as found in the `FT_Palette_Data` + * structure). If `apalette` is set to `NULL`, no array gets returned. * * In case the font doesn't support color palettes, `NULL` is returned. * @@ -266,6 +267,92 @@ FT_BEGIN_HEADER FT_Color* *apalette ); + /************************************************************************** + * + * @function: + * FT_Palette_Set + * + * @description: + * Set FreeType's 'working palette' and 'working palette index' to the + * given arguments. Use this function if you want to provide a + * user-defined palette, not being part of the font's 'CPAL' table. + * + * The current working palette and palette index can be retrieved with + * @FT_Palette_Get. + * + * @input: + * face :: + * The source face handle. + * + * palette_index :: + * A palette index, which must be an arbitrary, negative integer (since + * positive values are reserved for indices from the 'CPAL' table). + * FreeType sets the 'working palette index' to this value. + * + * palette :: + * A pointer to an array of color entries, having `num_palette_entries` + * elements (as found in the `FT_Palette_Data` structure). FreeType + * copies this array into its 'working palette'. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function always returns an error if the config macro + * `TT_CONFIG_OPTION_COLOR_LAYERS` is not defined in `ftoption.h`. + * + * @since: + * 2.12 + */ + FT_EXPORT( FT_Error ) + FT_Palette_Set( FT_Face face, + FT_Int index, + FT_Color* palette ); + + + /************************************************************************** + * + * @function: + * FT_Palette_Get + * + * @description: + * Get FreeType's 'working palette' and 'working palette index'. + * + * The working palette and palette index can be set with @FT_Palette_Set. + * + * @input: + * face :: + * The source face handle. + * + * @output: + * anindex :: + * The 'working palette index'. If the value is zero or positive, the + * working palette represents an entry from the font's 'CPAL' table + * (with the given index). Otherwise it is a user-defined palette. If + * `anindex` is set to `NULL`, no value gets returned. + * + * apalette :: + * A pointer to the 'working palette', which is an array of color + * entries for a palette having `num_palette_entries` elements (as + * found in the `FT_Palette_Data` structure). If `apalette` is set to + * `NULL`, no array gets returned. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * This function always returns an error if the config macro + * `TT_CONFIG_OPTION_COLOR_LAYERS` is not defined in `ftoption.h`. + * + * @since: + * 2.12 + */ + FT_EXPORT( FT_Error ) + FT_Palette_Get( FT_Face face, + FT_Int *anindex, + FT_Color* *apalette ); + + /************************************************************************** * * @function: @@ -286,11 +373,9 @@ FT_BEGIN_HEADER * FreeType error code. 0~means success. * * @note: - * If this function isn't called, the text foreground color is set to - * white opaque (BGRA value 0xFFFFFFFF) if - * @FT_PALETTE_FOR_DARK_BACKGROUND is present for the current palette, - * and black opaque (BGRA value 0x000000FF) otherwise, including the case - * that no palette types are available in the 'CPAL' table. + * See function @FT_Palette_Get_Foreground_Color for details on what + * foreground color is used if `FT_Palette_Set_Foreground_Color` is not + * called. * * This function always returns an error if the config macro * `TT_CONFIG_OPTION_COLOR_LAYERS` is not defined in `ftoption.h`. @@ -303,6 +388,53 @@ FT_BEGIN_HEADER FT_Color foreground_color ); + /************************************************************************** + * + * @function: + * FT_Palette_Get_Foreground_Color + * + * @description: + * Get the 'text foreground color' as set by a previous call to + * @FT_Palette_Set_Foreground_Color. + * + * @input: + * face :: + * The source face handle. + * + * @output: + * aforeground_color :: + * The text foreground color. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * The returned color is as follows. + * + * * If a foreground color was set with @FT_Palette_Get_Foreground_Color, + * return this value. + * + * * Otherwise, return black opaque (BGRA value 0x000000FF) if the + * 'working palette' is a user-defined palette. + * + * * Otherwise, return white opaque (BGRA value 0xFFFFFFFF) if + * @FT_PALETTE_FOR_DARK_BACKGROUND is present for the current palette. + * + * * Otherwise, return black opaque (BGRA value 0x000000FF). This + * includes the case that no palette types are available in the 'CPAL' + * table. + * + * This function always returns an error if the config macro + * `TT_CONFIG_OPTION_COLOR_LAYERS` is not defined in `ftoption.h`. + * + * @since: + * 2.12 + */ + FT_EXPORT( FT_Error ) + FT_Palette_Get_Foreground_Color( FT_Face face, + FT_Color* aforeground_color ); + + /************************************************************************** * * @section: diff --git a/include/freetype/internal/tttypes.h b/include/freetype/internal/tttypes.h index df719387b..5ecd08455 100644 --- a/include/freetype/internal/tttypes.h +++ b/include/freetype/internal/tttypes.h @@ -1537,7 +1537,7 @@ FT_BEGIN_HEADER /* glyph colors */ FT_Palette_Data palette_data; /* since 2.10 */ - FT_UShort palette_index; + FT_Int palette_index; FT_Color* palette; FT_Bool have_foreground_color; FT_Color foreground_color; diff --git a/src/base/ftcolor.c b/src/base/ftcolor.c index 0edf379b4..d769c9627 100644 --- a/src/base/ftcolor.c +++ b/src/base/ftcolor.c @@ -36,7 +36,7 @@ { if ( !face ) return FT_THROW( Invalid_Face_Handle ); - if ( !apalette_data) + if ( !apalette_data ) return FT_THROW( Invalid_Argument ); if ( FT_IS_SFNT( face ) ) @@ -88,6 +88,57 @@ } + /* documentation is in ftcolor.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Palette_Set( FT_Face face, + FT_Int index, + FT_Color* palette ) + { + TT_Face ttface; + FT_UShort i; + + + if ( !face || !FT_IS_SFNT( face ) ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !palette || index >= 0 ) + return FT_THROW( Invalid_Argument ); + + ttface = (TT_Face)face; + + for ( i = 0; i < ttface->palette_data.num_palette_entries; i++ ) + ttface->palette[i] = palette[i]; + ttface->palette_index = index; + + return FT_Err_Ok; + } + + + /* documentation is in ftcolor.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Palette_Get( FT_Face face, + FT_Int *anindex, + FT_Color* *apalette ) + { + TT_Face ttface; + + + if ( !face || !FT_IS_SFNT( face ) ) + return FT_THROW( Invalid_Face_Handle ); + + ttface = (TT_Face)face; + + if ( anindex ) + *anindex = ttface->palette_index; + if ( apalette ) + *apalette = ttface->palette; + + return FT_Err_Ok; + } + + /* documentation is in ftcolor.h */ FT_EXPORT_DEF( FT_Error ) @@ -111,6 +162,44 @@ return FT_Err_Ok; } + + /* documentation is in ftcolor.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Palette_Get_Foreground_Color( FT_Face face, + FT_Color* aforeground_color ) + { + TT_Face ttface; + + FT_Color white = { 0xFF, 0xFF, 0xFF, 0xFF }; + FT_Color black = { 0x00, 0x00, 0x00, 0xFF }; + + + if ( !face || !FT_IS_SFNT( face ) ) + return FT_THROW( Invalid_Face_Handle ); + + if ( !aforeground_color ) + return FT_THROW( Invalid_Argument ); + + ttface = (TT_Face)face; + + if ( ttface->have_foreground_color ) + *aforeground_color = ttface->foreground_color; + else if ( ttface->palette_index < 0 ) + *aforeground_color = black; + else + { + if ( ttface->palette_data.palette_flags && + ( ttface->palette_data.palette_flags[ttface->palette_index] & + FT_PALETTE_FOR_DARK_BACKGROUND ) ) + *aforeground_color = white; + else + *aforeground_color = black; + } + + return FT_Err_Ok; + } + #else /* !TT_CONFIG_OPTION_COLOR_LAYERS */ FT_EXPORT_DEF( FT_Error ) @@ -139,6 +228,34 @@ } + FT_EXPORT_DEF( FT_Error ) + FT_Palette_Set( FT_Face face, + FT_Int index, + FT_Color* palette ) + { + FT_UNUSED( face ); + FT_UNUSED( index ); + FT_UNUSED( palette ); + + + return FT_THROW( Unimplemented_Feature ); + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Palette_Get( FT_Face face, + FT_Int *anindex, + FT_Color* *apalette ) + { + FT_UNUSED( face ); + FT_UNUSED( anindex ); + FT_UNUSED( apalette ); + + + return FT_THROW( Unimplemented_Feature ); + } + + FT_EXPORT_DEF( FT_Error ) FT_Palette_Set_Foreground_Color( FT_Face face, FT_Color foreground_color ) @@ -150,6 +267,18 @@ return FT_THROW( Unimplemented_Feature ); } + + FT_EXPORT_DEF( FT_Error ) + FT_Palette_Get_Foreground_Color( FT_Face face, + FT_Color* aforeground_color ) + { + FT_UNUSED( face ); + FT_UNUSED( aforeground_color ); + + + return FT_THROW( Unimplemented_Feature ); + } + #endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */