freetype-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[freetype2] master ae4eb996a: [truetype] Add support for `avar` table 2.


From: Werner Lemberg
Subject: [freetype2] master ae4eb996a: [truetype] Add support for `avar` table 2.0 format.
Date: Fri, 4 Nov 2022 14:45:14 -0400 (EDT)

branch: master
commit ae4eb996ab1ed43a52fac19461de3bdcaf1a1742
Author: Behdad Esfahbod <behdad@behdad.org>
Commit: Werner Lemberg <wl@gnu.org>

    [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.
---
 src/truetype/ttgxvar.c | 195 +++++++++++++++++++++++++++++++++++++++----------
 src/truetype/ttgxvar.h |  21 +++++-
 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
@@ -62,6 +62,23 @@ FT_BEGIN_HEADER
   } GX_AVarSegmentRec, *GX_AVarSegment;
 
 
+  /**************************************************************************
+   *
+   * @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:
@@ -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;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]