Preliminary OpenType 1.8 support.
This commit is contained in:
parent
053943a757
commit
d1908a107d
9
README
9
README
|
@ -1,3 +1,12 @@
|
|||
Branch of FreeType to support OpenType 1.8
|
||||
==========================================
|
||||
|
||||
This branch contains changes for supporting OpenType 1.8.
|
||||
The changes will be merged back upstream in September 2016,
|
||||
when the specification for OpenType 1.8 is final and has
|
||||
been published.
|
||||
|
||||
|
||||
FreeType 2.6.5
|
||||
==============
|
||||
|
||||
|
|
|
@ -171,6 +171,7 @@ FT_BEGIN_HEADER
|
|||
{
|
||||
FT_Fixed* coords;
|
||||
FT_UInt strid;
|
||||
FT_UInt psid;
|
||||
|
||||
} FT_Var_Named_Style;
|
||||
|
||||
|
@ -329,6 +330,10 @@ FT_BEGIN_HEADER
|
|||
FT_UInt num_coords,
|
||||
FT_Fixed* coords );
|
||||
|
||||
FT_EXPORT( FT_Error )
|
||||
FT_Get_Var_Design_Coordinates( FT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords );
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
|
@ -375,6 +380,11 @@ FT_BEGIN_HEADER
|
|||
|
||||
/* */
|
||||
|
||||
FT_EXPORT( FT_Error )
|
||||
FT_Get_Var_Blend_Coordinates( FT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords );
|
||||
|
||||
|
||||
FT_END_HEADER
|
||||
|
||||
|
|
|
@ -90,6 +90,7 @@ FT_TRACE_DEF( cffparse )
|
|||
|
||||
FT_TRACE_DEF( cf2blues )
|
||||
FT_TRACE_DEF( cf2hints )
|
||||
FT_TRACE_DEF( cf2font )
|
||||
FT_TRACE_DEF( cf2interp )
|
||||
|
||||
/* Type 42 driver component */
|
||||
|
|
|
@ -58,6 +58,16 @@ FT_BEGIN_HEADER
|
|||
FT_UInt num_coords,
|
||||
FT_Long* coords );
|
||||
|
||||
typedef FT_Error
|
||||
(*FT_Get_Var_Design_Func)( FT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords );
|
||||
|
||||
typedef FT_Error
|
||||
(*FT_Get_Var_Blend_Func)( FT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords );
|
||||
|
||||
|
||||
FT_DEFINE_SERVICE( MultiMasters )
|
||||
{
|
||||
|
@ -66,6 +76,8 @@ FT_BEGIN_HEADER
|
|||
FT_Set_MM_Blend_Func set_mm_blend;
|
||||
FT_Get_MM_Var_Func get_mm_var;
|
||||
FT_Set_Var_Design_Func set_var_design;
|
||||
FT_Get_Var_Design_Func get_var_design;
|
||||
FT_Get_Var_Blend_Func get_var_blend;
|
||||
};
|
||||
|
||||
|
||||
|
@ -76,10 +88,13 @@ FT_BEGIN_HEADER
|
|||
set_mm_design_, \
|
||||
set_mm_blend_, \
|
||||
get_mm_var_, \
|
||||
set_var_design_ ) \
|
||||
set_var_design_, \
|
||||
get_var_design_, \
|
||||
get_var_blend_ ) \
|
||||
static const FT_Service_MultiMastersRec class_ = \
|
||||
{ \
|
||||
get_mm_, set_mm_design_, set_mm_blend_, get_mm_var_, set_var_design_ \
|
||||
get_mm_, set_mm_design_, set_mm_blend_, get_mm_var_, set_var_design_, \
|
||||
get_var_design_, get_var_blend_ \
|
||||
};
|
||||
|
||||
#else /* FT_CONFIG_OPTION_PIC */
|
||||
|
@ -89,7 +104,9 @@ FT_BEGIN_HEADER
|
|||
set_mm_design_, \
|
||||
set_mm_blend_, \
|
||||
get_mm_var_, \
|
||||
set_var_design_ ) \
|
||||
set_var_design_, \
|
||||
get_var_design_, \
|
||||
get_var_blend_ ) \
|
||||
void \
|
||||
FT_Init_Class_ ## class_( FT_Service_MultiMastersRec* clazz ) \
|
||||
{ \
|
||||
|
@ -98,6 +115,8 @@ FT_BEGIN_HEADER
|
|||
clazz->set_mm_blend = set_mm_blend_; \
|
||||
clazz->get_mm_var = get_mm_var_; \
|
||||
clazz->set_var_design = set_var_design_; \
|
||||
clazz->get_var_design = get_var_design_; \
|
||||
clazz->get_var_blend = get_var_blend_; \
|
||||
}
|
||||
|
||||
#endif /* FT_CONFIG_OPTION_PIC */
|
||||
|
|
|
@ -1346,6 +1346,7 @@ FT_BEGIN_HEADER
|
|||
FT_ULong glyf_len;
|
||||
|
||||
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
|
||||
FT_Bool isCFF2;
|
||||
FT_Bool doblend;
|
||||
GX_Blend blend;
|
||||
#endif
|
||||
|
|
|
@ -43,6 +43,7 @@ FT_BEGIN_HEADER
|
|||
#define TTAG_CBDT FT_MAKE_TAG( 'C', 'B', 'D', 'T' )
|
||||
#define TTAG_CBLC FT_MAKE_TAG( 'C', 'B', 'L', 'C' )
|
||||
#define TTAG_CFF FT_MAKE_TAG( 'C', 'F', 'F', ' ' )
|
||||
#define TTAG_CFF2 FT_MAKE_TAG( 'C', 'F', 'F', '2' )
|
||||
#define TTAG_CID FT_MAKE_TAG( 'C', 'I', 'D', ' ' )
|
||||
#define TTAG_cmap FT_MAKE_TAG( 'c', 'm', 'a', 'p' )
|
||||
#define TTAG_cvar FT_MAKE_TAG( 'c', 'v', 'a', 'r' )
|
||||
|
@ -61,6 +62,7 @@ FT_BEGIN_HEADER
|
|||
#define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' )
|
||||
#define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' )
|
||||
#define TTAG_gvar FT_MAKE_TAG( 'g', 'v', 'a', 'r' )
|
||||
#define TTAG_HVAR FT_MAKE_TAG( 'H', 'V', 'A', 'R' )
|
||||
#define TTAG_hdmx FT_MAKE_TAG( 'h', 'd', 'm', 'x' )
|
||||
#define TTAG_head FT_MAKE_TAG( 'h', 'e', 'a', 'd' )
|
||||
#define TTAG_hhea FT_MAKE_TAG( 'h', 'h', 'e', 'a' )
|
||||
|
|
|
@ -172,6 +172,34 @@
|
|||
}
|
||||
|
||||
|
||||
/* documentation is in ftmm.h */
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
FT_Get_Var_Design_Coordinates( FT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords )
|
||||
{
|
||||
FT_Error error;
|
||||
FT_Service_MultiMasters service;
|
||||
|
||||
|
||||
/* check of `face' delayed to `ft_face_get_mm_service' */
|
||||
|
||||
if ( !coords )
|
||||
return FT_THROW( Invalid_Argument );
|
||||
|
||||
error = ft_face_get_mm_service( face, &service );
|
||||
if ( !error )
|
||||
{
|
||||
error = FT_ERR( Invalid_Argument );
|
||||
if ( service->get_var_design )
|
||||
error = service->get_var_design( face, num_coords, coords );
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/* documentation is in ftmm.h */
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
|
@ -230,5 +258,32 @@
|
|||
return error;
|
||||
}
|
||||
|
||||
/* documentation is in ftmm.h */
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
FT_Get_Var_Blend_Coordinates( FT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords )
|
||||
{
|
||||
FT_Error error;
|
||||
FT_Service_MultiMasters service;
|
||||
|
||||
|
||||
/* check of `face' delayed to `ft_face_get_mm_service' */
|
||||
|
||||
if ( !coords )
|
||||
return FT_THROW( Invalid_Argument );
|
||||
|
||||
error = ft_face_get_mm_service( face, &service );
|
||||
if ( !error )
|
||||
{
|
||||
error = FT_ERR( Invalid_Argument );
|
||||
if ( service->get_var_blend )
|
||||
error = service->get_var_blend( face, num_coords, coords );
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/* END */
|
||||
|
|
|
@ -51,8 +51,8 @@ FT_BEGIN_HEADER
|
|||
|
||||
#define CF2_FIXED_MAX ( (CF2_Fixed)0x7FFFFFFFL )
|
||||
#define CF2_FIXED_MIN ( (CF2_Fixed)0x80000000L )
|
||||
#define CF2_FIXED_ONE 0x10000L
|
||||
#define CF2_FIXED_EPSILON 0x0001
|
||||
#define CF2_FIXED_ONE ( (CF2_Fixed)0x10000L )
|
||||
#define CF2_FIXED_EPSILON ( (CF2_Fixed)0x0001 )
|
||||
|
||||
/* in C 89, left and right shift of negative numbers is */
|
||||
/* implementation specific behaviour in the general case */
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
#include <ft2build.h>
|
||||
#include FT_INTERNAL_CALC_H
|
||||
#include FT_INTERNAL_DEBUG_H
|
||||
|
||||
#include "cf2ft.h"
|
||||
|
||||
|
@ -46,6 +47,8 @@
|
|||
#include "cf2error.h"
|
||||
#include "cf2intrp.h"
|
||||
|
||||
#undef FT_COMPONENT
|
||||
#define FT_COMPONENT trace_cf2font
|
||||
|
||||
/* Compute a stem darkening amount in character space. */
|
||||
static void
|
||||
|
@ -233,25 +236,155 @@
|
|||
*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_UNUSED( lenNormalizedVector );
|
||||
FT_UNUSED( vsindex );
|
||||
|
||||
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
|
||||
cf2_font_setup( CF2_Font font,
|
||||
const CF2_Matrix* transform )
|
||||
{
|
||||
FT_Error error = FT_Err_Ok; /* for FT_REALLOC */
|
||||
FT_Memory memory = font->memory; /* for FT_REALLOC */
|
||||
|
||||
/* pointer to parsed font object */
|
||||
CFF_Decoder* decoder = font->decoder;
|
||||
|
||||
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 +399,33 @@
|
|||
needExtraSetup = TRUE;
|
||||
}
|
||||
|
||||
/* check for variation vectors */
|
||||
vstore = cf2_getVStore( decoder );
|
||||
hasVariations = ( vstore->dataCount != 0 );
|
||||
|
||||
if ( hasVariations )
|
||||
{
|
||||
if ( font->lenBlendVector == 0 )
|
||||
needExtraSetup = TRUE; /* a blend vector is required */
|
||||
|
||||
/* Note: lenNormalizedVector is zero until FT_Get_MM_Var() is called */
|
||||
cf2_getNormalizedVector( decoder, &lenNormalizedV, &normalizedV );
|
||||
|
||||
/* determine if blend vector needs to be recomputed */
|
||||
if ( font->lastVsindex != subFont->font_dict.vsindex ||
|
||||
lenNormalizedV == 0 ||
|
||||
font->lenNormalizedVector != lenNormalizedV ||
|
||||
( lenNormalizedV &&
|
||||
memcmp( normalizedV,
|
||||
&font->lastNormalizedVector,
|
||||
lenNormalizedV * sizeof( *normalizedV ) ) != 0 ) )
|
||||
{
|
||||
font->lastVsindex = subFont->font_dict.vsindex;
|
||||
/* vectors will be copied below, during ExtraSetup */
|
||||
needExtraSetup = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 +583,37 @@
|
|||
|
||||
/* compute blue zones for this instance */
|
||||
cf2_blues_init( &font->blues, font );
|
||||
}
|
||||
|
||||
/* copy normalized vector used to compute blend vector */
|
||||
if ( hasVariations )
|
||||
{
|
||||
/* if user has set a normalized vector, use it */
|
||||
/* otherwise, assume default */
|
||||
if ( lenNormalizedV != 0 )
|
||||
{
|
||||
/* user has set a normalized vector */
|
||||
if ( FT_REALLOC( font->lastNormalizedVector,
|
||||
font->lenNormalizedVector,
|
||||
lenNormalizedV * sizeof( *normalizedV )) )
|
||||
{
|
||||
CF2_SET_ERROR( &font->error, Out_Of_Memory );
|
||||
return;
|
||||
}
|
||||
font->lenNormalizedVector = lenNormalizedV;
|
||||
FT_MEM_COPY( font->lastNormalizedVector,
|
||||
normalizedV,
|
||||
lenNormalizedV * sizeof( *normalizedV ));
|
||||
}
|
||||
|
||||
/* build blend vector for this instance */
|
||||
cf2_buildBlendVector( font, font->lastVsindex,
|
||||
font->lenNormalizedVector,
|
||||
font->lastNormalizedVector,
|
||||
&font->lenBlendVector,
|
||||
&font->blendVector );
|
||||
}
|
||||
|
||||
} /* needExtraSetup */
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
FT_BEGIN_HEADER
|
||||
|
||||
|
||||
#define CF2_OPERAND_STACK_SIZE 48
|
||||
#define CF2_OPERAND_STACK_SIZE 193/* TODO: this is temporary for CFF2 */
|
||||
#define CF2_MAX_SUBR 16 /* maximum subroutine nesting; */
|
||||
/* only 10 are allowed but there exist */
|
||||
/* fonts like `HiraKakuProN-W3.ttf' */
|
||||
|
@ -63,6 +63,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 +75,13 @@ FT_BEGIN_HEADER
|
|||
CF2_Matrix outerTransform; /* post hinting; includes rotations */
|
||||
CF2_Fixed ppem; /* transform-dependent */
|
||||
|
||||
/* variation data */
|
||||
CF2_UInt lastVsindex; /* last vsindex used */
|
||||
CF2_UInt lenNormalizedVector; /* normDV length (aka numAxes) */
|
||||
FT_Fixed * lastNormalizedVector;/* last normDV used */
|
||||
CF2_UInt lenBlendVector; /* blendV length (aka numMasters) */
|
||||
CF2_Fixed * blendVector; /* current blendV (per glyph) */
|
||||
|
||||
CF2_Int unitsPerEm;
|
||||
|
||||
CF2_Fixed syntheticEmboldeningAmountX; /* character space units */
|
||||
|
|
|
@ -102,9 +102,10 @@
|
|||
if ( font )
|
||||
{
|
||||
FT_Memory memory = font->memory;
|
||||
|
||||
|
||||
(void)memory;
|
||||
|
||||
FT_FREE( font->lastNormalizedVector );
|
||||
FT_FREE( font->blendVector );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,39 @@
|
|||
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 normalized design vector for current render request */
|
||||
/* returns pointer and length */
|
||||
/* if blend struct is not initialized, return length zero */
|
||||
/* Note: use FT_Fixed not CF2_Fixed for the vector */
|
||||
FT_LOCAL_DEF( void )
|
||||
cf2_getNormalizedVector( CFF_Decoder* decoder, CF2_UInt * len, FT_Fixed ** vec )
|
||||
{
|
||||
GX_Blend blend;
|
||||
|
||||
FT_ASSERT( decoder && decoder->builder.face );
|
||||
FT_ASSERT( vec && len );
|
||||
|
||||
blend = decoder->builder.face->blend;
|
||||
if ( blend )
|
||||
{
|
||||
*vec = blend->normalizedcoords;
|
||||
*len = blend->num_axis;
|
||||
}
|
||||
else
|
||||
{
|
||||
*vec = NULL;
|
||||
*len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* get `y_ppem' from `CFF_Size' */
|
||||
FT_LOCAL_DEF( CF2_Fixed )
|
||||
|
|
|
@ -64,6 +64,14 @@ FT_BEGIN_HEADER
|
|||
FT_LOCAL( CFF_SubFont )
|
||||
cf2_getSubfont( CFF_Decoder* decoder );
|
||||
|
||||
FT_LOCAL( CFF_VStore )
|
||||
cf2_getVStore( 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 );
|
||||
|
|
|
@ -216,7 +216,7 @@
|
|||
cf2_cmdRESERVED_13, /* 13 */
|
||||
cf2_cmdENDCHAR, /* 14 */
|
||||
cf2_cmdRESERVED_15, /* 15 */
|
||||
cf2_cmdRESERVED_16, /* 16 */
|
||||
cf2_cmdBLEND, /* 16 */
|
||||
cf2_cmdRESERVED_17, /* 17 */
|
||||
cf2_cmdHSTEMHM, /* 18 */
|
||||
cf2_cmdHINTMASK, /* 19 */
|
||||
|
@ -402,6 +402,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 CF2_Font font,
|
||||
CF2_Stack opStack,
|
||||
CF2_UInt numBlends )
|
||||
{
|
||||
CF2_UInt delta;
|
||||
CF2_UInt base;
|
||||
CF2_UInt i, j;
|
||||
CF2_UInt numOperands = (CF2_UInt)(numBlends * font->lenBlendVector);
|
||||
|
||||
base = cf2_stack_count( opStack ) - numOperands;
|
||||
delta = base + numBlends;
|
||||
for ( i = 0; i < numBlends; i++ )
|
||||
{
|
||||
const CF2_Fixed * weight = &font->blendVector[1];
|
||||
CF2_Fixed sum = cf2_stack_getReal( opStack, i+base ); /* start with first term */
|
||||
for ( j = 1; j < font->lenBlendVector; 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
|
||||
|
@ -585,12 +613,20 @@
|
|||
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_cmdBLEND:
|
||||
{
|
||||
FT_UInt numBlends = (FT_UInt)cf2_stack_popInt( opStack );
|
||||
FT_TRACE4(( " blend\n" ));
|
||||
cf2_doBlend( font, opStack, numBlends );
|
||||
}
|
||||
continue; /* do not clear the stack */
|
||||
|
||||
|
||||
case cf2_cmdHSTEMHM:
|
||||
case cf2_cmdHSTEM:
|
||||
FT_TRACE4(( op1 == cf2_cmdHSTEMHM ? " hstemhm\n" : " hstem\n" ));
|
||||
|
|
|
@ -194,6 +194,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,
|
||||
|
|
|
@ -93,6 +93,15 @@ FT_BEGIN_HEADER
|
|||
cf2_stack_getReal( CF2_Stack stack,
|
||||
CF2_UInt idx );
|
||||
|
||||
FT_LOCAL( void )
|
||||
cf2_stack_setReal( CF2_Stack stack,
|
||||
CF2_UInt idx,
|
||||
CF2_Fixed val );
|
||||
|
||||
FT_LOCAL( void )
|
||||
cf2_stack_pop( CF2_Stack stack,
|
||||
CF2_UInt num );
|
||||
|
||||
FT_LOCAL( void )
|
||||
cf2_stack_roll( CF2_Stack stack,
|
||||
CF2_Int count,
|
||||
|
|
|
@ -32,6 +32,12 @@
|
|||
#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
|
||||
|
||||
#include "cfferrs.h"
|
||||
#include "cffpic.h"
|
||||
|
||||
|
@ -291,6 +297,14 @@
|
|||
FT_Error error;
|
||||
|
||||
|
||||
/* TODO: for testing: cff2 does not have glyph names */
|
||||
/* will need to use post table method */
|
||||
if ( font->version_major == 2 )
|
||||
{
|
||||
FT_STRCPYN( buffer, "noname", buffer_max );
|
||||
return FT_Err_Ok;
|
||||
}
|
||||
|
||||
if ( !font->psnames )
|
||||
{
|
||||
FT_ERROR(( "cff_get_glyph_name:"
|
||||
|
@ -871,15 +885,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
|
||||
|
|
|
@ -589,12 +589,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 )
|
||||
|
@ -862,6 +865,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 +1082,130 @@
|
|||
}
|
||||
|
||||
|
||||
/* 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_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;
|
||||
FT_ULong dataOffsetArrayOffset;
|
||||
FT_ULong varDataOffset;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* save position of item variation data offsets */
|
||||
/* we'll parse region list first, then come back */
|
||||
dataOffsetArrayOffset = FT_STREAM_POS();
|
||||
|
||||
/* parse regionList and axisLists*/
|
||||
if ( FT_STREAM_SEEK( vsOffset + regionListOffset ) ||
|
||||
FT_READ_USHORT( vstore->axisCount ) ||
|
||||
FT_READ_USHORT( vstore->regionCount ) )
|
||||
goto Exit;
|
||||
|
||||
if ( FT_NEW_ARRAY( vstore->varRegionList, vstore->regionCount ) )
|
||||
goto Exit;
|
||||
|
||||
for ( i=0; i<vstore->regionCount; i++ )
|
||||
{
|
||||
CFF_VarRegion* region = &vstore->varRegionList[i];
|
||||
if ( FT_NEW_ARRAY( region->axisList, vstore->axisCount ) )
|
||||
goto Exit;
|
||||
for ( j=0; j<vstore->axisCount; j++ )
|
||||
{
|
||||
CFF_AxisCoords* axis = ®ion->axisList[j];
|
||||
FT_Int16 start14, peak14, end14;
|
||||
if ( FT_READ_SHORT( start14 ) ||
|
||||
FT_READ_SHORT( peak14 ) ||
|
||||
FT_READ_SHORT( end14 ) )
|
||||
goto Exit;
|
||||
axis->startCoord = FT_fdot14ToFixed( start14 );
|
||||
axis->peakCoord = FT_fdot14ToFixed( peak14 );
|
||||
axis->endCoord = FT_fdot14ToFixed( end14 );
|
||||
}
|
||||
}
|
||||
|
||||
/* re-position to parse varData and regionIndices */
|
||||
if ( FT_STREAM_SEEK( dataOffsetArrayOffset ) )
|
||||
goto Exit;
|
||||
|
||||
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_READ_ULONG( varDataOffset ) )
|
||||
goto Exit;
|
||||
|
||||
if ( FT_STREAM_SEEK( vsOffset + varDataOffset ) )
|
||||
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:
|
||||
if ( error )
|
||||
cff_vstore_done( vstore, memory );
|
||||
return error;
|
||||
}
|
||||
|
||||
static void
|
||||
cff_encoding_done( CFF_Encoding encoding )
|
||||
{
|
||||
|
@ -1442,7 +1595,8 @@
|
|||
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[] =
|
||||
{
|
||||
|
@ -1478,7 +1632,7 @@
|
|||
goto Exit;
|
||||
|
||||
/* check format */
|
||||
if ( font->version_major != 1 ||
|
||||
if ( font->version_major != ( cff2 ? 2 : 1 ) ||
|
||||
font->header_size < 4 ||
|
||||
font->absolute_offsize > 4 )
|
||||
{
|
||||
|
@ -1492,8 +1646,9 @@
|
|||
goto Exit;
|
||||
|
||||
/* read the name, top dict, string and global subrs index */
|
||||
if ( FT_SET_ERROR( cff_index_init( &font->name_index,
|
||||
stream, 0 ) ) ||
|
||||
/* CFF2 does not contain a name index */
|
||||
if ( ( !cff2 && FT_SET_ERROR( cff_index_init( &font->name_index,
|
||||
stream, 0 ) ) ) ||
|
||||
FT_SET_ERROR( cff_index_init( &font->font_dict_index,
|
||||
stream, 0 ) ) ||
|
||||
FT_SET_ERROR( cff_index_init( &string_index,
|
||||
|
@ -1636,7 +1791,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 );
|
||||
|
||||
|
@ -1660,6 +1815,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
/* read the Variation Store if available */
|
||||
error = cff_vstore_load( &font->vstore,
|
||||
stream,
|
||||
base_offset,
|
||||
dict->vstore_offset );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
||||
/* get the font name (/CIDFontName for CID-keyed fonts, */
|
||||
/* /FontName otherwise) */
|
||||
font->font_name = cff_index_get_name( font, subfont_index );
|
||||
|
@ -1696,6 +1859,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 );
|
||||
|
||||
|
|
|
@ -64,7 +64,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 );
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -782,6 +782,32 @@
|
|||
return error;
|
||||
}
|
||||
|
||||
/* TODO: replace this test code with doBlend */
|
||||
static FT_Error
|
||||
cff_parse_blend( CFF_Parser parser )
|
||||
{
|
||||
FT_UInt num_args = (FT_UInt)( parser->top - parser->stack );
|
||||
FT_UInt numBlends;
|
||||
FT_Error error;
|
||||
|
||||
error = FT_ERR( Stack_Underflow );
|
||||
FT_TRACE1(( " cff_parse_blend\n" ));
|
||||
|
||||
if ( parser->top >= parser->stack + 1 ) /* at least one operand */
|
||||
{
|
||||
/* top of stack gives number of blends */
|
||||
numBlends = (FT_UInt)cff_parse_num( parser->top - 1 );
|
||||
|
||||
if ( numBlends < num_args )
|
||||
{
|
||||
/* for testing, just reduce stack to first numBlends values */
|
||||
parser->top = parser->stack + numBlends;
|
||||
|
||||
error = FT_Err_Ok;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
#define CFF_FIELD_NUM( code, name, id ) \
|
||||
CFF_FIELD( code, name, id, cff_kind_num )
|
||||
|
@ -817,6 +843,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 +895,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, \
|
||||
|
@ -1386,7 +1431,7 @@
|
|||
}
|
||||
break;
|
||||
|
||||
default: /* callback */
|
||||
default: /* callback or blend */
|
||||
error = field->reader( parser );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
|
@ -1400,7 +1445,8 @@
|
|||
|
||||
Found:
|
||||
/* clear stack */
|
||||
parser->top = parser->stack;
|
||||
if ( field->kind != cff_kind_blend )
|
||||
parser->top = parser->stack;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
FT_BEGIN_HEADER
|
||||
|
||||
|
||||
#define CFF_MAX_STACK_DEPTH 96
|
||||
#define CFF_MAX_STACK_DEPTH 193
|
||||
|
||||
#define CFF_CODE_TOPDICT 0x1000
|
||||
#define CFF_CODE_PRIVATE 0x2000
|
||||
|
@ -77,6 +77,7 @@ FT_BEGIN_HEADER
|
|||
cff_kind_bool,
|
||||
cff_kind_delta,
|
||||
cff_kind_callback,
|
||||
cff_kind_blend,
|
||||
|
||||
cff_kind_max /* do not remove */
|
||||
};
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#define CFF_SERVICE_CID_INFO_GET cff_service_cid_info
|
||||
#define CFF_SERVICE_PROPERTIES_GET cff_service_properties
|
||||
#define CFF_SERVICES_GET cff_services
|
||||
#define CFF_SERVICE_MULTI_MASTERS_GET cff_service_multi_masters
|
||||
#define CFF_CMAP_ENCODING_CLASS_REC_GET cff_cmap_encoding_class_rec
|
||||
#define CFF_CMAP_UNICODE_CLASS_REC_GET cff_cmap_unicode_class_rec
|
||||
#define CFF_FIELD_HANDLERS_GET cff_field_handlers
|
||||
|
|
|
@ -45,6 +45,9 @@
|
|||
CFF_FIELD_NUM ( 16, encoding_offset, "Encoding" )
|
||||
CFF_FIELD_NUM ( 17, charstrings_offset, "CharStrings" )
|
||||
CFF_FIELD_CALLBACK( 18, private_dict, "Private" )
|
||||
CFF_FIELD_NUM ( 22, vsindex, "vsindex" )
|
||||
CFF_FIELD_NUM ( 24, vstore_offset, "vstore" )
|
||||
CFF_FIELD_NUM ( 25, maxstack, "maxstack" )
|
||||
CFF_FIELD_NUM ( 0x114, synthetic_base, "SyntheticBase" )
|
||||
CFF_FIELD_STRING ( 0x115, embedded_postscript, "PostScript" )
|
||||
|
||||
|
@ -101,5 +104,6 @@
|
|||
CFF_FIELD_NUM ( 20, default_width, "defaultWidthX" )
|
||||
CFF_FIELD_NUM ( 21, nominal_width, "nominalWidthX" )
|
||||
|
||||
CFF_FIELD_BLEND ( 31, "blend" )
|
||||
|
||||
/* END */
|
||||
|
|
|
@ -101,6 +101,38 @@ 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;
|
||||
|
||||
|
||||
typedef struct CFF_FontRecDictRec_
|
||||
{
|
||||
|
@ -151,6 +183,11 @@ FT_BEGIN_HEADER
|
|||
FT_UShort num_designs;
|
||||
FT_UShort num_axes;
|
||||
|
||||
/* fields for CFF2 */
|
||||
FT_UInt vsindex;
|
||||
FT_ULong vstore_offset;
|
||||
FT_UInt maxstack;
|
||||
|
||||
} CFF_FontRecDictRec, *CFF_FontRecDict;
|
||||
|
||||
|
||||
|
@ -280,6 +317,8 @@ FT_BEGIN_HEADER
|
|||
/* since version 2.4.12 */
|
||||
FT_Generic cf2_instance;
|
||||
|
||||
CFF_VStoreRec vstore;
|
||||
|
||||
} CFF_FontRec, *CFF_Font;
|
||||
|
||||
|
||||
|
|
|
@ -1085,10 +1085,12 @@
|
|||
#ifdef FT_CONFIG_OPTION_INCREMENTAL
|
||||
has_outline = FT_BOOL( face->root.internal->incremental_interface != 0 ||
|
||||
tt_face_lookup_table( face, TTAG_glyf ) != 0 ||
|
||||
tt_face_lookup_table( face, TTAG_CFF ) != 0 );
|
||||
tt_face_lookup_table( face, TTAG_CFF ) != 0 ||
|
||||
tt_face_lookup_table( face, TTAG_CFF2 ));
|
||||
#else
|
||||
has_outline = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) != 0 ||
|
||||
tt_face_lookup_table( face, TTAG_CFF ) != 0 );
|
||||
tt_face_lookup_table( face, TTAG_CFF ) != 0 ||
|
||||
tt_face_lookup_table( face, TTAG_CFF2 ));
|
||||
#endif
|
||||
|
||||
is_apple_sbit = 0;
|
||||
|
@ -1331,6 +1333,9 @@
|
|||
tt_face_lookup_table( face, TTAG_fvar ) != 0 &&
|
||||
tt_face_lookup_table( face, TTAG_gvar ) != 0 )
|
||||
flags |= FT_FACE_FLAG_MULTIPLE_MASTERS;
|
||||
if ( tt_face_lookup_table( face, TTAG_CFF2 ) != 0 &&
|
||||
tt_face_lookup_table( face, TTAG_fvar ) != 0 )
|
||||
flags |= FT_FACE_FLAG_MULTIPLE_MASTERS;
|
||||
#endif
|
||||
|
||||
root->face_flags = flags;
|
||||
|
|
|
@ -22,6 +22,10 @@
|
|||
#include FT_TRUETYPE_TAGS_H
|
||||
#include "ttmtx.h"
|
||||
|
||||
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
|
||||
#include "../truetype/ttgxvar.h"
|
||||
#endif
|
||||
|
||||
#include "sferrors.h"
|
||||
|
||||
|
||||
|
@ -274,6 +278,12 @@
|
|||
*abearing = 0;
|
||||
*aadvance = 0;
|
||||
}
|
||||
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
|
||||
/* TODO: handle VVAR and LSB */
|
||||
if ( !vertical )
|
||||
tt_adjust_advance( face, gindex, aadvance );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -449,7 +449,9 @@
|
|||
(FT_Set_MM_Design_Func) NULL, /* set_mm_design */
|
||||
(FT_Set_MM_Blend_Func) TT_Set_MM_Blend, /* set_mm_blend */
|
||||
(FT_Get_MM_Var_Func) TT_Get_MM_Var, /* get_mm_var */
|
||||
(FT_Set_Var_Design_Func)TT_Set_Var_Design ) /* set_var_design */
|
||||
(FT_Set_Var_Design_Func)TT_Set_Var_Design, /* set_var_design */
|
||||
(FT_Get_Var_Design_Func)TT_Get_Var_Design, /* get_var_design */
|
||||
(FT_Get_Var_Blend_Func) TT_Get_Var_Blend ) /* get_var_blend */
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -392,6 +392,418 @@
|
|||
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_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 data_offset_array_offset;
|
||||
FT_ULong data_offset;
|
||||
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;
|
||||
|
||||
if ( FT_READ_ULONG( region_offset ) ||
|
||||
FT_READ_USHORT( itemStore->dataCount ) )
|
||||
goto Exit;
|
||||
|
||||
/* save position of item variation data offsets */
|
||||
/* we'll parse region list first, then come back */
|
||||
data_offset_array_offset = FT_STREAM_POS();
|
||||
|
||||
/* 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 */
|
||||
|
||||
/* parse array of item variation data subtables */
|
||||
if ( FT_STREAM_SEEK( data_offset_array_offset ) )
|
||||
goto Exit;
|
||||
|
||||
if ( FT_NEW_ARRAY( itemStore->varData, itemStore->dataCount ) )
|
||||
goto Exit;
|
||||
|
||||
hvarData = itemStore->varData;
|
||||
for ( i=0; i<itemStore->dataCount; i++ )
|
||||
{
|
||||
if ( FT_READ_ULONG( data_offset ) )
|
||||
goto Exit;
|
||||
|
||||
if ( FT_STREAM_SEEK( table_offset + store_offset + data_offset ) ||
|
||||
FT_READ_USHORT( hvarData->itemCount ) ||
|
||||
FT_READ_USHORT( shortDeltaCount ) ||
|
||||
FT_READ_USHORT( hvarData->regionCount ) )
|
||||
goto Exit;
|
||||
|
||||
/* check some data consistency */
|
||||
if ( shortDeltaCount > hvarData->regionCount )
|
||||
{
|
||||
FT_TRACE2(( "bad short count %d or region count %d\n",
|
||||
shortDeltaCount, hvarData->regionCount ));
|
||||
error = FT_THROW( Invalid_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
if ( hvarData->regionCount > itemStore->regionCount )
|
||||
{
|
||||
FT_TRACE2(( "inconsistent regionCount %d in varData[ %d ]\n",
|
||||
hvarData->regionCount, i ));
|
||||
error = FT_THROW( Invalid_File_Format );
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* parse region indices */
|
||||
if ( FT_NEW_ARRAY( hvarData->regionIndices, hvarData->regionCount ) )
|
||||
goto Exit;
|
||||
|
||||
for ( j=0; j<hvarData->regionCount; j++ )
|
||||
{
|
||||
if ( FT_READ_USHORT( hvarData->regionIndices[j] ) )
|
||||
goto Exit;
|
||||
if ( hvarData->regionIndices[j] >= hvarData->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 + regionCount ) bytes each */
|
||||
/* on output, deltas are expanded to regionCount shorts each */
|
||||
if ( FT_NEW_ARRAY( hvarData->deltaSet, hvarData->regionCount * 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->regionCount; )
|
||||
{
|
||||
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->regionCount; 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:
|
||||
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[ face->blend->hvar_table->itemStore.regionCount * innerIndex ];
|
||||
|
||||
/* see pseudo code from Font Variations Overview */
|
||||
/* outer loop steps through master designs to be blended */
|
||||
for ( master=0; master<varData->regionCount; 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 */
|
||||
/* TODO check rounding: *aadvance is short */
|
||||
*aadvance += FT_fixedToInt( netAdjustment );
|
||||
|
||||
Exit:
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
typedef struct GX_GVar_Head_
|
||||
{
|
||||
|
@ -762,7 +1174,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 +1190,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 +1237,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 +1269,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 +1278,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 +1382,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 +1400,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 +1484,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 +1539,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 +1644,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 +1752,50 @@
|
|||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
face->doblend = FALSE;
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
|
@ -2153,7 +2639,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 +2658,31 @@
|
|||
FT_FREE( blend->avar_segment );
|
||||
}
|
||||
|
||||
if ( blend->hvar_table != NULL )
|
||||
{
|
||||
FT_UInt i;
|
||||
if ( blend->hvar_table->itemStore.varData )
|
||||
{
|
||||
for ( i=0; i<blend->hvar_table->itemStore.dataCount; i++ )
|
||||
{
|
||||
FT_FREE( blend->hvar_table->itemStore.varData[i].regionIndices );
|
||||
FT_FREE( blend->hvar_table->itemStore.varData[i].deltaSet );
|
||||
}
|
||||
FT_FREE( blend->hvar_table->itemStore.varData );
|
||||
}
|
||||
if ( blend->hvar_table->itemStore.varRegionList )
|
||||
{
|
||||
for ( i=0; i<blend->hvar_table->itemStore.regionCount; i++ )
|
||||
{
|
||||
FT_FREE( blend->hvar_table->itemStore.varRegionList[i].axisList );
|
||||
}
|
||||
FT_FREE( blend->hvar_table->itemStore.varRegionList );
|
||||
}
|
||||
FT_FREE( blend->hvar_table->widthMap.innerIndex );
|
||||
FT_FREE( blend->hvar_table->widthMap.outerIndex );
|
||||
FT_FREE( blend->hvar_table );
|
||||
}
|
||||
|
||||
FT_FREE( blend->tuplecoords );
|
||||
FT_FREE( blend->glyphoffsets );
|
||||
FT_FREE( blend );
|
||||
|
|
|
@ -61,6 +61,64 @@ FT_BEGIN_HEADER
|
|||
} GX_AVarSegmentRec, *GX_AVarSegment;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Struct> */
|
||||
/* GX_HVarRec */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* Data from the `HVAR' table. */
|
||||
/* */
|
||||
/* See similar variation store structures in cfftypes.h */
|
||||
/* */
|
||||
typedef struct GX_HVarData_
|
||||
{
|
||||
FT_UInt itemCount; /* # delta sets per item */
|
||||
FT_UInt regionCount; /* # regions in this var data */
|
||||
FT_UInt* regionIndices; /* array of regionCount indices */
|
||||
/* these index the varRegionList */
|
||||
FT_Short* deltaSet; /* array of itemCount deltas */
|
||||
/* use innerIndex for this array */
|
||||
} GX_HVarDataRec, *GX_HVarData;
|
||||
|
||||
typedef struct GX_AxisCoords_ /* contribution of one axis to a region */
|
||||
{
|
||||
FT_Fixed startCoord;
|
||||
FT_Fixed peakCoord; /* zero means no effect (factor = 1) */
|
||||
FT_Fixed endCoord;
|
||||
} GX_AxisCoordsRec, *GX_AxisCoords;
|
||||
|
||||
typedef struct GX_HVarRegion_
|
||||
{
|
||||
GX_AxisCoords axisList; /* array of axisCount records */
|
||||
} GX_HVarRegionRec, *GX_HVarRegion;
|
||||
|
||||
typedef struct GX_HVStoreRec_ /* HVAR item variation store */
|
||||
{
|
||||
FT_UInt dataCount;
|
||||
GX_HVarData varData; /* array of dataCount records */
|
||||
/* use outerIndex for this array */
|
||||
FT_UShort axisCount;
|
||||
FT_UInt regionCount; /* total # regions defined */
|
||||
GX_HVarRegion varRegionList;
|
||||
|
||||
} GX_HVStoreRec, *GX_HVStore;
|
||||
|
||||
typedef struct GX_WidthMapRec_
|
||||
{
|
||||
FT_UInt mapCount;
|
||||
FT_UInt* outerIndex; /* indices to item var data */
|
||||
FT_UInt* innerIndex; /* indices to delta set */
|
||||
} GX_WidthMapRec, *GX_WidthMap;
|
||||
|
||||
typedef struct GX_HVarRec_
|
||||
{
|
||||
GX_HVStoreRec itemStore; /* Item Variation Store */
|
||||
GX_WidthMapRec widthMap; /* Advance Width Mapping */
|
||||
/* GX_LSBMap LsbMap; Not implemented */
|
||||
/* GX_RSBMap RsbMap; Not implemented */
|
||||
} GX_HVarTableRec, *GX_HVarTable;
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Struct> */
|
||||
|
@ -89,6 +147,9 @@ FT_BEGIN_HEADER
|
|||
FT_Bool avar_checked;
|
||||
GX_AVarSegment avar_segment;
|
||||
|
||||
FT_Bool hvar_checked;
|
||||
GX_HVarTable hvar_table;
|
||||
|
||||
FT_UInt tuplecount; /* shared tuples in `gvar' */
|
||||
FT_Fixed* tuplecoords; /* tuplecoords[tuplecount][num_axis] */
|
||||
|
||||
|
@ -143,20 +204,29 @@ FT_BEGIN_HEADER
|
|||
#define TTAG_slnt FT_MAKE_TAG( 's', 'l', 'n', 't' )
|
||||
|
||||
|
||||
FT_LOCAL( FT_Error )
|
||||
FT_EXPORT( FT_Error )
|
||||
TT_Set_MM_Blend( TT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords );
|
||||
|
||||
FT_LOCAL( FT_Error )
|
||||
FT_EXPORT( FT_Error )
|
||||
TT_Set_Var_Design( TT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords );
|
||||
|
||||
FT_LOCAL( FT_Error )
|
||||
FT_EXPORT( FT_Error )
|
||||
TT_Get_MM_Var( TT_Face face,
|
||||
FT_MM_Var* *master );
|
||||
|
||||
FT_EXPORT( FT_Error )
|
||||
TT_Get_Var_Design( TT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords );
|
||||
|
||||
FT_EXPORT( FT_Error )
|
||||
TT_Get_Var_Blend( TT_Face face,
|
||||
FT_UInt num_coords,
|
||||
FT_Fixed* coords );
|
||||
|
||||
FT_LOCAL( FT_Error )
|
||||
tt_face_vary_cvt( TT_Face face,
|
||||
|
@ -169,8 +239,12 @@ FT_BEGIN_HEADER
|
|||
FT_Outline* outline,
|
||||
FT_UInt n_points );
|
||||
|
||||
FT_EXPORT( void )
|
||||
tt_adjust_advance( TT_Face face,
|
||||
FT_UInt gindex,
|
||||
FT_UShort *aadvance );
|
||||
|
||||
FT_LOCAL( void )
|
||||
FT_EXPORT( void )
|
||||
tt_done_blend( FT_Memory memory,
|
||||
GX_Blend blend );
|
||||
|
||||
|
|
Loading…
Reference in New Issue