From d52dd7f31d958980331fdffec70588785669a327 Mon Sep 17 00:00:00 2001 From: Ewald Hew Date: Mon, 25 Sep 2017 08:22:26 +0200 Subject: [PATCH] Fix Type 1 hinting. Type 1 hinting breaks sometimes when mid-charstring hints should have been in the initial hintmap. This fix adds a preprocessing pass that reads all hints and builds the correct initial hintmap first, before proceeding to build the glyph outline. * src/psaux/psintrp.c (cf2_interpT2CharString): New `initial_map_ready' boolean flag. Ignore outline commands and hint changes on first pass. : Add section to build hintmap and rewind. --- ChangeLog | 14 +++++++++ src/psaux/psintrp.c | 76 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 80 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3ab15c51a..7961ebe7d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2017-09-25 Ewald Hew + + [psaux] Fix Type 1 hinting. + + Type 1 hinting breaks sometimes when mid-charstring hints should + have been in the initial hintmap. This fix adds a preprocessing + pass that reads all hints and builds the correct initial hintmap + first, before proceeding to build the glyph outline. + + * src/psaux/psintrp.c (cf2_interpT2CharString): New + `initial_map_ready' boolean flag. + Ignore outline commands and hint changes on first pass. + : Add section to build hintmap and rewind. + 2017-09-25 Ewald Hew [psaux] Add tracing for hints. diff --git a/src/psaux/psintrp.c b/src/psaux/psintrp.c index 77f2632b8..3e0590f92 100644 --- a/src/psaux/psintrp.c +++ b/src/psaux/psintrp.c @@ -492,6 +492,7 @@ /* Stuff for Type 1 */ FT_Int known_othersubr_result_cnt = 0; FT_Bool large_int = FALSE; + FT_Bool initial_map_ready = FALSE; #define PS_STORAGE_SIZE 3 CF2_F16Dot16 results[PS_STORAGE_SIZE]; /* for othersubr results */ FT_Int result_cnt = 0; @@ -650,6 +651,20 @@ if ( font->isT1 ) { + if ( !initial_map_ready && + !( op1 == cf2_cmdHSTEM || + op1 == cf2_cmdVSTEM || + op1 == cf2_cmdHSBW || + op1 == cf2_cmdCALLSUBR || + op1 == cf2_cmdRETURN || + op1 == cf2_cmdESC || + op1 == cf2_cmdENDCHAR || + op1 >= 32 /* Numbers */ ) ) + { + cf2_stack_clear( opStack ); + continue; + } + if ( result_cnt > 0 && !( op1 == cf2_cmdCALLSUBR || op1 == cf2_cmdRETURN || @@ -1478,8 +1493,11 @@ if ( builder->metrics_only ) goto exit; - curX = ADD_INT32( curX, lsb_x ); - curY = ADD_INT32( curY, lsb_y ); + if ( initial_map_ready ) + { + curX = ADD_INT32( curX, lsb_x ); + curY = ADD_INT32( curY, lsb_y ); + } } } break; @@ -1647,8 +1665,9 @@ if ( arg_cnt != 3 ) goto Unexpected_OtherSubr; - if ( !decoder->flex_state || - decoder->num_flex_vectors != 7 ) + if ( initial_map_ready && + ( !decoder->flex_state || + decoder->num_flex_vectors != 7 ) ) { FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" " unexpected flex end\n" )); @@ -1666,6 +1685,9 @@ if ( arg_cnt != 0 ) goto Unexpected_OtherSubr; + if ( !initial_map_ready ) + break; + if ( ps_builder_check_points( &decoder->builder, 6 ) ) goto exit; @@ -1682,6 +1704,9 @@ if ( arg_cnt != 0 ) goto Unexpected_OtherSubr; + if ( !initial_map_ready ) + break; + if ( !decoder->flex_state ) { FT_ERROR(( "cf2_interpT2CharString (Type 1 mode):" @@ -1728,12 +1753,15 @@ if ( arg_cnt != 1 ) goto Unexpected_OtherSubr; - cf2_arrstack_clear( &vStemHintArray ); - cf2_arrstack_clear( &hStemHintArray ); + if ( initial_map_ready ) + { + cf2_arrstack_clear( &vStemHintArray ); + cf2_arrstack_clear( &hStemHintArray ); - cf2_hintmask_init( &hintMask, error ); - hintMask.isValid = FALSE; - hintMask.isNew = TRUE; + cf2_hintmask_init( &hintMask, error ); + hintMask.isValid = FALSE; + hintMask.isNew = TRUE; + } known_othersubr_result_cnt = 1; break; @@ -2281,6 +2309,9 @@ { FT_TRACE4(( " setcurrentpoint" )); + if ( !initial_map_ready ) + break; + /* From the T1 specification, section 6.4: */ /* */ /* The setcurrentpoint command is used only in */ @@ -2351,13 +2382,38 @@ if ( builder->metrics_only ) goto exit; - curX = ADD_INT32( curX, lsb_x ); + if ( initial_map_ready ) + curX = ADD_INT32( curX, lsb_x ); } break; case cf2_cmdENDCHAR: FT_TRACE4(( " endchar\n" )); + if ( font->isT1 && !initial_map_ready ) + { + FT_TRACE5(( "cf2_interpT2CharString (Type 1 mode): " + "Build initial hintmap, rewinding...\n" )); + + /* Trigger initial hintmap build */ + cf2_glyphpath_moveTo( &glyphPath, curX, curY ); + + initial_map_ready = TRUE; + + /* Change hints routine - clear for rewind */ + cf2_arrstack_clear( &vStemHintArray ); + cf2_arrstack_clear( &hStemHintArray ); + + cf2_hintmask_init( &hintMask, error ); + hintMask.isValid = FALSE; + hintMask.isNew = TRUE; + + /* Rewind charstring */ + charstring->ptr = charstring->start; + + break; + } + if ( cf2_stack_count( opStack ) == 1 || cf2_stack_count( opStack ) == 5 ) {