[cff] Add support for vsindex, DICT & CharString

Add cf2_cmdVSINDEX charstring operator.
Add cff_parse_vsindex as a callback function.
Add vsindex state machine to check for vsindex after blend.

Fix stack bugs in cff_blend_doBlend.
Report errors from cff_blend_build_vector.

Minor comment and TRACE edits.
This commit is contained in:
Dave Arnold 2016-11-10 13:18:38 -08:00
parent 304f0383ef
commit d5c247e923
6 changed files with 88 additions and 20 deletions

View File

@ -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;
}

View File

@ -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 );

View File

@ -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 */

View File

@ -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;
}

View File

@ -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" )

View File

@ -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 */