Preliminary OpenType 1.8 support.

OpenType-1.8
Dave Arnold 8 years ago committed by Werner Lemberg
parent 053943a757
commit d1908a107d
  1. 9
      README
  2. 10
      include/freetype/ftmm.h
  3. 1
      include/freetype/internal/fttrace.h
  4. 25
      include/freetype/internal/services/svmm.h
  5. 1
      include/freetype/internal/tttypes.h
  6. 2
      include/freetype/tttags.h
  7. 55
      src/base/ftmm.c
  8. 4
      src/cff/cf2fixed.h
  9. 192
      src/cff/cf2font.c
  10. 10
      src/cff/cf2font.h
  11. 41
      src/cff/cf2ft.c
  12. 8
      src/cff/cf2ft.h
  13. 40
      src/cff/cf2intrp.c
  14. 28
      src/cff/cf2stack.c
  15. 9
      src/cff/cf2stack.h
  16. 32
      src/cff/cffdrivr.c
  17. 176
      src/cff/cffload.c
  18. 3
      src/cff/cffload.h
  19. 23
      src/cff/cffobjs.c
  20. 50
      src/cff/cffparse.c
  21. 3
      src/cff/cffparse.h
  22. 1
      src/cff/cffpic.h
  23. 4
      src/cff/cfftoken.h
  24. 39
      src/cff/cfftypes.h
  25. 9
      src/sfnt/sfobjs.c
  26. 10
      src/sfnt/ttmtx.c
  27. 4
      src/truetype/ttdriver.c
  28. 537
      src/truetype/ttgxvar.c
  29. 82
      src/truetype/ttgxvar.h

@ -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 = &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 );
}
}
/* 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…
Cancel
Save