Compare commits
19 commits
master
...
OpenType-1
Author | SHA1 | Date | |
---|---|---|---|
|
71b45f99b1 | ||
|
c7f2a52f86 | ||
|
f34a28d614 | ||
|
410ff09eb6 | ||
|
8dba6305da | ||
|
88ad21fbe5 | ||
|
d49da66dcb | ||
|
dfce4760af | ||
|
e3ef1df506 | ||
|
c156b734dd | ||
|
d5c247e923 | ||
|
304f0383ef | ||
|
776a712be8 | ||
|
54d9993505 | ||
|
4c39089a4d | ||
|
dccfebc0f5 | ||
|
6a5ef34797 | ||
|
c7f87a1f8b | ||
|
d1908a107d |
30 changed files with 2537 additions and 507 deletions
9
README
9
README
|
@ -1,3 +1,12 @@
|
|||
Branch of FreeType to support OpenType 1.8
|
||||
==========================================
|
||||
|
||||
This branch contains changes for supporting OpenType 1.8.
|
||||
The changes will be merged back upstream in September 2016,
|
||||
when the specification for OpenType 1.8 is final and has
|
||||
been published.
|
||||
|
||||
|
||||
FreeType 2.6.5
|
||||
==============
|
||||
|
||||
|
|
|
@ -171,6 +171,7 @@ FT_BEGIN_HEADER
|
|||
{
|
||||
FT_Fixed* coords;
|
||||
FT_UInt strid;
|
||||
FT_UInt psid;
|
||||
|
||||
} FT_Var_Named_Style;
|
||||
|
||||
|
@ -329,6 +330,10 @@ FT_BEGIN_HEADER
|
|||
FT_UInt num_coords,
|
||||
FT_Fixed* coords );
|
||||
|
||||
FT_EXPORT( FT_Error )
|
||||
FT_Get_Var_Design_Coordinates( FT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords );
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
|
@ -375,6 +380,11 @@ FT_BEGIN_HEADER
|
|||
|
||||
/* */
|
||||
|
||||
FT_EXPORT( FT_Error )
|
||||
FT_Get_Var_Blend_Coordinates( FT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords );
|
||||
|
||||
|
||||
FT_END_HEADER
|
||||
|
||||
|
|
|
@ -90,6 +90,7 @@ FT_TRACE_DEF( cffparse )
|
|||
|
||||
FT_TRACE_DEF( cf2blues )
|
||||
FT_TRACE_DEF( cf2hints )
|
||||
FT_TRACE_DEF( cf2font )
|
||||
FT_TRACE_DEF( cf2interp )
|
||||
|
||||
/* Type 42 driver component */
|
||||
|
|
|
@ -58,6 +58,16 @@ FT_BEGIN_HEADER
|
|||
FT_UInt num_coords,
|
||||
FT_Long* coords );
|
||||
|
||||
typedef FT_Error
|
||||
(*FT_Get_Var_Design_Func)( FT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords );
|
||||
|
||||
typedef FT_Error
|
||||
(*FT_Get_Var_Blend_Func)( FT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords );
|
||||
|
||||
|
||||
FT_DEFINE_SERVICE( MultiMasters )
|
||||
{
|
||||
|
@ -66,6 +76,8 @@ FT_BEGIN_HEADER
|
|||
FT_Set_MM_Blend_Func set_mm_blend;
|
||||
FT_Get_MM_Var_Func get_mm_var;
|
||||
FT_Set_Var_Design_Func set_var_design;
|
||||
FT_Get_Var_Design_Func get_var_design;
|
||||
FT_Get_Var_Blend_Func get_var_blend;
|
||||
};
|
||||
|
||||
|
||||
|
@ -76,10 +88,13 @@ FT_BEGIN_HEADER
|
|||
set_mm_design_, \
|
||||
set_mm_blend_, \
|
||||
get_mm_var_, \
|
||||
set_var_design_ ) \
|
||||
set_var_design_, \
|
||||
get_var_design_, \
|
||||
get_var_blend_ ) \
|
||||
static const FT_Service_MultiMastersRec class_ = \
|
||||
{ \
|
||||
get_mm_, set_mm_design_, set_mm_blend_, get_mm_var_, set_var_design_ \
|
||||
get_mm_, set_mm_design_, set_mm_blend_, get_mm_var_, set_var_design_, \
|
||||
get_var_design_, get_var_blend_ \
|
||||
};
|
||||
|
||||
#else /* FT_CONFIG_OPTION_PIC */
|
||||
|
@ -89,7 +104,9 @@ FT_BEGIN_HEADER
|
|||
set_mm_design_, \
|
||||
set_mm_blend_, \
|
||||
get_mm_var_, \
|
||||
set_var_design_ ) \
|
||||
set_var_design_, \
|
||||
get_var_design_, \
|
||||
get_var_blend_ ) \
|
||||
void \
|
||||
FT_Init_Class_ ## class_( FT_Service_MultiMastersRec* clazz ) \
|
||||
{ \
|
||||
|
@ -98,6 +115,8 @@ FT_BEGIN_HEADER
|
|||
clazz->set_mm_blend = set_mm_blend_; \
|
||||
clazz->get_mm_var = get_mm_var_; \
|
||||
clazz->set_var_design = set_var_design_; \
|
||||
clazz->get_var_design = get_var_design_; \
|
||||
clazz->get_var_blend = get_var_blend_; \
|
||||
}
|
||||
|
||||
#endif /* FT_CONFIG_OPTION_PIC */
|
||||
|
|
|
@ -1346,6 +1346,7 @@ FT_BEGIN_HEADER
|
|||
FT_ULong glyf_len;
|
||||
|
||||
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
|
||||
FT_Bool isCFF2;
|
||||
FT_Bool doblend;
|
||||
GX_Blend blend;
|
||||
#endif
|
||||
|
|
|
@ -43,6 +43,7 @@ FT_BEGIN_HEADER
|
|||
#define TTAG_CBDT FT_MAKE_TAG( 'C', 'B', 'D', 'T' )
|
||||
#define TTAG_CBLC FT_MAKE_TAG( 'C', 'B', 'L', 'C' )
|
||||
#define TTAG_CFF FT_MAKE_TAG( 'C', 'F', 'F', ' ' )
|
||||
#define TTAG_CFF2 FT_MAKE_TAG( 'C', 'F', 'F', '2' )
|
||||
#define TTAG_CID FT_MAKE_TAG( 'C', 'I', 'D', ' ' )
|
||||
#define TTAG_cmap FT_MAKE_TAG( 'c', 'm', 'a', 'p' )
|
||||
#define TTAG_cvar FT_MAKE_TAG( 'c', 'v', 'a', 'r' )
|
||||
|
@ -61,6 +62,7 @@ FT_BEGIN_HEADER
|
|||
#define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' )
|
||||
#define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' )
|
||||
#define TTAG_gvar FT_MAKE_TAG( 'g', 'v', 'a', 'r' )
|
||||
#define TTAG_HVAR FT_MAKE_TAG( 'H', 'V', 'A', 'R' )
|
||||
#define TTAG_hdmx FT_MAKE_TAG( 'h', 'd', 'm', 'x' )
|
||||
#define TTAG_head FT_MAKE_TAG( 'h', 'e', 'a', 'd' )
|
||||
#define TTAG_hhea FT_MAKE_TAG( 'h', 'h', 'e', 'a' )
|
||||
|
|
|
@ -172,6 +172,34 @@
|
|||
}
|
||||
|
||||
|
||||
/* documentation is in ftmm.h */
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
FT_Get_Var_Design_Coordinates( FT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords )
|
||||
{
|
||||
FT_Error error;
|
||||
FT_Service_MultiMasters service;
|
||||
|
||||
|
||||
/* check of `face' delayed to `ft_face_get_mm_service' */
|
||||
|
||||
if ( !coords )
|
||||
return FT_THROW( Invalid_Argument );
|
||||
|
||||
error = ft_face_get_mm_service( face, &service );
|
||||
if ( !error )
|
||||
{
|
||||
error = FT_ERR( Invalid_Argument );
|
||||
if ( service->get_var_design )
|
||||
error = service->get_var_design( face, num_coords, coords );
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/* documentation is in ftmm.h */
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
|
@ -230,5 +258,32 @@
|
|||
return error;
|
||||
}
|
||||
|
||||
/* documentation is in ftmm.h */
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
FT_Get_Var_Blend_Coordinates( FT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords )
|
||||
{
|
||||
FT_Error error;
|
||||
FT_Service_MultiMasters service;
|
||||
|
||||
|
||||
/* check of `face' delayed to `ft_face_get_mm_service' */
|
||||
|
||||
if ( !coords )
|
||||
return FT_THROW( Invalid_Argument );
|
||||
|
||||
error = ft_face_get_mm_service( face, &service );
|
||||
if ( !error )
|
||||
{
|
||||
error = FT_ERR( Invalid_Argument );
|
||||
if ( service->get_var_blend )
|
||||
error = service->get_var_blend( face, num_coords, coords );
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/* END */
|
||||
|
|
|
@ -51,8 +51,8 @@ FT_BEGIN_HEADER
|
|||
|
||||
#define CF2_FIXED_MAX ( (CF2_Fixed)0x7FFFFFFFL )
|
||||
#define CF2_FIXED_MIN ( (CF2_Fixed)0x80000000L )
|
||||
#define CF2_FIXED_ONE 0x10000L
|
||||
#define CF2_FIXED_EPSILON 0x0001
|
||||
#define CF2_FIXED_ONE ( (CF2_Fixed)0x10000L )
|
||||
#define CF2_FIXED_EPSILON ( (CF2_Fixed)0x0001 )
|
||||
|
||||
/* in C 89, left and right shift of negative numbers is */
|
||||
/* implementation specific behaviour in the general case */
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
#include <ft2build.h>
|
||||
#include FT_INTERNAL_CALC_H
|
||||
#include FT_INTERNAL_DEBUG_H
|
||||
|
||||
#include "cf2ft.h"
|
||||
|
||||
|
@ -46,6 +47,8 @@
|
|||
#include "cf2error.h"
|
||||
#include "cf2intrp.h"
|
||||
|
||||
#undef FT_COMPONENT
|
||||
#define FT_COMPONENT trace_cf2font
|
||||
|
||||
/* Compute a stem darkening amount in character space. */
|
||||
static void
|
||||
|
@ -233,8 +236,127 @@
|
|||
*darkenAmount += boldenAmount / 2;
|
||||
}
|
||||
|
||||
/* compute a blend vector from variation store index and normalized vector */
|
||||
/* return size of blend vector and allocated storage for it */
|
||||
/* caller must free this */
|
||||
/* lenNormalizedVector == 0 produces a default blend vector */
|
||||
/* Note: normalizedVector uses FT_Fixed, not CF2_Fixed */
|
||||
static void
|
||||
cf2_buildBlendVector( CF2_Font font, CF2_UInt vsindex,
|
||||
CF2_UInt lenNormalizedVector, FT_Fixed * normalizedVector,
|
||||
CF2_UInt * lenBlendVector, CF2_Fixed ** blendVector )
|
||||
{
|
||||
FT_Error error = FT_Err_Ok; /* for FT_REALLOC */
|
||||
FT_Memory memory = font->memory; /* for FT_REALLOC */
|
||||
CF2_UInt len;
|
||||
CFF_VStore vs;
|
||||
CFF_VarData* varData;
|
||||
CF2_UInt master;
|
||||
|
||||
FT_ASSERT( lenBlendVector && blendVector );
|
||||
FT_ASSERT( lenNormalizedVector == 0 || normalizedVector );
|
||||
FT_TRACE4(( "cf2_buildBlendVector\n" ));
|
||||
|
||||
vs = cf2_getVStore( font->decoder );
|
||||
|
||||
/* VStore and fvar must be consistent */
|
||||
if ( lenNormalizedVector != 0 && lenNormalizedVector != vs->axisCount )
|
||||
{
|
||||
FT_TRACE4(( "cf2_buildBlendVector: Axis count mismatch\n" ));
|
||||
CF2_SET_ERROR( &font->error, Invalid_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
if ( vsindex >= vs->dataCount )
|
||||
{
|
||||
FT_TRACE4(( "cf2_buildBlendVector: vsindex out of range\n" ));
|
||||
CF2_SET_ERROR( &font->error, Invalid_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* select the item variation data structure */
|
||||
varData = &vs->varData[vsindex];
|
||||
|
||||
/* prepare an output buffer for the blend vector */
|
||||
len = varData->regionIdxCount + 1; /* add 1 for default */
|
||||
if ( FT_REALLOC( *blendVector, *lenBlendVector, len * sizeof( **blendVector )) )
|
||||
return;
|
||||
*lenBlendVector = len;
|
||||
|
||||
/* outer loop steps through master designs to be blended */
|
||||
for ( master=0; master<len; master++ )
|
||||
{
|
||||
CF2_UInt j;
|
||||
CF2_UInt idx;
|
||||
CFF_VarRegion* varRegion;
|
||||
|
||||
/* default factor is always one */
|
||||
if ( master == 0 )
|
||||
{
|
||||
*blendVector[master] = CF2_FIXED_ONE;
|
||||
FT_TRACE4(( "blend vector len %d\n [ %f ", len, (double)(*blendVector)[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" ));
|
||||
CF2_SET_ERROR( &font->error, Invalid_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* Note: lenNormalizedVector could be zero */
|
||||
/* In that case, build default blend vector */
|
||||
if ( lenNormalizedVector != 0 )
|
||||
(*blendVector)[master] = CF2_FIXED_ONE; /* default */
|
||||
|
||||
/* inner loop steps through axes in this region */
|
||||
for ( j=0; j<lenNormalizedVector; j++ )
|
||||
{
|
||||
CFF_AxisCoords* axis = &varRegion->axisList[j];
|
||||
CF2_Fixed axisScalar;
|
||||
|
||||
/* compute the scalar contribution of this axis */
|
||||
/* ignore invalid ranges */
|
||||
if ( axis->startCoord > axis->peakCoord || axis->peakCoord > axis->endCoord )
|
||||
axisScalar = CF2_FIXED_ONE;
|
||||
else if ( axis->startCoord < 0 && axis->endCoord > 0 && axis->peakCoord != 0 )
|
||||
axisScalar = CF2_FIXED_ONE;
|
||||
/* peak of 0 means ignore this axis */
|
||||
else if ( axis->peakCoord == 0 )
|
||||
axisScalar = CF2_FIXED_ONE;
|
||||
/* ignore this region if coords are out of range */
|
||||
else if ( normalizedVector[j] < axis->startCoord || normalizedVector[j] > axis->endCoord )
|
||||
axisScalar = 0;
|
||||
/* calculate a proportional factor */
|
||||
else
|
||||
{
|
||||
if ( normalizedVector[j] == axis->peakCoord )
|
||||
axisScalar = CF2_FIXED_ONE;
|
||||
else if ( normalizedVector[j] < axis->peakCoord )
|
||||
axisScalar = FT_DivFix( normalizedVector[j] - axis->startCoord,
|
||||
axis->peakCoord - axis->startCoord );
|
||||
else
|
||||
axisScalar = FT_DivFix( axis->endCoord - normalizedVector[j],
|
||||
axis->endCoord - axis->peakCoord );
|
||||
}
|
||||
/* take product of all the axis scalars */
|
||||
(*blendVector)[master] = FT_MulFix( (*blendVector)[master], axisScalar );
|
||||
}
|
||||
FT_TRACE4(( ", %f ", (double)(*blendVector)[master] / 65536 ));
|
||||
}
|
||||
FT_TRACE4(( "]\n" ));
|
||||
|
||||
Exit:
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* set up values for the current FontDict and matrix */
|
||||
/* called for each glyph to be rendered */
|
||||
|
||||
/* caller's transform is adjusted for subpixel positioning */
|
||||
static void
|
||||
|
@ -246,12 +368,17 @@
|
|||
|
||||
FT_Bool needExtraSetup = FALSE;
|
||||
|
||||
CFF_VStoreRec* vstore;
|
||||
FT_Bool hasVariations = FALSE;
|
||||
|
||||
/* character space units */
|
||||
CF2_Fixed boldenX = font->syntheticEmboldeningAmountX;
|
||||
CF2_Fixed boldenY = font->syntheticEmboldeningAmountY;
|
||||
|
||||
CFF_SubFont subFont;
|
||||
CF2_Fixed ppem;
|
||||
CF2_UInt lenNormalizedV = 0;
|
||||
FT_Fixed * normalizedV = NULL;
|
||||
|
||||
|
||||
/* clear previous error */
|
||||
|
@ -266,6 +393,32 @@
|
|||
needExtraSetup = TRUE;
|
||||
}
|
||||
|
||||
/* check for variation vectors */
|
||||
vstore = cf2_getVStore( decoder );
|
||||
hasVariations = ( vstore->dataCount != 0 );
|
||||
|
||||
if ( hasVariations )
|
||||
{
|
||||
/* 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 );
|
||||
|
||||
if ( cff_blend_check_vector( &subFont->blend,
|
||||
subFont->private_dict.vsindex,
|
||||
lenNormalizedV, normalizedV ) )
|
||||
{
|
||||
/* 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->blend.usedBV = FALSE; /* clear state of charstring blend */
|
||||
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 */
|
||||
/* note: because of CID font matrix concatenation, ppem and transform */
|
||||
/* do not necessarily track. */
|
||||
|
@ -423,7 +576,8 @@
|
|||
|
||||
/* compute blue zones for this instance */
|
||||
cf2_blues_init( &font->blues, font );
|
||||
}
|
||||
|
||||
} /* needExtraSetup */
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
|
||||
FT_BEGIN_HEADER
|
||||
|
||||
|
||||
#define CF2_OPERAND_STACK_SIZE 48
|
||||
#define CF2_MAX_SUBR 16 /* maximum subroutine nesting; */
|
||||
/* only 10 are allowed but there exist */
|
||||
|
@ -63,6 +62,7 @@ FT_BEGIN_HEADER
|
|||
FT_Memory memory;
|
||||
FT_Error error; /* shared error for this instance */
|
||||
|
||||
FT_Bool isCFF2;
|
||||
CF2_RenderingFlags renderingFlags;
|
||||
|
||||
/* variables that depend on Transform: */
|
||||
|
@ -74,6 +74,12 @@ FT_BEGIN_HEADER
|
|||
CF2_Matrix outerTransform; /* post hinting; includes rotations */
|
||||
CF2_Fixed ppem; /* transform-dependent */
|
||||
|
||||
/* variation data */
|
||||
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;
|
||||
|
||||
CF2_Fixed syntheticEmboldeningAmountX; /* character space units */
|
||||
|
|
|
@ -102,9 +102,10 @@
|
|||
if ( font )
|
||||
{
|
||||
FT_Memory memory = font->memory;
|
||||
|
||||
|
||||
(void)memory;
|
||||
|
||||
FT_FREE( font->blend.lastNDV );
|
||||
FT_FREE( font->blend.BV );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -366,6 +367,9 @@
|
|||
&hinted,
|
||||
&scaled );
|
||||
|
||||
/* copy isCFF2 boolean from TT_Face to CF2_Font */
|
||||
font->isCFF2 = builder->face->isCFF2;
|
||||
|
||||
font->renderingFlags = 0;
|
||||
if ( hinted )
|
||||
font->renderingFlags |= CF2_FlagsHinted;
|
||||
|
@ -412,6 +416,48 @@
|
|||
return decoder->current_subfont;
|
||||
}
|
||||
|
||||
/* get pointer to VStore structure */
|
||||
FT_LOCAL_DEF( CFF_VStore )
|
||||
cf2_getVStore( CFF_Decoder* decoder )
|
||||
{
|
||||
FT_ASSERT( decoder && decoder->cff );
|
||||
|
||||
return &decoder->cff->vstore;
|
||||
}
|
||||
|
||||
/* get maxstack value from CFF2 Top DICT */
|
||||
FT_LOCAL_DEF ( FT_UInt )
|
||||
cf2_getMaxstack( CFF_Decoder* decoder )
|
||||
{
|
||||
FT_ASSERT( decoder && decoder->cff );
|
||||
|
||||
return decoder->cff->top_font.font_dict.maxstack;
|
||||
}
|
||||
|
||||
/* get normalized design vector for current render request */
|
||||
/* returns pointer and length */
|
||||
/* if blend struct is not initialized, return length zero */
|
||||
/* Note: use FT_Fixed not CF2_Fixed for the vector */
|
||||
FT_LOCAL_DEF( void )
|
||||
cf2_getNormalizedVector( CFF_Decoder* decoder, CF2_UInt * len, FT_Fixed ** vec )
|
||||
{
|
||||
GX_Blend blend;
|
||||
|
||||
FT_ASSERT( decoder && decoder->builder.face );
|
||||
FT_ASSERT( vec && len );
|
||||
|
||||
blend = decoder->builder.face->blend;
|
||||
if ( blend )
|
||||
{
|
||||
*vec = blend->normalizedcoords;
|
||||
*len = blend->num_axis;
|
||||
}
|
||||
else
|
||||
{
|
||||
*vec = NULL;
|
||||
*len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* get `y_ppem' from `CFF_Size' */
|
||||
FT_LOCAL_DEF( CF2_Fixed )
|
||||
|
|
|
@ -64,6 +64,17 @@ FT_BEGIN_HEADER
|
|||
FT_LOCAL( CFF_SubFont )
|
||||
cf2_getSubfont( CFF_Decoder* decoder );
|
||||
|
||||
FT_LOCAL( CFF_VStore )
|
||||
cf2_getVStore( CFF_Decoder* decoder );
|
||||
|
||||
FT_LOCAL_DEF ( FT_UInt )
|
||||
cf2_getMaxstack( CFF_Decoder* decoder );
|
||||
|
||||
|
||||
FT_LOCAL_DEF( void )
|
||||
cf2_getNormalizedVector( CFF_Decoder* decoder,
|
||||
CF2_UInt * len,
|
||||
FT_Fixed ** vec );
|
||||
|
||||
FT_LOCAL( CF2_Fixed )
|
||||
cf2_getPpemY( CFF_Decoder* decoder );
|
||||
|
|
|
@ -215,8 +215,8 @@
|
|||
cf2_cmdESC, /* 12 */
|
||||
cf2_cmdRESERVED_13, /* 13 */
|
||||
cf2_cmdENDCHAR, /* 14 */
|
||||
cf2_cmdRESERVED_15, /* 15 */
|
||||
cf2_cmdRESERVED_16, /* 16 */
|
||||
cf2_cmdVSINDEX, /* 15 */
|
||||
cf2_cmdBLEND, /* 16 */
|
||||
cf2_cmdRESERVED_17, /* 17 */
|
||||
cf2_cmdHSTEMHM, /* 18 */
|
||||
cf2_cmdHINTMASK, /* 19 */
|
||||
|
@ -273,7 +273,8 @@
|
|||
cf2_escHFLEX, /* 34 */
|
||||
cf2_escFLEX, /* 35 */
|
||||
cf2_escHFLEX1, /* 36 */
|
||||
cf2_escFLEX1 /* 37 */
|
||||
cf2_escFLEX1, /* 37 */
|
||||
cf2_escRESERVED_38 /* 38 & all higher */
|
||||
};
|
||||
|
||||
|
||||
|
@ -402,6 +403,34 @@
|
|||
*curY = vals[13];
|
||||
}
|
||||
|
||||
/* Blend numOperands on the stack, */
|
||||
/* store results into the first numBlends values, */
|
||||
/* then pop remaining arguments. */
|
||||
static void
|
||||
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 * blend->lenBV);
|
||||
|
||||
base = cf2_stack_count( opStack ) - numOperands;
|
||||
delta = base + numBlends;
|
||||
for ( i = 0; i < numBlends; i++ )
|
||||
{
|
||||
const CF2_Fixed * weight = &blend->BV[1];
|
||||
CF2_Fixed sum = cf2_stack_getReal( opStack, i+base ); /* start with first term */
|
||||
for ( j = 1; j < blend->lenBV; j++ )
|
||||
{
|
||||
sum += FT_MulFix( *weight++, cf2_stack_getReal( opStack, delta++ ));
|
||||
}
|
||||
cf2_stack_setReal( opStack, i+base, sum ); /* store blended result */
|
||||
}
|
||||
/* leave only numBlends results on stack */
|
||||
cf2_stack_pop( opStack, numOperands - numBlends );
|
||||
}
|
||||
|
||||
/*
|
||||
* `error' is a shared error code used by many objects in this
|
||||
|
@ -445,6 +474,7 @@
|
|||
CF2_Fixed hintOriginY = curY;
|
||||
|
||||
CF2_Stack opStack = NULL;
|
||||
FT_UInt stackSize;
|
||||
FT_Byte op1; /* first opcode byte */
|
||||
|
||||
CF2_F16Dot16 storage[CF2_STORAGE_SIZE]; /* for `put' and `get' */
|
||||
|
@ -518,8 +548,10 @@
|
|||
* If one of the above operators occurs without explicitly specifying
|
||||
* a width, we assume the default width.
|
||||
*
|
||||
* CFF2 charstrings always return the default width (0)
|
||||
*
|
||||
*/
|
||||
haveWidth = FALSE;
|
||||
haveWidth = font->isCFF2 ? TRUE : FALSE;
|
||||
*width = cf2_getDefaultWidthX( decoder );
|
||||
|
||||
/*
|
||||
|
@ -530,7 +562,9 @@
|
|||
*/
|
||||
|
||||
/* allocate an operand stack */
|
||||
opStack = cf2_stack_init( memory, error );
|
||||
stackSize = font->isCFF2 ? cf2_getMaxstack( decoder ) :
|
||||
CF2_OPERAND_STACK_SIZE;
|
||||
opStack = cf2_stack_init( memory, error, stackSize );
|
||||
if ( !opStack )
|
||||
{
|
||||
lastError = FT_THROW( Out_Of_Memory );
|
||||
|
@ -559,14 +593,25 @@
|
|||
{
|
||||
/* If we've reached the end of the charstring, simulate a */
|
||||
/* cf2_cmdRETURN or cf2_cmdENDCHAR. */
|
||||
/* We do this for both CFF and CFF2. */
|
||||
if ( charstringIndex )
|
||||
op1 = cf2_cmdRETURN; /* end of buffer for subroutine */
|
||||
else
|
||||
op1 = cf2_cmdENDCHAR; /* end of buffer for top level charstring */
|
||||
}
|
||||
else
|
||||
{
|
||||
op1 = (FT_Byte)cf2_buf_readByte( charstring );
|
||||
|
||||
/* explicit RETURN and ENDCHAR in CFF2 should be ignored */
|
||||
/* Note: Trace message will report 0 instead of 11 or 14 */
|
||||
if ( ( op1 == cf2_cmdRETURN || op1 == cf2_cmdENDCHAR ) &&
|
||||
font->isCFF2 )
|
||||
{
|
||||
op1 = cf2_cmdRESERVED_0;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for errors once per loop */
|
||||
if ( *error )
|
||||
goto exit;
|
||||
|
@ -584,13 +629,54 @@
|
|||
case cf2_cmdRESERVED_2:
|
||||
case cf2_cmdRESERVED_9:
|
||||
case cf2_cmdRESERVED_13:
|
||||
case cf2_cmdRESERVED_15:
|
||||
case cf2_cmdRESERVED_16:
|
||||
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:
|
||||
{
|
||||
FT_TRACE4(( " %d\n" ));
|
||||
|
||||
if ( !font->isCFF2 )
|
||||
break; /* clear stack & ignore */
|
||||
|
||||
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 );
|
||||
break;
|
||||
}
|
||||
|
||||
case cf2_cmdBLEND:
|
||||
{
|
||||
FT_UInt numBlends;
|
||||
|
||||
FT_TRACE4(( " blend\n" ));
|
||||
|
||||
if ( !font->isCFF2 )
|
||||
break; /* clear stack & ignore */
|
||||
|
||||
/* check cached blend vector */
|
||||
if ( cff_blend_check_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 );
|
||||
cf2_doBlend( &font->blend, opStack, numBlends );
|
||||
|
||||
font->blend.usedBV = TRUE;
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
|
||||
case cf2_cmdHSTEMHM:
|
||||
case cf2_cmdHSTEM:
|
||||
FT_TRACE4(( op1 == cf2_cmdHSTEMHM ? " hstemhm\n" : " hstem\n" ));
|
||||
|
@ -828,325 +914,10 @@
|
|||
FT_Byte op2 = (FT_Byte)cf2_buf_readByte( charstring );
|
||||
|
||||
|
||||
/* first switch for 2-byte operators handles CFF2 */
|
||||
/* and opcodes that are reserved for both CFF and CFF2 */
|
||||
switch ( op2 )
|
||||
{
|
||||
case cf2_escDOTSECTION:
|
||||
/* something about `flip type of locking' -- ignore it */
|
||||
FT_TRACE4(( " dotsection\n" ));
|
||||
|
||||
break;
|
||||
|
||||
case cf2_escAND:
|
||||
{
|
||||
CF2_F16Dot16 arg1;
|
||||
CF2_F16Dot16 arg2;
|
||||
|
||||
|
||||
FT_TRACE4(( " and\n" ));
|
||||
|
||||
arg2 = cf2_stack_popFixed( opStack );
|
||||
arg1 = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushInt( opStack, arg1 && arg2 );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escOR:
|
||||
{
|
||||
CF2_F16Dot16 arg1;
|
||||
CF2_F16Dot16 arg2;
|
||||
|
||||
|
||||
FT_TRACE4(( " or\n" ));
|
||||
|
||||
arg2 = cf2_stack_popFixed( opStack );
|
||||
arg1 = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushInt( opStack, arg1 || arg2 );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escNOT:
|
||||
{
|
||||
CF2_F16Dot16 arg;
|
||||
|
||||
|
||||
FT_TRACE4(( " not\n" ));
|
||||
|
||||
arg = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushInt( opStack, !arg );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escABS:
|
||||
{
|
||||
CF2_F16Dot16 arg;
|
||||
|
||||
|
||||
FT_TRACE4(( " abs\n" ));
|
||||
|
||||
arg = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushFixed( opStack, FT_ABS( arg ) );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escADD:
|
||||
{
|
||||
CF2_F16Dot16 summand1;
|
||||
CF2_F16Dot16 summand2;
|
||||
|
||||
|
||||
FT_TRACE4(( " add\n" ));
|
||||
|
||||
summand2 = cf2_stack_popFixed( opStack );
|
||||
summand1 = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushFixed( opStack, summand1 + summand2 );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escSUB:
|
||||
{
|
||||
CF2_F16Dot16 minuend;
|
||||
CF2_F16Dot16 subtrahend;
|
||||
|
||||
|
||||
FT_TRACE4(( " sub\n" ));
|
||||
|
||||
subtrahend = cf2_stack_popFixed( opStack );
|
||||
minuend = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushFixed( opStack, minuend - subtrahend );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escDIV:
|
||||
{
|
||||
CF2_F16Dot16 dividend;
|
||||
CF2_F16Dot16 divisor;
|
||||
|
||||
|
||||
FT_TRACE4(( " div\n" ));
|
||||
|
||||
divisor = cf2_stack_popFixed( opStack );
|
||||
dividend = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushFixed( opStack, FT_DivFix( dividend, divisor ) );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escNEG:
|
||||
{
|
||||
CF2_F16Dot16 arg;
|
||||
|
||||
|
||||
FT_TRACE4(( " neg\n" ));
|
||||
|
||||
arg = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushFixed( opStack, -arg );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escEQ:
|
||||
{
|
||||
CF2_F16Dot16 arg1;
|
||||
CF2_F16Dot16 arg2;
|
||||
|
||||
|
||||
FT_TRACE4(( " eq\n" ));
|
||||
|
||||
arg2 = cf2_stack_popFixed( opStack );
|
||||
arg1 = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushInt( opStack, arg1 == arg2 );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escDROP:
|
||||
FT_TRACE4(( " drop\n" ));
|
||||
|
||||
(void)cf2_stack_popFixed( opStack );
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escPUT:
|
||||
{
|
||||
CF2_F16Dot16 val;
|
||||
CF2_Int idx;
|
||||
|
||||
|
||||
FT_TRACE4(( " put\n" ));
|
||||
|
||||
idx = cf2_stack_popInt( opStack );
|
||||
val = cf2_stack_popFixed( opStack );
|
||||
|
||||
if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
|
||||
storage[idx] = val;
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escGET:
|
||||
{
|
||||
CF2_Int idx;
|
||||
|
||||
|
||||
FT_TRACE4(( " get\n" ));
|
||||
|
||||
idx = cf2_stack_popInt( opStack );
|
||||
|
||||
if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
|
||||
cf2_stack_pushFixed( opStack, storage[idx] );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escIFELSE:
|
||||
{
|
||||
CF2_F16Dot16 arg1;
|
||||
CF2_F16Dot16 arg2;
|
||||
CF2_F16Dot16 cond1;
|
||||
CF2_F16Dot16 cond2;
|
||||
|
||||
|
||||
FT_TRACE4(( " ifelse\n" ));
|
||||
|
||||
cond2 = cf2_stack_popFixed( opStack );
|
||||
cond1 = cf2_stack_popFixed( opStack );
|
||||
arg2 = cf2_stack_popFixed( opStack );
|
||||
arg1 = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushFixed( opStack, cond1 <= cond2 ? arg1 : arg2 );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escRANDOM: /* in spec */
|
||||
FT_TRACE4(( " random\n" ));
|
||||
|
||||
CF2_FIXME;
|
||||
break;
|
||||
|
||||
case cf2_escMUL:
|
||||
{
|
||||
CF2_F16Dot16 factor1;
|
||||
CF2_F16Dot16 factor2;
|
||||
|
||||
|
||||
FT_TRACE4(( " mul\n" ));
|
||||
|
||||
factor2 = cf2_stack_popFixed( opStack );
|
||||
factor1 = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushFixed( opStack, FT_MulFix( factor1, factor2 ) );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escSQRT:
|
||||
{
|
||||
CF2_F16Dot16 arg;
|
||||
|
||||
|
||||
FT_TRACE4(( " sqrt\n" ));
|
||||
|
||||
arg = cf2_stack_popFixed( opStack );
|
||||
if ( arg > 0 )
|
||||
{
|
||||
FT_Fixed root = arg;
|
||||
FT_Fixed new_root;
|
||||
|
||||
|
||||
/* Babylonian method */
|
||||
for (;;)
|
||||
{
|
||||
new_root = ( root + FT_DivFix( arg, root ) + 1 ) >> 1;
|
||||
if ( new_root == root )
|
||||
break;
|
||||
root = new_root;
|
||||
}
|
||||
arg = new_root;
|
||||
}
|
||||
else
|
||||
arg = 0;
|
||||
|
||||
cf2_stack_pushFixed( opStack, arg );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escDUP:
|
||||
{
|
||||
CF2_F16Dot16 arg;
|
||||
|
||||
|
||||
FT_TRACE4(( " dup\n" ));
|
||||
|
||||
arg = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushFixed( opStack, arg );
|
||||
cf2_stack_pushFixed( opStack, arg );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escEXCH:
|
||||
{
|
||||
CF2_F16Dot16 arg1;
|
||||
CF2_F16Dot16 arg2;
|
||||
|
||||
|
||||
FT_TRACE4(( " exch\n" ));
|
||||
|
||||
arg2 = cf2_stack_popFixed( opStack );
|
||||
arg1 = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushFixed( opStack, arg2 );
|
||||
cf2_stack_pushFixed( opStack, arg1 );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escINDEX:
|
||||
{
|
||||
CF2_Int idx;
|
||||
CF2_UInt size;
|
||||
|
||||
|
||||
FT_TRACE4(( " index\n" ));
|
||||
|
||||
idx = cf2_stack_popInt( opStack );
|
||||
size = cf2_stack_count( opStack );
|
||||
|
||||
if ( size > 0 )
|
||||
{
|
||||
/* for `cf2_stack_getReal', index 0 is bottom of stack */
|
||||
CF2_UInt gr_idx;
|
||||
|
||||
|
||||
if ( idx < 0 )
|
||||
gr_idx = size - 1;
|
||||
else if ( (CF2_UInt)idx >= size )
|
||||
gr_idx = 0;
|
||||
else
|
||||
gr_idx = size - 1 - (CF2_UInt)idx;
|
||||
|
||||
cf2_stack_pushFixed( opStack,
|
||||
cf2_stack_getReal( opStack, gr_idx ) );
|
||||
}
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escROLL:
|
||||
{
|
||||
CF2_Int idx;
|
||||
CF2_Int count;
|
||||
|
||||
|
||||
FT_TRACE4(( " roll\n" ));
|
||||
|
||||
idx = cf2_stack_popInt( opStack );
|
||||
count = cf2_stack_popInt( opStack );
|
||||
|
||||
cf2_stack_roll( opStack, count, idx );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escHFLEX:
|
||||
{
|
||||
static const FT_Bool readFromStack[12] =
|
||||
|
@ -1243,6 +1014,7 @@
|
|||
}
|
||||
continue;
|
||||
|
||||
/* these opcodes are reserved in both CFF & CFF2 */
|
||||
case cf2_escRESERVED_1:
|
||||
case cf2_escRESERVED_2:
|
||||
case cf2_escRESERVED_6:
|
||||
|
@ -1256,13 +1028,342 @@
|
|||
case cf2_escRESERVED_31:
|
||||
case cf2_escRESERVED_32:
|
||||
case cf2_escRESERVED_33:
|
||||
default:
|
||||
FT_TRACE4(( " unknown op (12, %d)\n", op2 ));
|
||||
break;
|
||||
|
||||
}; /* end of switch statement checking `op2' */
|
||||
default:
|
||||
{
|
||||
if ( font->isCFF2 || op2 >= cf2_escRESERVED_38 )
|
||||
FT_TRACE4(( " unknown op (12, %d)\n", op2 ));
|
||||
else
|
||||
{
|
||||
/* second switch for 2-byte operators handles just CFF */
|
||||
switch ( op2 )
|
||||
{
|
||||
|
||||
} /* case cf2_cmdESC */
|
||||
break;
|
||||
case cf2_escDOTSECTION:
|
||||
/* something about `flip type of locking' -- ignore it */
|
||||
FT_TRACE4(( " dotsection\n" ));
|
||||
|
||||
break;
|
||||
|
||||
case cf2_escAND:
|
||||
{
|
||||
CF2_F16Dot16 arg1;
|
||||
CF2_F16Dot16 arg2;
|
||||
|
||||
|
||||
FT_TRACE4(( " and\n" ));
|
||||
|
||||
arg2 = cf2_stack_popFixed( opStack );
|
||||
arg1 = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushInt( opStack, arg1 && arg2 );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escOR:
|
||||
{
|
||||
CF2_F16Dot16 arg1;
|
||||
CF2_F16Dot16 arg2;
|
||||
|
||||
|
||||
FT_TRACE4(( " or\n" ));
|
||||
|
||||
arg2 = cf2_stack_popFixed( opStack );
|
||||
arg1 = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushInt( opStack, arg1 || arg2 );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escNOT:
|
||||
{
|
||||
CF2_F16Dot16 arg;
|
||||
|
||||
|
||||
FT_TRACE4(( " not\n" ));
|
||||
|
||||
arg = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushInt( opStack, !arg );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escABS:
|
||||
{
|
||||
CF2_F16Dot16 arg;
|
||||
|
||||
|
||||
FT_TRACE4(( " abs\n" ));
|
||||
|
||||
arg = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushFixed( opStack, FT_ABS( arg ) );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escADD:
|
||||
{
|
||||
CF2_F16Dot16 summand1;
|
||||
CF2_F16Dot16 summand2;
|
||||
|
||||
|
||||
FT_TRACE4(( " add\n" ));
|
||||
|
||||
summand2 = cf2_stack_popFixed( opStack );
|
||||
summand1 = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushFixed( opStack, summand1 + summand2 );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escSUB:
|
||||
{
|
||||
CF2_F16Dot16 minuend;
|
||||
CF2_F16Dot16 subtrahend;
|
||||
|
||||
|
||||
FT_TRACE4(( " sub\n" ));
|
||||
|
||||
subtrahend = cf2_stack_popFixed( opStack );
|
||||
minuend = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushFixed( opStack, minuend - subtrahend );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escDIV:
|
||||
{
|
||||
CF2_F16Dot16 dividend;
|
||||
CF2_F16Dot16 divisor;
|
||||
|
||||
|
||||
FT_TRACE4(( " div\n" ));
|
||||
|
||||
divisor = cf2_stack_popFixed( opStack );
|
||||
dividend = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushFixed( opStack, FT_DivFix( dividend, divisor ) );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escNEG:
|
||||
{
|
||||
CF2_F16Dot16 arg;
|
||||
|
||||
|
||||
FT_TRACE4(( " neg\n" ));
|
||||
|
||||
arg = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushFixed( opStack, -arg );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escEQ:
|
||||
{
|
||||
CF2_F16Dot16 arg1;
|
||||
CF2_F16Dot16 arg2;
|
||||
|
||||
|
||||
FT_TRACE4(( " eq\n" ));
|
||||
|
||||
arg2 = cf2_stack_popFixed( opStack );
|
||||
arg1 = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushInt( opStack, arg1 == arg2 );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escDROP:
|
||||
FT_TRACE4(( " drop\n" ));
|
||||
|
||||
(void)cf2_stack_popFixed( opStack );
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escPUT:
|
||||
{
|
||||
CF2_F16Dot16 val;
|
||||
CF2_Int idx;
|
||||
|
||||
|
||||
FT_TRACE4(( " put\n" ));
|
||||
|
||||
idx = cf2_stack_popInt( opStack );
|
||||
val = cf2_stack_popFixed( opStack );
|
||||
|
||||
if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
|
||||
storage[idx] = val;
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escGET:
|
||||
{
|
||||
CF2_Int idx;
|
||||
|
||||
|
||||
FT_TRACE4(( " get\n" ));
|
||||
|
||||
idx = cf2_stack_popInt( opStack );
|
||||
|
||||
if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
|
||||
cf2_stack_pushFixed( opStack, storage[idx] );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escIFELSE:
|
||||
{
|
||||
CF2_F16Dot16 arg1;
|
||||
CF2_F16Dot16 arg2;
|
||||
CF2_F16Dot16 cond1;
|
||||
CF2_F16Dot16 cond2;
|
||||
|
||||
|
||||
FT_TRACE4(( " ifelse\n" ));
|
||||
|
||||
cond2 = cf2_stack_popFixed( opStack );
|
||||
cond1 = cf2_stack_popFixed( opStack );
|
||||
arg2 = cf2_stack_popFixed( opStack );
|
||||
arg1 = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushFixed( opStack, cond1 <= cond2 ? arg1 : arg2 );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escRANDOM: /* in spec */
|
||||
FT_TRACE4(( " random\n" ));
|
||||
|
||||
CF2_FIXME;
|
||||
break;
|
||||
|
||||
case cf2_escMUL:
|
||||
{
|
||||
CF2_F16Dot16 factor1;
|
||||
CF2_F16Dot16 factor2;
|
||||
|
||||
|
||||
FT_TRACE4(( " mul\n" ));
|
||||
|
||||
factor2 = cf2_stack_popFixed( opStack );
|
||||
factor1 = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushFixed( opStack, FT_MulFix( factor1, factor2 ) );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escSQRT:
|
||||
{
|
||||
CF2_F16Dot16 arg;
|
||||
|
||||
|
||||
FT_TRACE4(( " sqrt\n" ));
|
||||
|
||||
arg = cf2_stack_popFixed( opStack );
|
||||
if ( arg > 0 )
|
||||
{
|
||||
FT_Fixed root = arg;
|
||||
FT_Fixed new_root;
|
||||
|
||||
|
||||
/* Babylonian method */
|
||||
for (;;)
|
||||
{
|
||||
new_root = ( root + FT_DivFix( arg, root ) + 1 ) >> 1;
|
||||
if ( new_root == root )
|
||||
break;
|
||||
root = new_root;
|
||||
}
|
||||
arg = new_root;
|
||||
}
|
||||
else
|
||||
arg = 0;
|
||||
|
||||
cf2_stack_pushFixed( opStack, arg );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escDUP:
|
||||
{
|
||||
CF2_F16Dot16 arg;
|
||||
|
||||
|
||||
FT_TRACE4(( " dup\n" ));
|
||||
|
||||
arg = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushFixed( opStack, arg );
|
||||
cf2_stack_pushFixed( opStack, arg );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escEXCH:
|
||||
{
|
||||
CF2_F16Dot16 arg1;
|
||||
CF2_F16Dot16 arg2;
|
||||
|
||||
|
||||
FT_TRACE4(( " exch\n" ));
|
||||
|
||||
arg2 = cf2_stack_popFixed( opStack );
|
||||
arg1 = cf2_stack_popFixed( opStack );
|
||||
|
||||
cf2_stack_pushFixed( opStack, arg2 );
|
||||
cf2_stack_pushFixed( opStack, arg1 );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escINDEX:
|
||||
{
|
||||
CF2_Int idx;
|
||||
CF2_UInt size;
|
||||
|
||||
|
||||
FT_TRACE4(( " index\n" ));
|
||||
|
||||
idx = cf2_stack_popInt( opStack );
|
||||
size = cf2_stack_count( opStack );
|
||||
|
||||
if ( size > 0 )
|
||||
{
|
||||
/* for `cf2_stack_getReal', index 0 is bottom of stack */
|
||||
CF2_UInt gr_idx;
|
||||
|
||||
|
||||
if ( idx < 0 )
|
||||
gr_idx = size - 1;
|
||||
else if ( (CF2_UInt)idx >= size )
|
||||
gr_idx = 0;
|
||||
else
|
||||
gr_idx = size - 1 - (CF2_UInt)idx;
|
||||
|
||||
cf2_stack_pushFixed( opStack,
|
||||
cf2_stack_getReal( opStack, gr_idx ) );
|
||||
}
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
case cf2_escROLL:
|
||||
{
|
||||
CF2_Int idx;
|
||||
CF2_Int count;
|
||||
|
||||
|
||||
FT_TRACE4(( " roll\n" ));
|
||||
|
||||
idx = cf2_stack_popInt( opStack );
|
||||
count = cf2_stack_popInt( opStack );
|
||||
|
||||
cf2_stack_roll( opStack, count, idx );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
} /* end of 2nd switch checking op2 */
|
||||
}
|
||||
}
|
||||
}; /* end of 1st switch checking op2 */
|
||||
} /* case cf2_cmdESC */
|
||||
break; /* break switch checking op1 */
|
||||
|
||||
case cf2_cmdENDCHAR:
|
||||
FT_TRACE4(( " endchar\n" ));
|
||||
|
@ -1283,7 +1384,8 @@
|
|||
/* close path if still open */
|
||||
cf2_glyphpath_closeOpenPath( &glyphPath );
|
||||
|
||||
if ( cf2_stack_count( opStack ) > 1 )
|
||||
/* disable seac for CFF2 (charstring ending with args on stack) */
|
||||
if ( !font->isCFF2 && cf2_stack_count( opStack ) > 1 )
|
||||
{
|
||||
/* must be either 4 or 5 -- */
|
||||
/* this is a (deprecated) implied `seac' operator */
|
||||
|
@ -1755,6 +1857,9 @@
|
|||
/* check whether last error seen is also the first one */
|
||||
cf2_setError( error, lastError );
|
||||
|
||||
if ( *error )
|
||||
FT_TRACE4(( "charstring error %d\n", *error ));
|
||||
|
||||
/* free resources from objects we've used */
|
||||
cf2_glyphpath_finalize( &glyphPath );
|
||||
cf2_arrstack_finalize( &vStemHintArray );
|
||||
|
|
|
@ -51,7 +51,8 @@
|
|||
/* `error'). */
|
||||
FT_LOCAL_DEF( CF2_Stack )
|
||||
cf2_stack_init( FT_Memory memory,
|
||||
FT_Error* e )
|
||||
FT_Error* e,
|
||||
FT_UInt stackSize )
|
||||
{
|
||||
FT_Error error = FT_Err_Ok; /* for FT_QNEW */
|
||||
|
||||
|
@ -63,9 +64,18 @@
|
|||
/* initialize the structure; FT_QNEW zeroes it */
|
||||
stack->memory = memory;
|
||||
stack->error = e;
|
||||
stack->top = &stack->buffer[0]; /* empty stack */
|
||||
}
|
||||
|
||||
/* allocate the stack buffer */
|
||||
if ( FT_NEW_ARRAY( stack->buffer, stackSize ) )
|
||||
{
|
||||
FT_FREE( stack );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stack->stackSize = stackSize;
|
||||
stack->top = stack->buffer; /* empty stack */
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
|
@ -77,6 +87,8 @@
|
|||
{
|
||||
FT_Memory memory = stack->memory;
|
||||
|
||||
/* free the buffer */
|
||||
FT_FREE( stack->buffer );
|
||||
|
||||
/* free the main structure */
|
||||
FT_FREE( stack );
|
||||
|
@ -87,7 +99,7 @@
|
|||
FT_LOCAL_DEF( CF2_UInt )
|
||||
cf2_stack_count( CF2_Stack stack )
|
||||
{
|
||||
return (CF2_UInt)( stack->top - &stack->buffer[0] );
|
||||
return (CF2_UInt)( stack->top - stack->buffer );
|
||||
}
|
||||
|
||||
|
||||
|
@ -95,7 +107,7 @@
|
|||
cf2_stack_pushInt( CF2_Stack stack,
|
||||
CF2_Int val )
|
||||
{
|
||||
if ( stack->top == &stack->buffer[CF2_OPERAND_STACK_SIZE] )
|
||||
if ( stack->top == stack->buffer + stack->stackSize )
|
||||
{
|
||||
CF2_SET_ERROR( stack->error, Stack_Overflow );
|
||||
return; /* stack overflow */
|
||||
|
@ -111,7 +123,7 @@
|
|||
cf2_stack_pushFixed( CF2_Stack stack,
|
||||
CF2_Fixed val )
|
||||
{
|
||||
if ( stack->top == &stack->buffer[CF2_OPERAND_STACK_SIZE] )
|
||||
if ( stack->top == stack->buffer + stack->stackSize )
|
||||
{
|
||||
CF2_SET_ERROR( stack->error, Stack_Overflow );
|
||||
return; /* stack overflow */
|
||||
|
@ -127,7 +139,7 @@
|
|||
FT_LOCAL_DEF( CF2_Int )
|
||||
cf2_stack_popInt( CF2_Stack stack )
|
||||
{
|
||||
if ( stack->top == &stack->buffer[0] )
|
||||
if ( stack->top == stack->buffer )
|
||||
{
|
||||
CF2_SET_ERROR( stack->error, Stack_Underflow );
|
||||
return 0; /* underflow */
|
||||
|
@ -149,7 +161,7 @@
|
|||
FT_LOCAL_DEF( CF2_Fixed )
|
||||
cf2_stack_popFixed( CF2_Stack stack )
|
||||
{
|
||||
if ( stack->top == &stack->buffer[0] )
|
||||
if ( stack->top == stack->buffer )
|
||||
{
|
||||
CF2_SET_ERROR( stack->error, Stack_Underflow );
|
||||
return cf2_intToFixed( 0 ); /* underflow */
|
||||
|
@ -175,7 +187,7 @@
|
|||
cf2_stack_getReal( CF2_Stack stack,
|
||||
CF2_UInt idx )
|
||||
{
|
||||
FT_ASSERT( cf2_stack_count( stack ) <= CF2_OPERAND_STACK_SIZE );
|
||||
FT_ASSERT( cf2_stack_count( stack ) <= stack->stackSize );
|
||||
|
||||
if ( idx >= cf2_stack_count( stack ) )
|
||||
{
|
||||
|
@ -194,6 +206,34 @@
|
|||
}
|
||||
}
|
||||
|
||||
/* provide random access to stack */
|
||||
FT_LOCAL_DEF( void )
|
||||
cf2_stack_setReal( CF2_Stack stack,
|
||||
CF2_UInt idx,
|
||||
CF2_Fixed val )
|
||||
{
|
||||
if ( idx > cf2_stack_count( stack ) )
|
||||
{
|
||||
CF2_SET_ERROR( stack->error, Stack_Overflow );
|
||||
return;
|
||||
}
|
||||
|
||||
stack->buffer[idx].u.r = val;
|
||||
stack->buffer[idx].type = CF2_NumberFixed;
|
||||
}
|
||||
|
||||
/* discard (pop) num values from stack */
|
||||
FT_LOCAL_DEF( void )
|
||||
cf2_stack_pop( CF2_Stack stack,
|
||||
CF2_UInt num )
|
||||
{
|
||||
if ( num > cf2_stack_count( stack ) )
|
||||
{
|
||||
CF2_SET_ERROR( stack->error, Stack_Underflow );
|
||||
return;
|
||||
}
|
||||
stack->top -= num;
|
||||
}
|
||||
|
||||
FT_LOCAL( void )
|
||||
cf2_stack_roll( CF2_Stack stack,
|
||||
|
@ -278,7 +318,7 @@
|
|||
FT_LOCAL_DEF( void )
|
||||
cf2_stack_clear( CF2_Stack stack )
|
||||
{
|
||||
stack->top = &stack->buffer[0];
|
||||
stack->top = stack->buffer;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -62,15 +62,17 @@ FT_BEGIN_HEADER
|
|||
{
|
||||
FT_Memory memory;
|
||||
FT_Error* error;
|
||||
CF2_StackNumber buffer[CF2_OPERAND_STACK_SIZE];
|
||||
CF2_StackNumber* buffer;
|
||||
CF2_StackNumber* top;
|
||||
FT_UInt stackSize;
|
||||
|
||||
} CF2_StackRec, *CF2_Stack;
|
||||
|
||||
|
||||
FT_LOCAL( CF2_Stack )
|
||||
cf2_stack_init( FT_Memory memory,
|
||||
FT_Error* error );
|
||||
FT_Error* error,
|
||||
FT_UInt stackSize );
|
||||
FT_LOCAL( void )
|
||||
cf2_stack_free( CF2_Stack stack );
|
||||
|
||||
|
@ -93,6 +95,15 @@ FT_BEGIN_HEADER
|
|||
cf2_stack_getReal( CF2_Stack stack,
|
||||
CF2_UInt idx );
|
||||
|
||||
FT_LOCAL( void )
|
||||
cf2_stack_setReal( CF2_Stack stack,
|
||||
CF2_UInt idx,
|
||||
CF2_Fixed val );
|
||||
|
||||
FT_LOCAL( void )
|
||||
cf2_stack_pop( CF2_Stack stack,
|
||||
CF2_UInt num );
|
||||
|
||||
FT_LOCAL( void )
|
||||
cf2_stack_roll( CF2_Stack stack,
|
||||
CF2_Int count,
|
||||
|
|
|
@ -32,6 +32,23 @@
|
|||
#include "cffcmap.h"
|
||||
#include "cffparse.h"
|
||||
|
||||
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
|
||||
#include FT_MULTIPLE_MASTERS_H
|
||||
#include FT_SERVICE_MULTIPLE_MASTERS_H
|
||||
#include "../truetype/ttgxvar.h"
|
||||
#endif
|
||||
|
||||
/* TODO use services interface to link to these functions (in sfdriver.c) */
|
||||
FT_EXPORT( FT_Error )
|
||||
sfnt_get_glyph_name( TT_Face face,
|
||||
FT_UInt glyph_index,
|
||||
FT_Pointer buffer,
|
||||
FT_UInt buffer_max );
|
||||
FT_EXPORT( FT_UInt )
|
||||
sfnt_get_name_index( TT_Face face,
|
||||
FT_String* glyph_name );
|
||||
|
||||
|
||||
#include "cfferrs.h"
|
||||
#include "cffpic.h"
|
||||
|
||||
|
@ -291,6 +308,13 @@
|
|||
FT_Error error;
|
||||
|
||||
|
||||
/* CFF2 table does not have glyph names */
|
||||
/* we need to use post table method */
|
||||
if ( font->version_major == 2 )
|
||||
{
|
||||
return sfnt_get_glyph_name( face, glyph_index, buffer, buffer_max );
|
||||
}
|
||||
|
||||
if ( !font->psnames )
|
||||
{
|
||||
FT_ERROR(( "cff_get_glyph_name:"
|
||||
|
@ -328,10 +352,16 @@
|
|||
FT_UShort sid;
|
||||
FT_UInt i;
|
||||
|
||||
|
||||
cff = (CFF_FontRec *)face->extra.data;
|
||||
charset = &cff->charset;
|
||||
|
||||
/* CFF2 table does not have glyph names */
|
||||
/* we need to use post table method */
|
||||
if ( cff->version_major == 2 )
|
||||
{
|
||||
return sfnt_get_name_index( face, glyph_name );
|
||||
}
|
||||
|
||||
FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS );
|
||||
if ( !psnames )
|
||||
return 0;
|
||||
|
@ -871,15 +901,31 @@
|
|||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
/* reuse some of the TT functions for the cff multi_master service */
|
||||
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
|
||||
FT_DEFINE_SERVICE_MULTIMASTERSREC(
|
||||
cff_service_multi_masters,
|
||||
(FT_Get_MM_Func) NULL, /* get_mm */
|
||||
(FT_Set_MM_Design_Func) NULL, /* set_mm_design */
|
||||
(FT_Set_MM_Blend_Func) TT_Set_MM_Blend, /* set_mm_blend */
|
||||
(FT_Get_MM_Var_Func) TT_Get_MM_Var, /* get_mm_var */
|
||||
(FT_Set_Var_Design_Func) TT_Set_Var_Design, /* set_var_design */
|
||||
(FT_Get_Var_Design_Func) TT_Get_Var_Design, /* get_var_design */
|
||||
(FT_Get_Var_Blend_Func) TT_Get_Var_Blend ) /* get_var_blend */
|
||||
|
||||
#endif
|
||||
|
||||
/* TODO: fix up ifdefs and we really need an 8-parameter FT_DEFINE_SERVICEDESCREC8 */
|
||||
#ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES
|
||||
FT_DEFINE_SERVICEDESCREC7(
|
||||
cff_services,
|
||||
FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_CFF,
|
||||
FT_SERVICE_ID_MULTI_MASTERS, &CFF_SERVICE_MULTI_MASTERS_GET,
|
||||
FT_SERVICE_ID_POSTSCRIPT_INFO, &CFF_SERVICE_PS_INFO_GET,
|
||||
FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &CFF_SERVICE_PS_NAME_GET,
|
||||
FT_SERVICE_ID_GLYPH_DICT, &CFF_SERVICE_GLYPH_DICT_GET,
|
||||
FT_SERVICE_ID_TT_CMAP, &CFF_SERVICE_GET_CMAP_INFO_GET,
|
||||
FT_SERVICE_ID_CID, &CFF_SERVICE_CID_INFO_GET,
|
||||
/*FT_SERVICE_ID_CID, &CFF_SERVICE_CID_INFO_GET,*/
|
||||
FT_SERVICE_ID_PROPERTIES, &CFF_SERVICE_PROPERTIES_GET
|
||||
)
|
||||
#else
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "cfferrs.h"
|
||||
|
||||
#define FT_FIXED_ONE ((FT_Fixed)0x10000)
|
||||
|
||||
#if 1
|
||||
|
||||
|
@ -225,19 +226,33 @@
|
|||
static FT_Error
|
||||
cff_index_init( CFF_Index idx,
|
||||
FT_Stream stream,
|
||||
FT_Bool load )
|
||||
FT_Bool load,
|
||||
FT_Bool cff2 )
|
||||
{
|
||||
FT_Error error;
|
||||
FT_Memory memory = stream->memory;
|
||||
FT_UShort count;
|
||||
FT_UInt count;
|
||||
|
||||
|
||||
FT_MEM_ZERO( idx, sizeof ( *idx ) );
|
||||
|
||||
idx->stream = stream;
|
||||
idx->start = FT_STREAM_POS();
|
||||
if ( !FT_READ_USHORT( count ) &&
|
||||
count > 0 )
|
||||
|
||||
if ( cff2 )
|
||||
{
|
||||
if ( FT_READ_ULONG( count ) )
|
||||
goto Exit;
|
||||
idx->hdr_size = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( FT_READ_USHORT( count ) )
|
||||
goto Exit;
|
||||
idx->hdr_size = 3;
|
||||
}
|
||||
|
||||
if ( count > 0 )
|
||||
{
|
||||
FT_Byte offsize;
|
||||
FT_ULong size;
|
||||
|
@ -258,7 +273,7 @@
|
|||
idx->off_size = offsize;
|
||||
size = (FT_ULong)( count + 1 ) * offsize;
|
||||
|
||||
idx->data_offset = idx->start + 3 + size;
|
||||
idx->data_offset = idx->start + idx->hdr_size + size;
|
||||
|
||||
if ( FT_STREAM_SKIP( size - offsize ) )
|
||||
goto Exit;
|
||||
|
@ -335,7 +350,7 @@
|
|||
data_size = (FT_ULong)( idx->count + 1 ) * offsize;
|
||||
|
||||
if ( FT_NEW_ARRAY( idx->offsets, idx->count + 1 ) ||
|
||||
FT_STREAM_SEEK( idx->start + 3 ) ||
|
||||
FT_STREAM_SEEK( idx->start + idx->hdr_size ) ||
|
||||
FT_FRAME_ENTER( data_size ) )
|
||||
goto Exit;
|
||||
|
||||
|
@ -493,7 +508,7 @@
|
|||
FT_ULong pos = element * idx->off_size;
|
||||
|
||||
|
||||
if ( FT_STREAM_SEEK( idx->start + 3 + pos ) )
|
||||
if ( FT_STREAM_SEEK( idx->start + idx->hdr_size + pos ) )
|
||||
goto Exit;
|
||||
|
||||
off1 = cff_index_read_offset( idx, &error );
|
||||
|
@ -589,12 +604,15 @@
|
|||
FT_UInt element )
|
||||
{
|
||||
CFF_Index idx = &font->name_index;
|
||||
FT_Memory memory = idx->stream->memory;
|
||||
FT_Memory memory;
|
||||
FT_Byte* bytes;
|
||||
FT_ULong byte_len;
|
||||
FT_Error error;
|
||||
FT_String* name = 0;
|
||||
|
||||
if ( !idx->stream ) /* CFF2 does not include a name index */
|
||||
goto Exit;
|
||||
memory = idx->stream->memory;
|
||||
|
||||
error = cff_index_access_element( idx, element, &bytes, &byte_len );
|
||||
if ( error )
|
||||
|
@ -723,6 +741,10 @@
|
|||
{
|
||||
FT_Byte fd = 0;
|
||||
|
||||
/* if there is no FDSelect, return zero */
|
||||
/* Note: CFF2 with just one Font Dict has no FDSelect */
|
||||
if ( fdselect->data == NULL )
|
||||
goto Exit;
|
||||
|
||||
switch ( fdselect->format )
|
||||
{
|
||||
|
@ -776,6 +798,7 @@
|
|||
;
|
||||
}
|
||||
|
||||
Exit:
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
@ -862,6 +885,32 @@
|
|||
charset->offset = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
cff_vstore_done( CFF_VStoreRec* vstore,
|
||||
FT_Memory memory )
|
||||
{
|
||||
FT_UInt i;
|
||||
|
||||
/* free regionList and axisLists */
|
||||
if ( vstore->varRegionList )
|
||||
{
|
||||
for ( i=0; i<vstore->regionCount; i++ )
|
||||
{
|
||||
FT_FREE( vstore->varRegionList[i].axisList );
|
||||
}
|
||||
}
|
||||
FT_FREE( vstore->varRegionList );
|
||||
|
||||
/* free varData and indices */
|
||||
if ( vstore->varData )
|
||||
{
|
||||
for ( i=0; i<vstore->dataCount; i++ )
|
||||
{
|
||||
FT_FREE( vstore->varData[i].regionIndices );
|
||||
}
|
||||
}
|
||||
FT_FREE( vstore->varData );
|
||||
}
|
||||
|
||||
static FT_Error
|
||||
cff_charset_load( CFF_Charset charset,
|
||||
|
@ -1053,6 +1102,376 @@
|
|||
}
|
||||
|
||||
|
||||
/* convert 2.14 to Fixed */
|
||||
#define FT_fdot14ToFixed( x ) \
|
||||
(((FT_Fixed)((FT_Int16)(x))) << 2 )
|
||||
|
||||
static FT_Error
|
||||
cff_vstore_load( CFF_VStoreRec* vstore,
|
||||
FT_Stream stream,
|
||||
FT_ULong base_offset,
|
||||
FT_ULong offset )
|
||||
{
|
||||
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 */
|
||||
if ( offset )
|
||||
{
|
||||
FT_UInt vsSize; /* currently unused */
|
||||
FT_UInt vsOffset;
|
||||
FT_UInt format;
|
||||
FT_ULong regionListOffset;
|
||||
|
||||
/* we need to parse the table to determine its size */
|
||||
if ( FT_STREAM_SEEK( base_offset + offset ) ||
|
||||
FT_READ_USHORT( vsSize ) )
|
||||
goto Exit;
|
||||
|
||||
/* actual variation store begins after the length */
|
||||
vsOffset = FT_STREAM_POS();
|
||||
|
||||
/* check the header */
|
||||
if ( FT_READ_USHORT( format ) )
|
||||
goto Exit;
|
||||
if ( format != 1 )
|
||||
{
|
||||
error = FT_THROW( Invalid_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* read top level fields */
|
||||
if ( FT_READ_ULONG( regionListOffset ) ||
|
||||
FT_READ_USHORT( vstore->dataCount ) )
|
||||
goto Exit;
|
||||
|
||||
/* 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 ) ||
|
||||
FT_READ_USHORT( vstore->axisCount ) ||
|
||||
FT_READ_USHORT( vstore->regionCount ) )
|
||||
goto Exit;
|
||||
|
||||
if ( FT_NEW_ARRAY( vstore->varRegionList, vstore->regionCount ) )
|
||||
goto Exit;
|
||||
|
||||
for ( i=0; i<vstore->regionCount; i++ )
|
||||
{
|
||||
CFF_VarRegion* region = &vstore->varRegionList[i];
|
||||
if ( FT_NEW_ARRAY( region->axisList, vstore->axisCount ) )
|
||||
goto Exit;
|
||||
for ( j=0; j<vstore->axisCount; j++ )
|
||||
{
|
||||
CFF_AxisCoords* axis = ®ion->axisList[j];
|
||||
FT_Int16 start14, peak14, end14;
|
||||
if ( FT_READ_SHORT( start14 ) ||
|
||||
FT_READ_SHORT( peak14 ) ||
|
||||
FT_READ_SHORT( end14 ) )
|
||||
goto Exit;
|
||||
axis->startCoord = FT_fdot14ToFixed( start14 );
|
||||
axis->peakCoord = FT_fdot14ToFixed( peak14 );
|
||||
axis->endCoord = FT_fdot14ToFixed( end14 );
|
||||
}
|
||||
}
|
||||
|
||||
/* use dataOffsetArray now to parse varData items */
|
||||
if ( FT_NEW_ARRAY( vstore->varData, vstore->dataCount ) )
|
||||
goto Exit;
|
||||
|
||||
for ( i=0; i<vstore->dataCount; i++ )
|
||||
{
|
||||
FT_UInt itemCount, shortDeltaCount;
|
||||
CFF_VarData* data = &vstore->varData[i];
|
||||
|
||||
if ( FT_STREAM_SEEK( vsOffset + dataOffsetArray[i] ) )
|
||||
goto Exit;
|
||||
|
||||
/* ignore these two values because CFF2 has no delta sets */
|
||||
if ( FT_READ_USHORT( itemCount ) ||
|
||||
FT_READ_USHORT( shortDeltaCount ) )
|
||||
goto Exit;
|
||||
|
||||
/* Note: just record values; consistency is checked later */
|
||||
/* by cf2_buildBlendVector when it consumes vstore */
|
||||
|
||||
if ( FT_READ_USHORT( data->regionIdxCount ) )
|
||||
goto Exit;
|
||||
if ( FT_NEW_ARRAY( data->regionIndices, data->regionIdxCount ) )
|
||||
goto Exit;
|
||||
for ( j=0; j<data->regionIdxCount; j++ )
|
||||
{
|
||||
if ( FT_READ_USHORT( data->regionIndices[j] ) )
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
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 */
|
||||
|
||||
/* compute expected number of operands for this blend */
|
||||
FT_UInt numOperands = (FT_UInt)(numBlends * blend->lenBV);
|
||||
FT_UInt count = (FT_UInt)( 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 */
|
||||
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 = 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];
|
||||
|
||||
/* 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_ASSERT( lenNDV == 0 || NDV );
|
||||
|
||||
blend->builtBV = FALSE;
|
||||
|
||||
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(( " build 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 )
|
||||
{
|
||||
|
@ -1305,26 +1724,110 @@
|
|||
}
|
||||
|
||||
|
||||
/* 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;
|
||||
FT_UInt stackSize;
|
||||
|
||||
if ( top->private_offset == 0 || top->private_size == 0 )
|
||||
goto Exit2; /* no private DICT, do nothing */
|
||||
|
||||
/* 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 ) );
|
||||
|
||||
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;
|
||||
|
||||
stackSize = font->cff2 ? font->top_font.font_dict.maxstack :
|
||||
CFF_MAX_STACK_DEPTH + 1;
|
||||
|
||||
if ( cff_parser_init( &parser,
|
||||
font->cff2 ? CFF2_CODE_PRIVATE : CFF_CODE_PRIVATE,
|
||||
priv,
|
||||
font->library,
|
||||
stackSize,
|
||||
top->num_designs,
|
||||
top->num_axes ) )
|
||||
goto Exit;
|
||||
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:
|
||||
/* clean up */
|
||||
cff_blend_clear( subfont ); /* clear blend stack */
|
||||
cff_parser_done( &parser ); /* free parser stack */
|
||||
|
||||
Exit2:
|
||||
/* no clean up (parser not inited) */
|
||||
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_Library library,
|
||||
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;
|
||||
|
||||
CFF_FontRecDict top = &subfont->font_dict;
|
||||
CFF_Private priv = &subfont->private_dict;
|
||||
FT_Bool cff2 = (code == CFF2_CODE_TOPDICT ||
|
||||
code == CFF2_CODE_FONTDICT );
|
||||
FT_UInt stackSize = cff2 ? CFF2_DEFAULT_STACK : CFF_MAX_STACK_DEPTH;
|
||||
|
||||
/* Note: we use default stack size for CFF2 Font DICT because */
|
||||
/* Top and Font DICTs are not allowed to have blend operators */
|
||||
cff_parser_init( &parser,
|
||||
CFF_CODE_TOPDICT,
|
||||
&font->font_dict,
|
||||
code,
|
||||
&subfont->font_dict,
|
||||
library,
|
||||
stackSize,
|
||||
0,
|
||||
0 );
|
||||
|
||||
|
@ -1352,14 +1855,30 @@
|
|||
top->cid_ordering = 0xFFFFU;
|
||||
top->cid_font_name = 0xFFFFU;
|
||||
|
||||
error = cff_index_access_element( idx, font_index, &dict, &dict_len );
|
||||
/* set default stack size */
|
||||
top->maxstack = cff2 ? CFF2_DEFAULT_STACK : 48;
|
||||
|
||||
if ( idx->count ) /* count is nonzero for a real index */
|
||||
error = cff_index_access_element( idx, font_index, &dict, &dict_len );
|
||||
else
|
||||
{
|
||||
/* cff2 has a fake top dict index. simulate cff_index_access_element */
|
||||
/* Note: macros implicitly use "stream" and set "error" */
|
||||
if ( !FT_STREAM_SEEK( idx->data_offset ) )
|
||||
FT_FRAME_EXTRACT( idx->data_size, dict );
|
||||
dict_len = idx->data_size;
|
||||
}
|
||||
if ( !error )
|
||||
{
|
||||
FT_TRACE4(( " top dictionary:\n" ));
|
||||
error = cff_parser_run( &parser, dict, dict + dict_len );
|
||||
}
|
||||
|
||||
cff_index_forget_element( idx, &dict );
|
||||
/* clean up regardless of error */
|
||||
if ( idx->count )
|
||||
cff_index_forget_element( idx, &dict );
|
||||
else
|
||||
FT_FRAME_RELEASE( dict );
|
||||
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
@ -1368,40 +1887,13 @@
|
|||
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,
|
||||
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. */
|
||||
error = cff_load_private_dict( font, subfont, 0, 0 );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
/* read the local subrs, if any */
|
||||
if ( priv->local_subrs_offset )
|
||||
|
@ -1410,17 +1902,19 @@
|
|||
priv->local_subrs_offset ) )
|
||||
goto Exit;
|
||||
|
||||
error = cff_index_init( &font->local_subrs_index, stream, 1 );
|
||||
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;
|
||||
}
|
||||
|
||||
Exit:
|
||||
cff_parser_done( &parser ); /* free parser stack */
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -1433,6 +1927,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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1442,18 +1939,18 @@
|
|||
FT_Stream stream,
|
||||
FT_Int face_index,
|
||||
CFF_Font font,
|
||||
FT_Bool pure_cff )
|
||||
FT_Bool pure_cff,
|
||||
FT_Bool cff2 )
|
||||
{
|
||||
static const FT_Frame_Field cff_header_fields[] =
|
||||
{
|
||||
#undef FT_STRUCTURE
|
||||
#define FT_STRUCTURE CFF_FontRec
|
||||
|
||||
FT_FRAME_START( 4 ),
|
||||
FT_FRAME_START( 3 ),
|
||||
FT_FRAME_BYTE( version_major ),
|
||||
FT_FRAME_BYTE( version_minor ),
|
||||
FT_FRAME_BYTE( header_size ),
|
||||
FT_FRAME_BYTE( absolute_offsize ),
|
||||
FT_FRAME_END
|
||||
};
|
||||
|
||||
|
@ -1468,43 +1965,81 @@
|
|||
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 != 1 ||
|
||||
font->header_size < 4 ||
|
||||
font->absolute_offsize > 4 )
|
||||
if ( cff2 )
|
||||
{
|
||||
FT_TRACE2(( " not a CFF font header\n" ));
|
||||
error = FT_THROW( Unknown_File_Format );
|
||||
goto Exit;
|
||||
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_SKIP( font->header_size - 4 ) )
|
||||
if ( FT_STREAM_SEEK( base_offset + font->header_size ) )
|
||||
goto Exit;
|
||||
|
||||
/* read the name, top dict, string and global subrs index */
|
||||
if ( FT_SET_ERROR( cff_index_init( &font->name_index,
|
||||
stream, 0 ) ) ||
|
||||
if ( cff2 )
|
||||
{
|
||||
/* For CFF2, the top dict data immediately follow the header */
|
||||
/* and the length is stored in the header offSize field */
|
||||
/* there is no index for it. */
|
||||
/* use the font_dict_index to save the current position and */
|
||||
/* length of data, but leave count at zero as an indicator */
|
||||
FT_ZERO( &font->font_dict_index );
|
||||
font->font_dict_index.data_offset = FT_STREAM_POS();
|
||||
font->font_dict_index.data_size = font->top_dict_length;
|
||||
|
||||
/* skip the top dict data for now, we'll parse it later */
|
||||
if ( FT_STREAM_SKIP( font->top_dict_length ) )
|
||||
goto Exit;
|
||||
|
||||
/* next, read the global subrs index */
|
||||
if ( FT_SET_ERROR( cff_index_init( &font->global_subrs_index,
|
||||
stream, 1, cff2 ) ) )
|
||||
goto Exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* for CFF, read the name, top dict, string and global subrs index */
|
||||
if ( FT_SET_ERROR( cff_index_init( &font->name_index,
|
||||
stream, 0, cff2 ) ) ||
|
||||
FT_SET_ERROR( cff_index_init( &font->font_dict_index,
|
||||
stream, 0 ) ) ||
|
||||
stream, 0, cff2 ) ) ||
|
||||
FT_SET_ERROR( cff_index_init( &string_index,
|
||||
stream, 1 ) ) ||
|
||||
stream, 1, cff2 ) ) ||
|
||||
FT_SET_ERROR( cff_index_init( &font->global_subrs_index,
|
||||
stream, 1 ) ) ||
|
||||
stream, 1, cff2 ) ) ||
|
||||
FT_SET_ERROR( cff_index_get_pointers( &string_index,
|
||||
&font->strings,
|
||||
&font->string_pool,
|
||||
&font->string_pool_size ) ) )
|
||||
goto Exit;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
font->num_strings = string_index.count;
|
||||
|
||||
|
@ -1550,34 +2085,48 @@
|
|||
subfont_index,
|
||||
stream,
|
||||
base_offset,
|
||||
library );
|
||||
library,
|
||||
cff2 ? CFF2_CODE_TOPDICT : CFF_CODE_TOPDICT,
|
||||
font );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
if ( FT_STREAM_SEEK( base_offset + dict->charstrings_offset ) )
|
||||
goto Exit;
|
||||
|
||||
error = cff_index_init( &font->charstrings_index, stream, 0 );
|
||||
error = cff_index_init( &font->charstrings_index, stream, 0, cff2 );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
/* now, check for a CID font */
|
||||
if ( dict->cid_registry != 0xFFFFU )
|
||||
/* now, check for a CID or CFF2 font */
|
||||
if ( dict->cid_registry != 0xFFFFU ||
|
||||
cff2 )
|
||||
{
|
||||
CFF_IndexRec fd_index;
|
||||
CFF_SubFont sub = NULL;
|
||||
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 ) )
|
||||
goto Exit;
|
||||
|
||||
error = cff_index_init( &fd_index, stream, 0 );
|
||||
error = cff_index_init( &fd_index, stream, 0, cff2 );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
/* Font Dicts are not limited to 256 for CFF2 */
|
||||
/* TODO: support this for CFF2 */
|
||||
if ( fd_index.count > CFF_MAX_CID_FONTS )
|
||||
{
|
||||
FT_TRACE0(( "cff_font_load: FD array too large in CID font\n" ));
|
||||
|
@ -1599,12 +2148,16 @@
|
|||
sub = font->subfonts[idx];
|
||||
FT_TRACE4(( "parsing subfont %u\n", idx ));
|
||||
error = cff_subfont_load( sub, &fd_index, idx,
|
||||
stream, base_offset, library );
|
||||
stream, base_offset, library,
|
||||
cff2 ? CFF2_CODE_FONTDICT : CFF_CODE_TOPDICT,
|
||||
font );
|
||||
if ( error )
|
||||
goto Fail_CID;
|
||||
}
|
||||
|
||||
/* now load the FD Select array */
|
||||
/* CFF2 omits FDSelect if there's only one FD */
|
||||
if ( !cff2 || fd_index.count > 1 )
|
||||
error = CFF_Load_FD_Select( &font->fd_select,
|
||||
font->charstrings_index.count,
|
||||
stream,
|
||||
|
@ -1636,7 +2189,7 @@
|
|||
goto Exit;
|
||||
|
||||
/* read the Charset and Encoding tables if available */
|
||||
if ( font->num_glyphs > 0 )
|
||||
if ( !cff2 && font->num_glyphs > 0 )
|
||||
{
|
||||
FT_Bool invert = FT_BOOL( dict->cid_registry != 0xFFFFU && pure_cff );
|
||||
|
||||
|
@ -1684,7 +2237,7 @@
|
|||
cff_index_done( &font->charstrings_index );
|
||||
|
||||
/* release font dictionaries, but only if working with */
|
||||
/* a CID keyed CFF font */
|
||||
/* a CID keyed CFF font or a CFF2 font */
|
||||
if ( font->num_subfonts > 0 )
|
||||
{
|
||||
for ( idx = 0; idx < font->num_subfonts; idx++ )
|
||||
|
@ -1696,6 +2249,7 @@
|
|||
|
||||
cff_encoding_done( &font->encoding );
|
||||
cff_charset_done( &font->charset, font->stream );
|
||||
cff_vstore_done( &font->vstore, memory );
|
||||
|
||||
cff_subfont_done( memory, &font->top_font );
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include <ft2build.h>
|
||||
#include "cfftypes.h"
|
||||
#include "cffparse.h"
|
||||
|
||||
|
||||
FT_BEGIN_HEADER
|
||||
|
@ -64,7 +65,8 @@ FT_BEGIN_HEADER
|
|||
FT_Stream stream,
|
||||
FT_Int face_index,
|
||||
CFF_Font font,
|
||||
FT_Bool pure_cff );
|
||||
FT_Bool pure_cff,
|
||||
FT_Bool cff2 );
|
||||
|
||||
FT_LOCAL( void )
|
||||
cff_font_done( CFF_Font font );
|
||||
|
@ -74,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
|
||||
|
||||
|
|
|
@ -491,6 +491,7 @@
|
|||
FT_Service_PsCMaps psnames;
|
||||
PSHinter_Service pshinter;
|
||||
FT_Bool pure_cff = 1;
|
||||
FT_Bool cff2 = 0;
|
||||
FT_Bool sfnt_format = 0;
|
||||
FT_Library library = cffface->driver->root.library;
|
||||
|
||||
|
@ -554,9 +555,22 @@
|
|||
}
|
||||
|
||||
/* now load the CFF part of the file */
|
||||
error = face->goto_table( face, TTAG_CFF, stream, 0 );
|
||||
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
|
||||
/* give priority to CFF2 */
|
||||
error = face->goto_table( face, TTAG_CFF2, stream, 0 );
|
||||
if ( !error )
|
||||
{
|
||||
cff2 = 1;
|
||||
face->isCFF2 = cff2;
|
||||
}
|
||||
if ( FT_ERR_EQ( error, Table_Missing ) )
|
||||
#endif
|
||||
{
|
||||
error = face->goto_table( face, TTAG_CFF, stream, 0 );
|
||||
}
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -579,7 +593,7 @@
|
|||
goto Exit;
|
||||
|
||||
face->extra.data = cff;
|
||||
error = cff_font_load( library, stream, face_index, cff, pure_cff );
|
||||
error = cff_font_load( library, stream, face_index, cff, pure_cff, cff2 );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
|
@ -1079,6 +1093,11 @@
|
|||
FT_FREE( face->extra.data );
|
||||
}
|
||||
}
|
||||
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
|
||||
tt_done_blend( memory, face->blend );
|
||||
face->blend = NULL;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "cfferrs.h"
|
||||
#include "cffpic.h"
|
||||
#include "cffgload.h"
|
||||
#include "cffload.h"
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
|
@ -36,22 +37,48 @@
|
|||
#define FT_COMPONENT trace_cffparse
|
||||
|
||||
|
||||
FT_LOCAL_DEF( void )
|
||||
FT_LOCAL_DEF( FT_Error )
|
||||
cff_parser_init( CFF_Parser parser,
|
||||
FT_UInt code,
|
||||
void* object,
|
||||
FT_Library library,
|
||||
FT_UInt stackSize,
|
||||
FT_UShort num_designs,
|
||||
FT_UShort num_axes )
|
||||
{
|
||||
FT_Memory memory = library->memory; /* for FT_NEW_ARRAY */
|
||||
FT_Error error; /* for FT_NEW_ARRAY */
|
||||
|
||||
FT_MEM_ZERO( parser, sizeof ( *parser ) );
|
||||
|
||||
parser->top = parser->stack;
|
||||
/*parser->top = parser->stack;*/
|
||||
parser->object_code = code;
|
||||
parser->object = object;
|
||||
parser->library = library;
|
||||
parser->num_designs = num_designs;
|
||||
parser->num_axes = num_axes;
|
||||
|
||||
/* allocate the stack buffer */
|
||||
if ( FT_NEW_ARRAY( parser->stack, stackSize ) )
|
||||
{
|
||||
FT_FREE( parser->stack );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
parser->stackSize = stackSize;
|
||||
parser->top = parser->stack; /* empty stack */
|
||||
|
||||
Exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
FT_LOCAL_DEF( void )
|
||||
cff_parser_done( CFF_Parser parser )
|
||||
{
|
||||
FT_Memory memory = parser->library->memory; /* for FT_FREE */
|
||||
|
||||
FT_FREE( parser->stack );
|
||||
}
|
||||
|
||||
|
||||
|
@ -383,7 +410,6 @@
|
|||
result = -result;
|
||||
|
||||
return result;
|
||||
|
||||
Overflow:
|
||||
result = 0x7FFFFFFFL;
|
||||
FT_TRACE4(( "!!!OVERFLOW:!!!" ));
|
||||
|
@ -403,23 +429,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 +483,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 +505,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 +582,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 +679,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 +711,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 +720,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 +765,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 +802,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 ));
|
||||
|
@ -782,6 +821,105 @@
|
|||
return error;
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
/* 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 );
|
||||
|
||||
if ( !priv || !priv->subfont )
|
||||
{
|
||||
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 ) )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* maxstack operator increases parser and operand stacks for CFF2 */
|
||||
static FT_Error
|
||||
cff_parse_maxstack( CFF_Parser parser )
|
||||
{
|
||||
/* maxstack operator can only be used in a Top DICT */
|
||||
CFF_FontRecDict dict = (CFF_FontRecDict)parser->object;
|
||||
FT_Byte** data = parser->stack;
|
||||
FT_Error error = FT_Err_Ok;
|
||||
|
||||
if ( !dict )
|
||||
{
|
||||
error = FT_ERR( Invalid_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
dict->maxstack = (FT_UInt)cff_parse_num( parser, data++ );
|
||||
if ( dict->maxstack > CFF2_MAX_STACK )
|
||||
dict->maxstack = CFF2_MAX_STACK;
|
||||
if ( dict->maxstack < CFF2_DEFAULT_STACK )
|
||||
dict->maxstack = CFF2_DEFAULT_STACK;
|
||||
|
||||
FT_TRACE4(( " %d\n", dict->maxstack ));
|
||||
error = FT_Err_Ok;
|
||||
|
||||
Exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define CFF_FIELD_NUM( code, name, id ) \
|
||||
CFF_FIELD( code, name, id, cff_kind_num )
|
||||
|
@ -794,9 +932,6 @@
|
|||
#define CFF_FIELD_BOOL( code, name, id ) \
|
||||
CFF_FIELD( code, name, id, cff_kind_bool )
|
||||
|
||||
#define CFFCODE_TOPDICT 0x1000
|
||||
#define CFFCODE_PRIVATE 0x2000
|
||||
|
||||
|
||||
#ifndef FT_CONFIG_OPTION_PIC
|
||||
|
||||
|
@ -817,6 +952,15 @@
|
|||
0, 0 \
|
||||
},
|
||||
|
||||
#define CFF_FIELD_BLEND( code, id ) \
|
||||
{ \
|
||||
cff_kind_blend, \
|
||||
code | CFFCODE, \
|
||||
0, 0, \
|
||||
cff_parse_blend, \
|
||||
0, 0 \
|
||||
},
|
||||
|
||||
#define CFF_FIELD( code, name, id, kind ) \
|
||||
{ \
|
||||
kind, \
|
||||
|
@ -860,6 +1004,16 @@
|
|||
id \
|
||||
},
|
||||
|
||||
#define CFF_FIELD_BLEND( code, id ) \
|
||||
{ \
|
||||
cff_kind_blend, \
|
||||
code | CFFCODE, \
|
||||
0, 0, \
|
||||
cff_parse_blend, \
|
||||
0, 0, \
|
||||
id \
|
||||
},
|
||||
|
||||
#define CFF_FIELD( code, name, id, kind ) \
|
||||
{ \
|
||||
kind, \
|
||||
|
@ -1067,11 +1221,13 @@
|
|||
{
|
||||
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 )
|
||||
if ( (FT_UInt)( parser->top - parser->stack ) >= parser->stackSize )
|
||||
goto Stack_Overflow;
|
||||
|
||||
*parser->top++ = p;
|
||||
|
@ -1162,7 +1318,7 @@
|
|||
FT_Bool neg;
|
||||
|
||||
|
||||
if ( parser->top - parser->stack >= CFF_MAX_STACK_DEPTH )
|
||||
if ( parser->top - parser->stack >= parser->stackSize )*/
|
||||
goto Stack_Overflow;
|
||||
|
||||
*parser->top++ = q;
|
||||
|
@ -1280,15 +1436,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 )
|
||||
|
@ -1357,7 +1513,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):
|
||||
|
@ -1386,7 +1542,7 @@
|
|||
}
|
||||
break;
|
||||
|
||||
default: /* callback */
|
||||
default: /* callback or blend */
|
||||
error = field->reader( parser );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
@ -1400,7 +1556,9 @@
|
|||
|
||||
Found:
|
||||
/* clear stack */
|
||||
parser->top = parser->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;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
|
|
@ -28,10 +28,17 @@
|
|||
FT_BEGIN_HEADER
|
||||
|
||||
|
||||
#define CFF_MAX_STACK_DEPTH 96
|
||||
/* CFF uses constant parser stack size */
|
||||
/* CFF2 can increase from default 193 */
|
||||
#define CFF_MAX_STACK_DEPTH 96
|
||||
#define CFF2_MAX_STACK 513
|
||||
#define CFF2_DEFAULT_STACK 193
|
||||
|
||||
#define CFF_CODE_TOPDICT 0x1000
|
||||
#define CFF_CODE_PRIVATE 0x2000
|
||||
#define CFF_CODE_TOPDICT 0x1000
|
||||
#define CFF_CODE_PRIVATE 0x2000
|
||||
#define CFF2_CODE_TOPDICT 0x3000
|
||||
#define CFF2_CODE_FONTDICT 0x4000
|
||||
#define CFF2_CODE_PRIVATE 0x5000
|
||||
|
||||
|
||||
typedef struct CFF_ParserRec_
|
||||
|
@ -41,8 +48,9 @@ FT_BEGIN_HEADER
|
|||
FT_Byte* limit;
|
||||
FT_Byte* cursor;
|
||||
|
||||
FT_Byte* stack[CFF_MAX_STACK_DEPTH + 1];
|
||||
FT_Byte** stack;
|
||||
FT_Byte** top;
|
||||
FT_UInt stackSize; /* allocated size */
|
||||
|
||||
FT_UInt object_code;
|
||||
void* object;
|
||||
|
@ -53,14 +61,18 @@ FT_BEGIN_HEADER
|
|||
} CFF_ParserRec, *CFF_Parser;
|
||||
|
||||
|
||||
FT_LOCAL( void )
|
||||
FT_LOCAL( FT_Error )
|
||||
cff_parser_init( CFF_Parser parser,
|
||||
FT_UInt code,
|
||||
void* object,
|
||||
FT_Library library,
|
||||
FT_UInt stackSize,
|
||||
FT_UShort num_designs,
|
||||
FT_UShort num_axes );
|
||||
|
||||
FT_LOCAL( void )
|
||||
cff_parser_done( CFF_Parser parser );
|
||||
|
||||
FT_LOCAL( FT_Error )
|
||||
cff_parser_run( CFF_Parser parser,
|
||||
FT_Byte* start,
|
||||
|
@ -77,6 +89,7 @@ FT_BEGIN_HEADER
|
|||
cff_kind_bool,
|
||||
cff_kind_delta,
|
||||
cff_kind_callback,
|
||||
cff_kind_blend,
|
||||
|
||||
cff_kind_max /* do not remove */
|
||||
};
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#define CFF_SERVICE_CID_INFO_GET cff_service_cid_info
|
||||
#define CFF_SERVICE_PROPERTIES_GET cff_service_properties
|
||||
#define CFF_SERVICES_GET cff_services
|
||||
#define CFF_SERVICE_MULTI_MASTERS_GET cff_service_multi_masters
|
||||
#define CFF_CMAP_ENCODING_CLASS_REC_GET cff_cmap_encoding_class_rec
|
||||
#define CFF_CMAP_UNICODE_CLASS_REC_GET cff_cmap_unicode_class_rec
|
||||
#define CFF_FIELD_HANDLERS_GET cff_field_handlers
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#define FT_STRUCTURE CFF_FontRecDictRec
|
||||
|
||||
#undef CFFCODE
|
||||
#define CFFCODE CFFCODE_TOPDICT
|
||||
#define CFFCODE CFF_CODE_TOPDICT
|
||||
|
||||
CFF_FIELD_STRING ( 0, version, "Version" )
|
||||
CFF_FIELD_STRING ( 1, notice, "Notice" )
|
||||
|
@ -78,7 +78,7 @@
|
|||
#undef FT_STRUCTURE
|
||||
#define FT_STRUCTURE CFF_PrivateRec
|
||||
#undef CFFCODE
|
||||
#define CFFCODE CFFCODE_PRIVATE
|
||||
#define CFFCODE CFF_CODE_PRIVATE
|
||||
|
||||
CFF_FIELD_DELTA ( 6, blue_values, 14, "BlueValues" )
|
||||
CFF_FIELD_DELTA ( 7, other_blues, 10, "OtherBlues" )
|
||||
|
@ -101,5 +101,50 @@
|
|||
CFF_FIELD_NUM ( 20, default_width, "defaultWidthX" )
|
||||
CFF_FIELD_NUM ( 21, nominal_width, "nominalWidthX" )
|
||||
|
||||
#undef FT_STRUCTURE
|
||||
#define FT_STRUCTURE CFF_FontRecDictRec
|
||||
|
||||
#undef CFFCODE
|
||||
#define CFFCODE CFF2_CODE_TOPDICT
|
||||
|
||||
CFF_FIELD_CALLBACK( 0x107, font_matrix, "FontMatrix" )
|
||||
CFF_FIELD_NUM ( 17, charstrings_offset, "CharStrings" )
|
||||
CFF_FIELD_NUM ( 0x124, cid_fd_array_offset, "FDArray" )
|
||||
CFF_FIELD_NUM ( 0x125, cid_fd_select_offset, "FDSelect" )
|
||||
CFF_FIELD_NUM ( 24, vstore_offset, "vstore" )
|
||||
CFF_FIELD_CALLBACK( 25, maxstack, "maxstack" )
|
||||
|
||||
#undef FT_STRUCTURE
|
||||
#define FT_STRUCTURE CFF_FontRecDictRec
|
||||
|
||||
#undef CFFCODE
|
||||
#define CFFCODE CFF2_CODE_FONTDICT
|
||||
|
||||
CFF_FIELD_CALLBACK( 18, private_dict, "Private" )
|
||||
CFF_FIELD_CALLBACK( 0x107, font_matrix, "FontMatrix" )
|
||||
|
||||
#undef FT_STRUCTURE
|
||||
#define FT_STRUCTURE CFF_PrivateRec
|
||||
|
||||
#undef CFFCODE
|
||||
#define CFFCODE CFF2_CODE_PRIVATE
|
||||
|
||||
CFF_FIELD_DELTA ( 6, blue_values, 14, "BlueValues" )
|
||||
CFF_FIELD_DELTA ( 7, other_blues, 10, "OtherBlues" )
|
||||
CFF_FIELD_DELTA ( 8, family_blues, 14, "FamilyBlues" )
|
||||
CFF_FIELD_DELTA ( 9, family_other_blues, 10, "FamilyOtherBlues" )
|
||||
CFF_FIELD_FIXED_1000( 0x109, blue_scale, "BlueScale" )
|
||||
CFF_FIELD_NUM ( 0x10A, blue_shift, "BlueShift" )
|
||||
CFF_FIELD_NUM ( 0x10B, blue_fuzz, "BlueFuzz" )
|
||||
CFF_FIELD_NUM ( 10, standard_width, "StdHW" )
|
||||
CFF_FIELD_NUM ( 11, standard_height, "StdVW" )
|
||||
CFF_FIELD_DELTA ( 0x10C, snap_widths, 13, "StemSnapH" )
|
||||
CFF_FIELD_DELTA ( 0x10D, snap_heights, 13, "StemSnapV" )
|
||||
CFF_FIELD_NUM ( 0x111, language_group, "LanguageGroup" )
|
||||
CFF_FIELD_FIXED ( 0x112, expansion_factor, "ExpansionFactor" )
|
||||
CFF_FIELD_CALLBACK ( 22, vsindex, "vsindex" )
|
||||
CFF_FIELD_BLEND ( 23, "blend" )
|
||||
CFF_FIELD_NUM ( 19, local_subrs_offset, "Subrs" )
|
||||
|
||||
|
||||
/* END */
|
||||
|
|
|
@ -64,6 +64,7 @@ FT_BEGIN_HEADER
|
|||
{
|
||||
FT_Stream stream;
|
||||
FT_ULong start;
|
||||
FT_UInt hdr_size;
|
||||
FT_UInt count;
|
||||
FT_Byte off_size;
|
||||
FT_ULong data_offset;
|
||||
|
@ -101,6 +102,62 @@ FT_BEGIN_HEADER
|
|||
|
||||
} CFF_CharsetRec, *CFF_Charset;
|
||||
|
||||
typedef struct CFF_VarData_
|
||||
{
|
||||
/* FT_UInt itemCount; not used; always zero */
|
||||
/* FT_UInt shortDeltaCount; not used; always zero */
|
||||
FT_UInt regionIdxCount; /* # regions in this var data */
|
||||
FT_UInt* regionIndices; /* array of regionCount indices */
|
||||
/* these index the varRegionList */
|
||||
} CFF_VarData;
|
||||
|
||||
typedef struct CFF_AxisCoords_ /* contribution of one axis to a region */
|
||||
{
|
||||
FT_Fixed startCoord;
|
||||
FT_Fixed peakCoord; /* zero peak means no effect (factor = 1) */
|
||||
FT_Fixed endCoord;
|
||||
} CFF_AxisCoords;
|
||||
|
||||
typedef struct CFF_VarRegion_
|
||||
{
|
||||
CFF_AxisCoords* axisList; /* array of axisCount records */
|
||||
} CFF_VarRegion;
|
||||
|
||||
typedef struct CFF_VstoreRec_
|
||||
{
|
||||
FT_UInt dataCount;
|
||||
CFF_VarData* varData; /* array of dataCount records */
|
||||
/* vsindex indexes this array */
|
||||
FT_UShort axisCount;
|
||||
FT_UInt regionCount; /* total # regions defined */
|
||||
CFF_VarRegion* varRegionList;
|
||||
|
||||
} CFF_VStoreRec, *CFF_VStore;
|
||||
|
||||
/* forward reference */
|
||||
typedef struct CFF_FontRec_ *CFF_Font;
|
||||
|
||||
typedef struct CFF_BlendRec_
|
||||
{
|
||||
/* 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 */
|
||||
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_
|
||||
{
|
||||
|
@ -151,9 +208,16 @@ FT_BEGIN_HEADER
|
|||
FT_UShort num_designs;
|
||||
FT_UShort num_axes;
|
||||
|
||||
/* fields for CFF2 */
|
||||
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;
|
||||
|
@ -186,6 +250,10 @@ FT_BEGIN_HEADER
|
|||
FT_Pos default_width;
|
||||
FT_Pos nominal_width;
|
||||
|
||||
/* fields for CFF2 */
|
||||
FT_UInt vsindex;
|
||||
CFF_SubFont subfont;
|
||||
|
||||
} CFF_PrivateRec, *CFF_Private;
|
||||
|
||||
|
||||
|
@ -213,6 +281,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 */
|
||||
|
||||
|
@ -224,16 +309,20 @@ 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;
|
||||
|
||||
FT_Byte version_major;
|
||||
FT_Byte version_minor;
|
||||
FT_Byte header_size;
|
||||
FT_Byte absolute_offsize;
|
||||
|
||||
FT_UInt top_dict_length; /* cff2 only */
|
||||
|
||||
FT_Bool cff2;
|
||||
|
||||
CFF_IndexRec name_index;
|
||||
CFF_IndexRec top_dict_index;
|
||||
|
@ -280,6 +369,8 @@ FT_BEGIN_HEADER
|
|||
/* since version 2.4.12 */
|
||||
FT_Generic cf2_instance;
|
||||
|
||||
CFF_VStoreRec vstore; /* parsed vstore structure */
|
||||
|
||||
} CFF_FontRec, *CFF_Font;
|
||||
|
||||
|
||||
|
|
|
@ -151,7 +151,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
static FT_Error
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
sfnt_get_glyph_name( TT_Face face,
|
||||
FT_UInt glyph_index,
|
||||
FT_Pointer buffer,
|
||||
|
@ -169,7 +169,7 @@
|
|||
}
|
||||
|
||||
|
||||
static FT_UInt
|
||||
FT_EXPORT_DEF( FT_UInt )
|
||||
sfnt_get_name_index( TT_Face face,
|
||||
FT_String* glyph_name )
|
||||
{
|
||||
|
|
|
@ -1085,10 +1085,12 @@
|
|||
#ifdef FT_CONFIG_OPTION_INCREMENTAL
|
||||
has_outline = FT_BOOL( face->root.internal->incremental_interface != 0 ||
|
||||
tt_face_lookup_table( face, TTAG_glyf ) != 0 ||
|
||||
tt_face_lookup_table( face, TTAG_CFF ) != 0 );
|
||||
tt_face_lookup_table( face, TTAG_CFF ) != 0 ||
|
||||
tt_face_lookup_table( face, TTAG_CFF2 ));
|
||||
#else
|
||||
has_outline = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) != 0 ||
|
||||
tt_face_lookup_table( face, TTAG_CFF ) != 0 );
|
||||
tt_face_lookup_table( face, TTAG_CFF ) != 0 ||
|
||||
tt_face_lookup_table( face, TTAG_CFF2 ));
|
||||
#endif
|
||||
|
||||
is_apple_sbit = 0;
|
||||
|
@ -1331,6 +1333,9 @@
|
|||
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;
|
||||
#endif
|
||||
|
||||
root->face_flags = flags;
|
||||
|
|
|
@ -22,6 +22,10 @@
|
|||
#include FT_TRUETYPE_TAGS_H
|
||||
#include "ttmtx.h"
|
||||
|
||||
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
|
||||
#include "../truetype/ttgxvar.h"
|
||||
#endif
|
||||
|
||||
#include "sferrors.h"
|
||||
|
||||
|
||||
|
@ -274,6 +278,12 @@
|
|||
*abearing = 0;
|
||||
*aadvance = 0;
|
||||
}
|
||||
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
|
||||
/* TODO: handle VVAR and LSB */
|
||||
if ( !vertical )
|
||||
tt_adjust_advance( face, gindex, aadvance );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -449,7 +449,9 @@
|
|||
(FT_Set_MM_Design_Func) NULL, /* set_mm_design */
|
||||
(FT_Set_MM_Blend_Func) TT_Set_MM_Blend, /* set_mm_blend */
|
||||
(FT_Get_MM_Var_Func) TT_Get_MM_Var, /* get_mm_var */
|
||||
(FT_Set_Var_Design_Func)TT_Set_Var_Design ) /* set_var_design */
|
||||
(FT_Set_Var_Design_Func)TT_Set_Var_Design, /* set_var_design */
|
||||
(FT_Get_Var_Design_Func)TT_Get_Var_Design, /* get_var_design */
|
||||
(FT_Get_Var_Blend_Func) TT_Get_Var_Blend ) /* get_var_blend */
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -392,6 +392,422 @@
|
|||
FT_FRAME_EXIT();
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Function> */
|
||||
/* ft_var_load_hvar */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* Parse the `HVAR' table if present. It need not be, so we return */
|
||||
/* nothing. */
|
||||
/* On success, blend->hvar_checked is TRUE */
|
||||
/* Some memory may remain allocated on error (hvar_checked FALSE) */
|
||||
/* Memory is always freed in tt_done_blend. */
|
||||
/* */
|
||||
/* <InOut> */
|
||||
/* face :: The font face. */
|
||||
/* */
|
||||
/* */
|
||||
|
||||
/* some macros we need */
|
||||
#define FT_fdot14ToFixed( x ) \
|
||||
(((FT_Fixed)((FT_Int16)(x))) << 2 )
|
||||
|
||||
#define FT_FIXED_ONE ((FT_Fixed)0x10000)
|
||||
#define FT_intToFixed( i ) \
|
||||
( (FT_Fixed)( (FT_UInt32)(i) << 16 ) )
|
||||
#define FT_fixedToInt( x ) \
|
||||
( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) )
|
||||
|
||||
static void
|
||||
ft_var_load_hvar( TT_Face face )
|
||||
{
|
||||
FT_Stream stream = FT_FACE_STREAM( face );
|
||||
FT_Memory memory = stream->memory;
|
||||
GX_Blend blend = face->blend;
|
||||
FT_Error error;
|
||||
FT_UShort majorVersion;
|
||||
FT_UShort minorVersion;
|
||||
FT_ULong table_len;
|
||||
FT_ULong table_offset;
|
||||
FT_ULong store_offset;
|
||||
FT_ULong map_offset;
|
||||
FT_ULong * dataOffsetArray = NULL;
|
||||
|
||||
|
||||
FT_TRACE2(( "HVAR " ));
|
||||
|
||||
/* if we allocated the table, assume we've already tried to parse it */
|
||||
if ( face->blend->hvar_table )
|
||||
return;
|
||||
|
||||
error = face->goto_table( face, TTAG_HVAR, stream, &table_len );
|
||||
if ( error )
|
||||
{
|
||||
FT_TRACE2(( "is missing\n" ));
|
||||
return;
|
||||
}
|
||||
|
||||
table_offset = FT_STREAM_POS();
|
||||
|
||||
if ( FT_READ_USHORT( majorVersion ) ||
|
||||
FT_READ_USHORT( minorVersion ) )
|
||||
goto Exit;
|
||||
if ( majorVersion != 1 )
|
||||
{
|
||||
FT_TRACE2(( "bad table version %d\n", majorVersion ));
|
||||
error = FT_THROW( Invalid_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if ( FT_READ_ULONG( store_offset ) ||
|
||||
FT_READ_ULONG( map_offset ) )
|
||||
goto Exit;
|
||||
|
||||
/* parse item variation store */
|
||||
{
|
||||
FT_UShort format;
|
||||
FT_ULong region_offset;
|
||||
GX_HVStore itemStore;
|
||||
FT_UInt i, j, k;
|
||||
FT_UInt shortDeltaCount;
|
||||
GX_HVarTable hvarTable;
|
||||
GX_HVarData hvarData;
|
||||
|
||||
if ( FT_STREAM_SEEK( table_offset + store_offset ) ||
|
||||
FT_READ_USHORT( format ) )
|
||||
goto Exit;
|
||||
if ( format != 1 )
|
||||
{
|
||||
FT_TRACE2(( "bad store format %d\n", format ));
|
||||
error = FT_THROW( Invalid_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if ( FT_NEW( blend->hvar_table ) ) /* allocate table at top level */
|
||||
goto Exit;
|
||||
|
||||
hvarTable = blend->hvar_table;
|
||||
itemStore = &hvarTable->itemStore;
|
||||
|
||||
/* read top level fields */
|
||||
if ( FT_READ_ULONG( region_offset ) ||
|
||||
FT_READ_USHORT( itemStore->dataCount ) )
|
||||
goto Exit;
|
||||
|
||||
/* make temporary copy of item variation data offsets */
|
||||
/* we'll parse region list first, then come back */
|
||||
if ( FT_NEW_ARRAY( dataOffsetArray, itemStore->dataCount ) )
|
||||
goto Exit;
|
||||
for ( i=0; i<itemStore->dataCount; i++ )
|
||||
{
|
||||
if ( FT_READ_ULONG( dataOffsetArray[i] ) )
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* parse array of region records (region list) */
|
||||
if ( FT_STREAM_SEEK( table_offset + store_offset + region_offset ) )
|
||||
goto Exit;
|
||||
|
||||
if ( FT_READ_USHORT( itemStore->axisCount ) ||
|
||||
FT_READ_USHORT( itemStore->regionCount ) )
|
||||
goto Exit;
|
||||
|
||||
if ( FT_NEW_ARRAY( itemStore->varRegionList, itemStore->regionCount ) )
|
||||
goto Exit;
|
||||
|
||||
for ( i=0; i<itemStore->regionCount; i++ )
|
||||
{
|
||||
GX_AxisCoords axisCoords;
|
||||
|
||||
if ( FT_NEW_ARRAY( itemStore->varRegionList[i].axisList, itemStore->axisCount ) )
|
||||
goto Exit;
|
||||
|
||||
axisCoords = itemStore->varRegionList[i].axisList;
|
||||
|
||||
for ( j=0; j<itemStore->axisCount; j++ )
|
||||
{
|
||||
FT_Short start, peak, end;
|
||||
|
||||
if ( FT_READ_SHORT( start ) ||
|
||||
FT_READ_SHORT( peak ) ||
|
||||
FT_READ_SHORT( end ) )
|
||||
goto Exit;
|
||||
axisCoords[j].startCoord = FT_fdot14ToFixed( start );
|
||||
axisCoords[j].peakCoord = FT_fdot14ToFixed( peak );
|
||||
axisCoords[j].endCoord = FT_fdot14ToFixed( end );
|
||||
}
|
||||
}
|
||||
/* end of region list parse */
|
||||
|
||||
/* use dataOffsetArray now to parse varData items */
|
||||
if ( FT_NEW_ARRAY( itemStore->varData, itemStore->dataCount ) )
|
||||
goto Exit;
|
||||
|
||||
for ( i=0; i<itemStore->dataCount; i++ )
|
||||
{
|
||||
hvarData = &itemStore->varData[i];
|
||||
|
||||
if ( FT_STREAM_SEEK( table_offset + store_offset + dataOffsetArray[i] ) )
|
||||
goto Exit;
|
||||
|
||||
if ( FT_READ_USHORT( hvarData->itemCount ) ||
|
||||
FT_READ_USHORT( shortDeltaCount ) ||
|
||||
FT_READ_USHORT( hvarData->regionIdxCount ) )
|
||||
goto Exit;
|
||||
|
||||
/* check some data consistency */
|
||||
if ( shortDeltaCount > hvarData->regionIdxCount )
|
||||
{
|
||||
FT_TRACE2(( "bad short count %d or region count %d\n",
|
||||
shortDeltaCount, hvarData->regionIdxCount ));
|
||||
error = FT_THROW( Invalid_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
if ( hvarData->regionIdxCount > itemStore->regionCount )
|
||||
{
|
||||
FT_TRACE2(( "inconsistent regionCount %d in varData[ %d ]\n",
|
||||
hvarData->regionIdxCount, i ));
|
||||
error = FT_THROW( Invalid_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* parse region indices */
|
||||
if ( FT_NEW_ARRAY( hvarData->regionIndices, hvarData->regionIdxCount ) )
|
||||
goto Exit;
|
||||
|
||||
for ( j=0; j<hvarData->regionIdxCount; j++ )
|
||||
{
|
||||
if ( FT_READ_USHORT( hvarData->regionIndices[j] ) )
|
||||
goto Exit;
|
||||
if ( hvarData->regionIndices[j] >= itemStore->regionCount )
|
||||
{
|
||||
FT_TRACE2(( "bad region index %d\n", hvarData->regionIndices[j] ));
|
||||
error = FT_THROW( Invalid_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* parse delta set */
|
||||
/* on input, deltas are ( shortDeltaCount + regionIdxCount ) bytes each */
|
||||
/* on output, deltas are expanded to regionIdxCount shorts each */
|
||||
if ( FT_NEW_ARRAY( hvarData->deltaSet, hvarData->regionIdxCount * hvarData->itemCount ) )
|
||||
goto Exit;
|
||||
|
||||
/* the delta set is stored as a 2-dimensional array of shorts */
|
||||
/* sign-extend signed bytes to signed shorts */
|
||||
for ( j=0; j<hvarData->itemCount * hvarData->regionIdxCount; )
|
||||
{
|
||||
for ( k=0; k<shortDeltaCount; k++,j++ )
|
||||
{
|
||||
/* read the short deltas */
|
||||
FT_Short delta;
|
||||
if ( FT_READ_SHORT( delta ) )
|
||||
goto Exit;
|
||||
hvarData->deltaSet[j] = delta;
|
||||
}
|
||||
for ( ; k<hvarData->regionIdxCount; k++,j++ )
|
||||
{
|
||||
/* read the (signed) byte deltas */
|
||||
FT_Char delta;
|
||||
if ( FT_READ_CHAR( delta ) )
|
||||
goto Exit;
|
||||
hvarData->deltaSet[j] = delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* end parse item variation store */
|
||||
|
||||
{
|
||||
/* parse width map */
|
||||
GX_WidthMap widthMap;
|
||||
FT_UShort format;
|
||||
FT_UInt entrySize;
|
||||
FT_UInt innerBitCount;
|
||||
FT_UInt innerIndexMask;
|
||||
FT_UInt outerBitCount;
|
||||
FT_UInt i, j;
|
||||
|
||||
widthMap = &blend->hvar_table->widthMap;
|
||||
if ( FT_READ_USHORT( format ) ||
|
||||
FT_READ_USHORT( widthMap->mapCount ) )
|
||||
goto Exit;
|
||||
|
||||
if ( format & 0xFFC0 )
|
||||
{
|
||||
FT_TRACE2(( "bad map format %d\n", format ));
|
||||
error = FT_THROW( Invalid_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
entrySize = ( ( format & 0x0030 ) >> 4 ) + 1; /* bytes per entry, 1,2,3 or 4 */
|
||||
innerBitCount = ( format & 0x000F ) + 1;
|
||||
innerIndexMask = ( 1 << innerBitCount ) - 1;
|
||||
outerBitCount = 8 * entrySize - innerBitCount;
|
||||
|
||||
if ( FT_NEW_ARRAY( widthMap->innerIndex, widthMap->mapCount ) )
|
||||
goto Exit;
|
||||
|
||||
if ( FT_NEW_ARRAY( widthMap->outerIndex, widthMap->mapCount ) )
|
||||
goto Exit;
|
||||
|
||||
for ( i=0; i<widthMap->mapCount; i++ )
|
||||
{
|
||||
FT_UInt mapData = 0;
|
||||
FT_UInt outerIndex, innerIndex;
|
||||
|
||||
/* read map data one unsigned byte at a time, big endian */
|
||||
for ( j=0; j<entrySize; j++ )
|
||||
{
|
||||
FT_Byte data;
|
||||
|
||||
if ( FT_READ_BYTE( data ) )
|
||||
goto Exit;
|
||||
mapData = ( mapData << 8 ) | data;
|
||||
}
|
||||
|
||||
outerIndex = mapData >> innerBitCount;
|
||||
if ( outerIndex >= blend->hvar_table->itemStore.dataCount )
|
||||
{
|
||||
FT_TRACE2(( "outerIndex[ %d ] == %d out of range\n",
|
||||
i, outerIndex ));
|
||||
error = FT_THROW( Invalid_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
widthMap->outerIndex[i] = outerIndex;
|
||||
|
||||
innerIndex = mapData & innerIndexMask;
|
||||
|
||||
if ( innerIndex >= blend->hvar_table->itemStore.varData[ outerIndex ].itemCount )
|
||||
{
|
||||
FT_TRACE2(( "innerIndex[ %d ] == %d out of range\n",
|
||||
i, innerIndex ));
|
||||
error = FT_THROW( Invalid_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
widthMap->innerIndex[i] = innerIndex;
|
||||
}
|
||||
|
||||
} /* end parse width map */
|
||||
|
||||
FT_TRACE2(( "loaded\n" ));
|
||||
error = FT_Err_Ok;
|
||||
|
||||
Exit:
|
||||
FT_FREE( dataOffsetArray );
|
||||
if ( error == FT_Err_Ok )
|
||||
blend->hvar_checked = TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Function> */
|
||||
/* tt_adjust_advance */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* Apply HVAR adjustment to advance width of gindex */
|
||||
/* */
|
||||
/* <In> */
|
||||
/* gindex :: The glyph */
|
||||
/* <InOut> */
|
||||
/* face :: The font face. */
|
||||
/* aadvance :: points to width value */
|
||||
/* */
|
||||
FT_EXPORT( void )
|
||||
tt_adjust_advance( TT_Face face,
|
||||
FT_UInt gindex,
|
||||
FT_UShort *aadvance )
|
||||
{
|
||||
FT_UInt innerIndex, outerIndex;
|
||||
GX_HVarData varData;
|
||||
FT_UInt master, j;
|
||||
FT_Fixed netAdjustment = 0; /* accumulated adjustment */
|
||||
FT_Fixed scaledDelta;
|
||||
FT_Short* deltaSet;
|
||||
FT_Fixed delta;
|
||||
|
||||
if ( !face->blend )
|
||||
return;
|
||||
|
||||
if ( !face->blend->hvar_checked )
|
||||
{
|
||||
/* initialize hvar table */
|
||||
ft_var_load_hvar( face );
|
||||
}
|
||||
if ( !face->blend->hvar_checked )
|
||||
return; /* HVAR parse failed */
|
||||
|
||||
if ( gindex >= face->blend->hvar_table->widthMap.mapCount )
|
||||
{
|
||||
FT_TRACE2(( "gindex %d out of range\n", gindex ));
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* trust that HVAR parser has checked indices */
|
||||
outerIndex = face->blend->hvar_table->widthMap.outerIndex[ gindex ];
|
||||
innerIndex = face->blend->hvar_table->widthMap.innerIndex[ gindex ];
|
||||
varData = &face->blend->hvar_table->itemStore.varData[ outerIndex ];
|
||||
deltaSet = &varData->deltaSet[ varData->regionIdxCount * innerIndex ];
|
||||
|
||||
/* see pseudo code from Font Variations Overview */
|
||||
/* outer loop steps through master designs to be blended */
|
||||
for ( master=0; master<varData->regionIdxCount; master++ )
|
||||
{
|
||||
FT_UInt regionIndex = varData->regionIndices[ master ];
|
||||
GX_AxisCoords axis = face->blend->hvar_table->itemStore.varRegionList[ regionIndex ].axisList;
|
||||
FT_Fixed scalar = FT_FIXED_ONE;
|
||||
|
||||
/* inner loop steps through axes in this region */
|
||||
for ( j=0; j<face->blend->hvar_table->itemStore.axisCount; j++, axis++ )
|
||||
{
|
||||
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 ( face->blend->normalizedcoords[j] < axis->startCoord || face->blend->normalizedcoords[j] > axis->endCoord )
|
||||
axisScalar = 0;
|
||||
/* calculate a proportional factor */
|
||||
else
|
||||
{
|
||||
if ( face->blend->normalizedcoords[j] == axis->peakCoord )
|
||||
axisScalar = FT_FIXED_ONE;
|
||||
else if ( face->blend->normalizedcoords[j] < axis->peakCoord )
|
||||
axisScalar = FT_DivFix( face->blend->normalizedcoords[j] - axis->startCoord,
|
||||
axis->peakCoord - axis->startCoord );
|
||||
else
|
||||
axisScalar = FT_DivFix( axis->endCoord - face->blend->normalizedcoords[j],
|
||||
axis->endCoord - axis->peakCoord );
|
||||
}
|
||||
/* take product of all the axis scalars */
|
||||
scalar = FT_MulFix( scalar, axisScalar );
|
||||
} /* per-axis loop */
|
||||
FT_TRACE4(( ", %f ", (double)scalar / 65536 ));
|
||||
|
||||
/* get the scaled delta for this region */
|
||||
delta = FT_intToFixed( deltaSet[master] );
|
||||
scaledDelta = FT_MulFix( scalar, delta );
|
||||
|
||||
/* accumulate the adjustments from each region */
|
||||
netAdjustment = netAdjustment + scaledDelta;
|
||||
|
||||
} /* per-region loop */
|
||||
FT_TRACE4(( "]\n" ));
|
||||
|
||||
/* apply the accumulated adjustment to the default to derive the interpolated value */
|
||||
*aadvance += FT_fixedToInt( netAdjustment );
|
||||
|
||||
Exit:
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
typedef struct GX_GVar_Head_
|
||||
{
|
||||
|
@ -762,7 +1178,7 @@
|
|||
/* <Return> */
|
||||
/* FreeType error code. 0 means success. */
|
||||
/* */
|
||||
FT_LOCAL_DEF( FT_Error )
|
||||
FT_EXPORT( FT_Error )
|
||||
TT_Get_MM_Var( TT_Face face,
|
||||
FT_MM_Var* *master )
|
||||
{
|
||||
|
@ -778,6 +1194,7 @@
|
|||
FT_Var_Axis* a;
|
||||
FT_Var_Named_Style* ns;
|
||||
GX_FVar_Head fvar_head;
|
||||
FT_Bool usePsName;
|
||||
|
||||
static const FT_Frame_Field fvar_fields[] =
|
||||
{
|
||||
|
@ -824,9 +1241,14 @@
|
|||
if ( ( error = face->goto_table( face, TTAG_gvar,
|
||||
stream, &table_len ) ) != 0 )
|
||||
{
|
||||
FT_TRACE1(( "\n"
|
||||
"TT_Get_MM_Var: `gvar' table is missing\n" ));
|
||||
goto Exit;
|
||||
/* CFF2 is an alternate to gvar here */
|
||||
if ( ( error = face->goto_table( face, TTAG_CFF2,
|
||||
stream, &table_len ) ) != 0 )
|
||||
{
|
||||
FT_TRACE1(( "\n"
|
||||
"TT_Get_MM_Var: `gvar' or `CFF2' table is missing\n" ));
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ( error = face->goto_table( face, TTAG_fvar,
|
||||
|
@ -851,8 +1273,6 @@
|
|||
fvar_head.axisSize != 20 ||
|
||||
/* axisCount limit implied by 16-bit instanceSize */
|
||||
fvar_head.axisCount > 0x3FFE ||
|
||||
fvar_head.instanceSize != 4 + 4 * fvar_head.axisCount ||
|
||||
/* instanceCount limit implied by limited range of name IDs */
|
||||
fvar_head.instanceCount > 0x7EFF ||
|
||||
fvar_head.offsetToData + fvar_head.axisCount * 20U +
|
||||
fvar_head.instanceCount * fvar_head.instanceSize > table_len )
|
||||
|
@ -862,7 +1282,21 @@
|
|||
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;
|
||||
}
|
||||
FT_TRACE2(( "loaded\n" ));
|
||||
|
||||
FT_TRACE5(( "number of GX style axes: %d\n", fvar_head.axisCount ));
|
||||
|
@ -952,8 +1386,17 @@
|
|||
ns = mmvar->namedstyle;
|
||||
for ( i = 0; i < fvar_head.instanceCount; i++, ns++ )
|
||||
{
|
||||
if ( FT_FRAME_ENTER( 4L + 4L * fvar_head.axisCount ) )
|
||||
goto Exit;
|
||||
/* PostScript names add 2 bytes to the instance record size */
|
||||
if ( usePsName )
|
||||
{
|
||||
if ( FT_FRAME_ENTER( 6L + 4L * fvar_head.axisCount ) )
|
||||
goto Exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( FT_FRAME_ENTER( 4L + 4L * fvar_head.axisCount ) )
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
ns->strid = FT_GET_USHORT();
|
||||
(void) /* flags = */ FT_GET_USHORT();
|
||||
|
@ -961,6 +1404,9 @@
|
|||
for ( j = 0; j < fvar_head.axisCount; j++ )
|
||||
ns->coords[j] = FT_GET_LONG();
|
||||
|
||||
if ( usePsName )
|
||||
ns->psid = FT_GET_USHORT();
|
||||
|
||||
FT_FRAME_EXIT();
|
||||
}
|
||||
}
|
||||
|
@ -1042,7 +1488,7 @@
|
|||
/* <Return> */
|
||||
/* FreeType error code. 0 means success. */
|
||||
/* */
|
||||
FT_LOCAL_DEF( FT_Error )
|
||||
FT_EXPORT( FT_Error )
|
||||
TT_Set_MM_Blend( TT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords )
|
||||
|
@ -1097,7 +1543,7 @@
|
|||
|
||||
FT_TRACE5(( "\n" ));
|
||||
|
||||
if ( blend->glyphoffsets == NULL )
|
||||
if ( !face->isCFF2 && blend->glyphoffsets == NULL )
|
||||
if ( ( error = ft_var_load_gvar( face ) ) != 0 )
|
||||
goto Exit;
|
||||
|
||||
|
@ -1202,7 +1648,7 @@
|
|||
/* <Return> */
|
||||
/* FreeType error code. 0 means success. */
|
||||
/* */
|
||||
FT_LOCAL_DEF( FT_Error )
|
||||
FT_EXPORT( FT_Error )
|
||||
TT_Set_Var_Design( TT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords )
|
||||
|
@ -1310,6 +1756,48 @@
|
|||
}
|
||||
|
||||
|
||||
FT_EXPORT( FT_Error )
|
||||
TT_Get_Var_Blend( TT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords )
|
||||
{
|
||||
FT_Error error = FT_Err_Ok;
|
||||
GX_Blend blend;
|
||||
FT_UInt i;
|
||||
|
||||
if ( face->blend == NULL )
|
||||
{
|
||||
if ( ( error = TT_Get_MM_Var( face, NULL ) ) != 0 )
|
||||
return error;
|
||||
}
|
||||
|
||||
blend = face->blend;
|
||||
|
||||
if ( num_coords > blend->num_axis )
|
||||
{
|
||||
FT_TRACE2(( "TT_Get_MM_Blend: only using first %d of %d coordinates\n",
|
||||
blend->num_axis, num_coords ));
|
||||
num_coords = blend->num_axis;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_coords; ++i)
|
||||
{
|
||||
coords[i] = blend->normalizedcoords[i];
|
||||
}
|
||||
|
||||
return FT_Err_Ok;
|
||||
}
|
||||
|
||||
FT_EXPORT( FT_Error )
|
||||
TT_Get_Var_Design( TT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords )
|
||||
{
|
||||
/* TODO: Implement this function. */
|
||||
return FT_THROW( Unimplemented_Feature );
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
|
@ -2022,7 +2510,12 @@
|
|||
FT_Pos delta_y = FT_MulFix( deltas_y[j], apply );
|
||||
|
||||
|
||||
outline->points[j].x += delta_x;
|
||||
/* experimental fix for double adjustment of advance width */
|
||||
/* adjust phantom point 2 only if there's no HVAR */
|
||||
/* TODO: handle LSB (pp1) and VVAR (pp3, pp4) too */
|
||||
if ( j != ( n_points - 3 ) || blend->hvar_checked == FALSE )
|
||||
outline->points[j].x += delta_x;
|
||||
|
||||
outline->points[j].y += delta_y;
|
||||
|
||||
#ifdef FT_DEBUG_LEVEL_TRACE
|
||||
|
@ -2153,7 +2646,7 @@
|
|||
/* <Description> */
|
||||
/* Free the blend internal data structure. */
|
||||
/* */
|
||||
FT_LOCAL_DEF( void )
|
||||
FT_EXPORT( void )
|
||||
tt_done_blend( FT_Memory memory,
|
||||
GX_Blend blend )
|
||||
{
|
||||
|
@ -2172,6 +2665,31 @@
|
|||
FT_FREE( blend->avar_segment );
|
||||
}
|
||||
|
||||
if ( blend->hvar_table != NULL )
|
||||
{
|
||||
FT_UInt i;
|
||||
if ( blend->hvar_table->itemStore.varData )
|
||||
{
|
||||
for ( i=0; i<blend->hvar_table->itemStore.dataCount; i++ )
|
||||
{
|
||||
FT_FREE( blend->hvar_table->itemStore.varData[i].regionIndices );
|
||||
FT_FREE( blend->hvar_table->itemStore.varData[i].deltaSet );
|
||||
}
|
||||
FT_FREE( blend->hvar_table->itemStore.varData );
|
||||
}
|
||||
if ( blend->hvar_table->itemStore.varRegionList )
|
||||
{
|
||||
for ( i=0; i<blend->hvar_table->itemStore.regionCount; i++ )
|
||||
{
|
||||
FT_FREE( blend->hvar_table->itemStore.varRegionList[i].axisList );
|
||||
}
|
||||
FT_FREE( blend->hvar_table->itemStore.varRegionList );
|
||||
}
|
||||
FT_FREE( blend->hvar_table->widthMap.innerIndex );
|
||||
FT_FREE( blend->hvar_table->widthMap.outerIndex );
|
||||
FT_FREE( blend->hvar_table );
|
||||
}
|
||||
|
||||
FT_FREE( blend->tuplecoords );
|
||||
FT_FREE( blend->glyphoffsets );
|
||||
FT_FREE( blend );
|
||||
|
|
|
@ -61,6 +61,64 @@ FT_BEGIN_HEADER
|
|||
} GX_AVarSegmentRec, *GX_AVarSegment;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Struct> */
|
||||
/* GX_HVarRec */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* Data from the `HVAR' table. */
|
||||
/* */
|
||||
/* See similar variation store structures in cfftypes.h */
|
||||
/* */
|
||||
typedef struct GX_HVarData_
|
||||
{
|
||||
FT_UInt itemCount; /* # delta sets per item */
|
||||
FT_UInt regionIdxCount; /* # region indices in this data */
|
||||
FT_UInt* regionIndices; /* array of regionCount indices */
|
||||
/* these index the varRegionList */
|
||||
FT_Short* deltaSet; /* array of itemCount deltas */
|
||||
/* use innerIndex for this array */
|
||||
} GX_HVarDataRec, *GX_HVarData;
|
||||
|
||||
typedef struct GX_AxisCoords_ /* contribution of one axis to a region */
|
||||
{
|
||||
FT_Fixed startCoord;
|
||||
FT_Fixed peakCoord; /* zero means no effect (factor = 1) */
|
||||
FT_Fixed endCoord;
|
||||
} GX_AxisCoordsRec, *GX_AxisCoords;
|
||||
|
||||
typedef struct GX_HVarRegion_
|
||||
{
|
||||
GX_AxisCoords axisList; /* array of axisCount records */
|
||||
} GX_HVarRegionRec, *GX_HVarRegion;
|
||||
|
||||
typedef struct GX_HVStoreRec_ /* HVAR item variation store */
|
||||
{
|
||||
FT_UInt dataCount;
|
||||
GX_HVarData varData; /* array of dataCount records */
|
||||
/* use outerIndex for this array */
|
||||
FT_UShort axisCount;
|
||||
FT_UInt regionCount; /* total # regions defined */
|
||||
GX_HVarRegion varRegionList;
|
||||
|
||||
} GX_HVStoreRec, *GX_HVStore;
|
||||
|
||||
typedef struct GX_WidthMapRec_
|
||||
{
|
||||
FT_UInt mapCount;
|
||||
FT_UInt* outerIndex; /* indices to item var data */
|
||||
FT_UInt* innerIndex; /* indices to delta set */
|
||||
} GX_WidthMapRec, *GX_WidthMap;
|
||||
|
||||
typedef struct GX_HVarRec_
|
||||
{
|
||||
GX_HVStoreRec itemStore; /* Item Variation Store */
|
||||
GX_WidthMapRec widthMap; /* Advance Width Mapping */
|
||||
/* GX_LSBMap LsbMap; Not implemented */
|
||||
/* GX_RSBMap RsbMap; Not implemented */
|
||||
} GX_HVarTableRec, *GX_HVarTable;
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Struct> */
|
||||
|
@ -89,6 +147,9 @@ FT_BEGIN_HEADER
|
|||
FT_Bool avar_checked;
|
||||
GX_AVarSegment avar_segment;
|
||||
|
||||
FT_Bool hvar_checked;
|
||||
GX_HVarTable hvar_table;
|
||||
|
||||
FT_UInt tuplecount; /* shared tuples in `gvar' */
|
||||
FT_Fixed* tuplecoords; /* tuplecoords[tuplecount][num_axis] */
|
||||
|
||||
|
@ -143,20 +204,29 @@ FT_BEGIN_HEADER
|
|||
#define TTAG_slnt FT_MAKE_TAG( 's', 'l', 'n', 't' )
|
||||
|
||||
|
||||
FT_LOCAL( FT_Error )
|
||||
FT_EXPORT( FT_Error )
|
||||
TT_Set_MM_Blend( TT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords );
|
||||
|
||||
FT_LOCAL( FT_Error )
|
||||
FT_EXPORT( FT_Error )
|
||||
TT_Set_Var_Design( TT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords );
|
||||
|
||||
FT_LOCAL( FT_Error )
|
||||
FT_EXPORT( FT_Error )
|
||||
TT_Get_MM_Var( TT_Face face,
|
||||
FT_MM_Var* *master );
|
||||
|
||||
FT_EXPORT( FT_Error )
|
||||
TT_Get_Var_Design( TT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords );
|
||||
|
||||
FT_EXPORT( FT_Error )
|
||||
TT_Get_Var_Blend( TT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords );
|
||||
|
||||
FT_LOCAL( FT_Error )
|
||||
tt_face_vary_cvt( TT_Face face,
|
||||
|
@ -169,8 +239,12 @@ FT_BEGIN_HEADER
|
|||
FT_Outline* outline,
|
||||
FT_UInt n_points );
|
||||
|
||||
FT_EXPORT( void )
|
||||
tt_adjust_advance( TT_Face face,
|
||||
FT_UInt gindex,
|
||||
FT_UShort *aadvance );
|
||||
|
||||
FT_LOCAL( void )
|
||||
FT_EXPORT( void )
|
||||
tt_done_blend( FT_Memory memory,
|
||||
GX_Blend blend );
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue