From 58f56950848bae9c90da3873090c7698e0128b12 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Wed, 14 Aug 2019 11:13:36 +0200 Subject: Update bundled Freetype to 2.10.1 [ChangeLog][Freetype] Upgraded bundled Freetype version to 2.10.1. Fixes: QTBUG-77466 Change-Id: I1de8b8b03e0ffd0b17eeafff1017df7c638c9279 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/3rdparty/freetype/src/truetype/ttgxvar.c | 1436 +++++++++++++++----------- 1 file changed, 825 insertions(+), 611 deletions(-) (limited to 'src/3rdparty/freetype/src/truetype/ttgxvar.c') diff --git a/src/3rdparty/freetype/src/truetype/ttgxvar.c b/src/3rdparty/freetype/src/truetype/ttgxvar.c index 29ab2a4efd..78d87dc097 100644 --- a/src/3rdparty/freetype/src/truetype/ttgxvar.c +++ b/src/3rdparty/freetype/src/truetype/ttgxvar.c @@ -1,42 +1,42 @@ -/***************************************************************************/ -/* */ -/* ttgxvar.c */ -/* */ -/* TrueType GX Font Variation loader */ -/* */ -/* Copyright 2004-2018 by */ -/* David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - - /*************************************************************************/ - /* */ - /* Apple documents the `fvar', `gvar', `cvar', and `avar' tables at */ - /* */ - /* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6[fgca]var.html */ - /* */ - /* The documentation for `gvar' is not intelligible; `cvar' refers you */ - /* to `gvar' and is thus also incomprehensible. */ - /* */ - /* The documentation for `avar' appears correct, but Apple has no fonts */ - /* with an `avar' table, so it is hard to test. */ - /* */ - /* Many thanks to John Jenkins (at Apple) in figuring this out. */ - /* */ - /* */ - /* Apple's `kern' table has some references to tuple indices, but as */ - /* there is no indication where these indices are defined, nor how to */ - /* interpolate the kerning values (different tuples have different */ - /* classes) this issue is ignored. */ - /* */ - /*************************************************************************/ +/**************************************************************************** + * + * ttgxvar.c + * + * TrueType GX Font Variation loader + * + * Copyright (C) 2004-2019 by + * David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + + + /************************************************************************** + * + * Apple documents the `fvar', `gvar', `cvar', and `avar' tables at + * + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6[fgca]var.html + * + * The documentation for `gvar' is not intelligible; `cvar' refers you + * to `gvar' and is thus also incomprehensible. + * + * The documentation for `avar' appears correct, but Apple has no fonts + * with an `avar' table, so it is hard to test. + * + * Many thanks to John Jenkins (at Apple) in figuring this out. + * + * + * Apple's `kern' table has some references to tuple indices, but as + * there is no indication where these indices are defined, nor how to + * interpolate the kerning values (different tuples have different + * classes) this issue is ignored. + * + */ #include @@ -67,14 +67,27 @@ : (stream)->limit - /*************************************************************************/ - /* */ - /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ - /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ - /* messages during execution. */ - /* */ + /* some macros we need */ +#define FT_fdot14ToFixed( x ) \ + ( (FT_Fixed)( (FT_ULong)(x) << 2 ) ) +#define FT_intToFixed( i ) \ + ( (FT_Fixed)( (FT_ULong)(i) << 16 ) ) +#define FT_fdot6ToFixed( i ) \ + ( (FT_Fixed)( (FT_ULong)(i) << 10 ) ) +#define FT_fixedToInt( x ) \ + ( (FT_Short)( ( (x) + 0x8000U ) >> 16 ) ) +#define FT_fixedToFdot6( x ) \ + ( (FT_Pos)( ( (x) + 0x200 ) >> 10 ) ) + + + /************************************************************************** + * + * The macro FT_COMPONENT is used in trace mode. It is an implicit + * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log + * messages during execution. + */ #undef FT_COMPONENT -#define FT_COMPONENT trace_ttgxvar +#define FT_COMPONENT ttgxvar /*************************************************************************/ @@ -86,12 +99,12 @@ /*************************************************************************/ - /*************************************************************************/ - /* */ - /* The macro ALL_POINTS is used in `ft_var_readpackedpoints'. It */ - /* indicates that there is a delta for every point without needing to */ - /* enumerate all of them. */ - /* */ + /************************************************************************** + * + * The macro ALL_POINTS is used in `ft_var_readpackedpoints'. It + * indicates that there is a delta for every point without needing to + * enumerate all of them. + */ /* ensure that value `0' has the same width as a pointer */ #define ALL_POINTS (FT_UShort*)~(FT_PtrDist)0 @@ -101,29 +114,32 @@ #define GX_PT_POINT_RUN_COUNT_MASK 0x7FU - /*************************************************************************/ - /* */ - /* */ - /* ft_var_readpackedpoints */ - /* */ - /* */ - /* Read a set of points to which the following deltas will apply. */ - /* Points are packed with a run length encoding. */ - /* */ - /* */ - /* stream :: The data stream. */ - /* */ - /* size :: The size of the table holding the data. */ - /* */ - /* */ - /* point_cnt :: The number of points read. A zero value means that */ - /* all points in the glyph will be affected, without */ - /* enumerating them individually. */ - /* */ - /* */ - /* An array of FT_UShort containing the affected points or the */ - /* special value ALL_POINTS. */ - /* */ + /************************************************************************** + * + * @Function: + * ft_var_readpackedpoints + * + * @Description: + * Read a set of points to which the following deltas will apply. + * Points are packed with a run length encoding. + * + * @Input: + * stream :: + * The data stream. + * + * size :: + * The size of the table holding the data. + * + * @Output: + * point_cnt :: + * The number of points read. A zero value means that + * all points in the glyph will be affected, without + * enumerating them individually. + * + * @Return: + * An array of FT_UShort containing the affected points or the + * special value ALL_POINTS. + */ static FT_UShort* ft_var_readpackedpoints( FT_Stream stream, FT_ULong size, @@ -211,34 +227,41 @@ #define GX_DT_DELTA_RUN_COUNT_MASK 0x3FU - /*************************************************************************/ - /* */ - /* */ - /* ft_var_readpackeddeltas */ - /* */ - /* */ - /* Read a set of deltas. These are packed slightly differently than */ - /* points. In particular there is no overall count. */ - /* */ - /* */ - /* stream :: The data stream. */ - /* */ - /* size :: The size of the table holding the data. */ - /* */ - /* delta_cnt :: The number of deltas to be read. */ - /* */ - /* */ - /* An array of FT_Short containing the deltas for the affected */ - /* points. (This only gets the deltas for one dimension. It will */ - /* generally be called twice, once for x, once for y. When used in */ - /* cvt table, it will only be called once.) */ - /* */ - static FT_Short* + /************************************************************************** + * + * @Function: + * ft_var_readpackeddeltas + * + * @Description: + * Read a set of deltas. These are packed slightly differently than + * points. In particular there is no overall count. + * + * @Input: + * stream :: + * The data stream. + * + * size :: + * The size of the table holding the data. + * + * delta_cnt :: + * The number of deltas to be read. + * + * @Return: + * An array of FT_Fixed containing the deltas for the affected + * points. (This only gets the deltas for one dimension. It will + * generally be called twice, once for x, once for y. When used in + * cvt table, it will only be called once.) + * + * We use FT_Fixed to avoid accumulation errors while summing up all + * deltas (the rounding to integer values happens as the very last + * step). + */ + static FT_Fixed* ft_var_readpackeddeltas( FT_Stream stream, FT_ULong size, FT_UInt delta_cnt ) { - FT_Short *deltas = NULL; + FT_Fixed *deltas = NULL; FT_UInt runcnt, cnt; FT_UInt i, j; FT_Memory memory = stream->memory; @@ -272,13 +295,13 @@ { /* `runcnt' shorts from the stack */ for ( j = 0; j <= cnt && i < delta_cnt; j++ ) - deltas[i++] = FT_GET_SHORT(); + deltas[i++] = FT_intToFixed( FT_GET_SHORT() ); } else { /* `runcnt' signed bytes from the stack */ for ( j = 0; j <= cnt && i < delta_cnt; j++ ) - deltas[i++] = FT_GET_CHAR(); + deltas[i++] = FT_intToFixed( FT_GET_CHAR() ); } if ( j <= cnt ) @@ -293,18 +316,19 @@ } - /*************************************************************************/ - /* */ - /* */ - /* ft_var_load_avar */ - /* */ - /* */ - /* Parse the `avar' table if present. It need not be, so we return */ - /* nothing. */ - /* */ - /* */ - /* face :: The font face. */ - /* */ + /************************************************************************** + * + * @Function: + * ft_var_load_avar + * + * @Description: + * Parse the `avar' table if present. It need not be, so we return + * nothing. + * + * @InOut: + * face :: + * The font face. + */ static void ft_var_load_avar( TT_Face face ) { @@ -377,9 +401,10 @@ for ( j = 0; j < segment->pairCount; j++ ) { - /* convert to Fixed */ - segment->correspondence[j].fromCoord = FT_GET_SHORT() * 4; - segment->correspondence[j].toCoord = FT_GET_SHORT() * 4; + segment->correspondence[j].fromCoord = + FT_fdot14ToFixed( FT_GET_SHORT() ); + segment->correspondence[j].toCoord = + FT_fdot14ToFixed( FT_GET_SHORT() ); FT_TRACE5(( " mapping %.5f to %.5f\n", segment->correspondence[j].fromCoord / 65536.0, @@ -394,17 +419,6 @@ } - /* some macros we need */ -#define FT_FIXED_ONE ( (FT_Fixed)0x10000 ) - -#define FT_fdot14ToFixed( x ) \ - ( (FT_Fixed)( (FT_ULong)(x) << 2 ) ) -#define FT_intToFixed( i ) \ - ( (FT_Fixed)( (FT_ULong)(i) << 16 ) ) -#define FT_fixedToInt( x ) \ - ( (FT_Short)( ( (FT_UInt32)(x) + 0x8000U ) >> 16 ) ) - - static FT_Error ft_var_load_item_variation_store( TT_Face face, FT_ULong offset, @@ -702,29 +716,30 @@ } - /*************************************************************************/ - /* */ - /* */ - /* ft_var_load_hvvar */ - /* */ - /* */ - /* If `vertical' is zero, parse the `HVAR' table and set */ - /* `blend->hvar_loaded' to TRUE. On success, `blend->hvar_checked' */ - /* is set to TRUE. */ - /* */ - /* If `vertical' is not zero, parse the `VVAR' table and set */ - /* `blend->vvar_loaded' to TRUE. On success, `blend->vvar_checked' */ - /* is set to TRUE. */ - /* */ - /* Some memory may remain allocated on error; it is always freed in */ - /* `tt_done_blend', however. */ - /* */ - /* */ - /* face :: The font face. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ + /************************************************************************** + * + * @Function: + * ft_var_load_hvvar + * + * @Description: + * If `vertical' is zero, parse the `HVAR' table and set + * `blend->hvar_loaded' to TRUE. On success, `blend->hvar_checked' + * is set to TRUE. + * + * If `vertical' is not zero, parse the `VVAR' table and set + * `blend->vvar_loaded' to TRUE. On success, `blend->vvar_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_hvvar( TT_Face face, FT_Bool vertical ) @@ -872,7 +887,7 @@ /* outer loop steps through master designs to be blended */ for ( master = 0; master < varData->regionIdxCount; master++ ) { - FT_Fixed scalar = FT_FIXED_ONE; + FT_Fixed scalar = 0x10000L; FT_UInt regionIndex = varData->regionIndices[master]; GX_AxisCoords axis = itemStore->varRegionList[regionIndex].axisList; @@ -881,47 +896,43 @@ /* inner loop steps through axes in this region */ for ( j = 0; j < 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; + continue; else if ( axis->startCoord < 0 && axis->endCoord > 0 && axis->peakCoord != 0 ) - axisScalar = FT_FIXED_ONE; + continue; /* peak of 0 means ignore this axis */ else if ( axis->peakCoord == 0 ) - axisScalar = FT_FIXED_ONE; + continue; - /* 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; + else if ( face->blend->normalizedcoords[j] == axis->peakCoord ) + continue; - /* calculate a proportional factor */ - else + /* ignore this region if coords are out of range */ + else if ( face->blend->normalizedcoords[j] <= axis->startCoord || + face->blend->normalizedcoords[j] >= axis->endCoord ) { - 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 ); + scalar = 0; + break; } - /* take product of all the axis scalars */ - scalar = FT_MulFix( scalar, axisScalar ); - + /* cumulative product of all the axis scalars */ + else if ( face->blend->normalizedcoords[j] < axis->peakCoord ) + scalar = + FT_MulDiv( scalar, + face->blend->normalizedcoords[j] - axis->startCoord, + axis->peakCoord - axis->startCoord ); + else + scalar = + FT_MulDiv( scalar, + axis->endCoord - face->blend->normalizedcoords[j], + axis->endCoord - axis->peakCoord ); } /* per-axis loop */ /* get the scaled delta for this region */ @@ -937,25 +948,29 @@ } - /*************************************************************************/ - /* */ - /* */ - /* tt_hvadvance_adjust */ - /* */ - /* */ - /* Apply `HVAR' advance width or `VVAR' advance height adjustment of */ - /* a given glyph. */ - /* */ - /* */ - /* gindex :: The glyph index. */ - /* */ - /* vertical :: If set, handle `VVAR' table. */ - /* */ - /* */ - /* face :: The font face. */ - /* */ - /* adelta :: Points to width or height value that gets modified. */ - /* */ + /************************************************************************** + * + * @Function: + * tt_hvadvance_adjust + * + * @Description: + * Apply `HVAR' advance width or `VVAR' advance height adjustment of + * a given glyph. + * + * @Input: + * gindex :: + * The glyph index. + * + * vertical :: + * If set, handle `VVAR' table. + * + * @InOut: + * face :: + * The font face. + * + * adelta :: + * Points to width or height value that gets modified. + */ static FT_Error tt_hvadvance_adjust( TT_Face face, FT_UInt gindex, @@ -1151,20 +1166,21 @@ } - /*************************************************************************/ - /* */ - /* */ - /* ft_var_load_mvar */ - /* */ - /* */ - /* Parse the `MVAR' table. */ - /* */ - /* Some memory may remain allocated on error; it is always freed in */ - /* `tt_done_blend', however. */ - /* */ - /* */ - /* face :: The font face. */ - /* */ + /************************************************************************** + * + * @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 ) { @@ -1297,22 +1313,26 @@ } - /*************************************************************************/ - /* */ - /* */ - /* tt_apply_mvar */ - /* */ - /* */ - /* Apply `MVAR' table adjustments. */ - /* */ - /* */ - /* face :: The font face. */ - /* */ + /************************************************************************** + * + * @Function: + * tt_apply_mvar + * + * @Description: + * Apply `MVAR' table adjustments. + * + * @InOut: + * face :: + * The font face. + */ FT_LOCAL_DEF( void ) tt_apply_mvar( TT_Face face ) { GX_Blend blend = face->blend; GX_Value value, limit; + FT_Short mvar_hasc_delta = 0; + FT_Short mvar_hdsc_delta = 0; + FT_Short mvar_hlgp_delta = 0; if ( !( face->variation_support & TT_FACE_FLAG_VAR_MVAR ) ) @@ -1347,6 +1367,14 @@ /* since we handle both signed and unsigned values as FT_Short, */ /* ensure proper overflow arithmetic */ *p = (FT_Short)( value->unmodified + (FT_Short)delta ); + + /* Treat hasc, hdsc and hlgp specially, see below. */ + if ( value->tag == MVAR_TAG_HASC ) + mvar_hasc_delta = (FT_Short)delta; + else if ( value->tag == MVAR_TAG_HDSC ) + mvar_hdsc_delta = (FT_Short)delta; + else if ( value->tag == MVAR_TAG_HLGP ) + mvar_hlgp_delta = (FT_Short)delta; } } @@ -1354,25 +1382,40 @@ { FT_Face root = &face->root; - - if ( face->os2.version != 0xFFFFU ) - { - if ( face->os2.sTypoAscender || face->os2.sTypoDescender ) - { - root->ascender = face->os2.sTypoAscender; - root->descender = face->os2.sTypoDescender; - - root->height = root->ascender - root->descender + - face->os2.sTypoLineGap; - } - else - { - root->ascender = (FT_Short)face->os2.usWinAscent; - root->descender = -(FT_Short)face->os2.usWinDescent; - - root->height = root->ascender - root->descender; - } - } + /* + * Apply the deltas of hasc, hdsc and hlgp to the FT_Face's ascender, + * descender and height attributes, no matter how they were originally + * computed. + * + * (Code that ignores those and accesses the font's metrics values + * directly is already served by the delta application code above.) + * + * The MVAR table supports variations for both typo and win metrics. + * According to Behdad Esfahbod, the thinking of the working group was + * that no one uses win metrics anymore for setting line metrics (the + * specification even calls these metrics "horizontal clipping + * ascent/descent", probably for their role on the Windows platform in + * computing clipping boxes), and new fonts should use typo metrics, so + * typo deltas should be applied to whatever sfnt_load_face decided the + * line metrics should be. + * + * Before, the following led to different line metrics between default + * outline and instances, visible when e.g. the default outlines were + * used as the regular face and instances for everything else: + * + * 1. sfnt_load_face applied the hhea metrics by default. + * 2. This code later applied the typo metrics by default, regardless of + * whether they were actually changed or the font had the OS/2 table's + * fsSelection's bit 7 (USE_TYPO_METRICS) set. + */ + FT_Short current_line_gap = root->height - root->ascender + + root->descender; + + + root->ascender = root->ascender + mvar_hasc_delta; + root->descender = root->descender + mvar_hdsc_delta; + root->height = root->ascender - root->descender + + current_line_gap + mvar_hlgp_delta; root->underline_position = face->postscript.underlinePosition - face->postscript.underlineThickness / 2; @@ -1400,21 +1443,22 @@ } GX_GVar_Head; - /*************************************************************************/ - /* */ - /* */ - /* ft_var_load_gvar */ - /* */ - /* */ - /* Parse the `gvar' table if present. If `fvar' is there, `gvar' had */ - /* better be there too. */ - /* */ - /* */ - /* face :: The font face. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ + /************************************************************************** + * + * @Function: + * ft_var_load_gvar + * + * @Description: + * Parse the `gvar' table if present. If `fvar' is there, `gvar' had + * better be there too. + * + * @InOut: + * face :: + * The font face. + * + * @Return: + * FreeType error code. 0 means success. + */ static FT_Error ft_var_load_gvar( TT_Face face ) { @@ -1512,28 +1556,55 @@ if ( gvar_head.flags & 1 ) { + FT_ULong limit = gvar_start + table_len; + + /* long offsets (one more offset than glyphs, to mark size of last) */ if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 4L ) ) goto Exit; for ( i = 0; i <= blend->gv_glyphcnt; i++ ) + { blend->glyphoffsets[i] = offsetToData + FT_GET_ULONG(); - - FT_FRAME_EXIT(); + /* use `>', not `>=' */ + if ( blend->glyphoffsets[i] > limit ) + { + FT_TRACE2(( "ft_var_load_gvar:" + " invalid glyph variation data offset for index %d\n", + i )); + error = FT_THROW( Invalid_Table ); + break; + } + } } else { + FT_ULong limit = gvar_start + table_len; + + /* short offsets (one more offset than glyphs, to mark size of last) */ if ( FT_FRAME_ENTER( ( blend->gv_glyphcnt + 1 ) * 2L ) ) goto Exit; for ( i = 0; i <= blend->gv_glyphcnt; i++ ) + { blend->glyphoffsets[i] = offsetToData + FT_GET_USHORT() * 2; - /* XXX: Undocumented: `*2'! */ - - FT_FRAME_EXIT(); + /* use `>', not `>=' */ + if ( blend->glyphoffsets[i] > limit ) + { + FT_TRACE2(( "ft_var_load_gvar:" + " invalid glyph variation data offset for index %d\n", + i )); + error = FT_THROW( Invalid_Table ); + break; + } + } } + FT_FRAME_EXIT(); + if ( error ) + goto Exit; + if ( blend->tuplecount != 0 ) { if ( FT_NEW_ARRAY( blend->tuplecoords, @@ -1550,7 +1621,7 @@ for ( j = 0; j < (FT_UInt)gvar_head.axisCount; j++ ) { blend->tuplecoords[i * gvar_head.axisCount + j] = - FT_GET_SHORT() * 4; /* convert to FT_Fixed */ + FT_fdot14ToFixed( FT_GET_SHORT() ); FT_TRACE5(( "%.5f ", blend->tuplecoords[i * gvar_head.axisCount + j] / 65536.0 )); } @@ -1567,33 +1638,38 @@ } - /*************************************************************************/ - /* */ - /* */ - /* ft_var_apply_tuple */ - /* */ - /* */ - /* Figure out whether a given tuple (design) applies to the current */ - /* blend, and if so, what is the scaling factor. */ - /* */ - /* */ - /* blend :: The current blend of the font. */ - /* */ - /* tupleIndex :: A flag saying whether this is an intermediate */ - /* tuple or not. */ - /* */ - /* tuple_coords :: The coordinates of the tuple in normalized axis */ - /* units. */ - /* */ - /* im_start_coords :: The initial coordinates where this tuple starts */ - /* to apply (for intermediate coordinates). */ - /* */ - /* im_end_coords :: The final coordinates after which this tuple no */ - /* longer applies (for intermediate coordinates). */ - /* */ - /* */ - /* An FT_Fixed value containing the scaling factor. */ - /* */ + /************************************************************************** + * + * @Function: + * ft_var_apply_tuple + * + * @Description: + * Figure out whether a given tuple (design) applies to the current + * blend, and if so, what is the scaling factor. + * + * @Input: + * blend :: + * The current blend of the font. + * + * tupleIndex :: + * A flag saying whether this is an intermediate + * tuple or not. + * + * tuple_coords :: + * The coordinates of the tuple in normalized axis + * units. + * + * im_start_coords :: + * The initial coordinates where this tuple starts + * to apply (for intermediate coordinates). + * + * im_end_coords :: + * The final coordinates after which this tuple no + * longer applies (for intermediate coordinates). + * + * @Return: + * An FT_Fixed value containing the scaling factor. + */ static FT_Fixed ft_var_apply_tuple( GX_Blend blend, FT_UShort tupleIndex, @@ -1607,13 +1683,8 @@ for ( i = 0; i < blend->num_axis; i++ ) { - FT_TRACE6(( " axis coordinate %d (%.5f):\n", + FT_TRACE6(( " axis %d coordinate %.5f:\n", i, blend->normalizedcoords[i] / 65536.0 )); - if ( !( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) ) - FT_TRACE6(( " intermediate coordinates %d (%.5f, %.5f):\n", - i, - im_start_coords[i] / 65536.0, - im_end_coords[i] / 65536.0 )); /* It's not clear why (for intermediate tuples) we don't need */ /* to check against start/end -- the documentation says we don't. */ @@ -1622,7 +1693,7 @@ if ( tuple_coords[i] == 0 ) { - FT_TRACE6(( " tuple coordinate is zero, ignored\n", i )); + FT_TRACE6(( " tuple coordinate is zero, ignore\n", i )); continue; } @@ -1635,7 +1706,7 @@ if ( blend->normalizedcoords[i] == tuple_coords[i] ) { - FT_TRACE6(( " tuple coordinate value %.5f fits perfectly\n", + FT_TRACE6(( " tuple coordinate %.5f fits perfectly\n", tuple_coords[i] / 65536.0 )); /* `apply' does not change */ continue; @@ -1648,13 +1719,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 %.5f is exceeded, stop\n", + FT_TRACE6(( " tuple coordinate %.5f is exceeded, stop\n", tuple_coords[i] / 65536.0 )); apply = 0; break; } - FT_TRACE6(( " tuple coordinate value %.5f fits\n", + FT_TRACE6(( " tuple coordinate %.5f fits\n", tuple_coords[i] / 65536.0 )); apply = FT_MulDiv( apply, blend->normalizedcoords[i], @@ -1664,10 +1735,10 @@ { /* intermediate tuple */ - if ( blend->normalizedcoords[i] < im_start_coords[i] || - blend->normalizedcoords[i] > im_end_coords[i] ) + if ( blend->normalizedcoords[i] <= im_start_coords[i] || + blend->normalizedcoords[i] >= im_end_coords[i] ) { - FT_TRACE6(( " intermediate tuple range [%.5f;%.5f] 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 )); @@ -1675,25 +1746,17 @@ break; } - else if ( blend->normalizedcoords[i] < tuple_coords[i] ) - { - FT_TRACE6(( " intermediate tuple range [%.5f;%.5f] fits\n", - im_start_coords[i] / 65536.0, - im_end_coords[i] / 65536.0 )); + FT_TRACE6(( " intermediate tuple range ]%.5f;%.5f[ fits\n", + im_start_coords[i] / 65536.0, + im_end_coords[i] / 65536.0 )); + if ( blend->normalizedcoords[i] < tuple_coords[i] ) apply = FT_MulDiv( apply, blend->normalizedcoords[i] - im_start_coords[i], tuple_coords[i] - im_start_coords[i] ); - } - else - { - 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, im_end_coords[i] - blend->normalizedcoords[i], im_end_coords[i] - tuple_coords[i] ); - } } } @@ -1756,11 +1819,11 @@ } if ( coord < a->def ) - normalized[i] = -FT_DivFix( coord - a->def, - a->minimum - a->def ); + normalized[i] = -FT_DivFix( SUB_LONG( coord, a->def ), + SUB_LONG( a->minimum, a->def ) ); else if ( coord > a->def ) - normalized[i] = FT_DivFix( coord - a->def, - a->maximum - a->def ); + normalized[i] = FT_DivFix( SUB_LONG( coord, a->def ), + SUB_LONG( a->maximum, a->def ) ); else normalized[i] = 0; } @@ -1910,27 +1973,29 @@ } GX_FVar_Axis; - /*************************************************************************/ - /* */ - /* */ - /* TT_Get_MM_Var */ - /* */ - /* */ - /* Check that the font's `fvar' table is valid, parse it, and return */ - /* those data. It also loads (and parses) the `MVAR' table, if */ - /* possible. */ - /* */ - /* */ - /* face :: The font face. */ - /* TT_Get_MM_Var initializes the blend structure. */ - /* */ - /* */ - /* master :: The `fvar' data (must be freed by caller). Can be NULL, */ - /* which makes this function simply load MM support. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ + /************************************************************************** + * + * @Function: + * TT_Get_MM_Var + * + * @Description: + * Check that the font's `fvar' table is valid, parse it, and return + * those data. It also loads (and parses) the `MVAR' table, if + * possible. + * + * @InOut: + * face :: + * The font face. + * TT_Get_MM_Var initializes the blend structure. + * + * @Output: + * master :: + * The `fvar' data (must be freed by caller). Can be NULL, + * which makes this function simply load MM support. + * + * @Return: + * FreeType error code. 0 means success. + */ FT_LOCAL_DEF( FT_Error ) TT_Get_MM_Var( TT_Face face, FT_MM_Var* *master ) @@ -2507,11 +2572,14 @@ if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) ) { - FT_UInt idx = (FT_UInt)face->root.face_index >> 16; + FT_UInt instance_index = (FT_UInt)face->root.face_index >> 16; c = blend->normalizedcoords + i; - n = blend->normalized_stylecoords + idx * mmvar->num_axis + i; + n = blend->normalized_stylecoords + + ( instance_index - 1 ) * mmvar->num_axis + + i; + for ( j = i; j < mmvar->num_axis; j++, n++, c++ ) if ( *c != *n ) have_diff = 1; @@ -2526,7 +2594,11 @@ /* return value -1 indicates `no change' */ if ( !have_diff ) + { + face->doblend = TRUE; + return -1; + } for ( ; i < mmvar->num_axis; i++ ) { @@ -2590,31 +2662,34 @@ } - /*************************************************************************/ - /* */ - /* */ - /* TT_Set_MM_Blend */ - /* */ - /* */ - /* Set the blend (normalized) coordinates for this instance of the */ - /* font. Check that the `gvar' table is reasonable and does some */ - /* initial preparation. */ - /* */ - /* */ - /* face :: The font. */ - /* Initialize the blend structure with `gvar' data. */ - /* */ - /* */ - /* num_coords :: The number of available coordinates. If it is */ - /* larger than the number of axes, ignore the excess */ - /* values. If it is smaller than the number of axes, */ - /* use the default value (0) for the remaining axes. */ - /* */ - /* coords :: An array of `num_coords', each between [-1,1]. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ + /************************************************************************** + * + * @Function: + * TT_Set_MM_Blend + * + * @Description: + * Set the blend (normalized) coordinates for this instance of the + * font. Check that the `gvar' table is reasonable and does some + * initial preparation. + * + * @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, ignore the excess + * values. If it is smaller than the number of axes, + * use the default value (0) for the remaining axes. + * + * coords :: + * An array of `num_coords', each between [-1,1]. + * + * @Return: + * FreeType error code. 0 means success. + */ FT_LOCAL_DEF( FT_Error ) TT_Set_MM_Blend( TT_Face face, FT_UInt num_coords, @@ -2636,29 +2711,32 @@ } - /*************************************************************************/ - /* */ - /* */ - /* TT_Get_MM_Blend */ - /* */ - /* */ - /* Get the blend (normalized) coordinates for this instance of the */ - /* font. */ - /* */ - /* */ - /* face :: The font. */ - /* Initialize the blend structure with `gvar' data. */ - /* */ - /* */ - /* 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]. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ + /************************************************************************** + * + * @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, @@ -2712,31 +2790,34 @@ } - /*************************************************************************/ - /* */ - /* */ - /* TT_Set_Var_Design */ - /* */ - /* */ - /* Set the coordinates for the instance, measured in the user */ - /* coordinate system. Parse the `avar' table (if present) to convert */ - /* from user to normalized coordinates. */ - /* */ - /* */ - /* face :: The font face. */ - /* Initialize the blend struct with `gvar' data. */ - /* */ - /* */ - /* num_coords :: The number of available coordinates. If it is */ - /* larger than the number of axes, ignore the excess */ - /* values. If it is smaller than the number of axes, */ - /* use the default values for the remaining axes. */ - /* */ - /* coords :: A coordinate array with `num_coords' elements. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ + /************************************************************************** + * + * @Function: + * TT_Set_Var_Design + * + * @Description: + * Set the coordinates for the instance, measured in the user + * coordinate system. Parse the `avar' table (if present) to convert + * from user to normalized coordinates. + * + * @InOut: + * face :: + * The font face. + * Initialize the blend struct with `gvar' data. + * + * @Input: + * num_coords :: + * The number of available coordinates. If it is + * larger than the number of axes, ignore the excess + * values. If it is smaller than the number of axes, + * use the default values for the remaining axes. + * + * coords :: + * A coordinate array with `num_coords' elements. + * + * @Return: + * FreeType error code. 0 means success. + */ FT_LOCAL_DEF( FT_Error ) TT_Set_Var_Design( TT_Face face, FT_UInt num_coords, @@ -2854,28 +2935,31 @@ } - /*************************************************************************/ - /* */ - /* */ - /* TT_Get_Var_Design */ - /* */ - /* */ - /* Get the design coordinates of the currently selected interpolated */ - /* font. */ - /* */ - /* */ - /* 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. */ - /* */ - /* */ - /* coords :: The design coordinates array. */ - /* */ - /* */ - /* FreeType error code. 0~means success. */ - /* */ + /************************************************************************** + * + * @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, @@ -2929,24 +3013,26 @@ } - /*************************************************************************/ - /* */ - /* */ - /* TT_Set_Named_Instance */ - /* */ - /* */ - /* Set the given named instance, also resetting any further */ - /* variation. */ - /* */ - /* */ - /* face :: A handle to the source face. */ - /* */ - /* instance_index :: The instance index, starting with value 1. */ - /* Value 0 indicates to not use an instance. */ - /* */ - /* */ - /* FreeType error code. 0~means success. */ - /* */ + /************************************************************************** + * + * @Function: + * TT_Set_Named_Instance + * + * @Description: + * Set the given named instance, also resetting any further + * variation. + * + * @Input: + * face :: + * A handle to the source face. + * + * instance_index :: + * The instance index, starting with value 1. + * Value 0 indicates to not use an instance. + * + * @Return: + * FreeType error code. 0~means success. + */ FT_LOCAL_DEF( FT_Error ) TT_Set_Named_Instance( TT_Face face, FT_UInt instance_index ) @@ -2973,7 +3059,7 @@ if ( instance_index > num_instances ) goto Exit; - if ( instance_index > 0 && mmvar->namedstyle ) + if ( instance_index > 0 ) { FT_Memory memory = face->root.memory; SFNT_Service sfnt = (SFNT_Service)face->sfnt; @@ -2999,7 +3085,12 @@ mmvar->num_axis, named_style->coords ); if ( error ) + { + /* internal error code -1 means `no change' */ + if ( error == -1 ) + error = FT_Err_Ok; goto Exit; + } } else error = TT_Set_Var_Design( face, 0, NULL ); @@ -3022,48 +3113,77 @@ /*************************************************************************/ - /*************************************************************************/ - /* */ - /* */ - /* tt_face_vary_cvt */ - /* */ - /* */ - /* Modify the loaded cvt table according to the `cvar' table and the */ - /* font's blend. */ - /* */ - /* */ - /* face :: A handle to the target face object. */ - /* */ - /* */ - /* stream :: A handle to the input stream. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ - /* Most errors are ignored. It is perfectly valid not to have a */ - /* `cvar' table even if there is a `gvar' and `fvar' table. */ - /* */ + static FT_Error + tt_cvt_ready_iterator( FT_ListNode node, + void* user ) + { + TT_Size size = (TT_Size)node->data; + + FT_UNUSED( user ); + + + size->cvt_ready = -1; + + return FT_Err_Ok; + } + + + /************************************************************************** + * + * @Function: + * tt_face_vary_cvt + * + * @Description: + * Modify the loaded cvt table according to the `cvar' table and the + * font's blend. + * + * @InOut: + * face :: + * A handle to the target face object. + * + * @Input: + * stream :: + * A handle to the input stream. + * + * @Return: + * FreeType error code. 0 means success. + * + * Most errors are ignored. It is perfectly valid not to have a + * `cvar' table even if there is a `gvar' and `fvar' table. + */ FT_LOCAL_DEF( FT_Error ) tt_face_vary_cvt( TT_Face face, FT_Stream stream ) { - FT_Error error; - FT_Memory memory = stream->memory; - FT_ULong table_start; - FT_ULong table_len; - FT_UInt tupleCount; - FT_ULong offsetToData; - FT_ULong here; - FT_UInt i, j; - FT_Fixed* tuple_coords = NULL; - FT_Fixed* im_start_coords = NULL; - FT_Fixed* im_end_coords = NULL; - GX_Blend blend = face->blend; - FT_UInt point_count, spoint_count = 0; + FT_Error error; + FT_Memory memory = stream->memory; + + FT_Face root = &face->root; + + FT_ULong table_start; + FT_ULong table_len; + + FT_UInt tupleCount; + FT_ULong offsetToData; + + FT_ULong here; + FT_UInt i, j; + + FT_Fixed* tuple_coords = NULL; + FT_Fixed* im_start_coords = NULL; + FT_Fixed* im_end_coords = NULL; + + GX_Blend blend = face->blend; + + FT_UInt point_count; + FT_UInt spoint_count = 0; + FT_UShort* sharedpoints = NULL; FT_UShort* localpoints = NULL; FT_UShort* points; - FT_Short* deltas; + + FT_Fixed* deltas = NULL; + FT_Fixed* cvt_deltas = NULL; FT_TRACE2(( "CVAR " )); @@ -3146,11 +3266,14 @@ } FT_TRACE5(( "cvar: there %s %d tuple%s:\n", - ( tupleCount & 0xFFF ) == 1 ? "is" : "are", - tupleCount & 0xFFF, - ( tupleCount & 0xFFF ) == 1 ? "" : "s" )); + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "is" : "are", + tupleCount & GX_TC_TUPLE_COUNT_MASK, + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" )); - for ( i = 0; i < ( tupleCount & 0xFFF ); i++ ) + if ( FT_NEW_ARRAY( cvt_deltas, face->cvt_size ) ) + goto FExit; + + for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ ) { FT_UInt tupleDataSize; FT_UInt tupleIndex; @@ -3165,8 +3288,7 @@ if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) { for ( j = 0; j < blend->num_axis; j++ ) - tuple_coords[j] = FT_GET_SHORT() * 4; /* convert from */ - /* short frac to fixed */ + tuple_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); } else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount ) { @@ -3174,20 +3296,32 @@ " invalid tuple index\n" )); error = FT_THROW( Invalid_Table ); - goto Exit; + goto FExit; } else + { + if ( !blend->tuplecoords ) + { + FT_TRACE2(( "tt_face_vary_cvt:" + " no valid tuple coordinates available\n" )); + + error = FT_THROW( Invalid_Table ); + goto FExit; + } + FT_MEM_COPY( tuple_coords, - &blend->tuplecoords[( tupleIndex & 0xFFF ) * blend->num_axis], + blend->tuplecoords + + ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis, blend->num_axis * sizeof ( FT_Fixed ) ); + } if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) { for ( j = 0; j < blend->num_axis; j++ ) - im_start_coords[j] = FT_GET_SHORT() * 4; + im_start_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); for ( j = 0; j < blend->num_axis; j++ ) - im_end_coords[j] = FT_GET_SHORT() * 4; + im_end_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); } apply = ft_var_apply_tuple( blend, @@ -3241,17 +3375,21 @@ /* this means that there are deltas for every entry in cvt */ for ( j = 0; j < face->cvt_size; j++ ) { - FT_Long orig_cvt = face->cvt[j]; + FT_Fixed old_cvt_delta; - face->cvt[j] = (FT_Short)( orig_cvt + - FT_MulFix( deltas[j], apply ) ); + old_cvt_delta = cvt_deltas[j]; + cvt_deltas[j] = old_cvt_delta + FT_MulFix( deltas[j], apply ); #ifdef FT_DEBUG_LEVEL_TRACE - if ( orig_cvt != face->cvt[j] ) + if ( old_cvt_delta != cvt_deltas[j] ) { - FT_TRACE7(( " %d: %d -> %d\n", - j, orig_cvt, face->cvt[j] )); + FT_TRACE7(( " %d: %f -> %f\n", + j, + ( FT_fdot6ToFixed( face->cvt[j] ) + + old_cvt_delta ) / 65536.0, + ( FT_fdot6ToFixed( face->cvt[j] ) + + cvt_deltas[j] ) / 65536.0 )); count++; } #endif @@ -3274,23 +3412,26 @@ for ( j = 0; j < point_count; j++ ) { - int pindex; - FT_Long orig_cvt; + int pindex; + FT_Fixed old_cvt_delta; pindex = points[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 ) ); + old_cvt_delta = cvt_deltas[pindex]; + cvt_deltas[pindex] = old_cvt_delta + FT_MulFix( deltas[j], apply ); #ifdef FT_DEBUG_LEVEL_TRACE - if ( orig_cvt != face->cvt[pindex] ) + if ( old_cvt_delta != cvt_deltas[pindex] ) { - FT_TRACE7(( " %d: %d -> %d\n", - pindex, orig_cvt, face->cvt[pindex] )); + FT_TRACE7(( " %d: %f -> %f\n", + pindex, + ( FT_fdot6ToFixed( face->cvt[pindex] ) + + old_cvt_delta ) / 65536.0, + ( FT_fdot6ToFixed( face->cvt[pindex] ) + + cvt_deltas[pindex] ) / 65536.0 )); count++; } #endif @@ -3313,6 +3454,9 @@ FT_TRACE5(( "\n" )); + for ( i = 0; i < face->cvt_size; i++ ) + face->cvt[i] += FT_fixedToFdot6( cvt_deltas[i] ); + FExit: FT_FRAME_EXIT(); @@ -3322,6 +3466,13 @@ FT_FREE( tuple_coords ); FT_FREE( im_start_coords ); FT_FREE( im_end_coords ); + FT_FREE( cvt_deltas ); + + /* iterate over all FT_Size objects and set `cvt_ready' to -1 */ + /* to trigger rescaling of all CVT values */ + FT_List_Iterate( &root->sizes_list, + tt_cvt_ready_iterator, + NULL ); return error; } @@ -3367,9 +3518,8 @@ /* between `p1' and `p2', using `ref1' and `ref2' as the reference */ /* point indices. */ - /* modeled after `af_iup_interp', `_iup_worker_interpolate', and */ - /* `Ins_IUP' */ - + /* modeled after `af_iup_interp', `_iup_worker_interpolate', and */ + /* `Ins_IUP' with spec differences in handling ill-defined cases. */ static void tt_delta_interpolate( int p1, int p2, @@ -3528,61 +3678,89 @@ } - /*************************************************************************/ - /* */ - /* */ - /* TT_Vary_Apply_Glyph_Deltas */ - /* */ - /* */ - /* Apply the appropriate deltas to the current glyph. */ - /* */ - /* */ - /* face :: A handle to the target face object. */ - /* */ - /* glyph_index :: The index of the glyph being modified. */ - /* */ - /* n_points :: The number of the points in the glyph, including */ - /* phantom points. */ - /* */ - /* */ - /* outline :: The outline to change. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ + /************************************************************************** + * + * @Function: + * TT_Vary_Apply_Glyph_Deltas + * + * @Description: + * Apply the appropriate deltas to the current glyph. + * + * @Input: + * face :: + * A handle to the target face object. + * + * glyph_index :: + * The index of the glyph being modified. + * + * n_points :: + * The number of the points in the glyph, including + * phantom points. + * + * @InOut: + * outline :: + * The outline to change. + * + * @Output: + * unrounded :: + * An array with `n_points' elements that is filled with unrounded + * point coordinates (in 26.6 format). + * + * @Return: + * FreeType error code. 0 means success. + */ FT_LOCAL_DEF( FT_Error ) TT_Vary_Apply_Glyph_Deltas( TT_Face face, FT_UInt glyph_index, FT_Outline* outline, + FT_Vector* unrounded, FT_UInt n_points ) { - FT_Stream stream = face->root.stream; - FT_Memory memory = stream->memory; - GX_Blend blend = face->blend; + FT_Error error; + FT_Stream stream = face->root.stream; + FT_Memory memory = stream->memory; - FT_Vector* points_org = NULL; - FT_Vector* points_out = NULL; + FT_Vector* points_org = NULL; /* coordinates in 16.16 format */ + FT_Vector* points_out = NULL; /* coordinates in 16.16 format */ FT_Bool* has_delta = NULL; - FT_Error error; - FT_ULong glyph_start; - FT_UInt tupleCount; - FT_ULong offsetToData; - FT_ULong here; - FT_UInt i, j; - FT_Fixed* tuple_coords = NULL; - FT_Fixed* im_start_coords = NULL; - FT_Fixed* im_end_coords = NULL; - FT_UInt point_count, spoint_count = 0; + FT_ULong glyph_start; + + FT_UInt tupleCount; + FT_ULong offsetToData; + FT_ULong dataSize; + + FT_ULong here; + FT_UInt i, j; + + FT_Fixed* tuple_coords = NULL; + FT_Fixed* im_start_coords = NULL; + FT_Fixed* im_end_coords = NULL; + + GX_Blend blend = face->blend; + + FT_UInt point_count; + FT_UInt spoint_count = 0; + FT_UShort* sharedpoints = NULL; FT_UShort* localpoints = NULL; FT_UShort* points; - FT_Short *deltas_x, *deltas_y; + + FT_Fixed* deltas_x = NULL; + FT_Fixed* deltas_y = NULL; + FT_Fixed* point_deltas_x = NULL; + FT_Fixed* point_deltas_y = NULL; if ( !face->doblend || !blend ) return FT_THROW( Invalid_Argument ); + for ( i = 0; i < n_points; i++ ) + { + unrounded[i].x = INT_TO_F26DOT6( outline->points[i].x ); + unrounded[i].y = INT_TO_F26DOT6( outline->points[i].y ); + } + if ( glyph_index >= blend->gv_glyphcnt || blend->glyphoffsets[glyph_index] == blend->glyphoffsets[glyph_index + 1] ) @@ -3597,9 +3775,11 @@ FT_NEW_ARRAY( has_delta, n_points ) ) goto Fail1; - if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] ) || - FT_FRAME_ENTER( blend->glyphoffsets[glyph_index + 1] - - blend->glyphoffsets[glyph_index] ) ) + dataSize = blend->glyphoffsets[glyph_index + 1] - + blend->glyphoffsets[glyph_index]; + + if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] ) || + FT_FRAME_ENTER( dataSize ) ) goto Fail1; glyph_start = FT_Stream_FTell( stream ); @@ -3615,8 +3795,8 @@ offsetToData = FT_GET_USHORT(); /* rough sanity test */ - if ( offsetToData + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) * 4 > - blend->gvar_size ) + if ( offsetToData > dataSize || + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) * 4 > dataSize ) { FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" " invalid glyph variation array header\n" )); @@ -3646,8 +3826,15 @@ tupleCount & GX_TC_TUPLE_COUNT_MASK, ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" )); + if ( FT_NEW_ARRAY( point_deltas_x, n_points ) || + FT_NEW_ARRAY( point_deltas_y, n_points ) ) + goto Fail3; + for ( j = 0; j < n_points; j++ ) - points_org[j] = outline->points[j]; + { + points_org[j].x = FT_intToFixed( outline->points[j].x ); + points_org[j].y = FT_intToFixed( outline->points[j].y ); + } for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ ) { @@ -3664,8 +3851,7 @@ if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) { for ( j = 0; j < blend->num_axis; j++ ) - tuple_coords[j] = FT_GET_SHORT() * 4; /* convert from */ - /* short frac to fixed */ + tuple_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); } else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount ) { @@ -3673,20 +3859,21 @@ " invalid tuple index\n" )); error = FT_THROW( Invalid_Table ); - goto Fail2; + goto Fail3; } else FT_MEM_COPY( tuple_coords, - &blend->tuplecoords[( tupleIndex & 0xFFF ) * blend->num_axis], + blend->tuplecoords + + ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis, blend->num_axis * sizeof ( FT_Fixed ) ); if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) { for ( j = 0; j < blend->num_axis; j++ ) - im_start_coords[j] = FT_GET_SHORT() * 4; + im_start_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); for ( j = 0; j < blend->num_axis; j++ ) - im_end_coords[j] = FT_GET_SHORT() * 4; + im_end_coords[j] = FT_fdot14ToFixed( FT_GET_SHORT() ); } apply = ft_var_apply_tuple( blend, @@ -3742,14 +3929,17 @@ /* this means that there are deltas for every point in the glyph */ for ( j = 0; j < n_points; j++ ) { - FT_Pos delta_x = FT_MulFix( deltas_x[j], apply ); - FT_Pos delta_y = FT_MulFix( deltas_y[j], apply ); + FT_Fixed old_point_delta_x = point_deltas_x[j]; + FT_Fixed old_point_delta_y = point_deltas_y[j]; + + FT_Fixed point_delta_x = FT_MulFix( deltas_x[j], apply ); + FT_Fixed point_delta_y = FT_MulFix( deltas_y[j], apply ); if ( j < n_points - 4 ) { - outline->points[j].x += delta_x; - outline->points[j].y += delta_y; + point_deltas_x[j] = old_point_delta_x + point_delta_x; + point_deltas_y[j] = old_point_delta_y + point_delta_y; } else { @@ -3759,33 +3949,37 @@ if ( j == ( n_points - 4 ) && !( face->variation_support & TT_FACE_FLAG_VAR_LSB ) ) - outline->points[j].x += delta_x; + point_deltas_x[j] = old_point_delta_x + point_delta_x; else if ( j == ( n_points - 3 ) && !( face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) - outline->points[j].x += delta_x; + point_deltas_x[j] = old_point_delta_x + point_delta_x; else if ( j == ( n_points - 2 ) && !( face->variation_support & TT_FACE_FLAG_VAR_TSB ) ) - outline->points[j].y += delta_y; + point_deltas_y[j] = old_point_delta_y + point_delta_y; else if ( j == ( n_points - 1 ) && !( face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) - outline->points[j].y += delta_y; + point_deltas_y[j] = old_point_delta_y + point_delta_y; } #ifdef FT_DEBUG_LEVEL_TRACE - if ( delta_x || delta_y ) + if ( point_delta_x || point_delta_y ) { - FT_TRACE7(( " %d: (%d, %d) -> (%d, %d)\n", + FT_TRACE7(( " %d: (%f, %f) -> (%f, %f)\n", j, - outline->points[j].x - delta_x, - outline->points[j].y - delta_y, - outline->points[j].x, - outline->points[j].y )); + ( FT_intToFixed( outline->points[j].x ) + + old_point_delta_x ) / 65536.0, + ( FT_intToFixed( outline->points[j].y ) + + old_point_delta_y ) / 65536.0, + ( FT_intToFixed( outline->points[j].x ) + + point_deltas_x[j] ) / 65536.0, + ( FT_intToFixed( outline->points[j].y ) + + point_deltas_y[j] ) / 65536.0 )); count++; } #endif @@ -3837,14 +4031,17 @@ for ( j = 0; j < n_points; j++ ) { - FT_Pos delta_x = points_out[j].x - points_org[j].x; - FT_Pos delta_y = points_out[j].y - points_org[j].y; + FT_Fixed old_point_delta_x = point_deltas_x[j]; + FT_Fixed old_point_delta_y = point_deltas_y[j]; + + FT_Pos point_delta_x = points_out[j].x - points_org[j].x; + FT_Pos point_delta_y = points_out[j].y - points_org[j].y; if ( j < n_points - 4 ) { - outline->points[j].x += delta_x; - outline->points[j].y += delta_y; + point_deltas_x[j] = old_point_delta_x + point_delta_x; + point_deltas_y[j] = old_point_delta_y + point_delta_y; } else { @@ -3854,33 +4051,37 @@ if ( j == ( n_points - 4 ) && !( face->variation_support & TT_FACE_FLAG_VAR_LSB ) ) - outline->points[j].x += delta_x; + point_deltas_x[j] = old_point_delta_x + point_delta_x; else if ( j == ( n_points - 3 ) && !( face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) ) - outline->points[j].x += delta_x; + point_deltas_x[j] = old_point_delta_x + point_delta_x; else if ( j == ( n_points - 2 ) && !( face->variation_support & TT_FACE_FLAG_VAR_TSB ) ) - outline->points[j].y += delta_y; + point_deltas_y[j] = old_point_delta_y + point_delta_y; else if ( j == ( n_points - 1 ) && !( face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) ) - outline->points[j].y += delta_y; + point_deltas_y[j] = old_point_delta_y + point_delta_y; } #ifdef FT_DEBUG_LEVEL_TRACE - if ( delta_x || delta_y ) + if ( point_delta_x || point_delta_y ) { - FT_TRACE7(( " %d: (%d, %d) -> (%d, %d)\n", + FT_TRACE7(( " %d: (%f, %f) -> (%f, %f)\n", j, - outline->points[j].x - delta_x, - outline->points[j].y - delta_y, - outline->points[j].x, - outline->points[j].y )); + ( FT_intToFixed( outline->points[j].x ) + + old_point_delta_x ) / 65536.0, + ( FT_intToFixed( outline->points[j].y ) + + old_point_delta_y ) / 65536.0, + ( FT_intToFixed( outline->points[j].x ) + + point_deltas_x[j] ) / 65536.0, + ( FT_intToFixed( outline->points[j].y ) + + point_deltas_y[j] ) / 65536.0 )); count++; } #endif @@ -3904,6 +4105,19 @@ FT_TRACE5(( "\n" )); + for ( i = 0; i < n_points; i++ ) + { + unrounded[i].x += FT_fixedToFdot6( point_deltas_x[i] ); + unrounded[i].y += FT_fixedToFdot6( point_deltas_y[i] ); + + outline->points[i].x += FT_fixedToInt( point_deltas_x[i] ); + outline->points[i].y += FT_fixedToInt( point_deltas_y[i] ); + } + + Fail3: + FT_FREE( point_deltas_x ); + FT_FREE( point_deltas_y ); + Fail2: if ( sharedpoints != ALL_POINTS ) FT_FREE( sharedpoints ); @@ -3922,16 +4136,16 @@ } - /*************************************************************************/ - /* */ - /* */ - /* tt_get_var_blend */ - /* */ - /* */ - /* 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. */ - /* */ + /************************************************************************** + * + * @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, @@ -3993,14 +4207,14 @@ } - /*************************************************************************/ - /* */ - /* */ - /* tt_done_blend */ - /* */ - /* */ - /* Free the blend internal data structure. */ - /* */ + /************************************************************************** + * + * @Function: + * tt_done_blend + * + * @Description: + * Free the blend internal data structure. + */ FT_LOCAL_DEF( void ) tt_done_blend( TT_Face face ) { -- cgit v1.2.3