From 78a1e69517ca067224d6e33beffd25e2ec8361d2 Mon Sep 17 00:00:00 2001 From: Chris Liddell Date: Tue, 27 Nov 2018 22:24:06 +0100 Subject: [PATCH] [type1,cff] Add FT_{Set,Get}_MM_WeightVector API calls. For multiple master fonts, common usage (in Postscript) is to modify the WeightVector of an existing font instance, this addition supports that use. * include/freetype/ftmm.h, src/base/ftmm.c (FT_Set_MM_WeightVector, FT_Get_MM_WeightVector): New API functions. * include/freetype/internalservices/svmm.h (FT_Set_MM_WeightVector_Func, FT_Get_MM_WeightVector_Func): New function types. (MultiMasters): Add `set_mm_weightvector' and `get_mm_weightvector' members. (FT_DEFINE_SERVICE_MULTIMASTERSREC): Updated. * src/cffcffdrivr.c (cff_set_mm_weightvector, cff_get_mm_weightvector): New functions. (cff_service_multi_masters): Register them. * src/truetype/ttdriver.c (tt_service_gx_multi_masters): Updated. This driver doesn't use the new interface. * src/type1/t1load.c (T1_Set_MM_WeightVector, T1_Get_MM_WeightVector): New functions. * src/type1/t1driver.c (t1_service_multi_masters): Register them. * src/type1/t1load.h: Updated. --- ChangeLog | 30 ++++++++ include/freetype/ftmm.h | 92 +++++++++++++++++++++++ include/freetype/internal/services/svmm.h | 82 ++++++++++++-------- src/base/ftmm.c | 61 +++++++++++++++ src/cff/cffdrivr.c | 46 +++++++++--- src/truetype/ttdriver.c | 22 +++--- src/type1/t1driver.c | 22 +++--- src/type1/t1load.c | 69 +++++++++++++++++ src/type1/t1load.h | 10 +++ 9 files changed, 371 insertions(+), 63 deletions(-) diff --git a/ChangeLog b/ChangeLog index ac7368412..3a0162b45 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,33 @@ +2018-11-27 Chris Liddell + + [type1,cff] Add FT_{Set,Get}_MM_WeightVector API calls. + + For multiple master fonts, common usage (in Postscript) is to modify + the WeightVector of an existing font instance, this addition + supports that use. + + * include/freetype/ftmm.h, src/base/ftmm.c (FT_Set_MM_WeightVector, + FT_Get_MM_WeightVector): New API functions. + + * include/freetype/internalservices/svmm.h + (FT_Set_MM_WeightVector_Func, FT_Get_MM_WeightVector_Func): New + function types. + (MultiMasters): Add `set_mm_weightvector' and `get_mm_weightvector' + members. + (FT_DEFINE_SERVICE_MULTIMASTERSREC): Updated. + + * src/cffcffdrivr.c (cff_set_mm_weightvector, + cff_get_mm_weightvector): New functions. + (cff_service_multi_masters): Register them. + + * src/truetype/ttdriver.c (tt_service_gx_multi_masters): Updated. + This driver doesn't use the new interface. + + * src/type1/t1load.c (T1_Set_MM_WeightVector, + T1_Get_MM_WeightVector): New functions. + * src/type1/t1driver.c (t1_service_multi_masters): Register them. + * src/type1/t1load.h: Updated. + 2018-11-27 Ben Wagner [cff] Fix compiler warning (#55105). diff --git a/include/freetype/ftmm.h b/include/freetype/ftmm.h index 0584ce6df..a432f5dab 100644 --- a/include/freetype/ftmm.h +++ b/include/freetype/ftmm.h @@ -561,6 +561,98 @@ FT_BEGIN_HEADER FT_Fixed* coords ); + /************************************************************************** + * + * @function: + * FT_Set_MM_WeightVector + * + * @description: + * For Adobe MM fonts, choose an interpolated font design by directly + * setting the weight vector. + * + * This function can't be used with TrueType GX or OpenType variation + * fonts. + * + * @inout: + * face :: + * A handle to the source face. + * + * @input: + * len :: + * The length of the weight vector array. If it is larger than the + * number of designs, the extra values are ignored. If it is less than + * the number of designs, the remaining values are set to zero. + * + * weightvector :: + * An array representing the weight vector. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Adobe Multiple Master fonts limit the number of designs, and thus the + * length of the weight vector to~16. + * + * If `len` is zero and `weightvector` is NULL, the weight vector array + * is reset to the default values. + * + * The Adobe documentation also states that the values in the + * WeightVector array must total 1.0 +/-~0.001. In practice this does + * not seem to be enforced, so is not enforced here, either. + * + * @since: + * 2.10 + */ + FT_EXPORT( FT_Error ) + FT_Set_MM_WeightVector( FT_Face face, + FT_UInt len, + FT_Fixed* weightvector ); + + + /************************************************************************** + * + * @function: + * FT_Get_MM_WeightVector + * + * @description: + * For Adobe MM fonts, retrieve the current weight vector of the font. + * + * This function can't be used with TrueType GX or OpenType variation + * fonts. + * + * @inout: + * face :: + * A handle to the source face. + * + * len :: + * A pointer to the size of the array to be filled. If the size of the + * array is less than the number of designs, `FT_Err_Invalid_Argument` + * is returned, and `len` is set to the required size (the number of + * designs). If the size of the array is greater than the number of + * designs, the remaining entries are set to~0. On successful + * completion, `len` is set to the number of designs (i.e., the number + * of values written to the array). + * + * @utput: + * weightvector :: + * An array to be filled. + * + * @return: + * FreeType error code. 0~means success. + * + * @note: + * Adobe Multiple Master fonts limit the number of designs, and thus the + * length of the WeightVector to~16. + * + * @since: + * 2.10 + */ + FT_EXPORT( FT_Error ) + FT_Get_MM_WeightVector( FT_Face face, + FT_UInt* len, + FT_Fixed* weightvector ); + + /************************************************************************** * * @enum: diff --git a/include/freetype/internal/services/svmm.h b/include/freetype/internal/services/svmm.h index 6aeaa4519..426425928 100644 --- a/include/freetype/internal/services/svmm.h +++ b/include/freetype/internal/services/svmm.h @@ -86,47 +86,63 @@ FT_BEGIN_HEADER typedef void (*FT_Done_Blend_Func)( FT_Face ); + typedef FT_Error + (*FT_Set_MM_WeightVector_Func)( FT_Face face, + FT_UInt len, + FT_Fixed* weight_vector ); + + typedef FT_Error + (*FT_Get_MM_WeightVector_Func)( FT_Face face, + FT_UInt* len, + FT_Fixed* weight_vector ); + FT_DEFINE_SERVICE( MultiMasters ) { - FT_Get_MM_Func get_mm; - FT_Set_MM_Design_Func set_mm_design; - FT_Set_MM_Blend_Func set_mm_blend; - FT_Get_MM_Blend_Func get_mm_blend; - FT_Get_MM_Var_Func get_mm_var; - FT_Set_Var_Design_Func set_var_design; - FT_Get_Var_Design_Func get_var_design; - FT_Set_Instance_Func set_instance; + FT_Get_MM_Func get_mm; + FT_Set_MM_Design_Func set_mm_design; + FT_Set_MM_Blend_Func set_mm_blend; + FT_Get_MM_Blend_Func get_mm_blend; + FT_Get_MM_Var_Func get_mm_var; + FT_Set_Var_Design_Func set_var_design; + FT_Get_Var_Design_Func get_var_design; + FT_Set_Instance_Func set_instance; + FT_Set_MM_WeightVector_Func set_mm_weightvector; + FT_Get_MM_WeightVector_Func get_mm_weightvector; /* for internal use; only needed for code sharing between modules */ - FT_Get_Var_Blend_Func get_var_blend; - FT_Done_Blend_Func done_blend; + FT_Get_Var_Blend_Func get_var_blend; + FT_Done_Blend_Func done_blend; }; -#define FT_DEFINE_SERVICE_MULTIMASTERSREC( class_, \ - get_mm_, \ - set_mm_design_, \ - set_mm_blend_, \ - get_mm_blend_, \ - get_mm_var_, \ - set_var_design_, \ - get_var_design_, \ - set_instance_, \ - get_var_blend_, \ - done_blend_ ) \ - static const FT_Service_MultiMastersRec class_ = \ - { \ - get_mm_, \ - set_mm_design_, \ - set_mm_blend_, \ - get_mm_blend_, \ - get_mm_var_, \ - set_var_design_, \ - get_var_design_, \ - set_instance_, \ - get_var_blend_, \ - done_blend_ \ +#define FT_DEFINE_SERVICE_MULTIMASTERSREC( class_, \ + get_mm_, \ + set_mm_design_, \ + set_mm_blend_, \ + get_mm_blend_, \ + get_mm_var_, \ + set_var_design_, \ + get_var_design_, \ + set_instance_, \ + set_weightvector_, \ + get_weightvector_, \ + get_var_blend_, \ + done_blend_ ) \ + static const FT_Service_MultiMastersRec class_ = \ + { \ + get_mm_, \ + set_mm_design_, \ + set_mm_blend_, \ + get_mm_blend_, \ + get_mm_var_, \ + set_var_design_, \ + get_var_design_, \ + set_instance_, \ + set_weightvector_, \ + get_weightvector_, \ + get_var_blend_, \ + done_blend_ \ }; /* */ diff --git a/src/base/ftmm.c b/src/base/ftmm.c index 54ab9e785..11c0e2709 100644 --- a/src/base/ftmm.c +++ b/src/base/ftmm.c @@ -199,6 +199,67 @@ } + /* documentation is in ftmm.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Set_MM_WeightVector( FT_Face face, + FT_UInt len, + FT_Fixed* weightvector ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( len && !weightvector ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service->set_mm_weightvector ) + error = service->set_mm_weightvector( face, len, weightvector ); + } + + /* enforce recomputation of auto-hinting data */ + if ( !error && face->autohint.finalizer ) + { + face->autohint.finalizer( face->autohint.data ); + face->autohint.data = NULL; + } + + return error; + } + + + FT_EXPORT_DEF( FT_Error ) + FT_Get_MM_WeightVector( FT_Face face, + FT_UInt* len, + FT_Fixed* weightvector ) + { + FT_Error error; + FT_Service_MultiMasters service; + + + /* check of `face' delayed to `ft_face_get_mm_service' */ + + if ( len && !weightvector ) + return FT_THROW( Invalid_Argument ); + + error = ft_face_get_mm_service( face, &service ); + if ( !error ) + { + error = FT_ERR( Invalid_Argument ); + if ( service->get_mm_weightvector ) + error = service->get_mm_weightvector( face, len, weightvector ); + } + + return error; + } + + /* documentation is in ftmm.h */ FT_EXPORT_DEF( FT_Error ) diff --git a/src/cff/cffdrivr.c b/src/cff/cffdrivr.c index 3e43bed0b..9fe07b832 100644 --- a/src/cff/cffdrivr.c +++ b/src/cff/cffdrivr.c @@ -867,6 +867,30 @@ } + static FT_Error + cff_set_mm_weightvector( CFF_Face face, + FT_UInt len, + FT_Fixed* weightvector ) + { + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + + return mm->set_mm_weightvector( FT_FACE( face ), len, weightvector ); + } + + + static FT_Error + cff_get_mm_weightvector( CFF_Face face, + FT_UInt* len, + FT_Fixed* weightvector ) + { + FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm; + + + return mm->get_mm_weightvector( FT_FACE( face ), len, weightvector ); + } + + static FT_Error cff_get_mm_var( CFF_Face face, FT_MM_Var* *master ) @@ -916,17 +940,19 @@ FT_DEFINE_SERVICE_MULTIMASTERSREC( cff_service_multi_masters, - (FT_Get_MM_Func) NULL, /* get_mm */ - (FT_Set_MM_Design_Func) NULL, /* set_mm_design */ - (FT_Set_MM_Blend_Func) cff_set_mm_blend, /* set_mm_blend */ - (FT_Get_MM_Blend_Func) cff_get_mm_blend, /* get_mm_blend */ - (FT_Get_MM_Var_Func) cff_get_mm_var, /* get_mm_var */ - (FT_Set_Var_Design_Func)cff_set_var_design, /* set_var_design */ - (FT_Get_Var_Design_Func)cff_get_var_design, /* get_var_design */ - (FT_Set_Instance_Func) cff_set_instance, /* set_instance */ + (FT_Get_MM_Func) NULL, /* get_mm */ + (FT_Set_MM_Design_Func) NULL, /* set_mm_design */ + (FT_Set_MM_Blend_Func) cff_set_mm_blend, /* set_mm_blend */ + (FT_Get_MM_Blend_Func) cff_get_mm_blend, /* get_mm_blend */ + (FT_Get_MM_Var_Func) cff_get_mm_var, /* get_mm_var */ + (FT_Set_Var_Design_Func) cff_set_var_design, /* set_var_design */ + (FT_Get_Var_Design_Func) cff_get_var_design, /* get_var_design */ + (FT_Set_Instance_Func) cff_set_instance, /* set_instance */ + (FT_Set_MM_WeightVector_Func)cff_set_mm_weightvector, /* set_mm_weightvector */ + (FT_Get_MM_WeightVector_Func)cff_get_mm_weightvector, /* get_mm_weightvector */ - (FT_Get_Var_Blend_Func) cff_get_var_blend, /* get_var_blend */ - (FT_Done_Blend_Func) cff_done_blend /* done_blend */ + (FT_Get_Var_Blend_Func) cff_get_var_blend, /* get_var_blend */ + (FT_Done_Blend_Func) cff_done_blend /* done_blend */ ) diff --git a/src/truetype/ttdriver.c b/src/truetype/ttdriver.c index a197d6c96..58d34c5bc 100644 --- a/src/truetype/ttdriver.c +++ b/src/truetype/ttdriver.c @@ -498,17 +498,19 @@ FT_DEFINE_SERVICE_MULTIMASTERSREC( tt_service_gx_multi_masters, - (FT_Get_MM_Func) NULL, /* get_mm */ - (FT_Set_MM_Design_Func) NULL, /* set_mm_design */ - (FT_Set_MM_Blend_Func) TT_Set_MM_Blend, /* set_mm_blend */ - (FT_Get_MM_Blend_Func) TT_Get_MM_Blend, /* get_mm_blend */ - (FT_Get_MM_Var_Func) TT_Get_MM_Var, /* get_mm_var */ - (FT_Set_Var_Design_Func)TT_Set_Var_Design, /* set_var_design */ - (FT_Get_Var_Design_Func)TT_Get_Var_Design, /* get_var_design */ - (FT_Set_Instance_Func) TT_Set_Named_Instance, /* set_instance */ + (FT_Get_MM_Func) NULL, /* get_mm */ + (FT_Set_MM_Design_Func) NULL, /* set_mm_design */ + (FT_Set_MM_Blend_Func) TT_Set_MM_Blend, /* set_mm_blend */ + (FT_Get_MM_Blend_Func) TT_Get_MM_Blend, /* get_mm_blend */ + (FT_Get_MM_Var_Func) TT_Get_MM_Var, /* get_mm_var */ + (FT_Set_Var_Design_Func) TT_Set_Var_Design, /* set_var_design */ + (FT_Get_Var_Design_Func) TT_Get_Var_Design, /* get_var_design */ + (FT_Set_Instance_Func) TT_Set_Named_Instance, /* set_instance */ + (FT_Set_MM_WeightVector_Func)NULL, /* set_mm_weightvector */ + (FT_Get_MM_WeightVector_Func)NULL, /* get_mm_weightvector */ - (FT_Get_Var_Blend_Func) tt_get_var_blend, /* get_var_blend */ - (FT_Done_Blend_Func) tt_done_blend /* done_blend */ + (FT_Get_Var_Blend_Func) tt_get_var_blend, /* get_var_blend */ + (FT_Done_Blend_Func) tt_done_blend /* done_blend */ ) FT_DEFINE_SERVICE_METRICSVARIATIONSREC( diff --git a/src/type1/t1driver.c b/src/type1/t1driver.c index 3cde1dc6f..710ff1463 100644 --- a/src/type1/t1driver.c +++ b/src/type1/t1driver.c @@ -122,17 +122,19 @@ #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT static const FT_Service_MultiMastersRec t1_service_multi_masters = { - (FT_Get_MM_Func) T1_Get_Multi_Master, /* get_mm */ - (FT_Set_MM_Design_Func) T1_Set_MM_Design, /* set_mm_design */ - (FT_Set_MM_Blend_Func) T1_Set_MM_Blend, /* set_mm_blend */ - (FT_Get_MM_Blend_Func) T1_Get_MM_Blend, /* get_mm_blend */ - (FT_Get_MM_Var_Func) T1_Get_MM_Var, /* get_mm_var */ - (FT_Set_Var_Design_Func)T1_Set_Var_Design, /* set_var_design */ - (FT_Get_Var_Design_Func)T1_Get_Var_Design, /* get_var_design */ - (FT_Set_Instance_Func) T1_Reset_MM_Blend, /* set_instance */ + (FT_Get_MM_Func) T1_Get_Multi_Master, /* get_mm */ + (FT_Set_MM_Design_Func) T1_Set_MM_Design, /* set_mm_design */ + (FT_Set_MM_Blend_Func) T1_Set_MM_Blend, /* set_mm_blend */ + (FT_Get_MM_Blend_Func) T1_Get_MM_Blend, /* get_mm_blend */ + (FT_Get_MM_Var_Func) T1_Get_MM_Var, /* get_mm_var */ + (FT_Set_Var_Design_Func) T1_Set_Var_Design, /* set_var_design */ + (FT_Get_Var_Design_Func) T1_Get_Var_Design, /* get_var_design */ + (FT_Set_Instance_Func) T1_Reset_MM_Blend, /* set_instance */ + (FT_Set_MM_WeightVector_Func)T1_Set_MM_WeightVector, /* set_mm_weightvector */ + (FT_Get_MM_WeightVector_Func)T1_Get_MM_WeightVector, /* get_mm_weightvector */ - (FT_Get_Var_Blend_Func) NULL, /* get_var_blend */ - (FT_Done_Blend_Func) T1_Done_Blend /* done_blend */ + (FT_Get_Var_Blend_Func) NULL, /* get_var_blend */ + (FT_Done_Blend_Func) T1_Done_Blend /* done_blend */ }; #endif diff --git a/src/type1/t1load.c b/src/type1/t1load.c index 01befa2d4..60a2c35da 100644 --- a/src/type1/t1load.c +++ b/src/type1/t1load.c @@ -480,6 +480,75 @@ } + FT_LOCAL_DEF( FT_Error ) + T1_Set_MM_WeightVector( T1_Face face, + FT_UInt len, + FT_Fixed* weightvector ) + { + PS_Blend blend = face->blend; + FT_UInt i, n; + + + if ( !blend ) + return FT_THROW( Invalid_Argument ); + + if ( !len && !weightvector ) + { + for ( i = 0; i < blend->num_designs; i++ ) + blend->weight_vector[i] = blend->default_weight_vector[i]; + } + else + { + if ( !weightvector ) + return FT_THROW( Invalid_Argument ); + + n = len < blend->num_designs ? len : blend->num_designs; + + for ( i = 0; i < n; i++ ) + blend->weight_vector[i] = weightvector[i]; + + for ( ; i < blend->num_designs; i++ ) + blend->weight_vector[i] = (FT_Fixed)0; + + if ( len ) + face->root.face_flags |= FT_FACE_FLAG_VARIATION; + else + face->root.face_flags &= ~FT_FACE_FLAG_VARIATION; + } + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( FT_Error ) + T1_Get_MM_WeightVector( T1_Face face, + FT_UInt* len, + FT_Fixed* weightvector ) + { + PS_Blend blend = face->blend; + FT_UInt i; + + + if ( !blend ) + return FT_THROW( Invalid_Argument ); + + if ( *len < blend->num_designs ) + { + *len = blend->num_designs; + return FT_THROW( Invalid_Argument ); + } + + for ( i = 0; i < blend->num_designs; i++ ) + weightvector[i] = blend->weight_vector[i]; + for ( ; i < *len; i++ ) + weightvector[i] = (FT_Fixed)0; + + *len = blend->num_designs; + + return FT_Err_Ok; + } + + FT_LOCAL_DEF( FT_Error ) T1_Set_MM_Design( T1_Face face, FT_UInt num_coords, diff --git a/src/type1/t1load.h b/src/type1/t1load.h index 43d5db58f..0535451c4 100644 --- a/src/type1/t1load.h +++ b/src/type1/t1load.h @@ -106,6 +106,16 @@ FT_BEGIN_HEADER FT_LOCAL( void ) T1_Done_Blend( T1_Face face ); + FT_LOCAL( FT_Error ) + T1_Set_MM_WeightVector( T1_Face face, + FT_UInt len, + FT_Fixed* weightvector ); + + FT_LOCAL( FT_Error ) + T1_Get_MM_WeightVector( T1_Face face, + FT_UInt* len, + FT_Fixed* weightvector ); + #endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */