forked from minhngoc25a/freetype2
[cff] Add CFF2 blend support to cff parser.
* src/cff/cf2font.c (cf2_font_setup): before rendering a glyph, check blend vector and reparse private DICT if it has changed. * src/cff/cf2intrp.c (cf2_interpT2CharString): check blend vector and build blend vector if needed at cf2_doBlend. * src/cff/cffload.c (cff_vstore_load): fix bug parsing vstore with > 1 data item. (cff_load_private_dict): factor out private dict parsing so we can reparse when vector changes. Add functions for handling CFF_Blend object. (cff_blend_clear): clear blend stack (cff_blend_check_vector): test if inputs have changed and blend vector needs rebuilding. (cff_blend_build_vector): construct blend vector from design vector using algorithm in OpenType Font Variations Overview. (cff_blend_doBlend): compute blended array, same as in cf2_intrp.c but with parser blend_stack instead of charstring operand stack. * src/cff/cffparse.c Add blend_stack alongside parser stack, so we have a place to write blend results. (cff_parse_num): add internal number type, opcode 255, for use with blend_stack. Change limit check on several number parsing functions, since stack is no longer contiguous. (cff_parse_blend): check blend vector and re-build it if needed. (cff_parser_run): ignore opcode 255 if it occurs in a font. * src/cff/cfftypes.h (CFF_Blend): add object data for cff_blend_* functions. (CFF_SubFont): add CFF_Blend and blend_stack.
This commit is contained in:
parent
54d9993505
commit
776a712be8
|
@ -366,9 +366,6 @@
|
|||
cf2_font_setup( CF2_Font font,
|
||||
const CF2_Matrix* transform )
|
||||
{
|
||||
FT_Error error = FT_Err_Ok; /* for FT_REALLOC */
|
||||
FT_Memory memory = font->memory; /* for FT_REALLOC */
|
||||
|
||||
/* pointer to parsed font object */
|
||||
CFF_Decoder* decoder = font->decoder;
|
||||
|
||||
|
@ -405,25 +402,23 @@
|
|||
|
||||
if ( hasVariations )
|
||||
{
|
||||
if ( font->lenBlendVector == 0 )
|
||||
needExtraSetup = TRUE; /* a blend vector is required */
|
||||
|
||||
/* see if Private DICT in this subfont needs to be reparsed */
|
||||
/* Note: lenNormalizedVector is zero until FT_Get_MM_Var() is called */
|
||||
cf2_getNormalizedVector( decoder, &lenNormalizedV, &normalizedV );
|
||||
|
||||
/* determine if blend vector needs to be recomputed */
|
||||
if ( font->lastVsindex != subFont->font_dict.vsindex ||
|
||||
lenNormalizedV == 0 ||
|
||||
font->lenNormalizedVector != lenNormalizedV ||
|
||||
( lenNormalizedV &&
|
||||
memcmp( normalizedV,
|
||||
font->lastNormalizedVector,
|
||||
lenNormalizedV * sizeof( *normalizedV ) ) != 0 ) )
|
||||
if ( cff_blend_check_vector( &subFont->blend,
|
||||
subFont->private_dict.vsindex,
|
||||
lenNormalizedV, normalizedV ) )
|
||||
{
|
||||
font->lastVsindex = subFont->font_dict.vsindex;
|
||||
/* vectors will be copied below, during ExtraSetup */
|
||||
/* blend has changed, reparse */
|
||||
cff_load_private_dict( decoder->cff, subFont, lenNormalizedV, normalizedV );
|
||||
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->lenNDV = lenNormalizedV;
|
||||
font->NDV = normalizedV;
|
||||
}
|
||||
|
||||
/* if ppem has changed, we need to recompute some cached data */
|
||||
|
@ -584,35 +579,6 @@
|
|||
/* compute blue zones for this instance */
|
||||
cf2_blues_init( &font->blues, font );
|
||||
|
||||
/* copy normalized vector used to compute blend vector */
|
||||
if ( hasVariations )
|
||||
{
|
||||
/* if user has set a normalized vector, use it */
|
||||
/* otherwise, assume default */
|
||||
if ( lenNormalizedV != 0 )
|
||||
{
|
||||
/* user has set a normalized vector */
|
||||
if ( FT_REALLOC( font->lastNormalizedVector,
|
||||
font->lenNormalizedVector,
|
||||
lenNormalizedV * sizeof( *normalizedV )) )
|
||||
{
|
||||
CF2_SET_ERROR( &font->error, Out_Of_Memory );
|
||||
return;
|
||||
}
|
||||
font->lenNormalizedVector = lenNormalizedV;
|
||||
FT_MEM_COPY( font->lastNormalizedVector,
|
||||
normalizedV,
|
||||
lenNormalizedV * sizeof( *normalizedV ));
|
||||
}
|
||||
|
||||
/* build blend vector for this instance */
|
||||
cf2_buildBlendVector( font, font->lastVsindex,
|
||||
font->lenNormalizedVector,
|
||||
font->lastNormalizedVector,
|
||||
&font->lenBlendVector,
|
||||
&font->blendVector );
|
||||
}
|
||||
|
||||
} /* needExtraSetup */
|
||||
}
|
||||
|
||||
|
|
|
@ -76,11 +76,10 @@ FT_BEGIN_HEADER
|
|||
CF2_Fixed ppem; /* transform-dependent */
|
||||
|
||||
/* variation data */
|
||||
CF2_UInt lastVsindex; /* last vsindex used */
|
||||
CF2_UInt lenNormalizedVector; /* normDV length (aka numAxes) */
|
||||
FT_Fixed * lastNormalizedVector;/* last normDV used */
|
||||
CF2_UInt lenBlendVector; /* blendV length (aka numMasters) */
|
||||
CF2_Fixed * blendVector; /* current blendV (per glyph) */
|
||||
CFF_BlendRec blend; /* cached charstring blend vector */
|
||||
CF2_UInt vsindex; /* current vsindex */
|
||||
CF2_UInt lenNDV; /* current length NDV or zero */
|
||||
FT_Fixed * NDV; /* ptr to current NDV or NULL */
|
||||
|
||||
CF2_Int unitsPerEm;
|
||||
|
||||
|
|
|
@ -104,8 +104,8 @@
|
|||
FT_Memory memory = font->memory;
|
||||
(void)memory;
|
||||
|
||||
FT_FREE( font->lastNormalizedVector );
|
||||
FT_FREE( font->blendVector );
|
||||
FT_FREE( font->blend.lastNDV );
|
||||
FT_FREE( font->blend.BV );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -406,22 +406,22 @@
|
|||
/* store results into the first numBlends values, */
|
||||
/* then pop remaining arguments. */
|
||||
static void
|
||||
cf2_doBlend( const CF2_Font font,
|
||||
cf2_doBlend( const CFF_Blend blend,
|
||||
CF2_Stack opStack,
|
||||
CF2_UInt numBlends )
|
||||
{
|
||||
CF2_UInt delta;
|
||||
CF2_UInt base;
|
||||
CF2_UInt i, j;
|
||||
CF2_UInt numOperands = (CF2_UInt)(numBlends * font->lenBlendVector);
|
||||
CF2_UInt numOperands = (CF2_UInt)(numBlends * blend->lenBV);
|
||||
|
||||
base = cf2_stack_count( opStack ) - numOperands;
|
||||
delta = base + numBlends;
|
||||
for ( i = 0; i < numBlends; i++ )
|
||||
{
|
||||
const CF2_Fixed * weight = &font->blendVector[1];
|
||||
const CF2_Fixed * weight = &blend->BV[1];
|
||||
CF2_Fixed sum = cf2_stack_getReal( opStack, i+base ); /* start with first term */
|
||||
for ( j = 1; j < font->lenBlendVector; j++ )
|
||||
for ( j = 1; j < blend->lenBV; j++ )
|
||||
{
|
||||
sum += FT_MulFix( *weight++, cf2_stack_getReal( opStack, delta++ ));
|
||||
}
|
||||
|
@ -620,9 +620,23 @@
|
|||
|
||||
case cf2_cmdBLEND:
|
||||
{
|
||||
FT_UInt numBlends = (FT_UInt)cf2_stack_popInt( opStack );
|
||||
FT_UInt numBlends;
|
||||
|
||||
FT_TRACE4(( " blend\n" ));
|
||||
cf2_doBlend( font, opStack, numBlends );
|
||||
|
||||
if ( !font->isCFF2 )
|
||||
break; /* clear stack & ignore */
|
||||
|
||||
/* 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 );
|
||||
}
|
||||
/* do the blend */
|
||||
numBlends = (FT_UInt)cf2_stack_popInt( opStack );
|
||||
cf2_doBlend( &font->blend, opStack, numBlends );
|
||||
|
||||
font->blend.usedBV = TRUE;
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "cfferrs.h"
|
||||
|
||||
#define FT_FIXED_ONE ((FT_Fixed)0x10000)
|
||||
|
||||
#if 1
|
||||
|
||||
|
@ -1113,6 +1114,7 @@
|
|||
{
|
||||
FT_Memory memory = stream->memory;
|
||||
FT_Error error = FT_THROW( Invalid_File_Format );
|
||||
FT_ULong * dataOffsetArray = NULL;
|
||||
FT_UInt i,j;
|
||||
|
||||
/* no offset means no vstore to parse */
|
||||
|
@ -1122,8 +1124,6 @@
|
|||
FT_UInt vsOffset;
|
||||
FT_UInt format;
|
||||
FT_ULong regionListOffset;
|
||||
FT_ULong dataOffsetArrayOffset;
|
||||
FT_ULong varDataOffset;
|
||||
|
||||
/* we need to parse the table to determine its size */
|
||||
if ( FT_STREAM_SEEK( base_offset + offset ) ||
|
||||
|
@ -1147,9 +1147,15 @@
|
|||
FT_READ_USHORT( vstore->dataCount ) )
|
||||
goto Exit;
|
||||
|
||||
/* save position of item variation data offsets */
|
||||
/* we'll parse region list first, then come back */
|
||||
dataOffsetArrayOffset = FT_STREAM_POS();
|
||||
/* make temporary copy of item variation data offsets */
|
||||
/* we'll parse region list first, then come back */
|
||||
if ( FT_NEW_ARRAY( dataOffsetArray, vstore->dataCount ) )
|
||||
goto Exit;
|
||||
for ( i=0; i<vstore->dataCount; i++ )
|
||||
{
|
||||
if ( FT_READ_ULONG( dataOffsetArray[i] ) )
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* parse regionList and axisLists*/
|
||||
if ( FT_STREAM_SEEK( vsOffset + regionListOffset ) ||
|
||||
|
@ -1179,10 +1185,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
/* re-position to parse varData and regionIndices */
|
||||
if ( FT_STREAM_SEEK( dataOffsetArrayOffset ) )
|
||||
goto Exit;
|
||||
|
||||
/* use dataOffsetArray now to parse varData items */
|
||||
if ( FT_NEW_ARRAY( vstore->varData, vstore->dataCount ) )
|
||||
goto Exit;
|
||||
|
||||
|
@ -1191,10 +1194,7 @@
|
|||
FT_UInt itemCount, shortDeltaCount;
|
||||
CFF_VarData* data = &vstore->varData[i];
|
||||
|
||||
if ( FT_READ_ULONG( varDataOffset ) )
|
||||
goto Exit;
|
||||
|
||||
if ( FT_STREAM_SEEK( vsOffset + varDataOffset ) )
|
||||
if ( FT_STREAM_SEEK( vsOffset + dataOffsetArray[i] ) )
|
||||
goto Exit;
|
||||
|
||||
/* ignore these two values because CFF2 has no delta sets */
|
||||
|
@ -1220,11 +1220,254 @@
|
|||
error = FT_Err_Ok;
|
||||
|
||||
Exit:
|
||||
FT_FREE( dataOffsetArray );
|
||||
if ( error )
|
||||
cff_vstore_done( vstore, memory );
|
||||
return error;
|
||||
}
|
||||
|
||||
/* clear blend stack (after blend values are consumed) */
|
||||
/* TODO: should do this in cff_run_parse, but subFont */
|
||||
/* ref is not available there. */
|
||||
/* allocation is not changed when stack is cleared */
|
||||
static void
|
||||
cff_blend_clear( CFF_SubFont subFont )
|
||||
{
|
||||
subFont->blend_top = subFont->blend_stack;
|
||||
subFont->blend_used = 0;
|
||||
}
|
||||
|
||||
/* Blend numOperands on the stack, */
|
||||
/* store results into the first numBlends values, */
|
||||
/* then pop remaining arguments. */
|
||||
/* This is comparable to cf2_doBlend() but */
|
||||
/* the cffparse stack is different and can't be written. */
|
||||
/* Blended values are written to a different buffer, */
|
||||
/* using reserved operator 255. */
|
||||
/* Blend calculation is done in 16.16 fixed point. */
|
||||
static FT_Error
|
||||
cff_blend_doBlend( CFF_SubFont subFont,
|
||||
CFF_Parser parser,
|
||||
FT_UInt numBlends )
|
||||
{
|
||||
FT_UInt delta;
|
||||
FT_UInt base;
|
||||
FT_UInt i, j;
|
||||
FT_UInt size;
|
||||
CFF_Blend blend = &subFont->blend;
|
||||
FT_Memory memory = subFont->blend.font->memory; /* for FT_REALLOC */
|
||||
FT_Error error = FT_Err_Ok; /* for FT_REALLOC */
|
||||
|
||||
FT_UInt numOperands = (FT_UInt)(numBlends * blend->lenBV);
|
||||
|
||||
/* check if we have room for numBlends values at blend_top */
|
||||
size = 5 * numBlends; /* add 5 bytes per entry */
|
||||
if ( subFont->blend_used + size > subFont->blend_alloc )
|
||||
{
|
||||
/* increase or allocate blend_stack and reset blend_top */
|
||||
/* prepare to append numBlends values to the buffer */
|
||||
if ( FT_REALLOC( subFont->blend_stack, subFont->blend_alloc, subFont->blend_alloc + size ) )
|
||||
goto Exit;
|
||||
subFont->blend_top = subFont->blend_stack + subFont->blend_used;
|
||||
subFont->blend_alloc += size;
|
||||
}
|
||||
subFont->blend_used += size;
|
||||
|
||||
base = ( parser->top - 1 - parser->stack ) - numOperands;
|
||||
delta = base + numBlends;
|
||||
for ( i = 0; i < numBlends; i++ )
|
||||
{
|
||||
const FT_Int32 * weight = &blend->BV[1];
|
||||
|
||||
/* convert inputs to 16.16 fixed point */
|
||||
FT_Int32 sum = cff_parse_num( parser, &parser->stack[ i+base ] ) << 16;
|
||||
for ( j = 1; j < blend->lenBV; j++ )
|
||||
{
|
||||
sum += FT_MulFix( *weight++, cff_parse_num( parser, &parser->stack[ delta++ ] ) << 16 );
|
||||
}
|
||||
/* point parser stack to new value on blend_stack */
|
||||
parser->stack[ i+base ] = subFont->blend_top;
|
||||
|
||||
/* push blended result as Type 2 5-byte fixed point number */
|
||||
/* (except that host byte order is used ) */
|
||||
/* this will not conflict with actual DICTs because 255 is a reserved opcode */
|
||||
/* in both CFF and CFF2 DICTs */
|
||||
/* see cff_parse_num() for decode of this, which rounds to an integer */
|
||||
*subFont->blend_top++ = 255;
|
||||
*(( FT_UInt32 *)subFont->blend_top ) = sum; /* write 4 bytes */
|
||||
subFont->blend_top += 4;
|
||||
}
|
||||
/* leave only numBlends results on parser stack */
|
||||
parser->top = &parser->stack[ base + numBlends ];
|
||||
|
||||
Exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
/* compute a blend vector from variation store index and normalized vector */
|
||||
/* based on pseudo-code in OpenType Font Variations Overview */
|
||||
/* Note: lenNDV == 0 produces a default blend vector, (1,0,0,...) */
|
||||
static FT_Error
|
||||
cff_blend_build_vector( CFF_Blend blend,
|
||||
FT_UInt vsindex,
|
||||
FT_UInt lenNDV, FT_Fixed * NDV )
|
||||
{
|
||||
FT_Error error = FT_Err_Ok; /* for FT_REALLOC */
|
||||
FT_Memory memory = blend->font->memory; /* for FT_REALLOC */
|
||||
FT_UInt len;
|
||||
CFF_VStore vs;
|
||||
CFF_VarData* varData;
|
||||
FT_UInt master;
|
||||
|
||||
FT_UNUSED( lenNDV );
|
||||
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" ));
|
||||
error = FT_THROW( Invalid_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
if ( vsindex >= vs->dataCount )
|
||||
{
|
||||
FT_TRACE4(( "cff_blend_build_vector: vsindex out of range\n" ));
|
||||
error = FT_THROW( Invalid_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* select the item variation data structure */
|
||||
varData = &vs->varData[vsindex];
|
||||
|
||||
/* prepare buffer for the blend vector */
|
||||
len = varData->regionIdxCount + 1; /* add 1 for default component */
|
||||
if ( FT_REALLOC( blend->BV, blend->lenBV * sizeof( *blend->BV ), len * sizeof( *blend->BV )) )
|
||||
goto Exit;
|
||||
blend->lenBV = len;
|
||||
|
||||
/* outer loop steps through master designs to be blended */
|
||||
for ( master=0; master<len; master++ )
|
||||
{
|
||||
FT_UInt j;
|
||||
FT_UInt idx;
|
||||
CFF_VarRegion* varRegion;
|
||||
|
||||
/* default factor is always one */
|
||||
if ( master == 0 )
|
||||
{
|
||||
blend->BV[master] = FT_FIXED_ONE;
|
||||
FT_TRACE4(( "blend vector len %d\n [ %f ", len, (double)(blend->BV[master] / 65536. ) ));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* VStore array does not include default master, so subtract one */
|
||||
idx = varData->regionIndices[master-1];
|
||||
varRegion = &vs->varRegionList[idx];
|
||||
|
||||
if ( idx >= vs->regionCount )
|
||||
{
|
||||
FT_TRACE4(( "cf2_buildBlendVector: region index out of range\n" ));
|
||||
error = FT_THROW( Invalid_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* Note: lenNDV could be zero */
|
||||
/* In that case, build default blend vector (1,0,0...) */
|
||||
/* In the normal case, init each component to 1 before inner loop */
|
||||
if ( lenNDV != 0 )
|
||||
blend->BV[master] = FT_FIXED_ONE; /* default */
|
||||
|
||||
/* inner loop steps through axes in this region */
|
||||
for ( j=0; j<lenNDV; j++ )
|
||||
{
|
||||
CFF_AxisCoords* axis = &varRegion->axisList[j];
|
||||
FT_Fixed axisScalar;
|
||||
|
||||
/* compute the scalar contribution of this axis */
|
||||
/* ignore invalid ranges */
|
||||
if ( axis->startCoord > axis->peakCoord || axis->peakCoord > axis->endCoord )
|
||||
axisScalar = FT_FIXED_ONE;
|
||||
else if ( axis->startCoord < 0 && axis->endCoord > 0 && axis->peakCoord != 0 )
|
||||
axisScalar = FT_FIXED_ONE;
|
||||
/* peak of 0 means ignore this axis */
|
||||
else if ( axis->peakCoord == 0 )
|
||||
axisScalar = FT_FIXED_ONE;
|
||||
/* ignore this region if coords are out of range */
|
||||
else if ( NDV[j] < axis->startCoord || NDV[j] > axis->endCoord )
|
||||
axisScalar = 0;
|
||||
/* calculate a proportional factor */
|
||||
else
|
||||
{
|
||||
if ( NDV[j] == axis->peakCoord )
|
||||
axisScalar = FT_FIXED_ONE;
|
||||
else if ( NDV[j] < axis->peakCoord )
|
||||
axisScalar = FT_DivFix( NDV[j] - axis->startCoord,
|
||||
axis->peakCoord - axis->startCoord );
|
||||
else
|
||||
axisScalar = FT_DivFix( axis->endCoord - NDV[j],
|
||||
axis->endCoord - axis->peakCoord );
|
||||
}
|
||||
/* take product of all the axis scalars */
|
||||
blend->BV[master] = FT_MulFix( blend->BV[master], axisScalar );
|
||||
}
|
||||
FT_TRACE4(( ", %f ", (double)blend->BV[master] / 65536. ));
|
||||
}
|
||||
FT_TRACE4(( "]\n" ));
|
||||
|
||||
/* record the parameters used to build the blend vector */
|
||||
blend->lastVsindex = vsindex;
|
||||
if ( lenNDV != 0 )
|
||||
{
|
||||
/* user has set a normalized vector */
|
||||
if ( FT_REALLOC( blend->lastNDV,
|
||||
blend->lenNDV * sizeof( *NDV ),
|
||||
lenNDV * sizeof( *NDV )) )
|
||||
{
|
||||
error = FT_THROW( Out_Of_Memory );
|
||||
goto Exit;
|
||||
}
|
||||
blend->lenNDV = lenNDV;
|
||||
FT_MEM_COPY( blend->lastNDV,
|
||||
NDV,
|
||||
lenNDV * sizeof( *NDV ));
|
||||
}
|
||||
blend->builtBV = TRUE;
|
||||
|
||||
Exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
/* lenNDV is zero for default vector */
|
||||
/* return TRUE if blend vector needs to be built */
|
||||
static FT_Bool
|
||||
cff_blend_check_vector( CFF_Blend blend,
|
||||
FT_UInt vsindex,
|
||||
FT_UInt lenNDV,
|
||||
FT_Fixed * NDV )
|
||||
{
|
||||
if ( !blend->builtBV ||
|
||||
blend->lastVsindex != vsindex ||
|
||||
blend->lenNDV != lenNDV ||
|
||||
( lenNDV &&
|
||||
memcmp( NDV,
|
||||
blend->lastNDV,
|
||||
lenNDV * sizeof( *NDV ) ) != 0 ) )
|
||||
{
|
||||
/* need to build blend vector */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
cff_encoding_done( CFF_Encoding encoding )
|
||||
{
|
||||
|
@ -1477,27 +1720,94 @@
|
|||
}
|
||||
|
||||
|
||||
/* parse private dictionary as separate function */
|
||||
/* first call is always from cff_face_init, so NDV has not been set */
|
||||
/* for CFF2 variation, cff_slot_load must call each time NDV changes */
|
||||
static FT_Error
|
||||
cff_subfont_load( CFF_SubFont font,
|
||||
cff_load_private_dict( CFF_Font font,
|
||||
CFF_SubFont subfont,
|
||||
FT_UInt lenNDV, FT_Fixed * NDV )
|
||||
{
|
||||
FT_Error error = FT_Err_Ok;
|
||||
CFF_ParserRec parser;
|
||||
CFF_FontRecDict top = &subfont->font_dict;
|
||||
CFF_Private priv = &subfont->private_dict;
|
||||
FT_Stream stream = font->stream;
|
||||
|
||||
if ( top->private_offset == 0 || top->private_size == 0 )
|
||||
goto Exit; /* no private DICT, do nothing */
|
||||
|
||||
/* store handle needed to access memory, vstore for blend */
|
||||
subfont->blend.font = font;
|
||||
|
||||
/* set defaults */
|
||||
FT_MEM_ZERO( priv, sizeof ( *priv ) );
|
||||
|
||||
priv->blue_shift = 7;
|
||||
priv->blue_fuzz = 1;
|
||||
priv->lenIV = -1;
|
||||
priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L );
|
||||
priv->blue_scale = (FT_Fixed)( 0.039625 * 0x10000L * 1000 );
|
||||
|
||||
/* provide inputs for blend calculations */
|
||||
priv->subfont = subfont;
|
||||
subfont->lenNDV = lenNDV;
|
||||
subfont->NDV = NDV;
|
||||
|
||||
cff_parser_init( &parser,
|
||||
font->cff2 ? CFF2_CODE_PRIVATE : CFF_CODE_PRIVATE,
|
||||
priv,
|
||||
font->library,
|
||||
top->num_designs,
|
||||
top->num_axes );
|
||||
if ( FT_STREAM_SEEK( font->base_offset + top->private_offset ) ||
|
||||
FT_FRAME_ENTER( top->private_size ) )
|
||||
goto Exit;
|
||||
|
||||
FT_TRACE4(( " private dictionary:\n" ));
|
||||
error = cff_parser_run( &parser,
|
||||
(FT_Byte*)stream->cursor,
|
||||
(FT_Byte*)stream->limit );
|
||||
FT_FRAME_EXIT();
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
/* ensure that `num_blue_values' is even */
|
||||
priv->num_blue_values &= ~1;
|
||||
|
||||
Exit:
|
||||
cff_blend_clear( subfont );
|
||||
return error;
|
||||
}
|
||||
|
||||
/* There are 3 ways to call this function, distinguished by code: */
|
||||
/* CFF_CODE_TOPDICT for either a CFF Top DICT or a CFF Font DICT */
|
||||
/* CFF2_CODE_TOPDICT for CFF2 Top DICT */
|
||||
/* CFF2_CODE_FONTDICT for CFF2 Font DICT */
|
||||
|
||||
static FT_Error
|
||||
cff_subfont_load( CFF_SubFont subfont,
|
||||
CFF_Index idx,
|
||||
FT_UInt font_index,
|
||||
FT_Stream stream,
|
||||
FT_ULong base_offset,
|
||||
FT_Library library,
|
||||
FT_UInt code )
|
||||
FT_UInt code,
|
||||
CFF_Font font )
|
||||
{
|
||||
FT_Error error;
|
||||
CFF_ParserRec parser;
|
||||
FT_Byte* dict = NULL;
|
||||
FT_ULong dict_len;
|
||||
CFF_FontRecDict top = &font->font_dict;
|
||||
CFF_Private priv = &font->private_dict;
|
||||
FT_Bool cff2 = (code == CFF2_CODE_TOPDICT );
|
||||
CFF_FontRecDict top = &subfont->font_dict;
|
||||
CFF_Private priv = &subfont->private_dict;
|
||||
FT_Bool cff2 = (code == CFF2_CODE_TOPDICT ||
|
||||
code == CFF2_CODE_FONTDICT );
|
||||
|
||||
|
||||
cff_parser_init( &parser,
|
||||
code,
|
||||
&font->font_dict,
|
||||
&subfont->font_dict,
|
||||
library,
|
||||
0,
|
||||
0 );
|
||||
|
@ -1555,40 +1865,12 @@
|
|||
if ( top->cid_registry != 0xFFFFU )
|
||||
goto Exit;
|
||||
|
||||
/* parse the private dictionary, if any */
|
||||
if ( top->private_offset && top->private_size )
|
||||
{
|
||||
/* set defaults */
|
||||
FT_MEM_ZERO( priv, sizeof ( *priv ) );
|
||||
|
||||
priv->blue_shift = 7;
|
||||
priv->blue_fuzz = 1;
|
||||
priv->lenIV = -1;
|
||||
priv->expansion_factor = (FT_Fixed)( 0.06 * 0x10000L );
|
||||
priv->blue_scale = (FT_Fixed)( 0.039625 * 0x10000L * 1000 );
|
||||
|
||||
cff_parser_init( &parser,
|
||||
code == CFF2_CODE_FONTDICT ? CFF2_CODE_PRIVATE : CFF_CODE_PRIVATE,
|
||||
priv,
|
||||
library,
|
||||
top->num_designs,
|
||||
top->num_axes );
|
||||
|
||||
if ( FT_STREAM_SEEK( base_offset + font->font_dict.private_offset ) ||
|
||||
FT_FRAME_ENTER( font->font_dict.private_size ) )
|
||||
goto Exit;
|
||||
|
||||
FT_TRACE4(( " private dictionary:\n" ));
|
||||
error = cff_parser_run( &parser,
|
||||
(FT_Byte*)stream->cursor,
|
||||
(FT_Byte*)stream->limit );
|
||||
FT_FRAME_EXIT();
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
/* ensure that `num_blue_values' is even */
|
||||
priv->num_blue_values &= ~1;
|
||||
}
|
||||
/* parse the private dictionary, if any */
|
||||
/* 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 ) )
|
||||
goto Exit;
|
||||
|
||||
/* read the local subrs, if any */
|
||||
if ( priv->local_subrs_offset )
|
||||
|
@ -1597,12 +1879,12 @@
|
|||
priv->local_subrs_offset ) )
|
||||
goto Exit;
|
||||
|
||||
error = cff_index_init( &font->local_subrs_index, stream, 1, cff2 );
|
||||
error = cff_index_init( &subfont->local_subrs_index, stream, 1, cff2 );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
error = cff_index_get_pointers( &font->local_subrs_index,
|
||||
&font->local_subrs, NULL, NULL );
|
||||
error = cff_index_get_pointers( &subfont->local_subrs_index,
|
||||
&subfont->local_subrs, NULL, NULL );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
}
|
||||
|
@ -1620,6 +1902,9 @@
|
|||
{
|
||||
cff_index_done( &subfont->local_subrs_index );
|
||||
FT_FREE( subfont->local_subrs );
|
||||
FT_FREE( subfont->blend.lastNDV );
|
||||
FT_FREE( subfont->blend.BV );
|
||||
FT_FREE( subfont->blend_stack );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1655,30 +1940,39 @@
|
|||
FT_ZERO( font );
|
||||
FT_ZERO( &string_index );
|
||||
|
||||
font->library = library;
|
||||
font->stream = stream;
|
||||
font->memory = memory;
|
||||
font->cff2 = cff2;
|
||||
base_offset = font->base_offset = FT_STREAM_POS();
|
||||
dict = &font->top_font.font_dict;
|
||||
base_offset = FT_STREAM_POS();
|
||||
|
||||
/* read CFF font header */
|
||||
if ( FT_STREAM_READ_FIELDS( cff_header_fields, font ) )
|
||||
goto Exit;
|
||||
|
||||
/* check format */
|
||||
if ( font->version_major != ( cff2 ? 2 : 1 ) ||
|
||||
font->header_size < 4 )
|
||||
{
|
||||
FT_TRACE2(( " not a CFF font header\n" ));
|
||||
error = FT_THROW( Unknown_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if ( cff2 )
|
||||
{
|
||||
if ( font->version_major != 2 ||
|
||||
font->header_size < 5 )
|
||||
{
|
||||
FT_TRACE2(( " not a CFF2 font header\n" ));
|
||||
error = FT_THROW( Unknown_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
if ( FT_READ_USHORT( font->top_dict_length ) )
|
||||
goto Exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( font->version_major != 1 ||
|
||||
font->header_size < 4 )
|
||||
{
|
||||
FT_TRACE2(( " not a CFF font header\n" ));
|
||||
error = FT_THROW( Unknown_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* skip the rest of the header */
|
||||
if ( FT_STREAM_SEEK( base_offset + font->header_size ) )
|
||||
|
@ -1767,7 +2061,8 @@
|
|||
stream,
|
||||
base_offset,
|
||||
library,
|
||||
cff2 ? CFF2_CODE_TOPDICT : CFF_CODE_TOPDICT );
|
||||
cff2 ? CFF2_CODE_TOPDICT : CFF_CODE_TOPDICT,
|
||||
font );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
|
@ -1787,6 +2082,15 @@
|
|||
FT_UInt idx;
|
||||
|
||||
|
||||
/* for CFF2, read the Variation Store if available */
|
||||
/* this must follow the Top DICT parse and precede any Private DICT */
|
||||
error = cff_vstore_load( &font->vstore,
|
||||
stream,
|
||||
base_offset,
|
||||
dict->vstore_offset );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
/* this is a CID-keyed font, we must now allocate a table of */
|
||||
/* sub-fonts, then load each of them separately */
|
||||
if ( FT_STREAM_SEEK( base_offset + dict->cid_fd_array_offset ) )
|
||||
|
@ -1819,7 +2123,8 @@
|
|||
FT_TRACE4(( "parsing subfont %u\n", idx ));
|
||||
error = cff_subfont_load( sub, &fd_index, idx,
|
||||
stream, base_offset, library,
|
||||
cff2 ? CFF2_CODE_FONTDICT : CFF_CODE_TOPDICT );
|
||||
cff2 ? CFF2_CODE_FONTDICT : CFF_CODE_TOPDICT,
|
||||
font );
|
||||
if ( error )
|
||||
goto Fail_CID;
|
||||
}
|
||||
|
@ -1882,14 +2187,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
/* read the Variation Store if available */
|
||||
error = cff_vstore_load( &font->vstore,
|
||||
stream,
|
||||
base_offset,
|
||||
dict->vstore_offset );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
/* get the font name (/CIDFontName for CID-keyed fonts, */
|
||||
/* /FontName otherwise) */
|
||||
font->font_name = cff_index_get_name( font, subfont_index );
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include <ft2build.h>
|
||||
#include "cfftypes.h"
|
||||
#include "cffparse.h"
|
||||
|
||||
|
||||
FT_BEGIN_HEADER
|
||||
|
@ -75,6 +76,28 @@ FT_BEGIN_HEADER
|
|||
cff_fd_select_get( CFF_FDSelect fdselect,
|
||||
FT_UInt glyph_index );
|
||||
|
||||
FT_LOCAL( FT_Bool )
|
||||
cff_blend_check_vector( CFF_Blend blend,
|
||||
FT_UInt vsindex,
|
||||
FT_UInt lenNDV,
|
||||
FT_Fixed * NDV );
|
||||
|
||||
FT_LOCAL( FT_Error )
|
||||
cff_blend_build_vector( CFF_Blend blend,
|
||||
FT_UInt vsindex,
|
||||
FT_UInt lenNDV,
|
||||
FT_Fixed * NDV );
|
||||
|
||||
FT_LOCAL( void )
|
||||
cff_blend_clear( CFF_SubFont subFont );
|
||||
|
||||
FT_LOCAL( FT_Error )
|
||||
cff_blend_doBlend( CFF_SubFont subfont,
|
||||
CFF_Parser parser,
|
||||
FT_UInt numBlends );
|
||||
|
||||
FT_LOCAL( FT_Bool )
|
||||
cff_check_blend_vector( CFF_Blend blend );
|
||||
|
||||
FT_END_HEADER
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "cfferrs.h"
|
||||
#include "cffpic.h"
|
||||
#include "cffgload.h"
|
||||
#include "cffload.h"
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
|
@ -403,23 +404,33 @@
|
|||
|
||||
/* read a number, either integer or real */
|
||||
static FT_Long
|
||||
cff_parse_num( FT_Byte** d )
|
||||
cff_parse_num( CFF_Parser parser, FT_Byte** d )
|
||||
{
|
||||
return **d == 30 ? ( cff_parse_real( d[0], d[1], 0, NULL ) >> 16 )
|
||||
: cff_parse_integer( d[0], d[1] );
|
||||
}
|
||||
if ( **d == 30 )
|
||||
/* BCD is truncated to integer */
|
||||
return cff_parse_real( *d, parser->limit, 0, NULL ) >> 16;
|
||||
else if ( **d == 255 )
|
||||
/* 16.16 fixed point is used internally for CFF2 blend results */
|
||||
/* Since these are trusted values, a limit check is not needed */
|
||||
|
||||
/* after the 255, 4 bytes are in host order */
|
||||
/* blend result is rounded to integer */
|
||||
return (FT_Long) ( *( (FT_UInt32 *) ( d[0] + 1 ) ) + 0x8000U ) >> 16;
|
||||
else
|
||||
return cff_parse_integer( *d, parser->limit );
|
||||
}
|
||||
|
||||
/* read a floating point number, either integer or real */
|
||||
static FT_Fixed
|
||||
do_fixed( FT_Byte** d,
|
||||
do_fixed( CFF_Parser parser,
|
||||
FT_Byte** d,
|
||||
FT_Long scaling )
|
||||
{
|
||||
if ( **d == 30 )
|
||||
return cff_parse_real( d[0], d[1], scaling, NULL );
|
||||
return cff_parse_real( *d, parser->limit, scaling, NULL );
|
||||
else
|
||||
{
|
||||
FT_Long val = cff_parse_integer( d[0], d[1] );
|
||||
FT_Long val = cff_parse_integer( *d, parser->limit );
|
||||
|
||||
|
||||
if ( scaling )
|
||||
|
@ -447,19 +458,21 @@
|
|||
|
||||
/* read a floating point number, either integer or real */
|
||||
static FT_Fixed
|
||||
cff_parse_fixed( FT_Byte** d )
|
||||
cff_parse_fixed( CFF_Parser parser,
|
||||
FT_Byte** d )
|
||||
{
|
||||
return do_fixed( d, 0 );
|
||||
return do_fixed( parser, d, 0 );
|
||||
}
|
||||
|
||||
|
||||
/* read a floating point number, either integer or real, */
|
||||
/* but return `10^scaling' times the number read in */
|
||||
static FT_Fixed
|
||||
cff_parse_fixed_scaled( FT_Byte** d,
|
||||
cff_parse_fixed_scaled( CFF_Parser parser,
|
||||
FT_Byte** d,
|
||||
FT_Long scaling )
|
||||
{
|
||||
return do_fixed( d, scaling );
|
||||
return do_fixed( parser, d, scaling );
|
||||
}
|
||||
|
||||
|
||||
|
@ -467,13 +480,14 @@
|
|||
/* and return it as precise as possible -- `scaling' returns */
|
||||
/* the scaling factor (as a power of 10) */
|
||||
static FT_Fixed
|
||||
cff_parse_fixed_dynamic( FT_Byte** d,
|
||||
cff_parse_fixed_dynamic( CFF_Parser parser,
|
||||
FT_Byte** d,
|
||||
FT_Long* scaling )
|
||||
{
|
||||
FT_ASSERT( scaling );
|
||||
|
||||
if ( **d == 30 )
|
||||
return cff_parse_real( d[0], d[1], 0, scaling );
|
||||
return cff_parse_real( *d, parser->limit, 0, scaling );
|
||||
else
|
||||
{
|
||||
FT_Long number;
|
||||
|
@ -543,7 +557,7 @@
|
|||
|
||||
for ( i = 0; i < 6; i++ )
|
||||
{
|
||||
values[i] = cff_parse_fixed_dynamic( data++, &scalings[i] );
|
||||
values[i] = cff_parse_fixed_dynamic( parser, data++, &scalings[i] );
|
||||
if ( values[i] )
|
||||
{
|
||||
if ( scalings[i] > max_scaling )
|
||||
|
@ -640,10 +654,10 @@
|
|||
|
||||
if ( parser->top >= parser->stack + 4 )
|
||||
{
|
||||
bbox->xMin = FT_RoundFix( cff_parse_fixed( data++ ) );
|
||||
bbox->yMin = FT_RoundFix( cff_parse_fixed( data++ ) );
|
||||
bbox->xMax = FT_RoundFix( cff_parse_fixed( data++ ) );
|
||||
bbox->yMax = FT_RoundFix( cff_parse_fixed( data ) );
|
||||
bbox->xMin = FT_RoundFix( cff_parse_fixed( parser, data++ ) );
|
||||
bbox->yMin = FT_RoundFix( cff_parse_fixed( parser, data++ ) );
|
||||
bbox->xMax = FT_RoundFix( cff_parse_fixed( parser, data++ ) );
|
||||
bbox->yMax = FT_RoundFix( cff_parse_fixed( parser, data ) );
|
||||
error = FT_Err_Ok;
|
||||
|
||||
FT_TRACE4(( " [%d %d %d %d]\n",
|
||||
|
@ -672,7 +686,7 @@
|
|||
FT_Long tmp;
|
||||
|
||||
|
||||
tmp = cff_parse_num( data++ );
|
||||
tmp = cff_parse_num( parser, data++ );
|
||||
if ( tmp < 0 )
|
||||
{
|
||||
FT_ERROR(( "cff_parse_private_dict: Invalid dictionary size\n" ));
|
||||
|
@ -681,7 +695,7 @@
|
|||
}
|
||||
dict->private_size = (FT_ULong)tmp;
|
||||
|
||||
tmp = cff_parse_num( data );
|
||||
tmp = cff_parse_num( parser, data );
|
||||
if ( tmp < 0 )
|
||||
{
|
||||
FT_ERROR(( "cff_parse_private_dict: Invalid dictionary offset\n" ));
|
||||
|
@ -726,7 +740,7 @@
|
|||
/* currently, we handle only the first argument */
|
||||
if ( parser->top >= parser->stack + 5 )
|
||||
{
|
||||
FT_Long num_designs = cff_parse_num( parser->stack );
|
||||
FT_Long num_designs = cff_parse_num( parser, parser->stack );
|
||||
|
||||
|
||||
if ( num_designs > 16 || num_designs < 2 )
|
||||
|
@ -763,11 +777,11 @@
|
|||
|
||||
if ( parser->top >= parser->stack + 3 )
|
||||
{
|
||||
dict->cid_registry = (FT_UInt)cff_parse_num( data++ );
|
||||
dict->cid_ordering = (FT_UInt)cff_parse_num( data++ );
|
||||
dict->cid_registry = (FT_UInt)cff_parse_num( parser, data++ );
|
||||
dict->cid_ordering = (FT_UInt)cff_parse_num( parser, data++ );
|
||||
if ( **data == 30 )
|
||||
FT_TRACE1(( "cff_parse_cid_ros: real supplement is rounded\n" ));
|
||||
dict->cid_supplement = cff_parse_num( data );
|
||||
dict->cid_supplement = cff_parse_num( parser, data );
|
||||
if ( dict->cid_supplement < 0 )
|
||||
FT_TRACE1(( "cff_parse_cid_ros: negative supplement %d is found\n",
|
||||
dict->cid_supplement ));
|
||||
|
@ -786,26 +800,31 @@
|
|||
static FT_Error
|
||||
cff_parse_blend( CFF_Parser parser )
|
||||
{
|
||||
FT_UInt num_args = (FT_UInt)( parser->top - parser->stack );
|
||||
/* blend operator can only be used in a Private DICT */
|
||||
CFF_Private priv = (CFF_Private)parser->object;
|
||||
CFF_SubFont subFont;
|
||||
CFF_Blend blend;
|
||||
FT_UInt numBlends;
|
||||
FT_Error error;
|
||||
|
||||
error = FT_ERR( Stack_Underflow );
|
||||
FT_TRACE1(( " cff_parse_blend\n" ));
|
||||
|
||||
if ( parser->top >= parser->stack + 1 ) /* at least one operand */
|
||||
if ( !priv || !priv->subfont )
|
||||
{
|
||||
/* top of stack gives number of blends */
|
||||
numBlends = (FT_UInt)cff_parse_num( parser->top - 1 );
|
||||
|
||||
if ( numBlends < num_args )
|
||||
{
|
||||
/* for testing, just reduce stack to first numBlends values */
|
||||
parser->top = parser->stack + numBlends;
|
||||
|
||||
error = FT_Err_Ok;
|
||||
}
|
||||
error = FT_ERR( Invalid_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
subFont = priv->subfont;
|
||||
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 );
|
||||
|
||||
numBlends = (FT_UInt)cff_parse_num( parser, parser->top - 1 );
|
||||
|
||||
error = cff_blend_doBlend(subFont, parser, numBlends );
|
||||
Exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -1109,8 +1128,10 @@
|
|||
{
|
||||
FT_UInt v = *p;
|
||||
|
||||
|
||||
if ( v >= 27 && v != 31 )
|
||||
/* opcode 31 is legacy MM T2 operator, not a number */
|
||||
/* opcode 255 is reserved and should not appear in fonts */
|
||||
/* it is used internally for CFF2 blends */
|
||||
if ( v >= 27 && v != 31 && v != 255 )
|
||||
{
|
||||
/* it's a number; we will push its position on the stack */
|
||||
if ( parser->top - parser->stack >= CFF_MAX_STACK_DEPTH )
|
||||
|
@ -1322,15 +1343,15 @@
|
|||
case cff_kind_bool:
|
||||
case cff_kind_string:
|
||||
case cff_kind_num:
|
||||
val = cff_parse_num( parser->stack );
|
||||
val = cff_parse_num( parser, parser->stack );
|
||||
goto Store_Number;
|
||||
|
||||
case cff_kind_fixed:
|
||||
val = cff_parse_fixed( parser->stack );
|
||||
val = cff_parse_fixed( parser, parser->stack );
|
||||
goto Store_Number;
|
||||
|
||||
case cff_kind_fixed_thousand:
|
||||
val = cff_parse_fixed_scaled( parser->stack, 3 );
|
||||
val = cff_parse_fixed_scaled( parser, parser->stack, 3 );
|
||||
|
||||
Store_Number:
|
||||
switch ( field->size )
|
||||
|
@ -1399,7 +1420,7 @@
|
|||
val = 0;
|
||||
while ( num_args > 0 )
|
||||
{
|
||||
val += cff_parse_num( data++ );
|
||||
val += cff_parse_num( parser, data++ );
|
||||
switch ( field->size )
|
||||
{
|
||||
case (8 / FT_CHAR_BIT):
|
||||
|
@ -1442,8 +1463,9 @@
|
|||
|
||||
Found:
|
||||
/* clear stack */
|
||||
/* TODO: could clear blend stack here, but we don't have access to subFont */
|
||||
if ( field->kind != cff_kind_blend )
|
||||
parser->top = parser->stack;
|
||||
parser->top = parser->stack;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
|
|
@ -134,6 +134,24 @@ FT_BEGIN_HEADER
|
|||
|
||||
} CFF_VStoreRec, *CFF_VStore;
|
||||
|
||||
/* forward reference */
|
||||
typedef struct CFF_FontRec_ *CFF_Font;
|
||||
|
||||
typedef struct CFF_BlendRec_
|
||||
{
|
||||
/* object to manage one cached blend vector */
|
||||
/* 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 */
|
||||
CFF_Font font; /* top level font struct */
|
||||
FT_UInt lastVsindex; /* last vsindex used */
|
||||
FT_UInt lenNDV; /* normDV length (aka numAxes) */
|
||||
FT_Fixed * lastNDV; /* last NDV used */
|
||||
FT_UInt lenBV; /* BlendV length (aka numMasters) */
|
||||
FT_Int32 * BV; /* current blendV (per DICT/glyph)*/
|
||||
|
||||
} CFF_BlendRec, *CFF_Blend;
|
||||
|
||||
|
||||
typedef struct CFF_FontRecDictRec_
|
||||
{
|
||||
|
@ -185,13 +203,15 @@ FT_BEGIN_HEADER
|
|||
FT_UShort num_axes;
|
||||
|
||||
/* fields for CFF2 */
|
||||
FT_UInt vsindex;
|
||||
FT_ULong vstore_offset;
|
||||
FT_UInt maxstack;
|
||||
|
||||
} CFF_FontRecDictRec, *CFF_FontRecDict;
|
||||
|
||||
|
||||
/* forward reference */
|
||||
typedef struct CFF_SubFontRec_ *CFF_SubFont;
|
||||
|
||||
typedef struct CFF_PrivateRec_
|
||||
{
|
||||
FT_Byte num_blue_values;
|
||||
|
@ -225,7 +245,8 @@ FT_BEGIN_HEADER
|
|||
FT_Pos nominal_width;
|
||||
|
||||
/* fields for CFF2 */
|
||||
FT_UInt vsindex;
|
||||
FT_UInt vsindex;
|
||||
CFF_SubFont subfont;
|
||||
|
||||
} CFF_PrivateRec, *CFF_Private;
|
||||
|
||||
|
@ -254,6 +275,23 @@ FT_BEGIN_HEADER
|
|||
CFF_FontRecDictRec font_dict;
|
||||
CFF_PrivateRec private_dict;
|
||||
|
||||
/* fields for CFF2 */
|
||||
CFF_BlendRec blend; /* current blend vector */
|
||||
FT_UInt lenNDV; /* current length NDV or zero */
|
||||
FT_Fixed * NDV; /* ptr to current NDV or NULL */
|
||||
|
||||
/* blend_stack is a writable buffer to hold blend results */
|
||||
/* this buffer is to the side of the normal cff parser stack */
|
||||
/* cff_parse_blend()/cff_blend_doBlend() pushes blend results here */
|
||||
/* the normal stack then points to these values instead of the DICT */
|
||||
/* because all other operators in Private DICT clear the stack, */
|
||||
/* blend_stack could be cleared at each operator other than blend */
|
||||
/* blended values are stored as 5-byte fixed point */
|
||||
FT_Byte * blend_stack; /* base of stack allocation */
|
||||
FT_Byte * blend_top; /* first empty slot */
|
||||
FT_UInt blend_used; /* number of bytes in use */
|
||||
FT_UInt blend_alloc; /* number of bytes allocated */
|
||||
|
||||
CFF_IndexRec local_subrs_index;
|
||||
FT_Byte** local_subrs; /* array of pointers into Local Subrs INDEX data */
|
||||
|
||||
|
@ -265,8 +303,10 @@ FT_BEGIN_HEADER
|
|||
|
||||
typedef struct CFF_FontRec_
|
||||
{
|
||||
FT_Library library;
|
||||
FT_Stream stream;
|
||||
FT_Memory memory;
|
||||
FT_Memory memory; /* TODO: take this from stream->memory? */
|
||||
FT_ULong base_offset; /* offset to start of CFF */
|
||||
FT_UInt num_faces;
|
||||
FT_UInt num_glyphs;
|
||||
|
||||
|
@ -323,7 +363,7 @@ FT_BEGIN_HEADER
|
|||
/* since version 2.4.12 */
|
||||
FT_Generic cf2_instance;
|
||||
|
||||
CFF_VStoreRec vstore;
|
||||
CFF_VStoreRec vstore; /* parsed vstore structure */
|
||||
|
||||
} CFF_FontRec, *CFF_Font;
|
||||
|
||||
|
|
Loading…
Reference in New Issue