📄 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 + -