[truetype] Parse `MVAR' table.

* src/truetype/ttgxvar.h (MVAR_TAG_XXX): New macros for MVAR tags.
(GX_Value, GX_MVarTable): New structures.
(GX_Blend): Add it.

* src/truetype/ttgxvar.c (GX_VALUE_SIZE, GX_VALUE_CASE,
GX_GASP_CASE): New macros.
(ft_var_get_value_pointer): New auxiliary function to get a pointer
to a value from various SFNT tables already stored in `TT_Face'.
(ft_var_load_mvar): New function.
(TT_Get_MM_Var): Call it.
(tt_done_blend): Updated.
This commit is contained in:
Werner Lemberg 2017-01-11 12:50:51 +01:00
parent 8ab08cff63
commit 07ee1d250c
3 changed files with 302 additions and 2 deletions

View File

@ -1,3 +1,19 @@
2017-01-11 Werner Lemberg <wl@gnu.org>
[truetype] Parse `MVAR' table.
* src/truetype/ttgxvar.h (MVAR_TAG_XXX): New macros for MVAR tags.
(GX_Value, GX_MVarTable): New structures.
(GX_Blend): Add it.
* src/truetype/ttgxvar.c (GX_VALUE_SIZE, GX_VALUE_CASE,
GX_GASP_CASE): New macros.
(ft_var_get_value_pointer): New auxiliary function to get a pointer
to a value from various SFNT tables already stored in `TT_Face'.
(ft_var_load_mvar): New function.
(TT_Get_MM_Var): Call it.
(tt_done_blend): Updated.
2017-01-11 Werner Lemberg <wl@gnu.org>
[truetype] More preparations for MVAR support.

View File

@ -744,6 +744,7 @@
if ( FT_READ_USHORT( majorVersion ) ||
FT_STREAM_SKIP( 2 ) )
goto Exit;
if ( majorVersion != 1 )
{
FT_TRACE2(( "bad table version %d\n", majorVersion ));
@ -964,7 +965,6 @@
outerIndex,
innerIndex );
/* apply the accumulated adjustment to derive the interpolated value */
FT_TRACE5(( "horizontal width %d adjusted by %d units (HVAR)\n",
*avalue,
delta ));
@ -976,6 +976,205 @@
}
#define GX_VALUE_SIZE 8
/* all values are FT_Short or FT_UShort entities; */
/* we treat them consistently as FT_Short */
#define GX_VALUE_CASE( tag, dflt ) \
case MVAR_TAG_ ## tag : \
p = (FT_Short*)&face->dflt; \
break
#define GX_GASP_CASE( idx ) \
case MVAR_TAG_GASP_ ## idx : \
if ( idx < face->gasp.numRanges - 1 ) \
p = (FT_Short*)&face->gasp.gaspRanges[idx].maxPPEM; \
else \
p = NULL; \
break
static FT_Short*
ft_var_get_value_pointer( TT_Face face,
FT_ULong mvar_tag )
{
FT_Short* p;
switch ( mvar_tag )
{
GX_GASP_CASE( 0 );
GX_GASP_CASE( 1 );
GX_GASP_CASE( 2 );
GX_GASP_CASE( 3 );
GX_GASP_CASE( 4 );
GX_GASP_CASE( 5 );
GX_GASP_CASE( 6 );
GX_GASP_CASE( 7 );
GX_GASP_CASE( 8 );
GX_GASP_CASE( 9 );
GX_VALUE_CASE( CPHT, os2.sCapHeight );
GX_VALUE_CASE( HASC, os2.sTypoAscender );
GX_VALUE_CASE( HCLA, os2.usWinAscent );
GX_VALUE_CASE( HCLD, os2.usWinDescent );
GX_VALUE_CASE( HCOF, horizontal.caret_Offset );
GX_VALUE_CASE( HCRN, horizontal.caret_Slope_Run );
GX_VALUE_CASE( HCRS, horizontal.caret_Slope_Rise );
GX_VALUE_CASE( HDSC, os2.sTypoDescender );
GX_VALUE_CASE( HLGP, os2.sTypoLineGap );
GX_VALUE_CASE( SBXO, os2.ySubscriptXOffset);
GX_VALUE_CASE( SBXS, os2.ySubscriptXSize );
GX_VALUE_CASE( SBYO, os2.ySubscriptYOffset );
GX_VALUE_CASE( SBYS, os2.ySubscriptYSize );
GX_VALUE_CASE( SPXO, os2.ySuperscriptXOffset );
GX_VALUE_CASE( SPXS, os2.ySuperscriptXSize );
GX_VALUE_CASE( SPYO, os2.ySuperscriptYOffset );
GX_VALUE_CASE( SPYS, os2.ySuperscriptYSize );
GX_VALUE_CASE( STRO, os2.yStrikeoutPosition );
GX_VALUE_CASE( STRS, os2.yStrikeoutSize );
GX_VALUE_CASE( UNDO, postscript.underlinePosition );
GX_VALUE_CASE( UNDS, postscript.underlineThickness );
GX_VALUE_CASE( VASC, vertical.Ascender );
GX_VALUE_CASE( VCOF, vertical.caret_Offset );
GX_VALUE_CASE( VCRN, vertical.caret_Slope_Run );
GX_VALUE_CASE( VCRS, vertical.caret_Slope_Rise );
GX_VALUE_CASE( VDSC, vertical.Descender );
GX_VALUE_CASE( VLGP, vertical.Line_Gap );
GX_VALUE_CASE( XHGT, os2.sxHeight );
default:
/* ignore unknown tag */
p = NULL;
}
return p;
}
/*************************************************************************/
/* */
/* <Function> */
/* ft_var_load_mvar */
/* */
/* <Description> */
/* Parse the `MVAR' table. */
/* */
/* Some memory may remain allocated on error; it is always freed in */
/* `tt_done_blend', however. */
/* */
/* <InOut> */
/* face :: The font face. */
/* */
static void
ft_var_load_mvar( TT_Face face )
{
FT_Stream stream = FT_FACE_STREAM( face );
FT_Memory memory = stream->memory;
GX_Blend blend = face->blend;
GX_ItemVarStore itemStore;
GX_Value value, limit;
FT_Error error;
FT_UShort majorVersion;
FT_ULong table_len;
FT_ULong table_offset;
FT_UShort store_offset;
FT_ULong records_offset;
FT_TRACE2(( "MVAR " ));
error = face->goto_table( face, TTAG_MVAR, stream, &table_len );
if ( error )
{
FT_TRACE2(( "is missing\n" ));
return;
}
table_offset = FT_STREAM_POS();
/* skip minor version */
if ( FT_READ_USHORT( majorVersion ) ||
FT_STREAM_SKIP( 2 ) )
return;
if ( majorVersion != 1 )
{
FT_TRACE2(( "bad table version %d\n", majorVersion ));
return;
}
if ( FT_NEW( blend->mvar_table ) )
return;
/* skip value record size */
if ( FT_READ_USHORT( blend->mvar_table->axisCount ) ||
FT_STREAM_SKIP( 2 ) ||
FT_READ_USHORT( blend->mvar_table->valueCount ) ||
FT_READ_USHORT( store_offset ) )
return;
records_offset = FT_STREAM_POS();
error = ft_var_load_item_variation_store(
face,
table_offset + store_offset,
&blend->mvar_table->itemStore );
if ( error )
return;
if ( FT_NEW_ARRAY( blend->mvar_table->values,
blend->mvar_table->valueCount ) )
return;
if ( FT_STREAM_SEEK( records_offset ) ||
FT_FRAME_ENTER( blend->mvar_table->valueCount * GX_VALUE_SIZE ) )
return;
value = blend->mvar_table->values;
limit = value + blend->mvar_table->valueCount;
itemStore = &blend->mvar_table->itemStore;
for ( ; value < limit; value++ )
{
value->tag = FT_GET_ULONG();
value->outerIndex = FT_GET_USHORT();
value->innerIndex = FT_GET_USHORT();
if ( value->outerIndex >= itemStore->dataCount ||
value->innerIndex >= itemStore->varData[value->outerIndex]
.itemCount )
{
error = FT_THROW( Invalid_Table );
break;
}
}
FT_FRAME_EXIT();
if ( error )
return;
FT_TRACE2(( "loaded\n" ));
value = blend->mvar_table->values;
limit = value + blend->mvar_table->valueCount;
/* save original values of the data MVAR is going to modify */
for ( ; value < limit; value++ )
{
FT_Short* p = ft_var_get_value_pointer( face, value->tag );
value->unmodified = *p;
}
face->variation_support |= TT_FACE_FLAG_VAR_MVAR;
}
typedef struct GX_GVar_Head_
{
FT_Long version;
@ -1332,7 +1531,8 @@
/* */
/* <Description> */
/* Check that the font's `fvar' table is valid, parse it, and return */
/* those data. */
/* those data. It also loads (and parses) the `MVAR' table, if */
/* possible. */
/* */
/* <InOut> */
/* face :: The font face. */
@ -1551,6 +1751,8 @@
FT_FRAME_EXIT();
}
ft_var_load_mvar( face );
}
/* fill the output array if requested */
@ -3074,6 +3276,15 @@
FT_FREE( blend->hvar_table );
}
if ( blend->mvar_table )
{
ft_var_done_item_variation_store( face,
&blend->mvar_table->itemStore );
FT_FREE( blend->mvar_table->values );
FT_FREE( blend->mvar_table );
}
FT_FREE( blend->tuplecoords );
FT_FREE( blend->glyphoffsets );
FT_FREE( blend );

View File

@ -132,6 +132,77 @@ FT_BEGIN_HEADER
} GX_HVarTableRec, *GX_HVarTable;
#define MVAR_TAG_GASP_0 FT_MAKE_TAG( 'g', 's', 'p', '0' )
#define MVAR_TAG_GASP_1 FT_MAKE_TAG( 'g', 's', 'p', '1' )
#define MVAR_TAG_GASP_2 FT_MAKE_TAG( 'g', 's', 'p', '2' )
#define MVAR_TAG_GASP_3 FT_MAKE_TAG( 'g', 's', 'p', '3' )
#define MVAR_TAG_GASP_4 FT_MAKE_TAG( 'g', 's', 'p', '4' )
#define MVAR_TAG_GASP_5 FT_MAKE_TAG( 'g', 's', 'p', '5' )
#define MVAR_TAG_GASP_6 FT_MAKE_TAG( 'g', 's', 'p', '6' )
#define MVAR_TAG_GASP_7 FT_MAKE_TAG( 'g', 's', 'p', '7' )
#define MVAR_TAG_GASP_8 FT_MAKE_TAG( 'g', 's', 'p', '8' )
#define MVAR_TAG_GASP_9 FT_MAKE_TAG( 'g', 's', 'p', '9' )
#define MVAR_TAG_CPHT FT_MAKE_TAG( 'c', 'p', 'h', 't' )
#define MVAR_TAG_HASC FT_MAKE_TAG( 'h', 'a', 's', 'c' )
#define MVAR_TAG_HCLA FT_MAKE_TAG( 'h', 'c', 'l', 'a' )
#define MVAR_TAG_HCLD FT_MAKE_TAG( 'h', 'c', 'l', 'd' )
#define MVAR_TAG_HCOF FT_MAKE_TAG( 'h', 'c', 'o', 'f' )
#define MVAR_TAG_HCRN FT_MAKE_TAG( 'h', 'c', 'r', 'n' )
#define MVAR_TAG_HCRS FT_MAKE_TAG( 'h', 'c', 'r', 's' )
#define MVAR_TAG_HDSC FT_MAKE_TAG( 'h', 'd', 's', 'c' )
#define MVAR_TAG_HLGP FT_MAKE_TAG( 'h', 'l', 'g', 'p' )
#define MVAR_TAG_SBXO FT_MAKE_TAG( 's', 'b', 'x', 'o' )
#define MVAR_TAG_SBXS FT_MAKE_TAG( 's', 'b', 'x', 's' )
#define MVAR_TAG_SBYO FT_MAKE_TAG( 's', 'b', 'y', 'o' )
#define MVAR_TAG_SBYS FT_MAKE_TAG( 's', 'b', 'y', 's' )
#define MVAR_TAG_SPXO FT_MAKE_TAG( 's', 'p', 'x', 'o' )
#define MVAR_TAG_SPXS FT_MAKE_TAG( 's', 'p', 'x', 's' )
#define MVAR_TAG_SPYO FT_MAKE_TAG( 's', 'p', 'y', 'o' )
#define MVAR_TAG_SPYS FT_MAKE_TAG( 's', 'p', 'y', 's' )
#define MVAR_TAG_STRO FT_MAKE_TAG( 's', 't', 'r', 'o' )
#define MVAR_TAG_STRS FT_MAKE_TAG( 's', 't', 'r', 's' )
#define MVAR_TAG_UNDO FT_MAKE_TAG( 'u', 'n', 'd', 'o' )
#define MVAR_TAG_UNDS FT_MAKE_TAG( 'u', 'n', 'd', 's' )
#define MVAR_TAG_VASC FT_MAKE_TAG( 'v', 'a', 's', 'c' )
#define MVAR_TAG_VCOF FT_MAKE_TAG( 'v', 'c', 'o', 'f' )
#define MVAR_TAG_VCRN FT_MAKE_TAG( 'v', 'c', 'r', 'n' )
#define MVAR_TAG_VCRS FT_MAKE_TAG( 'v', 'c', 'r', 's' )
#define MVAR_TAG_VDSC FT_MAKE_TAG( 'v', 'd', 's', 'c' )
#define MVAR_TAG_VLGP FT_MAKE_TAG( 'v', 'l', 'g', 'p' )
#define MVAR_TAG_XHGT FT_MAKE_TAG( 'x', 'h', 'g', 't' )
typedef struct GX_ValueRec_
{
FT_ULong tag;
FT_UShort outerIndex;
FT_UShort innerIndex;
FT_Short unmodified; /* values are either FT_Short or FT_UShort */
} GX_ValueRec, *GX_Value;
/*************************************************************************/
/* */
/* <Struct> */
/* GX_MVarTableRec */
/* */
/* <Description> */
/* Data from the `MVAR' table. */
/* */
typedef struct GX_MVarTableRec_
{
FT_UShort axisCount;
FT_UShort valueCount;
GX_ItemVarStoreRec itemStore; /* Item Variation Store */
GX_Value values; /* Value Records */
} GX_MVarTableRec, *GX_MVarTable;
/*************************************************************************/
/* */
/* <Struct> */
@ -165,6 +236,8 @@ FT_BEGIN_HEADER
FT_Error hvar_error;
GX_HVarTable hvar_table;
GX_MVarTable mvar_table;
FT_UInt tuplecount; /* shared tuples in `gvar' */
FT_Fixed* tuplecoords; /* tuplecoords[tuplecount][num_axis] */