diff --git a/src/cff/cf2font.c b/src/cff/cf2font.c index 6c3da5cfa..22044c691 100644 --- a/src/cff/cf2font.c +++ b/src/cff/cf2font.c @@ -415,8 +415,9 @@ needExtraSetup = TRUE; } /* store vector inputs for blends in charstring */ - font->blend.font = subFont->blend.font; /* copy from subfont */ - font->vsindex = subFont->private_dict.vsindex; /* initial value for charstring */ + font->blend.font = subFont->blend.font; /* copy from subfont */ + font->blend.usedBV = FALSE; /* clear state of charstring blend */ + font->vsindex = subFont->private_dict.vsindex; /* initial value for charstring */ font->lenNDV = lenNormalizedV; font->NDV = normalizedV; } diff --git a/src/cff/cf2intrp.c b/src/cff/cf2intrp.c index 978bcf4bd..6b99cd73c 100644 --- a/src/cff/cf2intrp.c +++ b/src/cff/cf2intrp.c @@ -215,7 +215,7 @@ cf2_cmdESC, /* 12 */ cf2_cmdRESERVED_13, /* 13 */ cf2_cmdENDCHAR, /* 14 */ - cf2_cmdRESERVED_15, /* 15 */ + cf2_cmdVSINDEX, /* 15 */ cf2_cmdBLEND, /* 16 */ cf2_cmdRESERVED_17, /* 17 */ cf2_cmdHSTEMHM, /* 18 */ @@ -612,12 +612,25 @@ case cf2_cmdRESERVED_2: case cf2_cmdRESERVED_9: case cf2_cmdRESERVED_13: - case cf2_cmdRESERVED_15: case cf2_cmdRESERVED_17: /* we may get here if we have a prior error */ FT_TRACE4(( " unknown op (%d)\n", op1 )); break; + case cf2_cmdVSINDEX: + { + if ( font->blend.usedBV ) + { + /* vsindex not allowed after blend */ + lastError = FT_THROW( Invalid_Glyph_Format ); + goto exit; + } + + font->vsindex = (FT_UInt)cf2_stack_popInt( opStack ); + FT_TRACE4(( " %d\n", font->vsindex )); + break; + } + case cf2_cmdBLEND: { FT_UInt numBlends; @@ -630,7 +643,9 @@ /* check cached blend vector */ if ( cff_blend_check_vector( &font->blend, font->vsindex, font->lenNDV, font->NDV ) ) { - cff_blend_build_vector( &font->blend, font->vsindex, font->lenNDV, font->NDV ); + lastError = cff_blend_build_vector( &font->blend, font->vsindex, font->lenNDV, font->NDV ); + if ( lastError != FT_Err_Ok ) + goto exit; } /* do the blend */ numBlends = (FT_UInt)cf2_stack_popInt( opStack ); diff --git a/src/cff/cffload.c b/src/cff/cffload.c index 44e71f1d1..fd0162f25 100644 --- a/src/cff/cffload.c +++ b/src/cff/cffload.c @@ -1258,7 +1258,16 @@ FT_Memory memory = subFont->blend.font->memory; /* for FT_REALLOC */ FT_Error error = FT_Err_Ok; /* for FT_REALLOC */ + /* compute expected number of operands for this blend */ FT_UInt numOperands = (FT_UInt)(numBlends * blend->lenBV); + FT_UInt count = parser->top - 1 - parser->stack; + + if ( numOperands > count ) + { + FT_TRACE4(( " cff_blend_doBlend: Stack underflow %d args\n", count )); + error = FT_THROW( Stack_Underflow ); + goto Exit; + } /* check if we have room for numBlends values at blend_top */ size = 5 * numBlends; /* add 5 bytes per entry */ @@ -1273,8 +1282,8 @@ } subFont->blend_used += size; - base = ( parser->top - 1 - parser->stack ) - numOperands; - delta = base + numBlends; + base = count - numOperands; /* index of first blend arg */ + delta = base + numBlends; /* index of first delta arg */ for ( i = 0; i < numBlends; i++ ) { const FT_Int32 * weight = &blend->BV[1]; @@ -1323,23 +1332,21 @@ Exit: FT_UNUSED( vsindex ); FT_ASSERT( lenNDV == 0 || NDV ); - FT_TRACE4(( "cff_blend_build_vector\n" )); blend->builtBV = FALSE; - /* vs = cf2_getVStore( font->decoder ); */ vs = &blend->font->vstore; /* VStore and fvar must be consistent */ if ( lenNDV != 0 && lenNDV != vs->axisCount ) { - FT_TRACE4(( "cff_blend_build_vector: Axis count mismatch\n" )); + FT_TRACE4(( " cff_blend_build_vector: Axis count mismatch\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } if ( vsindex >= vs->dataCount ) { - FT_TRACE4(( "cff_blend_build_vector: vsindex out of range\n" )); + FT_TRACE4(( " cff_blend_build_vector: vsindex out of range\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } @@ -1364,7 +1371,7 @@ Exit: if ( master == 0 ) { blend->BV[master] = FT_FIXED_ONE; - FT_TRACE4(( "blend vector len %d\n [ %f ", len, (double)(blend->BV[master] / 65536. ) )); + FT_TRACE4(( " build blend vector len %d\n [ %f ", len, (double)(blend->BV[master] / 65536. ) )); continue; } @@ -1374,7 +1381,7 @@ Exit: if ( idx >= vs->regionCount ) { - FT_TRACE4(( "cf2_buildBlendVector: region index out of range\n" )); + FT_TRACE4(( " cf2_buildBlendVector: region index out of range\n" )); error = FT_THROW( Invalid_File_Format ); goto Exit; } @@ -1739,6 +1746,7 @@ Exit: /* store handle needed to access memory, vstore for blend */ subfont->blend.font = font; + subfont->blend.usedBV = FALSE; /* clear state */ /* set defaults */ FT_MEM_ZERO( priv, sizeof ( *priv ) ); @@ -1869,7 +1877,8 @@ Exit: /* CFF2 does not have a private dictionary in the Top DICT */ /* but may have one in a Font DICT. We need to parse */ /* the latter here in order to load any local subrs. */ - if ( cff_load_private_dict( font, subfont, 0, 0 ) ) + error = cff_load_private_dict( font, subfont, 0, 0 ); + if ( error ) goto Exit; /* read the local subrs, if any */ diff --git a/src/cff/cffparse.c b/src/cff/cffparse.c index d4a5d4b75..8f54cb0e6 100644 --- a/src/cff/cffparse.c +++ b/src/cff/cffparse.c @@ -384,7 +384,6 @@ result = -result; return result; - Overflow: result = 0x7FFFFFFFL; FT_TRACE4(( "!!!OVERFLOW:!!!" )); @@ -796,7 +795,38 @@ return error; } - /* TODO: replace this test code with doBlend */ + static FT_Error + cff_parse_vsindex( CFF_Parser parser ) + { + /* vsindex operator can only be used in a Private DICT */ + CFF_Private priv = (CFF_Private)parser->object; + FT_Byte** data = parser->stack; + CFF_Blend blend; + FT_Error error; + + + if ( !priv || !priv->subfont ) + { + error = FT_ERR( Invalid_File_Format ); + goto Exit; + } + blend = &priv->subfont->blend; + + if ( blend->usedBV ) + { + FT_ERROR(( " cff_parse_vsindex: vsindex not allowed after blend\n" )); + error = FT_THROW( Syntax_Error ); + goto Exit; + } + priv->vsindex = (FT_UInt)cff_parse_num( parser, data++ ); + + FT_TRACE4(( " %d\n", priv->vsindex )); + error = FT_Err_Ok; + + Exit: + return error; + } + static FT_Error cff_parse_blend( CFF_Parser parser ) { @@ -808,7 +838,6 @@ FT_Error error; error = FT_ERR( Stack_Underflow ); - FT_TRACE1(( " cff_parse_blend\n" )); if ( !priv || !priv->subfont ) { @@ -819,11 +848,19 @@ blend = &subFont->blend; if ( cff_blend_check_vector( blend, priv->vsindex, subFont->lenNDV, subFont->NDV ) ) - cff_blend_build_vector( blend, priv->vsindex, subFont->lenNDV, subFont->NDV ); + { + error = cff_blend_build_vector( blend, priv->vsindex, subFont->lenNDV, subFont->NDV ); + if ( error != FT_Err_Ok ) + goto Exit; + } numBlends = (FT_UInt)cff_parse_num( parser, parser->top - 1 ); + FT_TRACE4(( " %d values blended\n", numBlends )); + error = cff_blend_doBlend(subFont, parser, numBlends ); + + blend->usedBV = TRUE; Exit: return error; } diff --git a/src/cff/cfftoken.h b/src/cff/cfftoken.h index a1b8ae664..f1cf3364a 100644 --- a/src/cff/cfftoken.h +++ b/src/cff/cfftoken.h @@ -143,7 +143,7 @@ CFF_FIELD_DELTA ( 0x10D, snap_heights, 13, "StemSnapV" ) CFF_FIELD_NUM ( 0x111, language_group, "LanguageGroup" ) CFF_FIELD_FIXED ( 0x112, expansion_factor, "ExpansionFactor" ) - CFF_FIELD_NUM ( 22, vsindex, "vsindex" ) + CFF_FIELD_CALLBACK ( 22, vsindex, "vsindex" ) CFF_FIELD_BLEND ( 23, "blend" ) CFF_FIELD_NUM ( 19, local_subrs_offset, "Subrs" ) diff --git a/src/cff/cfftypes.h b/src/cff/cfftypes.h index 912ee5698..61b7e169d 100644 --- a/src/cff/cfftypes.h +++ b/src/cff/cfftypes.h @@ -139,7 +139,13 @@ FT_BEGIN_HEADER typedef struct CFF_BlendRec_ { - /* object to manage one cached blend vector */ + /* This object manages one cached blend vector. */ + /* There is a BlendRec for Private DICT parsing in each subfont */ + /* and a BlendRec for charstrings in CF2_Font instance data. */ + /* A cached BV may be used across DICTs or Charstrings if inputs */ + /* have not changed. */ + /* usedBV is reset at the start of each parse or charstring. */ + /* vsindex cannot be changed after a BV is used. */ /* Note: NDV is long 32/64 bit, while BV is 16.16 (FT_Int32) */ FT_Bool builtBV; /* blendV has been built */ FT_Bool usedBV; /* blendV has been used */