Compare commits

...

19 Commits

Author SHA1 Message Date
Dave Arnold 71b45f99b1 [cff] minor cleanup 2016-11-21 17:58:27 -08:00
Dave Arnold c7f2a52f86 [cff] minor code cleanup 2016-11-21 15:32:50 -08:00
Dave Arnold f34a28d614 [cff] delete trailing whitespace 2016-11-21 15:00:03 -08:00
Dave Arnold 410ff09eb6 Experimental fix for double adjustment of advance. 2016-11-18 18:02:10 -08:00
Dave Arnold 8dba6305da [cff] Add glyph name support for CFF2 using post table
Temporarily make sfnt_get_glyph_name() extern
Need to replace this with service interface.
2016-11-18 15:29:13 -08:00
Dave Arnold 88ad21fbe5 [cff] Make cff parser stack dynamic
Allocate and free parser->stack. Allow maxstack to increase the default.

Do validation of maxstack at parse time; make it a CALLBACK.

Defer support for > 256 FDs in cff_font_load().
2016-11-16 14:57:52 -08:00
Dave Arnold d49da66dcb [cff] Change operand stack from fixed size to dynamic
CFF becomes dynamic as well as CFF2
maxstack in Top DICT can increase the CFF2 default from 193
2016-11-15 13:57:41 -08:00
Dave Arnold dfce4760af Don't allow CFF2 charstrings to specify a width 2016-11-11 14:16:21 -08:00
Dave Arnold e3ef1df506 Disable seac for CFF2 2016-11-11 13:59:24 -08:00
Dave Arnold c156b734dd Add code to ignore operators removed from CFF2 spec
Ignored operators clear the stack.
Ignore return and endChar in CFF2.
Ignore vsindex and blend in CFF.

Add a nested switch for op2.
First op2 switch handles 4 flex operators for CFF & CFF2 and all reserved
operators common to both.
Second op2 switch handles CFF operators that were removed from CFF2.
2016-11-11 13:17:22 -08:00
Dave Arnold d5c247e923 [cff] Add support for vsindex, DICT & CharString
Add cf2_cmdVSINDEX charstring operator.
Add cff_parse_vsindex as a callback function.
Add vsindex state machine to check for vsindex after blend.

Fix stack bugs in cff_blend_doBlend.
Report errors from cff_blend_build_vector.

Minor comment and TRACE edits.
2016-11-10 13:18:38 -08:00
Dave Arnold 304f0383ef [truetype] Fix HVAR bugs with more than one data item
* src/truetype/ttgxvar.c (ft_var_load_hvar, tt_adjust_advance): rename
regionCount to regionIdxCount. Clean up some comments.
2016-11-02 15:33:13 -07:00
Dave Arnold 776a712be8 [cff] Add CFF2 blend support to cff parser.
* src/cff/cf2font.c (cf2_font_setup): before rendering a glyph, check
blend vector and reparse private DICT if it has changed.

* src/cff/cf2intrp.c (cf2_interpT2CharString): check blend vector and
build blend vector if needed at cf2_doBlend.

* src/cff/cffload.c (cff_vstore_load): fix bug parsing vstore with > 1
data item.
(cff_load_private_dict): factor out private dict parsing so we can
reparse when vector changes.

Add functions for handling CFF_Blend object.
(cff_blend_clear): clear blend stack
(cff_blend_check_vector): test if inputs have changed and blend vector
needs rebuilding.
(cff_blend_build_vector): construct blend vector from design vector
using algorithm in OpenType Font Variations Overview.
(cff_blend_doBlend): compute blended array, same as in cf2_intrp.c but
with parser blend_stack instead of charstring operand stack.

* src/cff/cffparse.c Add blend_stack alongside parser stack, so we have
a place to write blend results.
(cff_parse_num): add internal number type, opcode 255, for use with
blend_stack. Change limit check on several number parsing functions,
since stack is no longer contiguous.
(cff_parse_blend): check blend vector and re-build it if needed.
(cff_parser_run): ignore opcode 255 if it occurs in a font.

* src/cff/cfftypes.h (CFF_Blend): add object data for cff_blend_*
functions.
(CFF_SubFont): add CFF_Blend and blend_stack.
2016-11-02 15:30:36 -07:00
Dave Arnold 54d9993505 Corrections to parse fonts following 1.8 spec.
INDEX count for CFF2 is 32 bits, while CFF is 16 bits
This means INDEX header size is either 5 or 3 bytes.

CFF2 header size is 5 bytes, while CFF is 4 bytes.
In CFF2, offSize field is length of the Top DICT data and is 16 bits.

Blend operator has changed from 31 to 23.
2016-10-18 21:20:19 -07:00
Dave Arnold 4c39089a4d Add separate parsing tables for CFF2
Limit Top, Font and Private dicts to operators allowed by spec
Remove duplicate constants (CFFCODE vs CFF_CODE)
Allow more than 256 Font Dicts (subfonts) in CFF2
2016-09-29 16:54:53 -07:00
Dave Arnold dccfebc0f5 Support v10 CFF2 fonts
remove string index, font index
top dict follows header, but has no index
font dict in FDArray, but skip FDSelect when there's only one font dict
2016-09-28 15:14:28 -07:00
Dave Arnold 6a5ef34797 Test. Minor change in comment 2016-09-15 10:21:01 -07:00
Behdad Esfahbod c7f87a1f8b Fix up commit d1d88cd08dd3d438abcf7e60087c72957a50fcb1
FT_Get_Var_Design_Coordinates() was turning blending off.  Apparently
CFF implementation does not respect that, but TrueType driver does.
2016-09-14 09:41:08 +02:00
Dave Arnold d1908a107d Preliminary OpenType 1.8 support. 2016-09-14 01:14:29 +02:00
30 changed files with 2537 additions and 507 deletions

9
README
View File

@ -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
==============

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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,

View File

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

View File

@ -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 = &region->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 );

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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