summaryrefslogtreecommitdiff
path: root/Build/source/libs/freetype2/freetype-src/src/truetype/ttgxvar.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/freetype2/freetype-src/src/truetype/ttgxvar.c')
-rw-r--r--Build/source/libs/freetype2/freetype-src/src/truetype/ttgxvar.c992
1 files changed, 903 insertions, 89 deletions
diff --git a/Build/source/libs/freetype2/freetype-src/src/truetype/ttgxvar.c b/Build/source/libs/freetype2/freetype-src/src/truetype/ttgxvar.c
index c0d013c17fe..cf4f7b17a94 100644
--- a/Build/source/libs/freetype2/freetype-src/src/truetype/ttgxvar.c
+++ b/Build/source/libs/freetype2/freetype-src/src/truetype/ttgxvar.c
@@ -380,7 +380,7 @@
segment->correspondence[j].fromCoord = FT_GET_SHORT() * 4;
segment->correspondence[j].toCoord = FT_GET_SHORT() * 4;
- FT_TRACE5(( " mapping %.4f to %.4f\n",
+ FT_TRACE5(( " mapping %.5f to %.5f\n",
segment->correspondence[j].fromCoord / 65536.0,
segment->correspondence[j].toCoord / 65536.0 ));
}
@@ -393,6 +393,514 @@
}
+ /* some macros we need */
+ #define FT_FIXED_ONE ( (FT_Fixed)0x10000 )
+
+ #define FT_fdot14ToFixed( x ) \
+ ( ( (FT_Fixed)( (FT_Int16)(x) ) ) << 2 )
+ #define FT_intToFixed( i ) \
+ ( (FT_Fixed)( (FT_UInt32)(i) << 16 ) )
+ #define FT_fixedToInt( x ) \
+ ( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) )
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ft_var_load_hvar */
+ /* */
+ /* <Description> */
+ /* Parse the `HVAR' table and set `blend->hvar_loaded' to TRUE. */
+ /* */
+ /* On success, `blend->hvar_checked' is set to TRUE. */
+ /* */
+ /* Some memory may remain allocated on error; it is always freed in */
+ /* `tt_done_blend', however. */
+ /* */
+ /* <InOut> */
+ /* face :: The font face. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ 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_ULong table_len;
+ FT_ULong table_offset;
+ FT_ULong store_offset;
+
+ FT_ULong* dataOffsetArray = NULL;
+
+
+ blend->hvar_loaded = TRUE;
+
+ FT_TRACE2(( "HVAR " ));
+
+ error = face->goto_table( face, TTAG_HVAR, stream, &table_len );
+ if ( error )
+ {
+ FT_TRACE2(( "is missing\n" ));
+ goto Exit;
+ }
+
+ table_offset = FT_STREAM_POS();
+
+ /* skip minor version */
+ if ( FT_READ_USHORT( majorVersion ) ||
+ FT_STREAM_SKIP( 2 ) )
+ goto Exit;
+ if ( majorVersion != 1 )
+ {
+ FT_TRACE2(( "bad table version %d\n", majorVersion ));
+ error = FT_THROW( Invalid_Table );
+ goto Exit;
+ }
+
+ /* skip map offset */
+ if ( FT_READ_ULONG( store_offset ) ||
+ FT_STREAM_SKIP( 4 ) )
+ goto Exit;
+
+ /* parse item variation store */
+ {
+ FT_UShort format;
+ FT_ULong region_offset;
+ FT_UInt i, j, k;
+ FT_UInt shortDeltaCount;
+
+ GX_HVStore itemStore;
+ 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_Table );
+ goto Exit;
+ }
+
+ if ( FT_NEW( blend->hvar_table ) ) /* allocate table at top level */
+ goto Exit;
+
+ hvarTable = blend->hvar_table;
+ itemStore = &hvarTable->itemStore;
+
+ /* read top level fields */
+ if ( FT_READ_ULONG( region_offset ) ||
+ FT_READ_USHORT( itemStore->dataCount ) )
+ goto Exit;
+
+ /* make temporary copy of item variation data offsets; */
+ /* we will parse region list first, then come back */
+ if ( FT_NEW_ARRAY( dataOffsetArray, itemStore->dataCount ) )
+ goto Exit;
+
+ for ( i = 0; i < itemStore->dataCount; i++ )
+ {
+ if ( FT_READ_ULONG( dataOffsetArray[i] ) )
+ goto Exit;
+ }
+
+ /* 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 */
+
+ /* use dataOffsetArray now to parse varData items */
+ if ( FT_NEW_ARRAY( itemStore->varData, itemStore->dataCount ) )
+ goto Exit;
+
+ for ( i = 0; i < itemStore->dataCount; i++ )
+ {
+ hvarData = &itemStore->varData[i];
+
+ if ( FT_STREAM_SEEK( table_offset +
+ store_offset +
+ dataOffsetArray[i] ) )
+ goto Exit;
+
+ if ( FT_READ_USHORT( hvarData->itemCount ) ||
+ FT_READ_USHORT( shortDeltaCount ) ||
+ FT_READ_USHORT( hvarData->regionIdxCount ) )
+ goto Exit;
+
+ /* check some data consistency */
+ if ( shortDeltaCount > hvarData->regionIdxCount )
+ {
+ FT_TRACE2(( "bad short count %d or region count %d\n",
+ shortDeltaCount,
+ hvarData->regionIdxCount ));
+ error = FT_THROW( Invalid_Table );
+ goto Exit;
+ }
+
+ if ( hvarData->regionIdxCount > itemStore->regionCount )
+ {
+ FT_TRACE2(( "inconsistent regionCount %d in varData[%d]\n",
+ hvarData->regionIdxCount,
+ i ));
+ error = FT_THROW( Invalid_Table );
+ goto Exit;
+ }
+
+ /* parse region indices */
+ if ( FT_NEW_ARRAY( hvarData->regionIndices,
+ hvarData->regionIdxCount ) )
+ goto Exit;
+
+ for ( j = 0; j < hvarData->regionIdxCount; j++ )
+ {
+ if ( FT_READ_USHORT( hvarData->regionIndices[j] ) )
+ goto Exit;
+
+ if ( hvarData->regionIndices[j] >= itemStore->regionCount )
+ {
+ FT_TRACE2(( "bad region index %d\n",
+ hvarData->regionIndices[j] ));
+ error = FT_THROW( Invalid_Table );
+ goto Exit;
+ }
+ }
+
+ /* Parse delta set. */
+ /* */
+ /* On input, deltas are ( shortDeltaCount + regionIdxCount ) bytes */
+ /* each; on output, deltas are expanded to `regionIdxCount' shorts */
+ /* each. */
+ if ( FT_NEW_ARRAY( hvarData->deltaSet,
+ hvarData->regionIdxCount * 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->regionIdxCount; )
+ {
+ 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->regionIdxCount; 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 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_Table );
+ goto Exit;
+ }
+
+ /* bytes per entry: 1, 2, 3, or 4 */
+ entrySize = ( ( format & 0x0030 ) >> 4 ) + 1;
+ innerBitCount = ( format & 0x000F ) + 1;
+ innerIndexMask = ( 1 << innerBitCount ) - 1;
+
+ 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_Table );
+ 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_Table );
+ goto Exit;
+ }
+
+ widthMap->innerIndex[i] = innerIndex;
+ }
+ }
+
+ /* end parse width map */
+
+ FT_TRACE2(( "loaded\n" ));
+ error = FT_Err_Ok;
+
+ Exit:
+ FT_FREE( dataOffsetArray );
+
+ if ( !error )
+ {
+ blend->hvar_checked = TRUE;
+
+ /* TODO: implement other HVAR stuff */
+ face->variation_support |= TT_FACE_FLAG_VAR_HADVANCE;
+ }
+
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* tt_hadvance_adjust */
+ /* */
+ /* <Description> */
+ /* Apply HVAR advance width adjustment of a given glyph. */
+ /* */
+ /* <Input> */
+ /* gindex :: The glyph index. */
+ /* */
+ /* <InOut> */
+ /* face :: The font face. */
+ /* */
+ /* adelta :: Points to width value that gets modified. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_hadvance_adjust( TT_Face face,
+ FT_UInt gindex,
+ FT_Int *avalue )
+ {
+ FT_Error error = FT_Err_Ok;
+
+ GX_HVarData varData;
+
+ FT_UInt innerIndex, outerIndex;
+ FT_UInt master, j;
+ FT_Fixed netAdjustment = 0; /* accumulated adjustment */
+ FT_Fixed scaledDelta;
+ FT_Short* deltaSet;
+ FT_Fixed delta;
+
+
+ if ( !face->doblend || !face->blend )
+ goto Exit;
+
+ if ( !face->blend->hvar_loaded )
+ {
+ /* initialize hvar table */
+ face->blend->hvar_error = ft_var_load_hvar( face );
+ }
+
+ if ( !face->blend->hvar_checked )
+ {
+ error = face->blend->hvar_error;
+ goto Exit;
+ }
+
+ /* advance width adjustments are always present in an `HVAR' table, */
+ /* so need to test for this capability */
+
+ if ( gindex >= face->blend->hvar_table->widthMap.mapCount )
+ {
+ FT_TRACE2(( "gindex %d out of range\n", gindex ));
+ error = FT_THROW( Invalid_Argument );
+ 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[varData->regionIdxCount * innerIndex];
+
+ /* See pseudo code from `Font Variations Overview' */
+ /* in the OpenType specification. */
+
+ /* outer loop steps through master designs to be blended */
+ for ( master = 0; master < varData->regionIdxCount; master++ )
+ {
+ FT_Fixed scalar = FT_FIXED_ONE;
+ FT_UInt regionIndex = varData->regionIndices[master];
+
+ GX_AxisCoords axis = face->blend
+ ->hvar_table
+ ->itemStore.varRegionList[regionIndex]
+ .axisList;
+
+
+ /* 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 */
+
+ /* 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 */
+
+ /* apply the accumulated adjustment to derive the interpolated value */
+ FT_TRACE5(( "horizontal width %d adjusted by %d units (HVAR)\n",
+ *avalue,
+ FT_fixedToInt( netAdjustment ) ));
+
+ *avalue += FT_fixedToInt( netAdjustment );
+
+ Exit:
+ return error;
+ }
+
+
typedef struct GX_GVar_Head_
{
FT_Long version;
@@ -454,10 +962,10 @@
FT_TRACE2(( "GVAR " ));
- if ( ( error = face->goto_table( face,
- TTAG_gvar,
- stream,
- &table_len ) ) != 0 )
+ if ( FT_SET_ERROR( face->goto_table( face,
+ TTAG_gvar,
+ stream,
+ &table_len ) ) )
{
FT_TRACE2(( "is missing\n" ));
goto Exit;
@@ -556,7 +1064,7 @@
{
blend->tuplecoords[i * gvar_head.axisCount + j] =
FT_GET_SHORT() * 4; /* convert to FT_Fixed */
- FT_TRACE5(( "%.4f ",
+ FT_TRACE5(( "%.5f ",
blend->tuplecoords[i * gvar_head.axisCount + j] / 65536.0 ));
}
FT_TRACE5(( "]\n" ));
@@ -612,10 +1120,10 @@
for ( i = 0; i < blend->num_axis; i++ )
{
- FT_TRACE6(( " axis coordinate %d (%.4f):\n",
+ FT_TRACE6(( " axis coordinate %d (%.5f):\n",
i, blend->normalizedcoords[i] / 65536.0 ));
if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) )
- FT_TRACE6(( " intermediate coordinates %d (%.4f, %.4f):\n",
+ FT_TRACE6(( " intermediate coordinates %d (%.5f, %.5f):\n",
i,
im_start_coords[i] / 65536.0,
im_end_coords[i] / 65536.0 ));
@@ -640,7 +1148,7 @@
if ( blend->normalizedcoords[i] == tuple_coords[i] )
{
- FT_TRACE6(( " tuple coordinate value %.4f fits perfectly\n",
+ FT_TRACE6(( " tuple coordinate value %.5f fits perfectly\n",
tuple_coords[i] / 65536.0 ));
/* `apply' does not change */
continue;
@@ -653,13 +1161,13 @@
if ( blend->normalizedcoords[i] < FT_MIN( 0, tuple_coords[i] ) ||
blend->normalizedcoords[i] > FT_MAX( 0, tuple_coords[i] ) )
{
- FT_TRACE6(( " tuple coordinate value %.4f is exceeded, stop\n",
+ FT_TRACE6(( " tuple coordinate value %.5f is exceeded, stop\n",
tuple_coords[i] / 65536.0 ));
apply = 0;
break;
}
- FT_TRACE6(( " tuple coordinate value %.4f fits\n",
+ FT_TRACE6(( " tuple coordinate value %.5f fits\n",
tuple_coords[i] / 65536.0 ));
apply = FT_MulDiv( apply,
blend->normalizedcoords[i],
@@ -672,7 +1180,7 @@
if ( blend->normalizedcoords[i] < im_start_coords[i] ||
blend->normalizedcoords[i] > im_end_coords[i] )
{
- FT_TRACE6(( " intermediate tuple range [%.4f;%.4f] is exceeded,"
+ FT_TRACE6(( " intermediate tuple range [%.5f;%.5f] is exceeded,"
" stop\n",
im_start_coords[i] / 65536.0,
im_end_coords[i] / 65536.0 ));
@@ -682,7 +1190,7 @@
else if ( blend->normalizedcoords[i] < tuple_coords[i] )
{
- FT_TRACE6(( " intermediate tuple range [%.4f;%.4f] fits\n",
+ FT_TRACE6(( " intermediate tuple range [%.5f;%.5f] fits\n",
im_start_coords[i] / 65536.0,
im_end_coords[i] / 65536.0 ));
apply = FT_MulDiv( apply,
@@ -692,7 +1200,7 @@
else
{
- FT_TRACE6(( " intermediate tuple range [%.4f;%.4f] fits\n",
+ FT_TRACE6(( " intermediate tuple range [%.5f;%.5f] fits\n",
im_start_coords[i] / 65536.0,
im_end_coords[i] / 65536.0 ));
apply = FT_MulDiv( apply,
@@ -702,7 +1210,7 @@
}
}
- FT_TRACE6(( " apply factor is %.4f\n", apply / 65536.0 ));
+ FT_TRACE6(( " apply factor is %.5f\n", apply / 65536.0 ));
return apply;
}
@@ -778,6 +1286,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[] =
{
@@ -816,21 +1325,26 @@
/* read the font data and set up the internal representation */
/* if not already done */
- if ( face->blend == NULL )
+ if ( !face->blend )
{
FT_TRACE2(( "FVAR " ));
/* both `fvar' and `gvar' must be present */
- if ( ( error = face->goto_table( face, TTAG_gvar,
- stream, &table_len ) ) != 0 )
+ if ( FT_SET_ERROR( face->goto_table( face, TTAG_gvar,
+ stream, &table_len ) ) )
{
- FT_TRACE1(( "\n"
- "TT_Get_MM_Var: `gvar' table is missing\n" ));
- goto Exit;
+ /* CFF2 is an alternate to gvar here */
+ if ( FT_SET_ERROR( face->goto_table( face, TTAG_CFF2,
+ stream, &table_len ) ) )
+ {
+ FT_TRACE1(( "\n"
+ "TT_Get_MM_Var: `gvar' or `CFF2' table is missing\n" ));
+ goto Exit;
+ }
}
- if ( ( error = face->goto_table( face, TTAG_fvar,
- stream, &table_len ) ) != 0 )
+ if ( FT_SET_ERROR( face->goto_table( face, TTAG_fvar,
+ stream, &table_len ) ) )
{
FT_TRACE1(( "is missing\n" ));
goto Exit;
@@ -838,30 +1352,13 @@
fvar_start = FT_STREAM_POS( );
+ /* the validity of the `fvar' header data was already checked */
+ /* in function `sfnt_init_face' */
if ( FT_STREAM_READ_FIELDS( fvar_fields, &fvar_head ) )
goto Exit;
- if ( fvar_head.version != (FT_Long)0x00010000L ||
-#if 0
- /* fonts like `JamRegular.ttf' have an incorrect value for */
- /* `countSizePairs'; since value 2 is hard-coded in `fvar' */
- /* version 1.0, we simply ignore it */
- fvar_head.countSizePairs != 2 ||
-#endif
- 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 )
- {
- FT_TRACE1(( "\n"
- "TT_Get_MM_Var: invalid `fvar' header\n" ));
- error = FT_THROW( Invalid_Table );
- goto Exit;
- }
+ usePsName = FT_BOOL( fvar_head.instanceSize ==
+ 6 + 4 * fvar_head.axisCount );
FT_TRACE2(( "loaded\n" ));
@@ -938,7 +1435,18 @@
a->name[3] = (FT_String)( ( a->tag ) & 0xFF );
a->name[4] = '\0';
- FT_TRACE5(( " \"%s\": minimum=%.4f, default=%.4f, maximum=%.4f\n",
+ if ( a->minimum > a->def ||
+ a->def > a->maximum )
+ {
+ FT_TRACE2(( "TT_Get_MM_Var:"
+ " invalid \"%s\" axis record; disabling\n",
+ a->name ));
+
+ a->minimum = a->def;
+ a->maximum = a->def;
+ }
+
+ FT_TRACE5(( " \"%s\": minimum=%.5f, default=%.5f, maximum=%.5f\n",
a->name,
a->minimum / 65536.0,
a->def / 65536.0,
@@ -952,7 +1460,9 @@
ns = mmvar->namedstyle;
for ( i = 0; i < fvar_head.instanceCount; i++, ns++ )
{
- if ( FT_FRAME_ENTER( 4L + 4L * fvar_head.axisCount ) )
+ /* PostScript names add 2 bytes to the instance record size */
+ if ( FT_FRAME_ENTER( ( usePsName ? 6L : 4L ) +
+ 4L * fvar_head.axisCount ) )
goto Exit;
ns->strid = FT_GET_USHORT();
@@ -961,13 +1471,16 @@
for ( j = 0; j < fvar_head.axisCount; j++ )
ns->coords[j] = FT_GET_LONG();
+ if ( usePsName )
+ ns->psid = FT_GET_USHORT();
+
FT_FRAME_EXIT();
}
}
/* fill the output array if requested */
- if ( master != NULL )
+ if ( master )
{
FT_UInt n;
@@ -1051,6 +1564,7 @@
GX_Blend blend;
FT_MM_Var* mmvar;
FT_UInt i;
+ FT_Bool is_default_instance = 1;
FT_Memory memory = face->root.memory;
enum
@@ -1064,9 +1578,9 @@
face->doblend = FALSE;
- if ( face->blend == NULL )
+ if ( !face->blend )
{
- if ( ( error = TT_Get_MM_Var( face, NULL ) ) != 0 )
+ if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
goto Exit;
}
@@ -1084,24 +1598,27 @@
for ( i = 0; i < num_coords; i++ )
{
- FT_TRACE5(( " %.4f\n", coords[i] / 65536.0 ));
+ FT_TRACE5(( " %.5f\n", coords[i] / 65536.0 ));
if ( coords[i] < -0x00010000L || coords[i] > 0x00010000L )
{
- FT_TRACE1(( "TT_Set_MM_Blend: normalized design coordinate %.4f\n"
+ FT_TRACE1(( "TT_Set_MM_Blend: normalized design coordinate %.5f\n"
" is out of range [-1;1]\n",
coords[i] / 65536.0 ));
error = FT_THROW( Invalid_Argument );
goto Exit;
}
+
+ if ( coords[i] != 0 )
+ is_default_instance = 0;
}
FT_TRACE5(( "\n" ));
- if ( blend->glyphoffsets == NULL )
- if ( ( error = ft_var_load_gvar( face ) ) != 0 )
+ if ( !face->isCFF2 && !blend->glyphoffsets )
+ if ( FT_SET_ERROR( ft_var_load_gvar( face ) ) )
goto Exit;
- if ( blend->normalizedcoords == NULL )
+ if ( !blend->normalizedcoords )
{
if ( FT_NEW_ARRAY( blend->normalizedcoords, mmvar->num_axis ) )
goto Exit;
@@ -1147,7 +1664,7 @@
face->doblend = TRUE;
- if ( face->cvt != NULL )
+ if ( face->cvt )
{
switch ( manageCvt )
{
@@ -1172,6 +1689,8 @@
}
}
+ face->is_default_instance = is_default_instance;
+
Exit:
return error;
}
@@ -1180,6 +1699,73 @@
/*************************************************************************/
/* */
/* <Function> */
+ /* TT_Get_MM_Blend */
+ /* */
+ /* <Description> */
+ /* Get the blend (normalized) coordinates for this instance of the */
+ /* font. */
+ /* */
+ /* <InOut> */
+ /* face :: The font. */
+ /* Initialize the blend structure with `gvar' data. */
+ /* */
+ /* <Input> */
+ /* num_coords :: The number of available coordinates. If it is */
+ /* larger than the number of axes, set the excess */
+ /* values to 0. */
+ /* */
+ /* coords :: An array of `num_coords', each between [-1,1]. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ TT_Get_MM_Blend( TT_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords )
+ {
+ FT_Error error = FT_Err_Ok;
+ GX_Blend blend;
+ FT_UInt i, nc;
+
+
+ if ( !face->blend )
+ {
+ if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
+ return error;
+ }
+
+ blend = face->blend;
+
+ nc = num_coords;
+ 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 ));
+ nc = blend->num_axis;
+ }
+
+ if ( face->doblend )
+ {
+ for ( i = 0; i < nc; i++ )
+ coords[i] = blend->normalizedcoords[i];
+ }
+ else
+ {
+ for ( i = 0; i < nc; i++ )
+ coords[i] = 0;
+ }
+
+ for ( ; i < num_coords; i++ )
+ coords[i] = 0;
+
+ return FT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
/* TT_Set_Var_Design */
/* */
/* <Description> */
@@ -1217,9 +1803,9 @@
FT_Memory memory = face->root.memory;
- if ( face->blend == NULL )
+ if ( !face->blend )
{
- if ( ( error = TT_Get_MM_Var( face, NULL ) ) != 0 )
+ if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
goto Exit;
}
@@ -1234,7 +1820,7 @@
num_coords = mmvar->num_axis;
}
- /* Axis normalization is a two stage process. First we normalize */
+ /* Axis normalization is a two-stage process. First we normalize */
/* based on the [min,def,max] values for the axis to be [-1,0,1]. */
/* Then, if there's an `avar' table, we renormalize this range. */
@@ -1246,26 +1832,33 @@
a = mmvar->axis;
for ( i = 0; i < num_coords; i++, a++ )
{
- FT_TRACE5(( " %.4f\n", coords[i] / 65536.0 ));
- if ( coords[i] > a->maximum || coords[i] < a->minimum )
+ FT_Fixed coord = coords[i];
+
+
+ FT_TRACE5(( " %.5f\n", coord / 65536.0 ));
+ if ( coord > a->maximum || coord < a->minimum )
{
- FT_TRACE1(( "TT_Set_Var_Design: normalized design coordinate %.4f\n"
- " is out of range [%.4f;%.4f]\n",
- coords[i] / 65536.0,
- a->minimum / 65536.0,
- a->maximum / 65536.0 ));
- error = FT_THROW( Invalid_Argument );
- goto Exit;
+ FT_TRACE1((
+ "TT_Set_Var_Design: design coordinate %.5f\n"
+ " is out of range [%.5f;%.5f]; clamping\n",
+ coord / 65536.0,
+ a->minimum / 65536.0,
+ a->maximum / 65536.0 ));
+
+ if ( coord > a->maximum)
+ coord = a->maximum;
+ else
+ coord = a->minimum;
}
- if ( coords[i] < a->def )
+ if ( coord < a->def )
normalized[i] = -FT_DivFix( coords[i] - a->def,
a->minimum - a->def );
- else if ( a->maximum == a->def )
- normalized[i] = 0;
- else
+ else if ( coord > a->def )
normalized[i] = FT_DivFix( coords[i] - a->def,
a->maximum - a->def );
+ else
+ normalized[i] = 0;
}
FT_TRACE5(( "\n" ));
@@ -1276,7 +1869,7 @@
if ( !blend->avar_checked )
ft_var_load_avar( face );
- if ( blend->avar_segment != NULL )
+ if ( blend->avar_segment )
{
FT_TRACE5(( "normalized design coordinates"
" before applying `avar' data:\n" ));
@@ -1286,9 +1879,10 @@
{
for ( j = 1; j < (FT_UInt)av->pairCount; j++ )
{
- FT_TRACE5(( " %.4f\n", normalized[i] / 65536.0 ));
if ( normalized[i] < av->correspondence[j].fromCoord )
{
+ FT_TRACE5(( " %.5f\n", normalized[i] / 65536.0 ));
+
normalized[i] =
FT_MulDiv( normalized[i] - av->correspondence[j - 1].fromCoord,
av->correspondence[j].toCoord -
@@ -1311,6 +1905,123 @@
/*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Get_Var_Design */
+ /* */
+ /* <Description> */
+ /* Get the design coordinates of the currently selected interpolated */
+ /* font. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face. */
+ /* */
+ /* num_coords :: The number of design coordinates to retrieve. If it */
+ /* is larger than the number of axes, set the excess */
+ /* values to~0. */
+ /* */
+ /* <Output> */
+ /* coords :: The design coordinates array. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0~means success. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ TT_Get_Var_Design( TT_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords )
+ {
+ FT_Error error = FT_Err_Ok;
+
+ GX_Blend blend;
+ FT_MM_Var* mmvar;
+ FT_Var_Axis* a;
+
+ FT_UInt i, j, nc;
+
+
+ if ( !face->blend )
+ {
+ if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
+ return error;
+ }
+
+ blend = face->blend;
+
+ nc = num_coords;
+ if ( num_coords > blend->num_axis )
+ {
+ FT_TRACE2(( "TT_Get_Var_Design: only using first %d of %d coordinates\n",
+ blend->num_axis, num_coords ));
+ nc = blend->num_axis;
+ }
+
+ if ( face->doblend )
+ {
+ for ( i = 0; i < nc; i++ )
+ coords[i] = blend->normalizedcoords[i];
+ }
+ else
+ {
+ for ( i = 0; i < nc; i++ )
+ coords[i] = 0;
+ }
+
+ for ( ; i < num_coords; i++ )
+ coords[i] = 0;
+
+ if ( !blend->avar_checked )
+ ft_var_load_avar( face );
+
+ if ( blend->avar_segment )
+ {
+ GX_AVarSegment av = blend->avar_segment;
+
+
+ FT_TRACE5(( "design coordinates"
+ " after removing `avar' distortion:\n" ));
+
+ for ( i = 0; i < nc; i++, av++ )
+ {
+ for ( j = 1; j < (FT_UInt)av->pairCount; j++ )
+ {
+ if ( coords[i] < av->correspondence[j].toCoord )
+ {
+ coords[i] =
+ FT_MulDiv( coords[i] - av->correspondence[j - 1].toCoord,
+ av->correspondence[j].fromCoord -
+ av->correspondence[j - 1].fromCoord,
+ av->correspondence[j].toCoord -
+ av->correspondence[j - 1].toCoord ) +
+ av->correspondence[j - 1].fromCoord;
+
+ FT_TRACE5(( " %.5f\n", coords[i] / 65536.0 ));
+ break;
+ }
+ }
+ }
+ }
+
+ mmvar = blend->mmvar;
+ a = mmvar->axis;
+
+ for ( i = 0; i < nc; i++, a++ )
+ {
+ if ( coords[i] < 0 )
+ coords[i] = a->def + FT_MulFix( coords[i],
+ a->def - a->minimum );
+ else if ( coords[i] > 0 )
+ coords[i] = a->def + FT_MulFix( coords[i],
+ a->maximum - a->def );
+ else
+ coords[i] = a->def;
+ }
+
+ return FT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
/*************************************************************************/
/***** *****/
/***** GX VAR PARSING ROUTINES *****/
@@ -1363,7 +2074,7 @@
FT_TRACE2(( "CVAR " ));
- if ( blend == NULL )
+ if ( !blend )
{
FT_TRACE2(( "\n"
"tt_face_vary_cvt: no blend specified\n" ));
@@ -1371,7 +2082,7 @@
goto Exit;
}
- if ( face->cvt == NULL )
+ if ( !face->cvt )
{
FT_TRACE2(( "\n"
"tt_face_vary_cvt: no `cvt ' table\n" ));
@@ -1414,7 +2125,8 @@
offsetToData = FT_GET_USHORT();
/* rough sanity test */
- if ( offsetToData + tupleCount * 4 > table_len )
+ if ( offsetToData + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) * 4 >
+ table_len )
{
FT_TRACE2(( "tt_face_vary_cvt:"
" invalid CVT variation array header\n" ));
@@ -1498,7 +2210,7 @@
table_len,
point_count == 0 ? face->cvt_size
: point_count );
- if ( localpoints == NULL || deltas == NULL )
+ if ( !localpoints || !deltas )
; /* failure, ignore it */
else if ( localpoints == ALL_POINTS )
@@ -1546,10 +2258,15 @@
for ( j = 0; j < point_count; j++ )
{
- int pindex = localpoints[j];
- FT_Long orig_cvt = face->cvt[pindex];
+ int pindex;
+ FT_Long orig_cvt;
+
+ pindex = localpoints[j];
+ if ( (FT_ULong)pindex >= face->cvt_size )
+ continue;
+ orig_cvt = face->cvt[pindex];
face->cvt[pindex] = (FT_Short)( orig_cvt +
FT_MulFix( deltas[j], apply ) );
@@ -1858,7 +2575,7 @@
FT_Short *deltas_x, *deltas_y;
- if ( !face->doblend || blend == NULL )
+ if ( !face->doblend || !blend )
return FT_THROW( Invalid_Argument );
if ( glyph_index >= blend->gv_glyphcnt ||
@@ -2004,7 +2721,7 @@
point_count == 0 ? n_points
: point_count );
- if ( points == NULL || deltas_y == NULL || deltas_x == NULL )
+ if ( !points || !deltas_y || !deltas_x )
; /* failure, ignore it */
else if ( points == ALL_POINTS )
@@ -2023,8 +2740,36 @@
FT_Pos delta_y = FT_MulFix( deltas_y[j], apply );
- outline->points[j].x += delta_x;
- outline->points[j].y += delta_y;
+ if ( j < n_points - 3 )
+ {
+ outline->points[j].x += delta_x;
+ outline->points[j].y += delta_y;
+ }
+ else
+ {
+ /* To avoid double adjustment of advance width or height, */
+ /* adjust phantom points only if there is no HVAR or VVAR */
+ /* support, respectively. */
+ if ( j == ( n_points - 3 ) &&
+ !( face->variation_support &
+ TT_FACE_FLAG_VAR_HADVANCE ) )
+ outline->points[j].x += delta_x;
+
+ else if ( j == ( n_points - 2 ) &&
+ !( face->variation_support &
+ TT_FACE_FLAG_VAR_LSB ) )
+ outline->points[j].x += delta_x;
+
+ else if ( j == ( n_points - 1 ) &&
+ !( face->variation_support &
+ TT_FACE_FLAG_VAR_VADVANCE ) )
+ outline->points[j].y += delta_y;
+
+ else if ( j == ( n_points - 0 ) &&
+ !( face->variation_support &
+ TT_FACE_FLAG_VAR_TSB ) )
+ outline->points[j].y += delta_y;
+ }
#ifdef FT_DEBUG_LEVEL_TRACE
if ( delta_x || delta_y )
@@ -2146,30 +2891,99 @@
/*************************************************************************/
/* */
/* <Function> */
+ /* tt_get_var_blend */
+ /* */
+ /* <Description> */
+ /* An extended internal version of `TT_Get_MM_Blend' that returns */
+ /* pointers instead of copying data, without any initialization of */
+ /* the MM machinery in case it isn't loaded yet. */
+ /* */
+ FT_LOCAL_DEF( FT_Error )
+ tt_get_var_blend( TT_Face face,
+ FT_UInt *num_coords,
+ FT_Fixed* *coords,
+ FT_MM_Var* *mm_var )
+ {
+ if ( face->blend )
+ {
+ if ( num_coords )
+ *num_coords = face->blend->num_axis;
+ if ( coords )
+ *coords = face->blend->normalizedcoords;
+ if ( mm_var )
+ *mm_var = face->blend->mmvar;
+ }
+ else
+ {
+ if ( num_coords )
+ *num_coords = 0;
+ if ( coords )
+ *coords = NULL;
+ if ( mm_var )
+ *mm_var = NULL;
+ }
+
+ return FT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
/* tt_done_blend */
/* */
/* <Description> */
/* Free the blend internal data structure. */
/* */
FT_LOCAL_DEF( void )
- tt_done_blend( FT_Memory memory,
- GX_Blend blend )
+ tt_done_blend( TT_Face face )
{
- if ( blend != NULL )
+ FT_Memory memory = FT_FACE_MEMORY( face );
+ GX_Blend blend = face->blend;
+
+
+ if ( blend )
{
- FT_UInt i;
+ FT_UInt i, num_axes;
+
+ /* blend->num_axis might not be set up yet */
+ num_axes = blend->mmvar->num_axis;
FT_FREE( blend->normalizedcoords );
FT_FREE( blend->mmvar );
- if ( blend->avar_segment != NULL )
+ if ( blend->avar_segment )
{
- for ( i = 0; i < blend->num_axis; i++ )
+ for ( i = 0; i < num_axes; i++ )
FT_FREE( blend->avar_segment[i].correspondence );
FT_FREE( blend->avar_segment );
}
+ if ( blend->hvar_table )
+ {
+ 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 );