44#include FT_CONFIG_CONFIG_H
60#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
63#define FT_Stream_FTell( stream ) \
64 (FT_ULong)( (stream)->cursor - (stream)->base )
65#define FT_Stream_SeekSet( stream, off ) \
67 ( (off) < (FT_ULong)( (stream)->limit - (stream)->base ) ) \
68 ? (stream)->base + (off) \
73#define FT_fdot14ToFixed( x ) \
74 ( (FT_Fixed)( (FT_ULong)(x) << 2 ) )
75#define FT_intToFixed( i ) \
76 ( (FT_Fixed)( (FT_ULong)(i) << 16 ) )
77#define FT_fdot6ToFixed( i ) \
78 ( (FT_Fixed)( (FT_ULong)(i) << 10 ) )
79#define FT_fixedToInt( x ) \
80 ( (FT_Short)( ( (x) + 0x8000U ) >> 16 ) )
81#define FT_fixedToFdot6( x ) \
82 ( (FT_Pos)( ( (x) + 0x200 ) >> 10 ) )
92#define FT_COMPONENT ttgxvar
112#define ALL_POINTS (FT_UShort*)~(FT_PtrDist)0
115#define GX_PT_POINTS_ARE_WORDS 0x80U
116#define GX_PT_POINT_RUN_COUNT_MASK 0x7FU
143 ft_var_readpackedpoints( FT_Stream stream,
146 FT_UShort *points = NULL;
152 FT_Memory memory = stream->memory;
162 if ( n & GX_PT_POINTS_ARE_WORDS )
164 n &= GX_PT_POINT_RUN_COUNT_MASK;
169 if ( FT_QNEW_ARRAY( points, n ) )
177 if ( p >= stream->limit )
180 runcnt = FT_NEXT_BYTE( p );
181 cnt = runcnt & GX_PT_POINT_RUN_COUNT_MASK;
188 if ( runcnt & GX_PT_POINTS_ARE_WORDS )
190 if ( 2 * cnt > (FT_UInt)( stream->limit - p ) )
193 for ( j = 0; j < cnt; j++ )
195 first += FT_NEXT_USHORT( p );
201 if ( cnt > (FT_UInt)( stream->limit - p ) )
204 for ( j = 0; j < cnt; j++ )
206 first += FT_NEXT_BYTE( p );
219 FT_TRACE1((
"ft_var_readpackedpoints: invalid table\n" ));
226#define GX_DT_DELTAS_ARE_ZERO 0x80U
227#define GX_DT_DELTAS_ARE_WORDS 0x40U
228#define GX_DT_DELTA_RUN_COUNT_MASK 0x3FU
258 ft_var_readpackeddeltas( FT_Stream stream,
261 FT_Fixed *deltas = NULL;
265 FT_Memory memory = stream->memory;
269 if ( FT_QNEW_ARRAY( deltas, delta_cnt ) )
274 while ( i < delta_cnt )
276 if ( p >= stream->limit )
279 runcnt = FT_NEXT_BYTE( p );
280 cnt = runcnt & GX_DT_DELTA_RUN_COUNT_MASK;
284 if ( cnt > delta_cnt - i )
287 if ( runcnt & GX_DT_DELTAS_ARE_ZERO )
289 for ( j = 0; j < cnt; j++ )
292 else if ( runcnt & GX_DT_DELTAS_ARE_WORDS )
294 if ( 2 * cnt > (FT_UInt)( stream->limit - p ) )
297 for ( j = 0; j < cnt; j++ )
298 deltas[i++] = FT_intToFixed( FT_NEXT_SHORT( p ) );
302 if ( cnt > (FT_UInt)( stream->limit - p ) )
305 for ( j = 0; j < cnt; j++ )
306 deltas[i++] = FT_intToFixed( FT_NEXT_CHAR( p ) );
315 FT_TRACE1((
"ft_var_readpackeddeltas: invalid table\n" ));
336 ft_var_load_avar( TT_Face face )
339 FT_Stream stream = FT_FACE_STREAM( face );
340 FT_Memory memory = stream->memory;
343 GX_Blend blend = face->blend;
344 GX_AVarSegment segment;
351#ifndef TT_CONFIG_OPTION_NO_BORING_EXPANSION
352 FT_ULong table_offset;
353 FT_ULong store_offset;
354 FT_ULong axisMap_offset;
358 FT_TRACE2((
"AVAR " ));
360 blend->avar_loaded = TRUE;
361 error = face->goto_table( face, TTAG_avar, stream, &table_len );
364 FT_TRACE2((
"is missing\n" ));
368#ifndef TT_CONFIG_OPTION_NO_BORING_EXPANSION
369 table_offset = FT_STREAM_POS();
372 if ( FT_FRAME_ENTER( table_len ) )
375 version = FT_GET_LONG();
376 axisCount = FT_GET_LONG();
378 if ( version != 0x00010000L
379#ifndef TT_CONFIG_OPTION_NO_BORING_EXPANSION
380 && version != 0x00020000L
384 FT_TRACE2((
"bad table version\n" ));
388 FT_TRACE2((
"loaded\n" ));
390 if ( axisCount != (FT_Long)blend->mmvar->num_axis )
392 FT_TRACE2((
"ft_var_load_avar:"
393 " number of axes in `avar' and `fvar'\n" ));
394 FT_TRACE2((
" table are different\n" ));
398 if ( FT_NEW( blend->avar_table ) )
400 table = blend->avar_table;
402 if ( FT_QNEW_ARRAY( table->avar_segment, axisCount ) )
405 segment = &table->avar_segment[0];
406 for ( i = 0; i < axisCount; i++, segment++ )
408 FT_TRACE5((
" axis %d:\n", i ));
410 segment->pairCount = FT_GET_USHORT();
411 if ( (FT_ULong)segment->pairCount * 4 > table_len ||
412 FT_QNEW_ARRAY( segment->correspondence, segment->pairCount ) )
417 for ( j = i - 1; j >= 0; j-- )
418 FT_FREE( table->avar_segment[j].correspondence );
420 FT_FREE( table->avar_segment );
424 for ( j = 0; j < segment->pairCount; j++ )
426 segment->correspondence[j].fromCoord =
427 FT_fdot14ToFixed( FT_GET_SHORT() );
428 segment->correspondence[j].toCoord =
429 FT_fdot14ToFixed( FT_GET_SHORT() );
431 FT_TRACE5((
" mapping %.5f to %.5f\n",
432 (
double)segment->correspondence[j].fromCoord / 65536,
433 (
double)segment->correspondence[j].toCoord / 65536 ));
439#ifndef TT_CONFIG_OPTION_NO_BORING_EXPANSION
440 if ( version < 0x00020000L )
443 axisMap_offset = FT_GET_ULONG();
444 store_offset = FT_GET_ULONG();
448 error = tt_var_load_item_variation_store(
450 table_offset + store_offset,
456 if ( axisMap_offset )
458 error = tt_var_load_delta_set_index_mapping(
460 table_offset + axisMap_offset,
475 FT_LOCAL_DEF( FT_Error )
476 tt_var_load_item_variation_store( FT_Face face,
478 GX_ItemVarStore itemStore )
480 TT_Face ttface = (TT_Face)face;
481 FT_Stream stream = FT_FACE_STREAM( face );
482 FT_Memory memory = stream->memory;
486 FT_ULong region_offset;
489 FT_UShort axis_count;
490 FT_UInt region_count;
496 GX_Blend blend = ttface->blend;
497 FT_ULong* dataOffsetArray = NULL;
500 if ( FT_STREAM_SEEK( offset ) ||
501 FT_READ_USHORT( format ) )
506 FT_TRACE2((
"tt_var_load_item_variation_store: bad store format %d\n",
508 error = FT_THROW( Invalid_Table );
513 if ( FT_READ_ULONG( region_offset ) ||
514 FT_READ_USHORT( data_count ) )
520 FT_TRACE2((
"tt_var_load_item_variation_store: missing varData\n" ));
521 error = FT_THROW( Invalid_Table );
527 if ( FT_QNEW_ARRAY( dataOffsetArray, data_count ) )
530 if ( FT_FRAME_ENTER( data_count * 4 ) )
533 bytes = stream->cursor;
535 for ( i = 0; i < data_count; i++ )
536 dataOffsetArray[i] = FT_NEXT_ULONG( bytes );
541 if ( FT_STREAM_SEEK( offset + region_offset ) )
544 if ( FT_READ_USHORT( axis_count ) ||
545 FT_READ_USHORT( region_count ) )
548 if ( axis_count != (FT_Long)blend->mmvar->num_axis )
550 FT_TRACE2((
"tt_var_load_item_variation_store:"
551 " number of axes in item variation store\n" ));
553 " and `fvar' table are different\n" ));
554 error = FT_THROW( Invalid_Table );
557 itemStore->axisCount = axis_count;
560 if ( region_count >= 32768U )
562 FT_TRACE2((
"tt_var_load_item_variation_store:"
563 " too many variation region tables\n" ));
564 error = FT_THROW( Invalid_Table );
568 if ( FT_NEW_ARRAY( itemStore->varRegionList, region_count ) )
570 itemStore->regionCount = region_count;
572 if ( FT_FRAME_ENTER( (FT_Long)region_count * axis_count * 6 ) )
574 FT_TRACE2((
"tt_var_load_item_variation_store:"
575 " not enough data for variation regions\n" ));
576 error = FT_THROW( Invalid_Table );
580 bytes = stream->cursor;
582 for ( i = 0; i < region_count; i++ )
584 GX_AxisCoords axisCoords;
587 if ( FT_NEW_ARRAY( itemStore->varRegionList[i].axisList, axis_count ) )
593 axisCoords = itemStore->varRegionList[i].axisList;
595 for ( j = 0; j < itemStore->axisCount; j++ )
597 FT_Int start, peak, end;
600 start = FT_NEXT_SHORT( bytes );
601 peak = FT_NEXT_SHORT( bytes );
602 end = FT_NEXT_SHORT( bytes );
605 if ( ( start < 0 && end > 0 ) || start > peak || peak > end )
608 axisCoords[j].startCoord = FT_fdot14ToFixed( start );
609 axisCoords[j].peakCoord = FT_fdot14ToFixed( peak );
610 axisCoords[j].endCoord = FT_fdot14ToFixed( end );
619 if ( FT_NEW_ARRAY( itemStore->varData, data_count ) )
621 itemStore->dataCount = data_count;
623 for ( i = 0; i < data_count; i++ )
625 GX_ItemVarData varData = &itemStore->varData[i];
628 FT_UShort word_delta_count;
629 FT_UInt region_idx_count;
630 FT_UInt per_region_size;
633 if ( FT_STREAM_SEEK( offset + dataOffsetArray[i] ) )
636 if ( FT_READ_USHORT( item_count ) ||
637 FT_READ_USHORT( word_delta_count ) ||
638 FT_READ_USHORT( region_idx_count ) )
641 long_words = !!( word_delta_count & 0x8000 );
642 word_delta_count &= 0x7FFF;
645 if ( word_delta_count > region_idx_count )
647 FT_TRACE2((
"bad short count %d or region count %u\n",
650 error = FT_THROW( Invalid_Table );
654 if ( region_idx_count > itemStore->regionCount )
656 FT_TRACE2((
"inconsistent regionCount %u in varData[%u]\n",
659 error = FT_THROW( Invalid_Table );
664 if ( FT_NEW_ARRAY( varData->regionIndices, region_idx_count ) )
666 varData->regionIdxCount = region_idx_count;
667 varData->wordDeltaCount = word_delta_count;
668 varData->longWords = long_words;
670 if ( FT_FRAME_ENTER( region_idx_count * 2 ) )
672 FT_TRACE2((
"tt_var_load_item_variation_store:"
673 " not enough data for region indices\n" ));
674 error = FT_THROW( Invalid_Table );
678 bytes = stream->cursor;
680 for ( j = 0; j < varData->regionIdxCount; j++ )
682 varData->regionIndices[j] = FT_NEXT_USHORT( bytes );
684 if ( varData->regionIndices[j] >= itemStore->regionCount )
686 FT_TRACE2((
"bad region index %u\n",
687 varData->regionIndices[j] ));
689 error = FT_THROW( Invalid_Table );
696 per_region_size = word_delta_count + region_idx_count;
698 per_region_size *= 2;
700 if ( FT_NEW_ARRAY( varData->deltaSet, per_region_size * item_count ) )
702 if ( FT_Stream_Read( stream,
704 per_region_size * item_count ) )
706 FT_TRACE2((
"deltaSet read failed." ));
707 error = FT_THROW( Invalid_Table );
711 varData->itemCount = item_count;
715 FT_FREE( dataOffsetArray );
721 FT_LOCAL_DEF( FT_Error )
722 tt_var_load_delta_set_index_mapping( FT_Face face,
724 GX_DeltaSetIdxMap map,
725 GX_ItemVarStore itemStore,
728 FT_Stream stream = FT_FACE_STREAM( face );
729 FT_Memory memory = stream->memory;
736 FT_UInt innerBitCount;
737 FT_UInt innerIndexMask;
743 if ( FT_STREAM_SEEK( offset ) ||
744 FT_READ_BYTE( format ) ||
745 FT_READ_BYTE( entryFormat ) )
750 if ( FT_READ_USHORT( map->mapCount ) )
753 else if ( format == 1 )
755 if ( FT_READ_ULONG( map->mapCount ) )
760 FT_TRACE2((
"bad map format %d\n", format ));
761 error = FT_THROW( Invalid_Table );
765 if ( entryFormat & 0xC0 )
767 FT_TRACE2((
"bad entry format %d\n", format ));
768 error = FT_THROW( Invalid_Table );
773 entrySize = ( ( entryFormat & 0x30 ) >> 4 ) + 1;
774 innerBitCount = ( entryFormat & 0x0F ) + 1;
775 innerIndexMask = ( 1 << innerBitCount ) - 1;
778 if ( map->mapCount * entrySize > table_len )
780 FT_TRACE1((
"tt_var_load_delta_set_index_mapping:"
781 " invalid number of delta-set index mappings\n" ));
782 error = FT_THROW( Invalid_Table );
786 if ( FT_NEW_ARRAY( map->innerIndex, map->mapCount ) )
789 if ( FT_NEW_ARRAY( map->outerIndex, map->mapCount ) )
792 if ( FT_FRAME_ENTER( map->mapCount * entrySize ) )
794 FT_TRACE2((
"tt_var_load_delta_set_index_mapping:"
795 " invalid number of delta-set index mappings\n" ));
796 error = FT_THROW( Invalid_Table );
800 bytes = stream->cursor;
802 for ( i = 0; i < map->mapCount; i++ )
805 FT_UInt outerIndex, innerIndex;
809 for ( j = 0; j < entrySize; j++ )
814 data = FT_NEXT_BYTE( bytes );
815 mapData = ( mapData << 8 ) | data;
819 if ( mapData == 0xFFFFFFFFUL )
822 map->outerIndex[i] = 0xFFFFU;
823 map->innerIndex[i] = 0xFFFFU;
828 outerIndex = mapData >> innerBitCount;
830 if ( outerIndex >= itemStore->dataCount )
832 FT_TRACE2((
"outerIndex[%lu] == %u out of range\n",
835 error = FT_THROW( Invalid_Table );
839 map->outerIndex[i] = outerIndex;
841 innerIndex = mapData & innerIndexMask;
843 if ( innerIndex >= itemStore->varData[outerIndex].itemCount )
845 FT_TRACE2((
"innerIndex[%lu] == %u out of range\n",
848 error = FT_THROW( Invalid_Table );
852 map->innerIndex[i] = innerIndex;
887 ft_var_load_hvvar( TT_Face face,
890 FT_Stream stream = FT_FACE_STREAM( face );
891 FT_Memory memory = stream->memory;
893 GX_Blend blend = face->blend;
898 FT_UShort majorVersion;
900 FT_ULong table_offset;
901 FT_ULong store_offset;
902 FT_ULong widthMap_offset;
907 blend->vvar_loaded = TRUE;
909 FT_TRACE2((
"VVAR " ));
911 error = face->goto_table( face, TTAG_VVAR, stream, &table_len );
915 blend->hvar_loaded = TRUE;
917 FT_TRACE2((
"HVAR " ));
919 error = face->goto_table( face, TTAG_HVAR, stream, &table_len );
924 FT_TRACE2((
"is missing\n" ));
928 table_offset = FT_STREAM_POS();
931 if ( FT_READ_USHORT( majorVersion ) ||
932 FT_STREAM_SKIP( 2 ) )
935 if ( majorVersion != 1 )
937 FT_TRACE2((
"bad table version %d\n", majorVersion ));
938 error = FT_THROW( Invalid_Table );
942 if ( FT_READ_ULONG( store_offset ) ||
943 FT_READ_ULONG( widthMap_offset ) )
948 if ( FT_NEW( blend->vvar_table ) )
950 table = blend->vvar_table;
954 if ( FT_NEW( blend->hvar_table ) )
956 table = blend->hvar_table;
959 error = tt_var_load_item_variation_store(
961 table_offset + store_offset,
966 if ( widthMap_offset )
968 error = tt_var_load_delta_set_index_mapping(
970 table_offset + widthMap_offset,
978 FT_TRACE2((
"loaded\n" ));
986 blend->vvar_checked = TRUE;
992 face->variation_support |= TT_FACE_FLAG_VAR_VADVANCE;
996 blend->hvar_checked = TRUE;
1002 face->variation_support |= TT_FACE_FLAG_VAR_HADVANCE;
1011 tt_calculate_scalar( GX_AxisCoords axis,
1013 FT_Fixed* normalizedcoords )
1015 FT_Fixed scalar = 0x10000L;
1020 for ( j = 0; j < axisCount; j++, axis++ )
1022 FT_Fixed ncv = normalizedcoords[j];
1027 if ( axis->peakCoord == ncv ||
1028 axis->peakCoord == 0 )
1032 else if ( ncv <= axis->startCoord ||
1033 ncv >= axis->endCoord )
1040 else if ( ncv < axis->peakCoord )
1041 scalar = FT_MulDiv( scalar,
1042 ncv - axis->startCoord,
1043 axis->peakCoord - axis->startCoord );
1045 scalar = FT_MulDiv( scalar,
1046 axis->endCoord - ncv,
1047 axis->endCoord - axis->peakCoord );
1056 ft_mul_add_delta_scalar( FT_Int64 returnValue,
1063 return returnValue + (FT_Int64)delta * scalar;
1067 if ( (FT_UInt32)( delta + 0x8000 ) <= 0x20000 )
1071 FT_Int32 lo = delta * scalar;
1074 returnValue.lo += (FT_UInt32)lo;
1076 if ( returnValue.lo < (FT_UInt32)lo )
1077 returnValue.hi += ( lo < 0 ) ? 0 : 1;
1080 returnValue.hi -= 1;
1091 FT_UInt32 a = ( delta < 0 ) ? -delta : delta;
1092 FT_UInt32 b = ( scalar < 0 ) ? -scalar : scalar;
1095 FT_UInt32 a_lo = a & 0xFFFF;
1096 FT_UInt32 a_hi = a >> 16;
1098 FT_UInt32 b_lo = b & 0xFFFF;
1099 FT_UInt32 b_hi = b >> 16;
1102 FT_UInt32 p0 = a_lo * b_lo;
1103 FT_UInt32 p1 = a_lo * b_hi;
1104 FT_UInt32 p2 = a_hi * b_lo;
1105 FT_UInt32 p3 = a_hi * b_hi;
1108 FT_UInt32 mid = p1 + p2;
1109 FT_UInt32 mid_carry = ( mid < p1 );
1114 product.lo = ( mid << 16 ) + ( p0 & 0xFFFF );
1115 carry = ( product.lo < ( p0 & 0xFFFF ) ) ? 1 : 0;
1116 product.hi = p3 + ( mid >> 16 ) + mid_carry + carry;
1119 if ( ( delta < 0 ) ^ ( scalar < 0 ) )
1121 product.lo = ~product.lo + 1;
1122 product.hi = ~product.hi + ( product.lo == 0 ? 1 : 0 );
1126 returnValue.lo += product.lo;
1127 if ( returnValue.lo < product.lo )
1129 returnValue.hi += product.hi;
1139 static FT_ItemVarDelta
1140 ft_round_and_shift16( FT_Int64 returnValue )
1145 return (FT_ItemVarDelta)( returnValue + 0x8000L ) >> 16;
1149 FT_UInt hi = returnValue.hi;
1150 FT_UInt lo = returnValue.lo;
1161 delta = ( hi << 16 ) | ( lo >> 16 );
1163 return (FT_ItemVarDelta)delta;
1170 FT_LOCAL_DEF( FT_ItemVarDelta )
1171 tt_var_get_item_delta( FT_Face face,
1172 GX_ItemVarStore itemStore,
1174 FT_UInt innerIndex )
1176 TT_Face ttface = (TT_Face)face;
1178 GX_ItemVarData varData;
1181 FT_Int64 returnValue = FT_INT64_ZERO;
1182 FT_UInt shift_base = 1;
1183 FT_UInt per_region_size;
1187 if ( !ttface->blend || !ttface->blend->normalizedcoords )
1192 if ( outerIndex == 0xFFFF && innerIndex == 0xFFFF )
1198 if ( outerIndex >= itemStore->dataCount )
1201 varData = &itemStore->varData[outerIndex];
1203 if ( innerIndex >= varData->itemCount )
1206 if ( varData->regionIdxCount == 0 )
1213 per_region_size = varData->wordDeltaCount + varData->regionIdxCount;
1214 if ( varData->longWords )
1217 per_region_size *= 2;
1220 bytes = varData->deltaSet + per_region_size * innerIndex;
1223 for ( master = 0; master < varData->regionIdxCount; master++ )
1225 FT_UInt regionIndex = varData->regionIndices[master];
1227 GX_AxisCoords axis = itemStore->varRegionList[regionIndex].axisList;
1229 FT_Fixed scalar = tt_calculate_scalar(
1231 itemStore->axisCount,
1232 ttface->blend->normalizedcoords );
1240 if ( varData->longWords )
1242 if ( master < varData->wordDeltaCount )
1243 delta = FT_NEXT_LONG( bytes );
1245 delta = FT_NEXT_SHORT( bytes );
1249 if ( master < varData->wordDeltaCount )
1250 delta = FT_NEXT_SHORT( bytes );
1252 delta = FT_NEXT_CHAR( bytes );
1255 returnValue = ft_mul_add_delta_scalar( returnValue, delta, scalar );
1260 bytes += shift_base << ( master < varData->wordDeltaCount );
1265 return ft_round_and_shift16( returnValue );
1293 tt_hvadvance_adjust( TT_Face face,
1298 FT_Error error = FT_Err_Ok;
1299 FT_UInt innerIndex, outerIndex;
1302 GX_HVVarTable table;
1305 if ( !face->doblend || !face->blend )
1310 if ( !face->blend->vvar_loaded )
1313 face->blend->vvar_error = ft_var_load_hvvar( face, 1 );
1316 if ( !face->blend->vvar_checked )
1318 error = face->blend->vvar_error;
1322 table = face->blend->vvar_table;
1326 if ( !face->blend->hvar_loaded )
1329 face->blend->hvar_error = ft_var_load_hvvar( face, 0 );
1332 if ( !face->blend->hvar_checked )
1334 error = face->blend->hvar_error;
1338 table = face->blend->hvar_table;
1344 if ( table->widthMap.innerIndex )
1346 FT_UInt idx = gindex;
1349 if ( idx >= table->widthMap.mapCount )
1350 idx = table->widthMap.mapCount - 1;
1353 outerIndex = table->widthMap.outerIndex[idx];
1354 innerIndex = table->widthMap.innerIndex[idx];
1360 innerIndex = gindex;
1363 delta = tt_var_get_item_delta( FT_FACE( face ),
1370 FT_TRACE5((
"%s value %d adjusted by %d unit%s (%s)\n",
1371 vertical ?
"vertical height" :
"horizontal width",
1374 delta == 1 ?
"" :
"s",
1375 vertical ?
"VVAR" :
"HVAR" ));
1377 *avalue = ADD_INT( *avalue, delta );
1385 FT_LOCAL_DEF( FT_Error )
1386 tt_hadvance_adjust( FT_Face face,
1390 return tt_hvadvance_adjust( (TT_Face)face, gindex, avalue, 0 );
1394 FT_LOCAL_DEF( FT_Error )
1395 tt_vadvance_adjust( FT_Face face,
1399 return tt_hvadvance_adjust( (TT_Face)face, gindex, avalue, 1 );
1403#define GX_VALUE_SIZE 8
1407#define GX_VALUE_CASE( tag, dflt ) \
1408 case MVAR_TAG_ ## tag : \
1409 p = (FT_Short*)&face->dflt; \
1412#define GX_GASP_CASE( idx ) \
1413 case MVAR_TAG_GASP_ ## idx : \
1414 if ( idx < face->gasp.numRanges - 1 ) \
1415 p = (FT_Short*)&face->gasp.gaspRanges[idx].maxPPEM; \
1422 ft_var_get_value_pointer( TT_Face face,
1441 GX_VALUE_CASE( CPHT, os2.sCapHeight );
1442 GX_VALUE_CASE( HASC, os2.sTypoAscender );
1443 GX_VALUE_CASE( HCLA, os2.usWinAscent );
1444 GX_VALUE_CASE( HCLD, os2.usWinDescent );
1445 GX_VALUE_CASE( HCOF, horizontal.caret_Offset );
1446 GX_VALUE_CASE( HCRN, horizontal.caret_Slope_Run );
1447 GX_VALUE_CASE( HCRS, horizontal.caret_Slope_Rise );
1448 GX_VALUE_CASE( HDSC, os2.sTypoDescender );
1449 GX_VALUE_CASE( HLGP, os2.sTypoLineGap );
1450 GX_VALUE_CASE( SBXO, os2.ySubscriptXOffset);
1451 GX_VALUE_CASE( SBXS, os2.ySubscriptXSize );
1452 GX_VALUE_CASE( SBYO, os2.ySubscriptYOffset );
1453 GX_VALUE_CASE( SBYS, os2.ySubscriptYSize );
1454 GX_VALUE_CASE( SPXO, os2.ySuperscriptXOffset );
1455 GX_VALUE_CASE( SPXS, os2.ySuperscriptXSize );
1456 GX_VALUE_CASE( SPYO, os2.ySuperscriptYOffset );
1457 GX_VALUE_CASE( SPYS, os2.ySuperscriptYSize );
1458 GX_VALUE_CASE( STRO, os2.yStrikeoutPosition );
1459 GX_VALUE_CASE( STRS, os2.yStrikeoutSize );
1460 GX_VALUE_CASE( UNDO, postscript.underlinePosition );
1461 GX_VALUE_CASE( UNDS, postscript.underlineThickness );
1462 GX_VALUE_CASE( VASC, vertical.Ascender );
1463 GX_VALUE_CASE( VCOF, vertical.caret_Offset );
1464 GX_VALUE_CASE( VCRN, vertical.caret_Slope_Run );
1465 GX_VALUE_CASE( VCRS, vertical.caret_Slope_Rise );
1466 GX_VALUE_CASE( VDSC, vertical.Descender );
1467 GX_VALUE_CASE( VLGP, vertical.Line_Gap );
1468 GX_VALUE_CASE( XHGT, os2.sxHeight );
1495 ft_var_load_mvar( TT_Face face )
1497 FT_Stream stream = FT_FACE_STREAM( face );
1498 FT_Memory memory = stream->memory;
1500 GX_Blend blend = face->blend;
1501 GX_ItemVarStore itemStore;
1502 GX_Value value, limit;
1505 FT_UShort majorVersion;
1507 FT_ULong table_offset;
1508 FT_UShort store_offset;
1509 FT_ULong records_offset;
1512 FT_TRACE2((
"MVAR " ));
1514 error = face->goto_table( face, TTAG_MVAR, stream, &table_len );
1517 FT_TRACE2((
"is missing\n" ));
1521 table_offset = FT_STREAM_POS();
1524 if ( FT_READ_USHORT( majorVersion ) ||
1525 FT_STREAM_SKIP( 2 ) )
1528 if ( majorVersion != 1 )
1530 FT_TRACE2((
"bad table version %d\n", majorVersion ));
1534 if ( FT_NEW( blend->mvar_table ) )
1538 if ( FT_STREAM_SKIP( 4 ) ||
1539 FT_READ_USHORT( blend->mvar_table->valueCount ) ||
1540 FT_READ_USHORT( store_offset ) )
1543 records_offset = FT_STREAM_POS();
1545 error = tt_var_load_item_variation_store(
1547 table_offset + store_offset,
1548 &blend->mvar_table->itemStore );
1552 if ( FT_NEW_ARRAY( blend->mvar_table->values,
1553 blend->mvar_table->valueCount ) )
1556 if ( FT_STREAM_SEEK( records_offset ) ||
1557 FT_FRAME_ENTER( blend->mvar_table->valueCount * GX_VALUE_SIZE ) )
1560 value = blend->mvar_table->values;
1561 limit = FT_OFFSET( value, blend->mvar_table->valueCount );
1562 itemStore = &blend->mvar_table->itemStore;
1564 for ( ; value < limit; value++ )
1566 value->tag = FT_GET_ULONG();
1567 value->outerIndex = FT_GET_USHORT();
1568 value->innerIndex = FT_GET_USHORT();
1571 if ( value->outerIndex == 0xFFFFU && value->innerIndex == 0xFFFFU )
1577 if ( value->outerIndex >= itemStore->dataCount ||
1578 value->innerIndex >= itemStore->varData[value->outerIndex]
1581 error = FT_THROW( Invalid_Table );
1591 FT_TRACE2((
"loaded\n" ));
1593 value = blend->mvar_table->values;
1594 limit = FT_OFFSET( value, blend->mvar_table->valueCount );
1597 for ( ; value < limit; value++ )
1599 FT_Short* p = ft_var_get_value_pointer( face, value->tag );
1603 value->unmodified = *p;
1604#ifdef FT_DEBUG_LEVEL_TRACE
1606 FT_TRACE1((
"ft_var_load_mvar: Ignoring unknown tag `%c%c%c%c'\n",
1607 (FT_Char)( value->tag >> 24 ),
1608 (FT_Char)( value->tag >> 16 ),
1609 (FT_Char)( value->tag >> 8 ),
1610 (FT_Char)( value->tag ) ));
1614 face->variation_support |= TT_FACE_FLAG_VAR_MVAR;
1619 ft_size_reset_iterator( FT_ListNode node,
1622 FT_Size size = (FT_Size)node->data;
1623 FT_Service_MetricsVariations var = (FT_Service_MetricsVariations)user;
1626 var->size_reset( size );
1644 FT_LOCAL_DEF(
void )
1645 tt_apply_mvar( FT_Face face )
1647 TT_Face ttface = (TT_Face)face;
1649 GX_Blend blend = ttface->blend;
1650 GX_Value value, limit;
1652 FT_Short mvar_hasc_delta = 0;
1653 FT_Short mvar_hdsc_delta = 0;
1654 FT_Short mvar_hlgp_delta = 0;
1657 if ( !( ttface->variation_support & TT_FACE_FLAG_VAR_MVAR ) )
1660 value = blend->mvar_table->values;
1661 limit = FT_OFFSET( value, blend->mvar_table->valueCount );
1663 for ( ; value < limit; value++ )
1665 FT_Short* p = ft_var_get_value_pointer( ttface, value->tag );
1669 delta = tt_var_get_item_delta( face,
1670 &blend->mvar_table->itemStore,
1672 value->innerIndex );
1676 FT_TRACE5((
"value %c%c%c%c (%d unit%s) adjusted by %d unit%s (MVAR)\n",
1677 (FT_Char)( value->tag >> 24 ),
1678 (FT_Char)( value->tag >> 16 ),
1679 (FT_Char)( value->tag >> 8 ),
1680 (FT_Char)( value->tag ),
1682 value->unmodified == 1 ?
"" :
"s",
1684 delta == 1 ?
"" :
"s" ));
1688 *p = (FT_Short)( value->unmodified + (FT_Short)delta );
1691 if ( value->tag == MVAR_TAG_HASC )
1692 mvar_hasc_delta = (FT_Short)delta;
1693 else if ( value->tag == MVAR_TAG_HDSC )
1694 mvar_hdsc_delta = (FT_Short)delta;
1695 else if ( value->tag == MVAR_TAG_HLGP )
1696 mvar_hlgp_delta = (FT_Short)delta;
1702 FT_Service_MetricsVariations var =
1703 (FT_Service_MetricsVariations)ttface->face_var;
1731 FT_Short current_line_gap = face->height - face->ascender +
1735 face->ascender = face->ascender + mvar_hasc_delta;
1736 face->descender = face->descender + mvar_hdsc_delta;
1737 face->height = face->ascender - face->descender +
1738 current_line_gap + mvar_hlgp_delta;
1740 face->underline_position = ttface->postscript.underlinePosition -
1741 ttface->postscript.underlineThickness / 2;
1742 face->underline_thickness = ttface->postscript.underlineThickness;
1746 if ( var && var->size_reset )
1747 FT_List_Iterate( &face->sizes_list,
1748 ft_size_reset_iterator,
1754 typedef struct GX_GVar_Head_
1757 FT_UShort axisCount;
1758 FT_UShort globalCoordCount;
1759 FT_ULong offsetToCoord;
1760 FT_UShort glyphCount;
1762 FT_ULong offsetToData;
1784 ft_var_load_gvar( TT_Face face )
1786 FT_Stream stream = FT_FACE_STREAM( face );
1787 FT_Memory memory = stream->memory;
1788 GX_Blend blend = face->blend;
1793 FT_ULong gvar_start;
1794 FT_ULong offsetToData;
1795 FT_ULong offsets_len;
1796 GX_GVar_Head gvar_head;
1798 static const FT_Frame_Field gvar_fields[] =
1802#define FT_STRUCTURE GX_GVar_Head
1804 FT_FRAME_START( 20 ),
1805 FT_FRAME_LONG ( version ),
1806 FT_FRAME_USHORT( axisCount ),
1807 FT_FRAME_USHORT( globalCoordCount ),
1808 FT_FRAME_ULONG ( offsetToCoord ),
1809 FT_FRAME_USHORT( glyphCount ),
1810 FT_FRAME_USHORT( flags ),
1811 FT_FRAME_ULONG ( offsetToData ),
1816 FT_TRACE2((
"GVAR " ));
1818 if ( FT_SET_ERROR( face->goto_table( face,
1823 FT_TRACE2((
"is missing\n" ));
1827 gvar_start = FT_STREAM_POS( );
1828 if ( FT_STREAM_READ_FIELDS( gvar_fields, &gvar_head ) )
1831 if ( gvar_head.version != 0x00010000L )
1833 FT_TRACE1((
"bad table version\n" ));
1834 error = FT_THROW( Invalid_Table );
1838 if ( gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis )
1840 FT_TRACE1((
"ft_var_load_gvar:"
1841 " number of axes in `gvar' and `cvar'\n" ));
1842 FT_TRACE1((
" table are different\n" ));
1843 error = FT_THROW( Invalid_Table );
1848 if ( (FT_ULong)gvar_head.globalCoordCount * gvar_head.axisCount >
1851 FT_TRACE1((
"ft_var_load_gvar:"
1852 " invalid number of global coordinates\n" ));
1853 error = FT_THROW( Invalid_Table );
1859 offsets_len = ( gvar_head.glyphCount + 1 ) *
1860 ( ( gvar_head.flags & 1 ) ? 4L : 2L );
1863 if (offsets_len > table_len )
1865 FT_TRACE1((
"ft_var_load_gvar: invalid number of glyphs\n" ));
1866 error = FT_THROW( Invalid_Table );
1870 FT_TRACE2((
"loaded\n" ));
1872 blend->gvar_size = table_len;
1873 offsetToData = gvar_start + gvar_head.offsetToData;
1875 FT_TRACE5((
"gvar: there %s %d shared coordinate%s:\n",
1876 gvar_head.globalCoordCount == 1 ?
"is" :
"are",
1877 gvar_head.globalCoordCount,
1878 gvar_head.globalCoordCount == 1 ?
"" :
"s" ));
1880 if ( FT_FRAME_ENTER( offsets_len ) )
1883 bytes = stream->cursor;
1886 if ( FT_QNEW_ARRAY( blend->glyphoffsets, gvar_head.glyphCount + 1 ) )
1889 if ( gvar_head.flags & 1 )
1891 FT_ULong limit = gvar_start + table_len;
1892 FT_ULong max_offset = 0;
1895 if ( stream->limit - stream->cursor < gvar_head.glyphCount * 4 )
1897 FT_TRACE2((
"ft_var_load_gvar:"
1898 " glyph variation data offset not enough\n" ));
1899 error = FT_THROW( Invalid_Table );
1903 for ( i = 0; i <= gvar_head.glyphCount; i++ )
1905 blend->glyphoffsets[i] = offsetToData + FT_NEXT_ULONG( bytes );
1907 if ( max_offset <= blend->glyphoffsets[i] )
1908 max_offset = blend->glyphoffsets[i];
1911 FT_TRACE2((
"ft_var_load_gvar:"
1912 " glyph variation data offset %u not monotonic\n",
1914 blend->glyphoffsets[i] = max_offset;
1918 if ( limit < blend->glyphoffsets[i] )
1920 FT_TRACE2((
"ft_var_load_gvar:"
1921 " glyph variation data offset %u out of range\n",
1923 blend->glyphoffsets[i] = limit;
1929 FT_ULong limit = gvar_start + table_len;
1930 FT_ULong max_offset = 0;
1933 if ( stream->limit - stream->cursor < gvar_head.glyphCount * 2 )
1935 FT_TRACE2((
"ft_var_load_gvar:"
1936 " glyph variation data offset not enough\n" ));
1937 error = FT_THROW( Invalid_Table );
1941 for ( i = 0; i <= gvar_head.glyphCount; i++ )
1943 blend->glyphoffsets[i] = offsetToData + FT_NEXT_USHORT( bytes ) * 2;
1945 if ( max_offset <= blend->glyphoffsets[i] )
1946 max_offset = blend->glyphoffsets[i];
1949 FT_TRACE2((
"ft_var_load_gvar:"
1950 " glyph variation data offset %u not monotonic\n",
1952 blend->glyphoffsets[i] = max_offset;
1956 if ( limit < blend->glyphoffsets[i] )
1958 FT_TRACE2((
"ft_var_load_gvar:"
1959 " glyph variation data offset %u out of range\n",
1961 blend->glyphoffsets[i] = limit;
1966 blend->gv_glyphcnt = gvar_head.glyphCount;
1970 if ( gvar_head.globalCoordCount != 0 )
1972 if ( FT_STREAM_SEEK( gvar_start + gvar_head.offsetToCoord ) ||
1973 FT_FRAME_ENTER( gvar_head.globalCoordCount *
1974 gvar_head.axisCount * 2L ) )
1976 FT_TRACE2((
"ft_var_load_gvar:"
1977 " glyph variation shared tuples missing\n" ));
1981 bytes = stream->cursor;
1983 if ( FT_QNEW_ARRAY( blend->tuplecoords,
1984 gvar_head.axisCount * gvar_head.globalCoordCount ) )
1987 for ( i = 0; i < gvar_head.globalCoordCount; i++ )
1989 FT_TRACE5((
" [ " ));
1990 for ( j = 0; j < (FT_UInt)gvar_head.axisCount; j++ )
1992 blend->tuplecoords[i * gvar_head.axisCount + j] =
1993 FT_fdot14ToFixed( FT_NEXT_SHORT( bytes ) );
1994 FT_TRACE5((
"%.5f ",
1995 (
double)blend->tuplecoords[i * gvar_head.axisCount + j] / 65536 ));
1997 FT_TRACE5((
"]\n" ));
2000 if ( FT_NEW_ARRAY( blend->tuplescalars,
2001 gvar_head.globalCoordCount ) )
2004 blend->tuplecount = gvar_head.globalCoordCount;
2006 FT_TRACE5((
"\n" ));
2018 FT_FREE( blend->glyphoffsets );
2019 blend->gv_glyphcnt = 0;
2057 ft_var_apply_tuple( GX_Blend blend,
2058 FT_UShort tupleIndex,
2059 FT_Fixed* tuple_coords,
2060 FT_Fixed* im_start_coords,
2061 FT_Fixed* im_end_coords )
2064 FT_Fixed apply = 0x10000L;
2067 for ( i = 0; i < blend->num_axis; i++ )
2072 if ( tuple_coords[i] == 0 )
2074 FT_TRACE6((
" tuple coordinate is zero, ignore\n" ));
2078 ncv = blend->normalizedcoords[i];
2080 FT_TRACE6((
" axis %u coordinate %.5f:\n", i, (
double)ncv / 65536 ));
2084 FT_TRACE6((
" axis coordinate is zero, stop\n" ));
2089 if ( tuple_coords[i] == ncv )
2091 FT_TRACE6((
" tuple coordinate %.5f fits perfectly\n",
2092 (
double)tuple_coords[i] / 65536 ));
2097 if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) )
2101 if ( ( tuple_coords[i] > ncv && ncv > 0 ) ||
2102 ( tuple_coords[i] < ncv && ncv < 0 ) )
2104 FT_TRACE6((
" tuple coordinate %.5f fits\n",
2105 (
double)tuple_coords[i] / 65536 ));
2106 apply = FT_MulDiv( apply, ncv, tuple_coords[i] );
2110 FT_TRACE6((
" tuple coordinate %.5f is exceeded, stop\n",
2111 (
double)tuple_coords[i] / 65536 ));
2120 if ( ncv <= im_start_coords[i] ||
2121 ncv >= im_end_coords[i] )
2123 FT_TRACE6((
" intermediate tuple range ]%.5f;%.5f[ is exceeded,"
2125 (
double)im_start_coords[i] / 65536,
2126 (
double)im_end_coords[i] / 65536 ));
2131 FT_TRACE6((
" intermediate tuple range ]%.5f;%.5f[ fits\n",
2132 (
double)im_start_coords[i] / 65536,
2133 (
double)im_end_coords[i] / 65536 ));
2134 if ( ncv < tuple_coords[i] )
2135 apply = FT_MulDiv( apply,
2136 ncv - im_start_coords[i],
2137 tuple_coords[i] - im_start_coords[i] );
2139 apply = FT_MulDiv( apply,
2140 im_end_coords[i] - ncv,
2141 im_end_coords[i] - tuple_coords[i] );
2145 FT_TRACE6((
" apply factor is %.5f\n", (
double)apply / 65536 ));
2154 ft_var_to_normalized( TT_Face face,
2157 FT_Fixed* normalized )
2159 FT_Error error = FT_Err_Ok;
2160 FT_Memory memory = face->root.memory;
2168 FT_Fixed* new_normalized = NULL;
2169 FT_Fixed* old_normalized;
2172 blend = face->blend;
2173 mmvar = blend->mmvar;
2175 if ( num_coords > mmvar->num_axis )
2177 FT_TRACE2((
"ft_var_to_normalized:"
2178 " only using first %u of %u coordinates\n",
2179 mmvar->num_axis, num_coords ));
2180 num_coords = mmvar->num_axis;
2188 for ( i = 0; i < num_coords; i++, a++ )
2190 FT_Fixed coord = coords[i];
2193 FT_TRACE5((
" %u: %.5f\n", i, (
double)coord / 65536 ));
2194 if ( coord > a->maximum || coord < a->minimum )
2196 FT_TRACE1((
"ft_var_to_normalized: design coordinate %.5f\n",
2197 (
double)coord / 65536 ));
2198 FT_TRACE1((
" is out of range [%.5f;%.5f];"
2200 (
double)a->minimum / 65536,
2201 (
double)a->maximum / 65536 ));
2204 if ( coord > a->def )
2205 normalized[i] = coord >= a->maximum ? 0x10000L :
2206 FT_DivFix( SUB_LONG( coord, a->def ),
2207 SUB_LONG( a->maximum, a->def ) );
2208 else if ( coord < a->def )
2209 normalized[i] = coord <= a->minimum ? -0x10000L :
2210 FT_DivFix( SUB_LONG( coord, a->def ),
2211 SUB_LONG( a->def, a->minimum ) );
2216 FT_TRACE5((
"\n" ));
2218 for ( ; i < mmvar->num_axis; i++ )
2221 if ( blend->avar_table )
2223 GX_AVarTable table = blend->avar_table;
2226 FT_TRACE5((
"normalized design coordinates"
2227 " before applying `avar' data:\n" ));
2229 if ( table->avar_segment )
2231 av = table->avar_segment;
2233 for ( i = 0; i < mmvar->num_axis; i++, av++ )
2235 for ( j = 1; j < (FT_UInt)av->pairCount; j++ )
2237 if ( normalized[i] < av->correspondence[j].fromCoord )
2239 FT_TRACE5((
" %.5f\n", (
double)normalized[i] / 65536 ));
2242 FT_MulDiv( normalized[i] - av->correspondence[j - 1].fromCoord,
2243 av->correspondence[j].toCoord -
2244 av->correspondence[j - 1].toCoord,
2245 av->correspondence[j].fromCoord -
2246 av->correspondence[j - 1].fromCoord ) +
2247 av->correspondence[j - 1].toCoord;
2254 if ( table->itemStore.varData )
2256 if ( FT_QNEW_ARRAY( new_normalized, mmvar->num_axis ) )
2261 old_normalized = face->blend->normalizedcoords;
2262 face->blend->normalizedcoords = normalized;
2264 for ( i = 0; i < mmvar->num_axis; i++ )
2266 FT_Fixed v = normalized[i];
2267 FT_UInt innerIndex = i;
2268 FT_UInt outerIndex = 0;
2272 if ( table->axisMap.innerIndex )
2277 if ( idx >= table->axisMap.mapCount )
2278 idx = table->axisMap.mapCount - 1;
2280 outerIndex = table->axisMap.outerIndex[idx];
2281 innerIndex = table->axisMap.innerIndex[idx];
2284 delta = tt_var_get_item_delta( FT_FACE( face ),
2290 v += MUL_INT( delta, 4 );
2293 v = v >= 0x10000L ? 0x10000 : v;
2294 v = v <= -0x10000L ? -0x10000 : v;
2296 new_normalized[i] = v;
2299 for ( i = 0; i < mmvar->num_axis; i++ )
2301 normalized[i] = new_normalized[i];
2304 face->blend->normalizedcoords = old_normalized;
2306 FT_FREE( new_normalized );
2315 ft_var_to_design( TT_Face face,
2327 blend = face->blend;
2330 if ( num_coords > blend->num_axis )
2332 FT_TRACE2((
"ft_var_to_design:"
2333 " only using first %u of %u coordinates\n",
2334 blend->num_axis, num_coords ));
2335 nc = blend->num_axis;
2338 for ( i = 0; i < nc; i++ )
2339 design[i] = coords[i];
2341 for ( ; i < num_coords; i++ )
2344 if ( blend->avar_table && blend->avar_table->avar_segment )
2346 GX_AVarSegment av = blend->avar_table->avar_segment;
2349 FT_TRACE5((
"design coordinates"
2350 " after removing `avar' distortion:\n" ));
2352 for ( i = 0; i < nc; i++, av++ )
2354 for ( j = 1; j < (FT_UInt)av->pairCount; j++ )
2356 if ( design[i] < av->correspondence[j].toCoord )
2359 FT_MulDiv( design[i] - av->correspondence[j - 1].toCoord,
2360 av->correspondence[j].fromCoord -
2361 av->correspondence[j - 1].fromCoord,
2362 av->correspondence[j].toCoord -
2363 av->correspondence[j - 1].toCoord ) +
2364 av->correspondence[j - 1].fromCoord;
2366 FT_TRACE5((
" %.5f\n", (
double)design[i] / 65536 ));
2373 mmvar = blend->mmvar;
2376 for ( i = 0; i < nc; i++, a++ )
2378 if ( design[i] < 0 )
2379 design[i] = a->def + FT_MulFix( design[i],
2380 a->def - a->minimum );
2381 else if ( design[i] > 0 )
2382 design[i] = a->def + FT_MulFix( design[i],
2383 a->maximum - a->def );
2399 typedef struct GX_FVar_Head_
2402 FT_UShort offsetToData;
2403 FT_UShort axisCount;
2405 FT_UShort instanceCount;
2406 FT_UShort instanceSize;
2411 typedef struct fvar_axis_
2415 FT_Fixed defaultValue;
2446 FT_LOCAL_DEF( FT_Error )
2447 TT_Get_MM_Var( FT_Face face,
2448 FT_MM_Var* *master )
2450 TT_Face ttface = (TT_Face)face;
2451 FT_Stream stream = FT_FACE_STREAM( face );
2452 FT_Memory memory = FT_FACE_MEMORY( face );
2454 FT_Error error = FT_Err_Ok;
2455 FT_ULong fvar_start = 0;
2457 FT_MM_Var* mmvar = NULL;
2458 FT_Fixed* next_coords;
2460 FT_String* next_name;
2463 FT_Var_Named_Style* ns;
2464 GX_FVar_Head fvar_head = { 0, 0, 0, 0, 0, 0 };
2465 FT_Bool usePsName = 0;
2466 FT_UInt num_instances;
2468 FT_UShort* axis_flags;
2470 FT_Offset mmvar_size;
2471 FT_Offset axis_flags_size;
2472 FT_Offset axis_size;
2473 FT_Offset namedstyle_size;
2474 FT_Offset next_coords_size;
2475 FT_Offset next_name_size;
2479 static const FT_Frame_Field fvar_fields[] =
2483#define FT_STRUCTURE GX_FVar_Head
2485 FT_FRAME_START( 16 ),
2486 FT_FRAME_LONG ( version ),
2487 FT_FRAME_USHORT ( offsetToData ),
2488 FT_FRAME_SKIP_SHORT,
2489 FT_FRAME_USHORT ( axisCount ),
2490 FT_FRAME_USHORT ( axisSize ),
2491 FT_FRAME_USHORT ( instanceCount ),
2492 FT_FRAME_USHORT ( instanceSize ),
2496 static const FT_Frame_Field fvaraxis_fields[] =
2500#define FT_STRUCTURE GX_FVar_Axis
2502 FT_FRAME_START( 20 ),
2503 FT_FRAME_ULONG ( axisTag ),
2504 FT_FRAME_LONG ( minValue ),
2505 FT_FRAME_LONG ( defaultValue ),
2506 FT_FRAME_LONG ( maxValue ),
2507 FT_FRAME_USHORT( flags ),
2508 FT_FRAME_USHORT( nameID ),
2516 num_instances = (FT_UInt)face->style_flags >> 16;
2521 need_init = !ttface->blend;
2525 FT_TRACE2((
"FVAR " ));
2527 if ( FT_SET_ERROR( ttface->goto_table( ttface, TTAG_fvar,
2528 stream, &table_len ) ) )
2530 FT_TRACE1((
"is missing\n" ));
2534 fvar_start = FT_STREAM_POS( );
2538 if ( FT_STREAM_READ_FIELDS( fvar_fields, &fvar_head ) )
2546 if ( num_instances < fvar_head.instanceCount )
2548 error = FT_THROW( Invalid_Table );
2552 usePsName = FT_BOOL( fvar_head.instanceSize ==
2553 6 + 4 * fvar_head.axisCount );
2555 FT_TRACE2((
"loaded\n" ));
2557 FT_TRACE5((
"%d variation ax%s\n",
2558 fvar_head.axisCount,
2559 fvar_head.axisCount == 1 ?
"is" :
"es" ));
2561 if ( FT_NEW( ttface->blend ) )
2564 num_axes = fvar_head.axisCount;
2565 ttface->blend->num_axis = num_axes;
2568 num_axes = ttface->blend->num_axis;
2580#define ALIGN_SIZE( n ) \
2581 ( ( (n) + sizeof (void*) - 1 ) & ~( sizeof (void*) - 1 ) )
2583 mmvar_size = ALIGN_SIZE(
sizeof ( FT_MM_Var ) );
2584 axis_flags_size = ALIGN_SIZE( num_axes *
2585 sizeof ( FT_UShort ) );
2586 axis_size = ALIGN_SIZE( num_axes *
2587 sizeof ( FT_Var_Axis ) );
2588 namedstyle_size = ALIGN_SIZE( num_instances *
2589 sizeof ( FT_Var_Named_Style ) );
2590 next_coords_size = ALIGN_SIZE( num_instances *
2592 sizeof ( FT_Fixed ) );
2593 next_name_size = num_axes * 5;
2597 ttface->blend->mmvar_len = mmvar_size +
2604 if ( FT_ALLOC( mmvar, ttface->blend->mmvar_len ) )
2606 ttface->blend->mmvar = mmvar;
2613 mmvar->num_designs =
2617 mmvar->num_namedstyles =
2622 (FT_UShort*)( (
char*)mmvar + mmvar_size );
2624 (FT_Var_Axis*)( (
char*)axis_flags + axis_flags_size );
2626 (FT_Var_Named_Style*)( (
char*)mmvar->axis + axis_size );
2628 next_coords = (FT_Fixed*)( (
char*)mmvar->namedstyle +
2630 for ( i = 0; i < num_instances; i++ )
2632 mmvar->namedstyle[i].coords = next_coords;
2633 next_coords += num_axes;
2636 next_name = (FT_String*)( (
char*)mmvar->namedstyle +
2637 namedstyle_size + next_coords_size );
2638 for ( i = 0; i < num_axes; i++ )
2640 mmvar->axis[i].name = next_name;
2646 if ( FT_STREAM_SEEK( fvar_start + fvar_head.offsetToData ) )
2650 for ( i = 0; i < num_axes; i++ )
2652 GX_FVar_Axis axis_rec;
2654#ifdef FT_DEBUG_LEVEL_TRACE
2659 if ( FT_STREAM_READ_FIELDS( fvaraxis_fields, &axis_rec ) )
2661 a->tag = axis_rec.axisTag;
2662 a->minimum = axis_rec.minValue;
2663 a->def = axis_rec.defaultValue;
2664 a->maximum = axis_rec.maxValue;
2665 a->strid = axis_rec.nameID;
2667 a->name[0] = (FT_String)( a->tag >> 24 );
2668 a->name[1] = (FT_String)( ( a->tag >> 16 ) & 0xFF );
2669 a->name[2] = (FT_String)( ( a->tag >> 8 ) & 0xFF );
2670 a->name[3] = (FT_String)( ( a->tag ) & 0xFF );
2673 *axis_flags = axis_rec.flags;
2675 if ( a->minimum > a->def ||
2676 a->def > a->maximum )
2678 a->minimum = a->def;
2679 a->maximum = a->def;
2681#ifdef FT_DEBUG_LEVEL_TRACE
2686#ifdef FT_DEBUG_LEVEL_TRACE
2688 FT_TRACE5((
" idx tag "
2690 " minimum default maximum flags\n" ));
2693 FT_TRACE5((
" %3u `%s'"
2694 " %10.5f %10.5f %10.5f 0x%04X%s\n",
2697 (
double)a->minimum / 65536,
2698 (
double)a->def / 65536,
2699 (
double)a->maximum / 65536,
2701 invalid ?
" (invalid, disabled)" :
"" ));
2708 FT_TRACE5((
"\n" ));
2712 if ( FT_NEW_ARRAY( ttface->blend->normalized_stylecoords,
2713 num_axes * num_instances ) )
2716 if ( fvar_head.instanceCount && !ttface->blend->avar_loaded )
2718 FT_ULong offset = FT_STREAM_POS();
2721 ft_var_load_avar( ttface );
2723 if ( FT_STREAM_SEEK( offset ) )
2727 FT_TRACE5((
"%d named instance%s\n",
2728 fvar_head.instanceCount,
2729 fvar_head.instanceCount == 1 ?
"" :
"s" ));
2731 ns = mmvar->namedstyle;
2732 nsc = ttface->blend->normalized_stylecoords;
2733 for ( i = 0; i < fvar_head.instanceCount; i++, ns++ )
2736 if ( FT_FRAME_ENTER( ( usePsName ? 6L : 4L ) +
2740 ns->strid = FT_GET_USHORT();
2741 (void) FT_GET_USHORT();
2744 for ( j = 0; j < num_axes; j++, c++ )
2749 ns->psid = FT_GET_USHORT();
2753#ifdef FT_DEBUG_LEVEL_TRACE
2755 SFNT_Service sfnt = (SFNT_Service)ttface->sfnt;
2757 FT_String* strname = NULL;
2758 FT_String* psname = NULL;
2763 pos = FT_STREAM_POS();
2765 if ( ns->strid != 0xFFFF )
2767 (void)sfnt->get_name( ttface,
2768 (FT_UShort)ns->strid,
2770 if ( strname && !ft_strcmp( strname,
".notdef" ) )
2774 if ( ns->psid != 0xFFFF )
2776 (void)sfnt->get_name( ttface,
2777 (FT_UShort)ns->psid,
2779 if ( psname && !ft_strcmp( psname,
".notdef" ) )
2783 (void)FT_STREAM_SEEK( pos );
2785 FT_TRACE5((
" named instance %u (%s%s%s, %s%s%s)\n",
2787 strname ?
"name: `" :
"",
2788 strname ? strname :
"unnamed",
2790 psname ?
"PS name: `" :
"",
2791 psname ? psname :
"no PS name",
2792 psname ?
"'" :
"" ));
2799 ft_var_to_normalized( ttface, num_axes, ns->coords, nsc );
2805 if ( num_instances != fvar_head.instanceCount )
2807 SFNT_Service sfnt = (SFNT_Service)ttface->sfnt;
2809 FT_Int found, dummy1, dummy2;
2810 FT_UInt strid = ~0U;
2817 found = sfnt->get_name_id( ttface,
2818 TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY,
2822 strid = TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY;
2825 found = sfnt->get_name_id( ttface,
2826 TT_NAME_ID_FONT_SUBFAMILY,
2830 strid = TT_NAME_ID_FONT_SUBFAMILY;
2835 found = sfnt->get_name_id( ttface,
2841 FT_TRACE5((
"TT_Get_MM_Var:"
2842 " Adding default instance to named instances\n" ));
2845 ttface->var_default_named_instance = num_instances;
2847 ns = &mmvar->namedstyle[fvar_head.instanceCount];
2850 ns->psid = TT_NAME_ID_PS_NAME;
2854 for ( j = 0; j < num_axes; j++, a++, c++ )
2860 ft_var_load_mvar( ttface );
2870 if ( FT_DUP( mmvar, ttface->blend->mmvar, ttface->blend->mmvar_len ) )
2874 (FT_UShort*)( (
char*)mmvar + mmvar_size );
2876 (FT_Var_Axis*)( (
char*)axis_flags + axis_flags_size );
2878 (FT_Var_Named_Style*)( (
char*)mmvar->axis+ axis_size );
2880 next_coords = (FT_Fixed*)( (
char*)mmvar->namedstyle +
2882 for ( n = 0; n < mmvar->num_namedstyles; n++ )
2884 mmvar->namedstyle[n].coords = next_coords;
2885 next_coords += num_axes;
2889 next_name = (FT_String*)( (
char*)mmvar->namedstyle +
2890 namedstyle_size + next_coords_size );
2891 for ( n = 0; n < num_axes; n++ )
2893 a->name = next_name;
2896 if ( a->tag == TTAG_wght )
2897 a->name = (
char*)
"Weight";
2898 else if ( a->tag == TTAG_wdth )
2899 a->name = (
char*)
"Width";
2900 else if ( a->tag == TTAG_opsz )
2901 a->name = (
char*)
"OpticalSize";
2902 else if ( a->tag == TTAG_slnt )
2903 a->name = (
char*)
"Slant";
2904 else if ( a->tag == TTAG_ital )
2905 a->name = (
char*)
"Italic";
2920 tt_set_mm_blend( TT_Face face,
2923 FT_Bool set_design_coords )
2925 FT_Error error = FT_Err_Ok;
2930 FT_Bool all_design_coords = FALSE;
2932 FT_Memory memory = face->root.memory;
2945 face->doblend = FALSE;
2946 for ( i = 0; i < num_coords; i++ )
2949 face->doblend = TRUE;
2952 if ( !face->doblend )
2955 if ( FT_SET_ERROR( TT_Get_MM_Var( FT_FACE( face ), NULL ) ) )
2959 blend = face->blend;
2960 mmvar = blend->mmvar;
2962 if ( num_coords > mmvar->num_axis )
2964 FT_TRACE2((
"TT_Set_MM_Blend:"
2965 " only using first %u of %u coordinates\n",
2966 mmvar->num_axis, num_coords ));
2967 num_coords = mmvar->num_axis;
2970 FT_TRACE5((
"TT_Set_MM_Blend:\n" ));
2971 FT_TRACE5((
" normalized design coordinates:\n" ));
2973 for ( i = 0; i < num_coords; i++ )
2975 FT_TRACE5((
" %.5f\n", (
double)coords[i] / 65536 ));
2976 if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L )
2978 FT_TRACE1((
"TT_Set_MM_Blend: normalized design coordinate %.5f\n",
2979 (
double)coords[i] / 65536 ));
2980 FT_TRACE1((
" is out of range [-1;1]\n" ));
2981 error = FT_THROW( Invalid_Argument );
2986 FT_TRACE5((
"\n" ));
2988 if ( !face->is_cff2 && !blend->glyphoffsets )
2994 error = ft_var_load_gvar( face );
2995 if ( error != FT_Err_Table_Missing && error != FT_Err_Ok )
3000 if ( !blend->coords )
3002 if ( FT_NEW_ARRAY( blend->coords, mmvar->num_axis ) )
3006 all_design_coords = TRUE;
3009 if ( !blend->normalizedcoords )
3011 if ( FT_NEW_ARRAY( blend->normalizedcoords, mmvar->num_axis ) )
3014 manageCvt = mcvt_modify;
3022 FT_Bool have_diff = 0;
3028 manageCvt = mcvt_retain;
3030 for ( i = 0; i < num_coords; i++ )
3032 if ( blend->normalizedcoords[i] != coords[i] )
3034 manageCvt = mcvt_load;
3042 if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) )
3044 FT_UInt instance_index = (FT_UInt)face->root.face_index >> 16;
3047 c = blend->normalizedcoords + i;
3048 n = blend->normalized_stylecoords +
3049 ( instance_index - 1 ) * mmvar->num_axis +
3052 for ( j = i; j < mmvar->num_axis; j++, n++, c++ )
3058 c = blend->normalizedcoords + i;
3059 for ( j = i; j < mmvar->num_axis; j++, c++ )
3069 for ( ; i < mmvar->num_axis; i++ )
3071 if ( blend->normalizedcoords[i] != 0 )
3073 manageCvt = mcvt_load;
3084 blend->num_axis = mmvar->num_axis;
3086 FT_MEM_COPY( blend->normalizedcoords,
3088 num_coords * sizeof ( FT_Fixed ) );
3090 if ( set_design_coords )
3091 ft_var_to_design( face,
3092 all_design_coords ? blend->num_axis : num_coords,
3093 blend->normalizedcoords,
3096 face->doblend = FALSE;
3097 for ( i = 0; i < blend->num_axis; i++ )
3099 if ( blend->normalizedcoords[i] )
3101 face->doblend = TRUE;
3108 switch ( manageCvt )
3113 FT_FREE( face->cvt );
3115 error = tt_face_load_cvt( face, face->root.stream );
3121 error = tt_face_vary_cvt( face, face->root.stream );
3130 for ( i = 0 ; i < blend->tuplecount ; i++ )
3131 blend->tuplescalars[i] = (FT_Fixed)-0x20000L;
3167 FT_LOCAL_DEF( FT_Error )
3168 TT_Set_MM_Blend( FT_Face face,
3175 error = tt_set_mm_blend( (TT_Face)face, num_coords, coords, 1 );
3176 if ( error == FT_Err_Ok )
3181 for ( i = 0; i < num_coords; i++ )
3220 FT_LOCAL_DEF( FT_Error )
3221 TT_Get_MM_Blend( FT_Face face,
3225 TT_Face ttface = (TT_Face)face;
3227 FT_Error error = FT_Err_Ok;
3232 if ( !ttface->blend )
3234 if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
3238 blend = ttface->blend;
3240 if ( !blend->coords )
3244 if ( FT_SET_ERROR( tt_set_mm_blend( ttface, 0, NULL, 1 ) ) )
3249 if ( num_coords > blend->num_axis )
3251 FT_TRACE2((
"TT_Get_MM_Blend:"
3252 " only using first %u of %u coordinates\n",
3253 blend->num_axis, num_coords ));
3254 nc = blend->num_axis;
3257 if ( ttface->doblend )
3259 for ( i = 0; i < nc; i++ )
3260 coords[i] = blend->normalizedcoords[i];
3264 for ( i = 0; i < nc; i++ )
3268 for ( ; i < num_coords; i++ )
3303 FT_LOCAL_DEF( FT_Error )
3304 TT_Set_Var_Design( FT_Face face,
3308 TT_Face ttface = (TT_Face)face;
3309 FT_Error error = FT_Err_Ok;
3313 FT_Memory memory = FT_FACE_MEMORY( face );
3317 FT_Fixed* normalized = NULL;
3319 FT_Bool have_diff = 0;
3322 if ( !ttface->blend )
3324 if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
3328 blend = ttface->blend;
3329 mmvar = blend->mmvar;
3331 if ( num_coords > mmvar->num_axis )
3333 FT_TRACE2((
"TT_Set_Var_Design:"
3334 " only using first %u of %u coordinates\n",
3335 mmvar->num_axis, num_coords ));
3336 num_coords = mmvar->num_axis;
3339 if ( !blend->coords )
3341 if ( FT_NEW_ARRAY( blend->coords, mmvar->num_axis ) )
3347 for ( i = 0; i < num_coords; i++, n++, c++ )
3356 if ( FT_IS_NAMED_INSTANCE( face ) )
3358 FT_UInt instance_index;
3359 FT_Var_Named_Style* named_style;
3362 instance_index = (FT_UInt)face->face_index >> 16;
3363 named_style = mmvar->namedstyle + instance_index - 1;
3365 n = named_style->coords + num_coords;
3366 for ( ; i < mmvar->num_axis; i++, n++, c++ )
3380 a = mmvar->axis + num_coords;
3381 for ( ; i < mmvar->num_axis; i++, a++, c++ )
3393 if ( blend->normalizedcoords && !have_diff )
3396 if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) )
3399 if ( !ttface->blend->avar_loaded )
3400 ft_var_load_avar( ttface );
3402 FT_TRACE5((
"TT_Set_Var_Design:\n" ));
3403 FT_TRACE5((
" normalized design coordinates:\n" ));
3404 ft_var_to_normalized( ttface, num_coords, blend->coords, normalized );
3406 error = tt_set_mm_blend( ttface, mmvar->num_axis, normalized, 0 );
3410 for ( i = 0; i < num_coords; i++ )
3412 if ( normalized[i] )
3420 FT_FREE( normalized );
3450 FT_LOCAL_DEF( FT_Error )
3451 TT_Get_Var_Design( FT_Face face,
3455 TT_Face ttface = (TT_Face)face;
3456 FT_Error error = FT_Err_Ok;
3463 if ( !ttface->blend )
3465 if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
3469 blend = ttface->blend;
3471 if ( !blend->coords )
3475 if ( FT_SET_ERROR( tt_set_mm_blend( ttface, 0, NULL, 1 ) ) )
3480 if ( num_coords > blend->num_axis )
3482 FT_TRACE2((
"TT_Get_Var_Design:"
3483 " only using first %u of %u coordinates\n",
3484 blend->num_axis, num_coords ));
3485 nc = blend->num_axis;
3488 mmvar = blend->mmvar;
3490 if ( ttface->doblend )
3492 for ( i = 0; i < nc; i++, a++ )
3493 coords[i] = blend->coords[i];
3497 for ( i = 0; i < nc; i++, a++ )
3501 for ( ; i < num_coords; i++, a++ )
3529 FT_LOCAL_DEF( FT_Error )
3530 TT_Set_Named_Instance( FT_Face face,
3531 FT_UInt instance_index )
3533 TT_Face ttface = (TT_Face)face;
3538 FT_Memory memory = FT_FACE_MEMORY( face );
3540 FT_UInt num_instances;
3543 if ( !ttface->blend )
3545 if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
3549 blend = ttface->blend;
3550 mmvar = blend->mmvar;
3552 num_instances = (FT_UInt)face->style_flags >> 16;
3555 if ( instance_index > num_instances )
3557 error = FT_ERR( Invalid_Argument );
3561 if ( instance_index > 0 )
3563 SFNT_Service sfnt = (SFNT_Service)ttface->sfnt;
3565 FT_Var_Named_Style* named_style;
3566 FT_String* style_name;
3569 named_style = mmvar->namedstyle + instance_index - 1;
3571 error = sfnt->get_name( ttface,
3572 (FT_UShort)named_style->strid,
3578 FT_FREE( face->style_name );
3579 face->style_name = style_name;
3582 error = TT_Set_Var_Design( face,
3584 named_style->coords );
3589 FT_FREE( face->style_name );
3590 if ( FT_STRDUP( face->style_name, ttface->non_var_style_name ) )
3592 error = TT_Set_Var_Design( face, 0, NULL );
3595 if ( error == -1 || error == -2 )
3622 FT_LOCAL_DEF( FT_Error )
3623 TT_Get_Default_Named_Instance( FT_Face face,
3624 FT_UInt *instance_index )
3626 TT_Face ttface = (TT_Face)face;
3627 FT_Error error = FT_Err_Ok;
3630 if ( !ttface->blend )
3632 if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
3636 *instance_index = ttface->var_default_named_instance;
3646 FT_LOCAL_DEF(
void )
3647 tt_construct_ps_name( FT_Face face )
3649 TT_Face ttface = (TT_Face)face;
3650 FT_Memory memory = FT_FACE_MEMORY( face );
3653 FT_FREE( ttface->postscript_name );
3666#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
3669 tt_cvt_ready_iterator( FT_ListNode node,
3672 TT_Size size = (TT_Size)node->data;
3677 size->cvt_ready = -1;
3709 FT_LOCAL_DEF( FT_Error )
3710 tt_face_vary_cvt( TT_Face face,
3713#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
3716 FT_Memory memory = stream->memory;
3718 FT_Face root = &face->root;
3720 FT_ULong table_start;
3724 FT_ULong offsetToData;
3729 FT_Fixed* peak_coords = NULL;
3730 FT_Fixed* tuple_coords;
3731 FT_Fixed* im_start_coords;
3732 FT_Fixed* im_end_coords;
3734 GX_Blend blend = face->blend;
3736 FT_UInt point_count;
3737 FT_UInt spoint_count = 0;
3739 FT_UShort* sharedpoints = NULL;
3740 FT_UShort* localpoints = NULL;
3743 FT_Fixed* deltas = NULL;
3744 FT_Fixed* cvt_deltas = NULL;
3747 FT_TRACE2((
"CVAR " ));
3751 FT_TRACE2((
"\n" ));
3752 FT_TRACE2((
"tt_face_vary_cvt: no blend specified\n" ));
3759 FT_TRACE2((
"\n" ));
3760 FT_TRACE2((
"tt_face_vary_cvt: no `cvt ' table\n" ));
3765 error = face->goto_table( face, TTAG_cvar, stream, &table_len );
3768 FT_TRACE2((
"is missing\n" ));
3773 if ( FT_FRAME_ENTER( table_len ) )
3776 table_start = FT_Stream_FTell( stream );
3777 if ( FT_GET_LONG() != 0x00010000L )
3779 FT_TRACE2((
"bad table version\n" ));
3785 FT_TRACE2((
"loaded\n" ));
3787 tupleCount = FT_GET_USHORT();
3788 offsetToData = FT_GET_USHORT();
3791 if ( offsetToData + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) * 4 >
3794 FT_TRACE2((
"tt_face_vary_cvt:"
3795 " invalid CVT variation array header\n" ));
3797 error = FT_THROW( Invalid_Table );
3801 offsetToData += table_start;
3803 if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS )
3805 here = FT_Stream_FTell( stream );
3807 FT_Stream_SeekSet( stream, offsetToData );
3809 sharedpoints = ft_var_readpackedpoints( stream, &spoint_count );
3811 offsetToData = FT_Stream_FTell( stream );
3813 FT_Stream_SeekSet( stream, here );
3816 FT_TRACE5((
"cvar: there %s %u tuple%s:\n",
3817 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ?
"is" :
"are",
3818 tupleCount & GX_TC_TUPLE_COUNT_MASK,
3819 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ?
"" :
"s" ));
3821 if ( FT_QNEW_ARRAY( peak_coords, 3 * blend->num_axis ) ||
3822 FT_NEW_ARRAY( cvt_deltas, face->cvt_size ) )
3825 im_start_coords = peak_coords + blend->num_axis;
3826 im_end_coords = im_start_coords + blend->num_axis;
3828 for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ )
3830 FT_UInt tupleDataSize;
3835 FT_TRACE6((
" tuple %u:\n", i ));
3837 tupleDataSize = FT_GET_USHORT();
3838 tupleIndex = FT_GET_USHORT();
3840 if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
3842 for ( j = 0; j < blend->num_axis; j++ )
3843 peak_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() );
3844 tuple_coords = peak_coords;
3846 else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) < blend->tuplecount )
3847 tuple_coords = blend->tuplecoords +
3848 ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis;
3851 FT_TRACE2((
"tt_face_vary_cvt:"
3852 " invalid tuple index\n" ));
3854 error = FT_THROW( Invalid_Table );
3858 if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
3860 for ( j = 0; j < blend->num_axis; j++ )
3861 im_start_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() );
3862 for ( j = 0; j < blend->num_axis; j++ )
3863 im_end_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() );
3866 apply = ft_var_apply_tuple( blend,
3867 (FT_UShort)tupleIndex,
3874 offsetToData += tupleDataSize;
3878 here = FT_Stream_FTell( stream );
3880 FT_Stream_SeekSet( stream, offsetToData );
3882 if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS )
3884 localpoints = ft_var_readpackedpoints( stream, &point_count );
3885 points = localpoints;
3890 points = sharedpoints;
3891 point_count = spoint_count;
3894 deltas = ft_var_readpackeddeltas( stream,
3895 point_count == 0 ? face->cvt_size
3898 if ( !points || !deltas )
3901 else if ( points == ALL_POINTS )
3903#ifdef FT_DEBUG_LEVEL_TRACE
3908 FT_TRACE7((
" CVT deltas:\n" ));
3911 for ( j = 0; j < face->cvt_size; j++ )
3913 FT_Fixed old_cvt_delta;
3916 old_cvt_delta = cvt_deltas[j];
3917 cvt_deltas[j] = old_cvt_delta + FT_MulFix( deltas[j], apply );
3919#ifdef FT_DEBUG_LEVEL_TRACE
3920 if ( old_cvt_delta != cvt_deltas[j] )
3922 FT_TRACE7((
" %u: %f -> %f\n",
3924 (
double)( FT_fdot6ToFixed( face->cvt[j] ) +
3925 old_cvt_delta ) / 65536,
3926 (
double)( FT_fdot6ToFixed( face->cvt[j] ) +
3927 cvt_deltas[j] ) / 65536 ));
3933#ifdef FT_DEBUG_LEVEL_TRACE
3935 FT_TRACE7((
" none\n" ));
3941#ifdef FT_DEBUG_LEVEL_TRACE
3946 FT_TRACE7((
" CVT deltas:\n" ));
3948 for ( j = 0; j < point_count; j++ )
3951 FT_Fixed old_cvt_delta;
3955 if ( (FT_ULong)pindex >= face->cvt_size )
3958 old_cvt_delta = cvt_deltas[pindex];
3959 cvt_deltas[pindex] = old_cvt_delta + FT_MulFix( deltas[j], apply );
3961#ifdef FT_DEBUG_LEVEL_TRACE
3962 if ( old_cvt_delta != cvt_deltas[pindex] )
3964 FT_TRACE7((
" %d: %f -> %f\n",
3966 (
double)( FT_fdot6ToFixed( face->cvt[pindex] ) +
3967 old_cvt_delta ) / 65536,
3968 (
double)( FT_fdot6ToFixed( face->cvt[pindex] ) +
3969 cvt_deltas[pindex] ) / 65536 ));
3975#ifdef FT_DEBUG_LEVEL_TRACE
3977 FT_TRACE7((
" none\n" ));
3981 if ( localpoints != ALL_POINTS )
3982 FT_FREE( localpoints );
3985 offsetToData += tupleDataSize;
3987 FT_Stream_SeekSet( stream, here );
3990 FT_TRACE5((
"\n" ));
3992 for ( i = 0; i < face->cvt_size; i++ )
3993 face->cvt[i] += FT_fixedToFdot6( cvt_deltas[i] );
3997 FT_List_Iterate( &root->sizes_list,
3998 tt_cvt_ready_iterator,
4002 if ( sharedpoints != ALL_POINTS )
4003 FT_FREE( sharedpoints );
4004 FT_FREE( cvt_deltas );
4005 FT_FREE( peak_coords );
4015 FT_UNUSED( stream );
4030 tt_delta_shift(
int p1,
4033 FT_Vector* in_points,
4034 FT_Vector* out_points )
4040 delta.x = out_points[ref].x - in_points[ref].x;
4041 delta.y = out_points[ref].y - in_points[ref].y;
4043 if ( delta.x == 0 && delta.y == 0 )
4046 for ( p = p1; p < ref; p++ )
4048 out_points[p].x += delta.x;
4049 out_points[p].y += delta.y;
4052 for ( p = ref + 1; p <= p2; p++ )
4054 out_points[p].x += delta.x;
4055 out_points[p].y += delta.y;
4067 tt_delta_interpolate(
int p1,
4071 FT_Vector* in_points,
4072 FT_Vector* out_points )
4076 FT_Pos out, in1, in2, out1, out2, d1, d2;
4083 for ( i = 0; i <= 1; i++ )
4086 in_points = (FT_Vector*)( (FT_Pos*)in_points + i );
4087 out_points = (FT_Vector*)( (FT_Pos*)out_points + i );
4089 if ( in_points[ref1].x > in_points[ref2].x )
4096 in1 = in_points[ref1].x;
4097 in2 = in_points[ref2].x;
4098 out1 = out_points[ref1].x;
4099 out2 = out_points[ref2].x;
4105 if ( in1 != in2 || out1 == out2 )
4107 FT_Fixed scale = in1 != in2 ? FT_DivFix( out2 - out1, in2 - in1 )
4111 for ( p = p1; p <= p2; p++ )
4113 out = in_points[p].x;
4117 else if ( out >= in2 )
4120 out = out1 + FT_MulFix( out - in1, scale );
4122 out_points[p].x = out;
4135 tt_interpolate_deltas( FT_Outline* outline,
4136 FT_Vector* out_points,
4137 FT_Vector* in_points,
4138 FT_Bool* has_delta )
4151 if ( !outline->n_contours )
4159 end_point = outline->contours[contour];
4160 first_point = point;
4163 while ( point <= end_point && !has_delta[point] )
4166 if ( point <= end_point )
4168 first_delta = point;
4173 while ( point <= end_point )
4177 if ( has_delta[point] )
4179 tt_delta_interpolate( cur_delta + 1,
4192 if ( cur_delta == first_delta )
4193 tt_delta_shift( first_point,
4202 tt_delta_interpolate( cur_delta + 1,
4209 if ( first_delta > 0 )
4210 tt_delta_interpolate( first_point,
4220 }
while ( contour < outline->n_contours );
4247 FT_LOCAL_DEF( FT_Error )
4248 TT_Vary_Apply_Glyph_Deltas( TT_Loader loader,
4249 FT_Outline* outline,
4250 FT_Vector* unrounded )
4252 FT_Error error = FT_Err_Ok;
4253 TT_Face face = loader->face;
4254 FT_Stream stream = face->root.stream;
4255 FT_Memory memory = stream->memory;
4256 FT_UInt glyph_index = loader->glyph_index;
4257 FT_UInt n_points = (FT_UInt)outline->n_points + 4;
4259 FT_Vector* points_org = NULL;
4260 FT_Vector* points_out = NULL;
4261 FT_Bool* has_delta = NULL;
4263 FT_ULong glyph_start;
4266 FT_ULong offsetToData;
4272 FT_UInt peak_coords_size;
4273 FT_UInt point_deltas_x_size;
4274 FT_UInt points_org_size;
4275 FT_UInt points_out_size;
4276 FT_UInt has_delta_size;
4278 FT_Byte* pool = NULL;
4281 FT_Fixed* peak_coords = NULL;
4282 FT_Fixed* tuple_coords;
4283 FT_Fixed* im_start_coords;
4284 FT_Fixed* im_end_coords;
4286 GX_Blend blend = face->blend;
4288 FT_UInt point_count;
4289 FT_UInt spoint_count = 0;
4291 FT_UShort* sharedpoints = NULL;
4292 FT_UShort* localpoints = NULL;
4295 FT_Fixed* deltas_x = NULL;
4296 FT_Fixed* deltas_y = NULL;
4297 FT_Fixed* point_deltas_x = NULL;
4298 FT_Fixed* point_deltas_y = NULL;
4301 for ( i = 0; i < n_points; i++ )
4303 unrounded[i].x = INT_TO_F26DOT6( outline->points[i].x );
4304 unrounded[i].y = INT_TO_F26DOT6( outline->points[i].y );
4307 if ( !face->doblend )
4311 return FT_THROW( Invalid_Argument );
4313 if ( glyph_index >= blend->gv_glyphcnt ||
4314 blend->glyphoffsets[glyph_index] ==
4315 blend->glyphoffsets[glyph_index + 1] )
4317 FT_TRACE2((
"TT_Vary_Apply_Glyph_Deltas:"
4318 " no variation data for glyph %u\n", glyph_index ));
4322 dataSize = blend->glyphoffsets[glyph_index + 1] -
4323 blend->glyphoffsets[glyph_index];
4325 if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] ) ||
4326 FT_FRAME_ENTER( dataSize ) )
4329 glyph_start = FT_Stream_FTell( stream );
4333 tupleCount = FT_GET_USHORT();
4334 offsetToData = FT_GET_USHORT();
4337 if ( offsetToData > dataSize ||
4338 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) * 4 > dataSize )
4340 FT_TRACE2((
"TT_Vary_Apply_Glyph_Deltas:"
4341 " invalid glyph variation array header\n" ));
4343 error = FT_THROW( Invalid_Table );
4347 offsetToData += glyph_start;
4349 if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS )
4351 here = FT_Stream_FTell( stream );
4353 FT_Stream_SeekSet( stream, offsetToData );
4355 sharedpoints = ft_var_readpackedpoints( stream, &spoint_count );
4357 offsetToData = FT_Stream_FTell( stream );
4359 FT_Stream_SeekSet( stream, here );
4362 FT_TRACE5((
"gvar: there %s %u tuple%s:\n",
4363 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ?
"is" :
"are",
4364 tupleCount & GX_TC_TUPLE_COUNT_MASK,
4365 ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ?
"" :
"s" ));
4367 peak_coords_size = ALIGN_SIZE( 3 * blend->num_axis *
4368 sizeof ( *peak_coords ) );
4369 point_deltas_x_size = ALIGN_SIZE( 2 * n_points *
4370 sizeof ( *point_deltas_x ) );
4371 points_org_size = ALIGN_SIZE( n_points *
sizeof ( *points_org ) );
4372 points_out_size = ALIGN_SIZE( n_points *
sizeof ( *points_out ) );
4373 has_delta_size = ALIGN_SIZE( n_points *
sizeof ( *has_delta ) );
4375 pool_size = peak_coords_size +
4376 point_deltas_x_size +
4381 if ( FT_ALLOC( pool, pool_size ) )
4385 peak_coords = (FT_Fixed*)p;
4386 p += peak_coords_size;
4387 point_deltas_x = (FT_Fixed*)p;
4388 p += point_deltas_x_size;
4389 points_org = (FT_Vector*)p;
4390 p += points_org_size;
4391 points_out = (FT_Vector*)p;
4392 p += points_out_size;
4393 has_delta = (FT_Bool*)p;
4395 FT_ARRAY_ZERO( point_deltas_x, 2 * n_points );
4397 im_start_coords = peak_coords + blend->num_axis;
4398 im_end_coords = im_start_coords + blend->num_axis;
4399 point_deltas_y = point_deltas_x + n_points;
4401 for ( j = 0; j < n_points; j++ )
4403 points_org[j].x = FT_intToFixed( outline->points[j].x );
4404 points_org[j].y = FT_intToFixed( outline->points[j].y );
4409 tupleCount &= GX_TC_TUPLE_COUNT_MASK;
4410 for ( i = 0; i < tupleCount; i++ )
4412 FT_UInt tupleDataSize;
4415 FT_Fixed* tupleScalars;
4418 FT_TRACE6((
" tuple %u:\n", i ));
4420 tupleScalars = blend->tuplescalars;
4423 if ( 4 > stream->limit - p )
4425 FT_TRACE2((
"TT_Vary_Apply_Glyph_Deltas:"
4426 " invalid glyph variation array header\n" ));
4427 error = FT_THROW( Invalid_Table );
4431 tupleDataSize = FT_NEXT_USHORT( p );
4432 tupleIndex = FT_NEXT_USHORT( p );
4434 if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
4435 tupleScalars = NULL;
4437 if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
4439 if ( 2 * blend->num_axis > (FT_UInt)( stream->limit - p ) )
4441 FT_TRACE2((
"TT_Vary_Apply_Glyph_Deltas:"
4442 " invalid glyph variation array header\n" ));
4443 error = FT_THROW( Invalid_Table );
4447 for ( j = 0; j < blend->num_axis; j++ )
4448 peak_coords[j] = FT_fdot14ToFixed( FT_NEXT_SHORT( p ) );
4450 tuple_coords = peak_coords;
4451 tupleScalars = NULL;
4453 else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) < blend->tuplecount )
4457 ? tupleScalars[tupleIndex & GX_TI_TUPLE_INDEX_MASK]
4458 : (FT_Fixed)-0x20000;
4461 if ( scalar != (FT_Fixed)-0x20000 )
4467 tuple_coords = blend->tuplecoords +
4468 ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) *
4473 FT_TRACE2((
"TT_Vary_Apply_Glyph_Deltas:"
4474 " invalid tuple index\n" ));
4476 error = FT_THROW( Invalid_Table );
4480 if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
4482 if ( 4 * blend->num_axis > (FT_UInt)( stream->limit - p ) )
4484 FT_TRACE2((
"TT_Vary_Apply_Glyph_Deltas:"
4485 " invalid glyph variation array header\n" ));
4486 error = FT_THROW( Invalid_Table );
4490 for ( j = 0; j < blend->num_axis; j++ )
4491 im_start_coords[j] = FT_fdot14ToFixed( FT_NEXT_SHORT( p ) );
4492 for ( j = 0; j < blend->num_axis; j++ )
4493 im_end_coords[j] = FT_fdot14ToFixed( FT_NEXT_SHORT( p ) );
4496 apply = ft_var_apply_tuple( blend,
4497 (FT_UShort)tupleIndex,
4503 tupleScalars[tupleIndex & GX_TI_TUPLE_INDEX_MASK] = apply;
4509 offsetToData += tupleDataSize;
4513 here = FT_Stream_FTell( stream );
4515 FT_Stream_SeekSet( stream, offsetToData );
4517 if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS )
4519 localpoints = ft_var_readpackedpoints( stream, &point_count );
4520 points = localpoints;
4524 points = sharedpoints;
4525 point_count = spoint_count;
4528 deltas_x = ft_var_readpackeddeltas( stream,
4529 point_count == 0 ? n_points
4531 deltas_y = ft_var_readpackeddeltas( stream,
4532 point_count == 0 ? n_points
4535 if ( !points || !deltas_y || !deltas_x )
4538 else if ( points == ALL_POINTS )
4540#ifdef FT_DEBUG_LEVEL_TRACE
4545 FT_TRACE7((
" point deltas:\n" ));
4548 for ( j = 0; j < n_points; j++ )
4550 FT_Fixed old_point_delta_x = point_deltas_x[j];
4551 FT_Fixed old_point_delta_y = point_deltas_y[j];
4553 FT_Fixed point_delta_x = FT_MulFix( deltas_x[j], apply );
4554 FT_Fixed point_delta_y = FT_MulFix( deltas_y[j], apply );
4557 point_deltas_x[j] = old_point_delta_x + point_delta_x;
4558 point_deltas_y[j] = old_point_delta_y + point_delta_y;
4560#ifdef FT_DEBUG_LEVEL_TRACE
4561 if ( point_delta_x || point_delta_y )
4563 FT_TRACE7((
" %u: (%f, %f) -> (%f, %f)\n",
4565 (
double)( FT_intToFixed( outline->points[j].x ) +
4566 old_point_delta_x ) / 65536,
4567 (
double)( FT_intToFixed( outline->points[j].y ) +
4568 old_point_delta_y ) / 65536,
4569 (
double)( FT_intToFixed( outline->points[j].x ) +
4570 point_deltas_x[j] ) / 65536,
4571 (
double)( FT_intToFixed( outline->points[j].y ) +
4572 point_deltas_y[j] ) / 65536 ));
4578#ifdef FT_DEBUG_LEVEL_TRACE
4580 FT_TRACE7((
" none\n" ));
4586#ifdef FT_DEBUG_LEVEL_TRACE
4593 for ( j = 0; j < n_points; j++ )
4595 has_delta[j] = FALSE;
4596 points_out[j] = points_org[j];
4599 for ( j = 0; j < point_count; j++ )
4601 FT_UShort idx = points[j];
4604 if ( idx >= n_points )
4607 has_delta[idx] = TRUE;
4609 points_out[idx].x += FT_MulFix( deltas_x[j], apply );
4610 points_out[idx].y += FT_MulFix( deltas_y[j], apply );
4615 tt_interpolate_deltas( outline,
4620 FT_TRACE7((
" point deltas:\n" ));
4622 for ( j = 0; j < n_points; j++ )
4624 FT_Fixed old_point_delta_x = point_deltas_x[j];
4625 FT_Fixed old_point_delta_y = point_deltas_y[j];
4627 FT_Pos point_delta_x = points_out[j].x - points_org[j].x;
4628 FT_Pos point_delta_y = points_out[j].y - points_org[j].y;
4631 point_deltas_x[j] = old_point_delta_x + point_delta_x;
4632 point_deltas_y[j] = old_point_delta_y + point_delta_y;
4634#ifdef FT_DEBUG_LEVEL_TRACE
4635 if ( point_delta_x || point_delta_y )
4637 FT_TRACE7((
" %u: (%f, %f) -> (%f, %f)\n",
4639 (
double)( FT_intToFixed( outline->points[j].x ) +
4640 old_point_delta_x ) / 65536,
4641 (
double)( FT_intToFixed( outline->points[j].y ) +
4642 old_point_delta_y ) / 65536,
4643 (
double)( FT_intToFixed( outline->points[j].x ) +
4644 point_deltas_x[j] ) / 65536,
4645 (
double)( FT_intToFixed( outline->points[j].y ) +
4646 point_deltas_y[j] ) / 65536 ));
4652#ifdef FT_DEBUG_LEVEL_TRACE
4654 FT_TRACE7((
" none\n" ));
4658 if ( localpoints != ALL_POINTS )
4659 FT_FREE( localpoints );
4660 FT_FREE( deltas_x );
4661 FT_FREE( deltas_y );
4663 offsetToData += tupleDataSize;
4665 FT_Stream_SeekSet( stream, here );
4668 FT_TRACE5((
"\n" ));
4673 if ( face->variation_support & TT_FACE_FLAG_VAR_HADVANCE )
4675 point_deltas_x[n_points - 4] = 0;
4676 point_deltas_y[n_points - 4] = 0;
4677 point_deltas_x[n_points - 3] = 0;
4678 point_deltas_y[n_points - 3] = 0;
4680 if ( face->variation_support & TT_FACE_FLAG_VAR_VADVANCE )
4682 point_deltas_x[n_points - 2] = 0;
4683 point_deltas_y[n_points - 2] = 0;
4684 point_deltas_x[n_points - 1] = 0;
4685 point_deltas_y[n_points - 1] = 0;
4688 for ( i = 0; i < n_points; i++ )
4690 unrounded[i].x += FT_fixedToFdot6( point_deltas_x[i] );
4691 unrounded[i].y += FT_fixedToFdot6( point_deltas_y[i] );
4693 outline->points[i].x += FT_fixedToInt( point_deltas_x[i] );
4694 outline->points[i].y += FT_fixedToInt( point_deltas_y[i] );
4700 if ( !( face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) )
4702 loader->pp1 = outline->points[n_points - 4];
4703 loader->pp2 = outline->points[n_points - 3];
4704 loader->linear = FT_PIX_ROUND( unrounded[n_points - 3].x -
4705 unrounded[n_points - 4].x ) / 64;
4707 if ( !( face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) )
4709 loader->pp3 = outline->points[n_points - 2];
4710 loader->pp4 = outline->points[n_points - 1];
4711 loader->vadvance = FT_PIX_ROUND( unrounded[n_points - 1].y -
4712 unrounded[n_points - 2].y ) / 64;
4716 if ( sharedpoints != ALL_POINTS )
4717 FT_FREE( sharedpoints );
4737 FT_LOCAL_DEF( FT_Error )
4738 tt_get_var_blend( FT_Face face,
4739 FT_UInt *num_coords,
4741 FT_Fixed* *normalizedcoords,
4742 FT_MM_Var* *mm_var )
4744 TT_Face ttface = (TT_Face)face;
4747 if ( ttface->blend )
4750 *num_coords = ttface->blend->num_axis;
4752 *coords = ttface->blend->coords;
4753 if ( normalizedcoords )
4754 *normalizedcoords = ttface->blend->normalizedcoords;
4756 *mm_var = ttface->blend->mmvar;
4772 FT_LOCAL_DEF(
void )
4773 tt_var_done_item_variation_store( FT_Face face,
4774 GX_ItemVarStore itemStore )
4776 FT_Memory memory = FT_FACE_MEMORY( face );
4780 if ( itemStore->varData )
4782 for ( i = 0; i < itemStore->dataCount; i++ )
4784 FT_FREE( itemStore->varData[i].regionIndices );
4785 FT_FREE( itemStore->varData[i].deltaSet );
4788 FT_FREE( itemStore->varData );
4791 if ( itemStore->varRegionList )
4793 for ( i = 0; i < itemStore->regionCount; i++ )
4794 FT_FREE( itemStore->varRegionList[i].axisList );
4796 FT_FREE( itemStore->varRegionList );
4801 FT_LOCAL_DEF(
void )
4802 tt_var_done_delta_set_index_map( FT_Face face,
4803 GX_DeltaSetIdxMap deltaSetIdxMap )
4805 FT_Memory memory = FT_FACE_MEMORY( face );
4808 FT_FREE( deltaSetIdxMap->innerIndex );
4809 FT_FREE( deltaSetIdxMap->outerIndex );
4821 FT_LOCAL_DEF(
void )
4822 tt_done_blend( FT_Face face )
4824 TT_Face ttface = (TT_Face)face;
4825 FT_Memory memory = FT_FACE_MEMORY( face );
4826 GX_Blend blend = ttface->blend;
4831 FT_UInt i, num_axes;
4835 num_axes = blend->mmvar->num_axis;
4837 FT_FREE( blend->coords );
4838 FT_FREE( blend->normalizedcoords );
4839 FT_FREE( blend->normalized_stylecoords );
4840 FT_FREE( blend->mmvar );
4842 if ( blend->avar_table )
4844 if ( blend->avar_table->avar_segment )
4846 for ( i = 0; i < num_axes; i++ )
4847 FT_FREE( blend->avar_table->avar_segment[i].correspondence );
4848 FT_FREE( blend->avar_table->avar_segment );
4851 tt_var_done_item_variation_store( face,
4852 &blend->avar_table->itemStore );
4854 tt_var_done_delta_set_index_map( face,
4855 &blend->avar_table->axisMap );
4857 FT_FREE( blend->avar_table );
4860 if ( blend->hvar_table )
4862 tt_var_done_item_variation_store( face,
4863 &blend->hvar_table->itemStore );
4865 tt_var_done_delta_set_index_map( face,
4866 &blend->hvar_table->widthMap );
4867 FT_FREE( blend->hvar_table );
4870 if ( blend->vvar_table )
4872 tt_var_done_item_variation_store( face,
4873 &blend->vvar_table->itemStore );
4875 tt_var_done_delta_set_index_map( face,
4876 &blend->vvar_table->widthMap );
4877 FT_FREE( blend->vvar_table );
4880 if ( blend->mvar_table )
4882 tt_var_done_item_variation_store( face,
4883 &blend->mvar_table->itemStore );
4885 FT_FREE( blend->mvar_table->values );
4886 FT_FREE( blend->mvar_table );
4889 FT_FREE( blend->tuplescalars );
4890 FT_FREE( blend->tuplecoords );
4891 FT_FREE( blend->glyphoffsets );
4899 typedef int tt_gxvar_dummy_;