From 27fee7f8c6ae75e066b5a23472b33925c6e8b1e0 Mon Sep 17 00:00:00 2001 From: Werner Lemberg Date: Mon, 6 Mar 2017 20:45:44 +0100 Subject: [PATCH] [sfnt, truetype] Always provide default instance. As documented in the OpenType specification, an entry for the default instance may be omitted in the named instance table. In particular this means that even if there is no named instance table in the font we actually do have a named instance, namely the default instance. For consistency, we always want the default instance in our list of named instances. If it is missing, we try to synthesize it. * src/sfnt/sfobjs.c (sfnt_init_face): Check whether the default instance is in the table of named instances. Otherwise adjust number of instances. * src/truetype/ttgxvar.c: Include FT_TRUETYPE_IDS_H. (TT_Get_MM_Var): Use `face->root.style_flags' as the number of named instances. Sythesize a named instance entry if necessary. (tt_done_blend): Free `normalized_stylecoords'. --- ChangeLog | 23 ++++++++++ src/sfnt/sfobjs.c | 63 ++++++++++++++++++++++++++++ src/truetype/ttgxvar.c | 95 +++++++++++++++++++++++++++++++++--------- 3 files changed, 162 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3bbfe4206..3074bcb10 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2017-03-06 Werner Lemberg + + [sfnt, truetype] Always provide default instance. + + As documented in the OpenType specification, an entry for the + default instance may be omitted in the named instance table. In + particular this means that even if there is no named instance table + in the font we actually do have a named instance, namely the default + instance. + + For consistency, we always want the default instance in our list of + named instances. If it is missing, we try to synthesize it. + + * src/sfnt/sfobjs.c (sfnt_init_face): Check whether the default + instance is in the table of named instances. Otherwise adjust + number of instances. + + * src/truetype/ttgxvar.c: Include FT_TRUETYPE_IDS_H. + (TT_Get_MM_Var): Use `face->root.style_flags' as the number of named + instances. + Sythesize a named instance entry if necessary. + (tt_done_blend): Free `normalized_stylecoords'. + 2017-03-05 Werner Lemberg [sfnt] Remove redundant code. diff --git a/src/sfnt/sfobjs.c b/src/sfnt/sfobjs.c index 4cc3e3fe7..51be1c20d 100644 --- a/src/sfnt/sfobjs.c +++ b/src/sfnt/sfobjs.c @@ -856,6 +856,7 @@ FT_Parameter* params ) { FT_Error error; + FT_Memory memory = face->root.memory; FT_Library library = face->root.driver->root.library; SFNT_Service sfnt; FT_Int face_index; @@ -954,6 +955,9 @@ FT_Int instance_index; + FT_Byte* default_values = NULL; + FT_Byte* instance_values = NULL; + face->is_default_instance = 1; @@ -999,6 +1003,65 @@ if ( !face->goto_table( face, TTAG_CFF, stream, 0 ) ) num_instances = 0; + /* + * As documented in the OpenType specification, an entry for the + * default instance may be omitted in the named instance table. In + * particular this means that even if there is no named instance + * table in the font we actually do have a named instance, namely the + * default instance. + * + * For consistency, we always want the default instance in our list + * of named instances. If it is missing, we try to synthesize it + * later on. Here, we have to adjust `num_instances' accordingly. + */ + + if ( !( FT_ALLOC( default_values, num_axes * 2 ) || + FT_ALLOC( instance_values, num_axes * 2 ) ) ) + { + /* the current stream position is 16 bytes after the table start */ + FT_ULong array_start = FT_STREAM_POS() - 16 + offset; + FT_ULong default_value_offset, instance_offset; + + FT_Byte* p; + FT_UInt i; + + + default_value_offset = array_start + 8; + p = default_values; + + for ( i = 0; i < num_axes; i++ ) + { + (void)FT_STREAM_READ_AT( default_value_offset, p, 2 ); + + default_value_offset += axis_size; + p += 2; + } + + instance_offset = array_start + axis_size * num_axes + 4; + + for ( i = 0; i < num_instances; i++ ) + { + (void)FT_STREAM_READ_AT( instance_offset, + instance_values, + num_axes * 2 ); + + if ( !ft_memcmp( default_values, instance_values, num_axes * 2 ) ) + break; + + instance_offset += instance_size; + } + + if ( i == num_instances ) + { + /* no default instance in named instance table; */ + /* we thus have to synthesize it */ + num_instances++; + } + } + + FT_FREE( default_values ); + FT_FREE( instance_values ); + /* instance indices in `face_instance_index' start with index 1, */ /* thus `>' and not `>=' */ if ( instance_index > num_instances ) diff --git a/src/truetype/ttgxvar.c b/src/truetype/ttgxvar.c index 50da2ea90..fa614ca1a 100644 --- a/src/truetype/ttgxvar.c +++ b/src/truetype/ttgxvar.c @@ -45,6 +45,7 @@ #include FT_INTERNAL_STREAM_H #include FT_INTERNAL_SFNT_H #include FT_TRUETYPE_TAGS_H +#include FT_TRUETYPE_IDS_H #include FT_MULTIPLE_MASTERS_H #include FT_LIST_H @@ -1930,15 +1931,17 @@ FT_ULong table_len; FT_Error error = FT_Err_Ok; FT_ULong fvar_start; - FT_Int i, j; + FT_UInt i, j; FT_MM_Var* mmvar = NULL; FT_Fixed* next_coords; FT_Fixed* nsc; FT_String* next_name; FT_Var_Axis* a; + FT_Fixed* c; FT_Var_Named_Style* ns; GX_FVar_Head fvar_head; FT_Bool usePsName; + FT_UInt num_instances; static const FT_Frame_Field fvar_fields[] = { @@ -2019,12 +2022,18 @@ if ( FT_NEW( face->blend ) ) goto Exit; - /* cannot overflow 32-bit arithmetic because of the validity check */ + /* `num_instances' holds the number of all named instances, */ + /* including the default instance which might be missing */ + /* in fvar's table of named instances */ + num_instances = face->root.style_flags >> 16; + + /* cannot overflow 32-bit arithmetic because of the size limits */ + /* used in the `fvar' table validity check in `sfnt_init_face' */ face->blend->mmvar_len = sizeof ( FT_MM_Var ) + fvar_head.axisCount * sizeof ( FT_Var_Axis ) + - fvar_head.instanceCount * sizeof ( FT_Var_Named_Style ) + - fvar_head.instanceCount * fvar_head.axisCount * sizeof ( FT_Fixed ) + + num_instances * sizeof ( FT_Var_Named_Style ) + + num_instances * fvar_head.axisCount * sizeof ( FT_Fixed ) + 5 * fvar_head.axisCount; if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) ) @@ -2041,15 +2050,15 @@ /* may have a different number of designs */ /* (or tuples, as called by Apple) */ mmvar->num_namedstyles = - fvar_head.instanceCount; + num_instances; mmvar->axis = (FT_Var_Axis*)&( mmvar[1] ); mmvar->namedstyle = (FT_Var_Named_Style*)&( mmvar->axis[fvar_head.axisCount] ); next_coords = - (FT_Fixed*)&( mmvar->namedstyle[fvar_head.instanceCount] ); - for ( i = 0; i < fvar_head.instanceCount; i++ ) + (FT_Fixed*)&( mmvar->namedstyle[num_instances] ); + for ( i = 0; i < num_instances; i++ ) { mmvar->namedstyle[i].coords = next_coords; next_coords += fvar_head.axisCount; @@ -2109,17 +2118,14 @@ FT_TRACE5(( "\n" )); - if ( fvar_head.instanceCount ) - { - /* named instance coordinates are stored as design coordinates; */ - /* we have to convert them to normalized coordinates also */ - if ( FT_NEW_ARRAY( face->blend->normalized_stylecoords, - fvar_head.axisCount * fvar_head.instanceCount ) ) - goto Exit; + /* named instance coordinates are stored as design coordinates; */ + /* we have to convert them to normalized coordinates also */ + if ( FT_NEW_ARRAY( face->blend->normalized_stylecoords, + fvar_head.axisCount * num_instances ) ) + goto Exit; - if ( !face->blend->avar_checked ) - ft_var_load_avar( face ); - } + if ( fvar_head.instanceCount && !face->blend->avar_checked ) + ft_var_load_avar( face ); ns = mmvar->namedstyle; nsc = face->blend->normalized_stylecoords; @@ -2133,8 +2139,9 @@ ns->strid = FT_GET_USHORT(); (void) /* flags = */ FT_GET_USHORT(); - for ( j = 0; j < fvar_head.axisCount; j++ ) - ns->coords[j] = FT_GET_LONG(); + c = ns->coords; + for ( j = 0; j < fvar_head.axisCount; j++, c++ ) + *c = FT_GET_LONG(); if ( usePsName ) ns->psid = FT_GET_USHORT(); @@ -2148,6 +2155,55 @@ FT_FRAME_EXIT(); } + if ( num_instances != fvar_head.instanceCount ) + { + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + + FT_Int found, win, apple; + + + /* the default instance is missing in array the */ + /* of named instances; try to synthesize an entry */ + found = sfnt->get_name_id( face, + TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY, + &win, + &apple ); + if ( !found ) + found = sfnt->get_name_id( face, + TT_NAME_ID_FONT_SUBFAMILY, + &win, + &apple ); + + if ( found ) + { + FT_Int strid = win >= 0 ? win : apple; + + + found = sfnt->get_name_id( face, + TT_NAME_ID_PS_NAME, + &win, + &apple ); + if ( found ) + { + FT_Int psid = win >= 0 ? win : apple; + + + FT_TRACE5(( "TT_Get_MM_Var:" + " Adding default instance to named instances\n" )); + + ns = &mmvar->namedstyle[fvar_head.instanceCount]; + + ns->strid = strid; + ns->psid = psid; + + a = mmvar->axis; + c = ns->coords; + for ( j = 0; j < fvar_head.axisCount; j++, a++, c++ ) + *c = a->def; + } + } + } + ft_var_load_mvar( face ); } @@ -3528,6 +3584,7 @@ num_axes = blend->mmvar->num_axis; FT_FREE( blend->normalizedcoords ); + FT_FREE( blend->normalized_stylecoords ); FT_FREE( blend->mmvar ); if ( blend->avar_segment )