[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`.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
diff --git a/include/freetype/internal/ftmmtypes.h b/include/freetype/internal/ftmmtypes.h
index 44f7e74..570c7fd 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 22ddc8c..b67ea7c 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 1bf9deb..65fc701 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 );
+ } /* per-axis loop */
- /* 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 15c2637..513c40b 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,