From dece9535164696777c1ae0000b399c470c306d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20R=C3=B6ttsches?= Date: Wed, 29 Jun 2022 11:48:53 +0300 Subject: [PATCH] [truetype] Perform variation store delta computation with 64-bit precision. * include/freetype/internal/ftmmtypes.h (FT_ItemVarDelta): Make type explicitly 32-bit. * include/freetype/internal/services/svmm.h (FT_Var_Get_Item_Delta_Func): Change return type to `FT_ItemVarDelta` * truetype/ttgxvar.h (tt_var_get_item_delta): Change return type to `FT_ItemVarDelta`. * truetype/ttgxvar.c (tt_var_get_item_delta): Store scalars and deltas to intermediate array, perform computation using new method `FT_MulAddFix`. --- include/freetype/internal/ftmmtypes.h | 2 +- include/freetype/internal/services/svmm.h | 2 +- src/truetype/ttgxvar.c | 46 +++++++++++++++++------ src/truetype/ttgxvar.h | 2 +- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/include/freetype/internal/ftmmtypes.h b/include/freetype/internal/ftmmtypes.h index 44f7e74dd..570c7fdd1 100644 --- a/include/freetype/internal/ftmmtypes.h +++ b/include/freetype/internal/ftmmtypes.h @@ -24,7 +24,7 @@ FT_BEGIN_HEADER - typedef FT_Long FT_ItemVarDelta; + typedef FT_Int32 FT_ItemVarDelta; typedef struct GX_ItemVarDataRec_ { diff --git a/include/freetype/internal/services/svmm.h b/include/freetype/internal/services/svmm.h index 22ddc8c66..b67ea7c60 100644 --- a/include/freetype/internal/services/svmm.h +++ b/include/freetype/internal/services/svmm.h @@ -109,7 +109,7 @@ FT_BEGIN_HEADER FT_ULong offset, GX_ItemVarStore itemStore ); - typedef FT_Int + typedef FT_ItemVarDelta (*FT_Var_Get_Item_Delta_Func)( FT_Face face, GX_ItemVarStore itemStore, FT_UInt outerIndex, diff --git a/src/truetype/ttgxvar.c b/src/truetype/ttgxvar.c index 1bf9debb0..65fc7012c 100644 --- a/src/truetype/ttgxvar.c +++ b/src/truetype/ttgxvar.c @@ -939,19 +939,23 @@ } - FT_LOCAL_DEF( FT_Int ) + FT_LOCAL_DEF( FT_ItemVarDelta ) tt_var_get_item_delta( TT_Face face, GX_ItemVarStore itemStore, FT_UInt outerIndex, FT_UInt innerIndex ) { + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = stream->memory; + FT_Error error = FT_Err_Ok; + GX_ItemVarData varData; FT_ItemVarDelta* deltaSet; - FT_UInt master, j; - FT_Fixed netAdjustment = 0; /* accumulated adjustment */ - FT_Fixed scaledDelta; - FT_Fixed delta; + FT_UInt master, j; + FT_Fixed* scalars; + FT_ItemVarDelta returnValue; + /* OpenType 1.8.4+: No variation data for this item * as indices have special value 0xFFFF. */ @@ -964,6 +968,9 @@ varData = &itemStore->varData[outerIndex]; deltaSet = &varData->deltaSet[varData->regionIdxCount * innerIndex]; + if ( FT_QNEW_ARRAY( scalars, varData->regionIdxCount ) ) + return 0; + /* outer loop steps through master designs to be blended */ for ( master = 0; master < varData->regionIdxCount; master++ ) { @@ -1013,18 +1020,33 @@ FT_MulDiv( scalar, axis->endCoord - face->blend->normalizedcoords[j], axis->endCoord - axis->peakCoord ); + } /* 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; + scalars[master] = scalar; } /* per-region loop */ - return FT_fixedToInt( netAdjustment ); + + /* Compute the scaled delta for this region. + * + * From: https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#item-variation-store-header-and-item-variation-data-subtables: + * + * `Fixed` is a 32-bit (16.16) type and, in the general case, requires + * 32-bit deltas. As described above, the `DeltaSet` record can + * accommodate deltas that are, logically, either 16-bit or 32-bit. + * When scaled deltas are applied to `Fixed` values, the `Fixed` value + * is treated like a 32-bit integer. + * + * `FT_MulAddFix` internally uses 64-bit precision; it thus can handle + * deltas ranging from small 8-bit to large 32-bit values that are + * applied to 16.16 `FT_Fixed` / OpenType `Fixed` values. + */ + returnValue = FT_MulAddFix( scalars, deltaSet, varData->regionIdxCount ); + + FT_FREE( scalars ); + + return returnValue; } diff --git a/src/truetype/ttgxvar.h b/src/truetype/ttgxvar.h index 15c26373d..513c40b8a 100644 --- a/src/truetype/ttgxvar.h +++ b/src/truetype/ttgxvar.h @@ -391,7 +391,7 @@ FT_BEGIN_HEADER GX_ItemVarStore itemStore, FT_ULong table_len ); - FT_LOCAL( FT_Int ) + FT_LOCAL( FT_ItemVarDelta ) tt_var_get_item_delta( TT_Face face, GX_ItemVarStore itemStore, FT_UInt outerIndex,