summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBehdad Esfahbod <behdad@behdad.org>2022-07-23 13:49:27 -0600
committerWerner Lemberg <wl@gnu.org>2022-11-04 19:44:36 +0100
commitae4eb996ab1ed43a52fac19461de3bdcaf1a1742 (patch)
tree06c3cb10edeb7f79386b40c2e900d48d72f4ff03
parentdea2e6358b2f963008d447d27564dd79890b61f0 (diff)
downloadfreetype2-ae4eb996ab1ed43a52fac19461de3bdcaf1a1742.tar.gz
[truetype] Add support for `avar` table 2.0 format.
See https://github.com/harfbuzz/boring-expansion-spec/blob/main/avar2.md for the specification. Currently, this is implemented only in most recent OS versions on Apple platforms and in the HarfBuzz library, but it is expected to be added to the OpenType standard soon. * src/truetype/ttgxvar.h (GX_AVarTableRec): New structure. (GX_BlendRec): Use it to replace `avar_segment` with `avar_table`. * src/truetype/ttgxvar.c (ft_var_load_avar): Load new table version. (ft_var_to_normalized, tt_done_blend): Extend for new format. (ft_var_load_hvvar, ft_var_to_design): Updated.
-rw-r--r--src/truetype/ttgxvar.c195
-rw-r--r--src/truetype/ttgxvar.h21
2 files changed, 176 insertions, 40 deletions
diff --git a/src/truetype/ttgxvar.c b/src/truetype/ttgxvar.c
index 14d272f58..663fb2e48 100644
--- a/src/truetype/ttgxvar.c
+++ b/src/truetype/ttgxvar.c
@@ -353,15 +353,21 @@
static void
ft_var_load_avar( TT_Face face )
{
- FT_Stream stream = FT_FACE_STREAM( face );
- FT_Memory memory = stream->memory;
+ FT_Error error;
+ FT_Stream stream = FT_FACE_STREAM( face );
+ FT_Memory memory = stream->memory;
+ FT_Int i, j;
+
GX_Blend blend = face->blend;
GX_AVarSegment segment;
- FT_Error error;
- FT_Long version;
- FT_Long axisCount;
- FT_Int i, j;
- FT_ULong table_len;
+ GX_AVarTable table;
+
+ FT_Long version;
+ FT_Long axisCount;
+ FT_ULong table_offset;
+ FT_ULong table_len;
+ FT_ULong store_offset;
+ FT_ULong axisMap_offset;
FT_TRACE2(( "AVAR " ));
@@ -374,13 +380,15 @@
return;
}
+ table_offset = FT_STREAM_POS();
+
if ( FT_FRAME_ENTER( table_len ) )
return;
version = FT_GET_LONG();
axisCount = FT_GET_LONG();
- if ( version != 0x00010000L )
+ if ( version != 0x00010000L && version != 0x00020000L )
{
FT_TRACE2(( "bad table version\n" ));
goto Exit;
@@ -396,10 +404,14 @@
goto Exit;
}
- if ( FT_QNEW_ARRAY( blend->avar_segment, axisCount ) )
+ if ( FT_NEW( blend->avar_table ) )
+ goto Exit;
+ table = blend->avar_table;
+
+ if ( FT_QNEW_ARRAY( table->avar_segment, axisCount ) )
goto Exit;
- segment = &blend->avar_segment[0];
+ segment = &table->avar_segment[0];
for ( i = 0; i < axisCount; i++, segment++ )
{
FT_TRACE5(( " axis %d:\n", i ));
@@ -412,9 +424,9 @@
/* it right now since loading the `avar' table is optional. */
for ( j = i - 1; j >= 0; j-- )
- FT_FREE( blend->avar_segment[j].correspondence );
+ FT_FREE( table->avar_segment[j].correspondence );
- FT_FREE( blend->avar_segment );
+ FT_FREE( table->avar_segment );
goto Exit;
}
@@ -433,6 +445,35 @@
FT_TRACE5(( "\n" ));
}
+ if ( version < 0x00020000L )
+ goto Exit;
+
+ axisMap_offset = FT_GET_ULONG();
+ store_offset = FT_GET_ULONG();
+
+ if ( store_offset )
+ {
+ error = tt_var_load_item_variation_store(
+ face,
+ table_offset + store_offset,
+ &table->itemStore );
+ if ( error )
+ goto Exit;
+ }
+
+ if ( axisMap_offset )
+ {
+ error = tt_var_load_delta_set_index_mapping(
+ face,
+ table_offset + axisMap_offset,
+ &table->axisMap,
+ &table->itemStore,
+ table_len );
+ if ( error )
+ goto Exit;
+ }
+
+
Exit:
FT_FRAME_EXIT();
}
@@ -888,12 +929,15 @@
table = blend->hvar_table;
}
- error = tt_var_load_item_variation_store(
- face,
- table_offset + store_offset,
- &table->itemStore );
- if ( error )
- goto Exit;
+ if ( store_offset )
+ {
+ error = tt_var_load_item_variation_store(
+ face,
+ table_offset + store_offset,
+ &table->itemStore );
+ if ( error )
+ goto Exit;
+ }
if ( widthMap_offset )
{
@@ -1924,12 +1968,18 @@
FT_Fixed* coords,
FT_Fixed* normalized )
{
+ FT_Error error = FT_Err_Ok;
+ FT_Memory memory = face->root.memory;
+ FT_UInt i, j;
+
GX_Blend blend;
FT_MM_Var* mmvar;
- FT_UInt i, j;
FT_Var_Axis* a;
GX_AVarSegment av;
+ FT_Fixed* new_normalized;
+ FT_Fixed* old_normalized;
+
blend = face->blend;
mmvar = blend->mmvar;
@@ -1980,30 +2030,91 @@
for ( ; i < mmvar->num_axis; i++ )
normalized[i] = 0;
- if ( blend->avar_segment )
+ if ( blend->avar_table )
{
+ GX_AVarTable table = blend->avar_table;
+
+
FT_TRACE5(( "normalized design coordinates"
" before applying `avar' data:\n" ));
- av = blend->avar_segment;
- for ( i = 0; i < mmvar->num_axis; i++, av++ )
+ if ( table->avar_segment )
{
- for ( j = 1; j < (FT_UInt)av->pairCount; j++ )
+ av = table->avar_segment;
+
+ for ( i = 0; i < mmvar->num_axis; i++, av++ )
{
- if ( normalized[i] < av->correspondence[j].fromCoord )
+ for ( j = 1; j < (FT_UInt)av->pairCount; j++ )
{
- FT_TRACE5(( " %.5f\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 -
+ av->correspondence[j - 1].toCoord,
+ av->correspondence[j].fromCoord -
+ av->correspondence[j - 1].fromCoord ) +
+ av->correspondence[j - 1].toCoord;
+ break;
+ }
+ }
+ }
+ }
- normalized[i] =
- FT_MulDiv( normalized[i] - av->correspondence[j - 1].fromCoord,
- av->correspondence[j].toCoord -
- av->correspondence[j - 1].toCoord,
- av->correspondence[j].fromCoord -
- av->correspondence[j - 1].fromCoord ) +
- av->correspondence[j - 1].toCoord;
- break;
+ if ( table->itemStore.varData )
+ {
+ if ( FT_QNEW_ARRAY( new_normalized, mmvar->num_axis ) )
+ return;
+
+ /* Install our half-normalized coordinates for the next */
+ /* Item Variation Store to work with. */
+ old_normalized = face->blend->normalizedcoords;
+ face->blend->normalizedcoords = normalized;
+
+ for ( i = 0; i < mmvar->num_axis; i++ )
+ {
+ FT_Fixed v = normalized[i];
+ FT_UInt innerIndex = i;
+ FT_UInt outerIndex = 0;
+ FT_Int delta;
+
+
+ if ( table->axisMap.innerIndex )
+ {
+ FT_UInt idx = i;
+
+
+ if ( idx >= table->axisMap.mapCount )
+ idx = table->axisMap.mapCount - 1;
+
+ outerIndex = table->axisMap.outerIndex[idx];
+ innerIndex = table->axisMap.innerIndex[idx];
}
+
+ delta = tt_var_get_item_delta( face,
+ &table->itemStore,
+ outerIndex,
+ innerIndex );
+
+ v += delta << 2;
+
+ /* Clamp value range. */
+ v = v >= 0x10000L ? 0x10000 : v;
+ v = v <= -0x10000L ? -0x10000 : v;
+
+ new_normalized[i] = v;
}
+
+ for ( i = 0; i < mmvar->num_axis; i++ )
+ {
+ normalized[i] = new_normalized[i];
+ }
+
+ face->blend->normalizedcoords = old_normalized;
+
+ FT_FREE( new_normalized );
}
}
}
@@ -2041,9 +2152,9 @@
for ( ; i < num_coords; i++ )
design[i] = 0;
- if ( blend->avar_segment )
+ if ( blend->avar_table && blend->avar_table->avar_segment )
{
- GX_AVarSegment av = blend->avar_segment;
+ GX_AVarSegment av = blend->avar_table->avar_segment;
FT_TRACE5(( "design coordinates"
@@ -4390,11 +4501,19 @@
FT_FREE( blend->normalized_stylecoords );
FT_FREE( blend->mmvar );
- if ( blend->avar_segment )
+ if ( blend->avar_table )
{
for ( i = 0; i < num_axes; i++ )
- FT_FREE( blend->avar_segment[i].correspondence );
- FT_FREE( blend->avar_segment );
+ FT_FREE( blend->avar_table->avar_segment[i].correspondence );
+ FT_FREE( blend->avar_table->avar_segment );
+
+ tt_var_done_item_variation_store( face,
+ &blend->avar_table->itemStore );
+
+ tt_var_done_delta_set_index_map( face,
+ &blend->avar_table->axisMap );
+
+ FT_FREE( blend->avar_table );
}
if ( blend->hvar_table )
diff --git a/src/truetype/ttgxvar.h b/src/truetype/ttgxvar.h
index 513c40b8a..3a7829d26 100644
--- a/src/truetype/ttgxvar.h
+++ b/src/truetype/ttgxvar.h
@@ -65,6 +65,23 @@ FT_BEGIN_HEADER
/**************************************************************************
*
* @Struct:
+ * GX_AVarTableRec
+ *
+ * @Description:
+ * Data from the `avar' table.
+ */
+ typedef struct GX_AVarTableRec_
+ {
+ GX_AVarSegment avar_segment; /* avar_segment[num_axis] */
+ GX_ItemVarStoreRec itemStore; /* Item Variation Store */
+ GX_DeltaSetIdxMapRec axisMap; /* Axis Mapping */
+
+ } GX_AVarTableRec, *GX_AVarTable;
+
+
+ /**************************************************************************
+ *
+ * @Struct:
* GX_HVVarTableRec
*
* @Description:
@@ -194,7 +211,7 @@ FT_BEGIN_HEADER
* A Boolean; if set, FreeType tried to load (and parse) the `avar'
* table.
*
- * avar_segment ::
+ * avar_table ::
* Data from the `avar' table.
*
* hvar_loaded ::
@@ -259,7 +276,7 @@ FT_BEGIN_HEADER
/* normalized_stylecoords[num_namedstyles][num_axis] */
FT_Bool avar_loaded;
- GX_AVarSegment avar_segment; /* avar_segment[num_axis] */
+ GX_AVarTable avar_table;
FT_Bool hvar_loaded;
FT_Bool hvar_checked;