📄 ttgxvar.c
字号:
FT_FRAME_START( 20 ),
FT_FRAME_LONG ( version ),
FT_FRAME_USHORT( axisCount ),
FT_FRAME_USHORT( globalCoordCount ),
FT_FRAME_ULONG ( offsetToCoord ),
FT_FRAME_USHORT( glyphCount ),
FT_FRAME_USHORT( flags ),
FT_FRAME_ULONG ( offsetToData ),
FT_FRAME_END
};
if ( (error = face->goto_table( face, TTAG_gvar, stream, &table_len )) != 0 )
goto Exit;
gvar_start = FT_STREAM_POS( );
if ( FT_STREAM_READ_FIELDS( gvar_fields, &gvar_head ) )
goto Exit;
blend->tuplecount = gvar_head.globalCoordCount;
blend->gv_glyphcnt = gvar_head.glyphCount;
offsetToData = gvar_start + gvar_head.offsetToData;
if ( gvar_head.version != (FT_Long)0x00010000L ||
gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis )
{
error = TT_Err_Invalid_Table;
goto Exit;
}
if ( FT_NEW_ARRAY( blend->glyphoffsets, blend->gv_glyphcnt + 1 ) )
goto Exit;
if ( gvar_head.flags & 1 )
{
/* long offsets (one more offset than glyphs, to mark size of last) */
if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 4L ) )
goto Exit;
for ( i = 0; i <= blend->gv_glyphcnt; ++i )
blend->glyphoffsets[i] = offsetToData + FT_GET_LONG();
FT_FRAME_EXIT();
}
else
{
/* short offsets (one more offset than glyphs, to mark size of last) */
if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 2L ) )
goto Exit;
for ( i = 0; i <= blend->gv_glyphcnt; ++i )
blend->glyphoffsets[i] = offsetToData + FT_GET_USHORT() * 2;
/* XXX: Undocumented: `*2'! */
FT_FRAME_EXIT();
}
if ( blend->tuplecount != 0 )
{
if ( FT_NEW_ARRAY( blend->tuplecoords,
gvar_head.axisCount * blend->tuplecount ) )
goto Exit;
if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord ) ||
FT_FRAME_ENTER( blend->tuplecount * gvar_head.axisCount * 2L ) )
goto Exit;
for ( i = 0; i < blend->tuplecount; ++i )
for ( j = 0 ; j < (FT_UInt)gvar_head.axisCount; ++j )
blend->tuplecoords[i * gvar_head.axisCount + j] =
FT_GET_SHORT() << 2; /* convert to FT_Fixed */
FT_FRAME_EXIT();
}
Exit:
return error;
}
/*************************************************************************/
/* */
/* <Function> */
/* ft_var_apply_tuple */
/* */
/* <Description> */
/* Figure out whether a given tuple (design) applies to the current */
/* blend, and if so, what is the scaling factor. */
/* */
/* <Input> */
/* blend :: The current blend of the font. */
/* */
/* tupleIndex :: A flag saying whether this is an intermediate */
/* tuple or not. */
/* */
/* tuple_coords :: The coordinates of the tuple in normalized axis */
/* units. */
/* */
/* im_start_coords :: The initial coordinates where this tuple starts */
/* to apply (for intermediate coordinates). */
/* */
/* im_end_coords :: The final coordinates after which this tuple no */
/* longer applies (for intermediate coordinates). */
/* */
/* <Return> */
/* An FT_Fixed value containing the scaling factor. */
/* */
static FT_Fixed
ft_var_apply_tuple( GX_Blend blend,
FT_UShort tupleIndex,
FT_Fixed* tuple_coords,
FT_Fixed* im_start_coords,
FT_Fixed* im_end_coords )
{
FT_UInt i;
FT_Fixed apply;
FT_Fixed temp;
apply = 0x10000L;
for ( i = 0; i < blend->num_axis; ++i )
{
if ( tuple_coords[i] == 0 )
/* It's not clear why (for intermediate tuples) we don't need */
/* to check against start/end -- the documentation says we don't. */
/* Similarly, it's unclear why we don't need to scale along the */
/* axis. */
continue;
else if ( blend->normalizedcoords[i] == 0 ||
( blend->normalizedcoords[i] < 0 && tuple_coords[i] > 0 ) ||
( blend->normalizedcoords[i] > 0 && tuple_coords[i] < 0 ) )
{
apply = 0;
break;
}
else if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) )
/* not an intermediate tuple */
apply = FT_MulDiv( apply,
blend->normalizedcoords[i] > 0
? blend->normalizedcoords[i]
: -blend->normalizedcoords[i],
0x10000L );
else if ( blend->normalizedcoords[i] <= im_start_coords[i] ||
blend->normalizedcoords[i] >= im_end_coords[i] )
{
apply = 0;
break;
}
else if ( blend->normalizedcoords[i] < tuple_coords[i] )
{
temp = FT_MulDiv( blend->normalizedcoords[i] - im_start_coords[i],
0x10000L,
tuple_coords[i] - im_start_coords[i]);
apply = FT_MulDiv( apply, temp, 0x10000L );
}
else
{
temp = FT_MulDiv( im_end_coords[i] - blend->normalizedcoords[i],
0x10000L,
im_end_coords[i] - tuple_coords[i] );
apply = FT_MulDiv( apply, temp, 0x10000L );
}
}
return apply;
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** MULTIPLE MASTERS SERVICE FUNCTIONS *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
typedef struct GX_FVar_Head_ {
FT_Long version;
FT_UShort offsetToData;
FT_UShort countSizePairs;
FT_UShort axisCount;
FT_UShort axisSize;
FT_UShort instanceCount;
FT_UShort instanceSize;
} GX_FVar_Head;
typedef struct fvar_axis {
FT_ULong axisTag;
FT_ULong minValue;
FT_ULong defaultValue;
FT_ULong maxValue;
FT_UShort flags;
FT_UShort nameID;
} GX_FVar_Axis;
/*************************************************************************/
/* */
/* <Function> */
/* TT_Get_MM_Var */
/* */
/* <Description> */
/* Check that the font's `fvar' table is valid, parse it, and return */
/* those data. */
/* */
/* <InOut> */
/* face :: The font face. */
/* TT_Get_MM_Var initializes the blend structure. */
/* */
/* <Output> */
/* master :: The `fvar' data (must be freed by caller). */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
FT_LOCAL_DEF( FT_Error )
TT_Get_MM_Var( TT_Face face,
FT_MM_Var* *master )
{
FT_Stream stream = face->root.stream;
FT_Memory memory = face->root.memory;
FT_ULong table_len;
FT_Error error = TT_Err_Ok;
FT_ULong fvar_start;
FT_Int i, j;
FT_MM_Var* mmvar;
FT_Fixed* next_coords;
FT_String* next_name;
FT_Var_Axis* a;
FT_Var_Named_Style* ns;
GX_FVar_Head fvar_head;
static const FT_Frame_Field fvar_fields[] =
{
#undef FT_STRUCTURE
#define FT_STRUCTURE GX_FVar_Head
FT_FRAME_START( 16 ),
FT_FRAME_LONG ( version ),
FT_FRAME_USHORT( offsetToData ),
FT_FRAME_USHORT( countSizePairs ),
FT_FRAME_USHORT( axisCount ),
FT_FRAME_USHORT( axisSize ),
FT_FRAME_USHORT( instanceCount ),
FT_FRAME_USHORT( instanceSize ),
FT_FRAME_END
};
static const FT_Frame_Field fvaraxis_fields[] =
{
#undef FT_STRUCTURE
#define FT_STRUCTURE GX_FVar_Axis
FT_FRAME_START( 20 ),
FT_FRAME_ULONG ( axisTag ),
FT_FRAME_ULONG ( minValue ),
FT_FRAME_ULONG ( defaultValue ),
FT_FRAME_ULONG ( maxValue ),
FT_FRAME_USHORT( flags ),
FT_FRAME_USHORT( nameID ),
FT_FRAME_END
};
if ( face->blend == NULL )
{
/* both `fvar' and `gvar' must be present */
if ( (error = face->goto_table( face, TTAG_gvar,
stream, &table_len )) != 0 )
goto Exit;
if ( (error = face->goto_table( face, TTAG_fvar,
stream, &table_len )) != 0 )
goto Exit;
fvar_start = FT_STREAM_POS( );
if ( FT_STREAM_READ_FIELDS( fvar_fields, &fvar_head ) )
goto Exit;
if ( fvar_head.version != (FT_Long)0x00010000L ||
fvar_head.countSizePairs != 2 ||
fvar_head.axisSize != 20 ||
fvar_head.instanceSize != 4 + 4 * fvar_head.axisCount ||
fvar_head.offsetToData + fvar_head.axisCount * 20U +
fvar_head.instanceCount * fvar_head.instanceSize > table_len )
{
error = TT_Err_Invalid_Table;
goto Exit;
}
if ( FT_NEW( face->blend ) )
goto Exit;
/* XXX: TODO - check for overflows */
face->blend->mmvar_len =
sizeof ( FT_MM_Var ) +
fvar_head.axisCount * sizeof ( FT_Var_Axis ) +
fvar_head.instanceCount * sizeof ( FT_Var_Named_Style ) +
fvar_head.instanceCount * fvar_head.axisCount * sizeof ( FT_Fixed ) +
5 * fvar_head.axisCount;
if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
goto Exit;
face->blend->mmvar = mmvar;
mmvar->num_axis =
fvar_head.axisCount;
mmvar->num_designs =
(FT_UInt)-1; /* meaningless in this context; each glyph */
/* may have a different number of designs */
/* (or tuples, as called by Apple) */
mmvar->num_namedstyles =
fvar_head.instanceCount;
mmvar->axis =
(FT_Var_Axis*)&(mmvar[1]);
mmvar->namedstyle =
(FT_Var_Named_Style*)&(mmvar->axis[fvar_head.axisCount]);
next_coords =
(FT_Fixed*)&(mmvar->namedstyle[fvar_head.instanceCount]);
for ( i = 0; i < fvar_head.instanceCount; ++i )
{
mmvar->namedstyle[i].coords = next_coords;
next_coords += fvar_head.axisCount;
}
next_name = (FT_String*)next_coords;
for ( i = 0; i < fvar_head.axisCount; ++i )
{
mmvar->axis[i].name = next_name;
next_name += 5;
}
if ( FT_STREAM_SEEK( fvar_start + fvar_head.offsetToData ) )
goto Exit;
a = mmvar->axis;
for ( i = 0; i < fvar_head.axisCount; ++i )
{
GX_FVar_Axis axis_rec;
if ( FT_STREAM_READ_FIELDS( fvaraxis_fields, &axis_rec ) )
goto Exit;
a->tag = axis_rec.axisTag;
a->minimum = axis_rec.minValue; /* A Fixed */
a->def = axis_rec.defaultValue; /* A Fixed */
a->maximum = axis_rec.maxValue; /* A Fixed */
a->strid = axis_rec.nameID;
a->name[0] = (FT_String)( a->tag >> 24 );
a->name[1] = (FT_String)( ( a->tag >> 16 ) & 0xFF );
a->name[2] = (FT_String)( ( a->tag >> 8 ) & 0xFF );
a->name[3] = (FT_String)( ( a->tag ) & 0xFF );
a->name[4] = 0;
++a;
}
ns = mmvar->namedstyle;
for ( i = 0; i < fvar_head.instanceCount; ++i )
{
if ( FT_FRAME_ENTER( 4L + 4L * fvar_head.axisCount ) )
goto Exit;
ns->strid = FT_GET_USHORT();
(void) /* flags = */ FT_GET_USHORT();
for ( j = 0; j < fvar_head.axisCount; ++j )
ns->coords[j] = FT_GET_ULONG(); /* A Fixed */
FT_FRAME_EXIT();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -