diff --git a/ChangeLog b/ChangeLog index 35150c1d1..75a33bd86 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2016-12-18 Werner Lemberg + + [sfnt] Handle `fvar' with zero axes as a non-MM font. + + This is better behaviour than exiting with an error. + + * include/freetype/internal/tttypes.h (TT_Face): Add `use_fvar' + field. + + * src/sfnt/sfobjs.c (sfnt_init_face): Compute `use_fvar', also + updating the validation code. + Use `use_fvar' to compute FT_FACE_FLAG_MULTIPLE_MASTERS. + + * src/truetype/ttgxvar.c (TT_Get_MM_Var): Remove `fvar' validation + code. + 2016-12-18 Werner Lemberg Minor GX code shuffling. diff --git a/include/freetype/internal/tttypes.h b/include/freetype/internal/tttypes.h index 5fca84d87..82aaafc8b 100644 --- a/include/freetype/internal/tttypes.h +++ b/include/freetype/internal/tttypes.h @@ -1163,6 +1163,9 @@ FT_BEGIN_HEADER /* */ /* mm :: A pointer to the Multiple Masters service. */ /* */ + /* var :: A pointer to the Metrics Variations */ + /* service. */ + /* */ /* hdmx :: The face's horizontal device metrics */ /* (`hdmx' table). This table is optional in */ /* TrueType/OpenType fonts. */ @@ -1234,6 +1237,9 @@ FT_BEGIN_HEADER /* unmodified (i.e., without applying glyph */ /* variation deltas). */ /* */ + /* use_fvar :: Set if the `fvar' table header is valid, */ + /* and we have at least one design axis. */ + /* */ /* horz_metrics_size :: The size of the `hmtx' table. */ /* */ /* vert_metrics_size :: The size of the `vmtx' table. */ @@ -1426,6 +1432,7 @@ FT_BEGIN_HEADER GX_Blend blend; FT_Bool is_default_instance; /* since 2.7.1 */ + FT_Bool use_fvar; /* since 2.7.1 */ #endif /* since version 2.2 */ diff --git a/src/sfnt/sfobjs.c b/src/sfnt/sfobjs.c index fbb8a52b7..c40325a94 100644 --- a/src/sfnt/sfobjs.c +++ b/src/sfnt/sfobjs.c @@ -949,7 +949,7 @@ fvar_len < 20 || FT_READ_ULONG( version ) || FT_READ_USHORT( offset ) || - FT_STREAM_SKIP( 2 ) || + FT_STREAM_SKIP( 2 ) /* count_size_pairs */ || FT_READ_USHORT( num_axes ) || FT_READ_USHORT( axis_size ) || FT_READ_USHORT( num_instances ) || @@ -963,18 +963,30 @@ instance_size = 0; } - /* check that the data is bound by the table length; */ - /* based on similar code in function `TT_Get_MM_Var' */ + /* check that the data is bound by the table length */ if ( version != 0x00010000UL || +#if 0 + /* fonts like `JamRegular.ttf' have an incorrect value for */ + /* `count_size_pairs'; since value 2 is hard-coded in `fvar' */ + /* version 1.0, we simply ignore it */ + count_size_pairs != 2 || +#endif axis_size != 20 || num_axes == 0 || + /* `num_axes' limit implied by 16-bit `instance_size' */ num_axes > 0x3FFE || - instance_size != 4 + 4 * num_axes || + !( instance_size == 4 + 4 * num_axes || + instance_size == 6 + 4 * num_axes ) || num_instances > 0x7EFF || offset + axis_size * num_axes + instance_size * num_instances > fvar_len ) - num_instances = 0; + { + num_instances = 0; + face->use_fvar = 0; + } + else + face->use_fvar = 1; /* we don't support Multiple Master CFFs yet */ if ( !face->goto_table( face, TTAG_CFF, stream, 0 ) ) @@ -1356,13 +1368,14 @@ #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT /* Don't bother to load the tables unless somebody asks for them. */ /* No need to do work which will (probably) not be used. */ - if ( tt_face_lookup_table( face, TTAG_glyf ) != 0 && - tt_face_lookup_table( face, TTAG_fvar ) != 0 && - tt_face_lookup_table( face, TTAG_gvar ) != 0 ) - flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; - if ( tt_face_lookup_table( face, TTAG_CFF2 ) != 0 && - tt_face_lookup_table( face, TTAG_fvar ) != 0 ) - flags |= FT_FACE_FLAG_MULTIPLE_MASTERS; + if ( face->use_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; + } #endif root->face_flags = flags; diff --git a/src/truetype/ttgxvar.c b/src/truetype/ttgxvar.c index 06080d73b..3bcec27ac 100644 --- a/src/truetype/ttgxvar.c +++ b/src/truetype/ttgxvar.c @@ -1344,41 +1344,13 @@ fvar_start = FT_STREAM_POS( ); + /* the validity of the `fvar' header data was already checked */ + /* in function `sfnt_init_face' */ if ( FT_STREAM_READ_FIELDS( fvar_fields, &fvar_head ) ) goto Exit; - if ( fvar_head.version != (FT_Long)0x00010000L || -#if 0 - /* fonts like `JamRegular.ttf' have an incorrect value for */ - /* `countSizePairs'; since value 2 is hard-coded in `fvar' */ - /* version 1.0, we simply ignore it */ - fvar_head.countSizePairs != 2 || -#endif - fvar_head.axisSize != 20 || - fvar_head.axisCount == 0 || - /* axisCount limit implied by 16-bit instanceSize */ - fvar_head.axisCount > 0x3FFE || - fvar_head.instanceCount > 0x7EFF || - fvar_head.offsetToData + fvar_head.axisCount * 20U + - fvar_head.instanceCount * fvar_head.instanceSize > table_len ) - { - FT_TRACE1(( "\n" - "TT_Get_MM_Var: invalid `fvar' header\n" )); - error = FT_THROW( Invalid_Table ); - goto Exit; - } - - if ( fvar_head.instanceSize == 4 + 4 * fvar_head.axisCount ) - usePsName = FALSE; - else if ( fvar_head.instanceSize == 6 + 4 * fvar_head.axisCount ) - usePsName = TRUE; - else - { - FT_TRACE1(( "\n" - "TT_Get_MM_Var: invalid `fvar' header\n" )); - error = FT_THROW( Invalid_Table ); - goto Exit; - } + usePsName = FT_BOOL( fvar_head.instanceSize == + 6 + 4 * fvar_head.axisCount ); FT_TRACE2(( "loaded\n" ));