Commit aa0c4b4f55f88a489cf5f766c26ba0c285ac738a

Dave Arnold 2016-12-15T14:04:51

[truetype] Provide function to apply `HVAR' advance width variation. * src/truetype/ttgxvar.c (tt_hadvance_adjust): New function. * src/truetype/ttgxvar.h: Updated.

diff --git a/ChangeLog b/ChangeLog
index 26abc08..5408870 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,14 @@
 2016-12-15  Dave Arnold  <darnold@adobe.com>
 	    Werner Lemberg  <wl@gnu.org>
 
+	[truetype] Provide function to apply `HVAR' advance width variation.
+
+	* src/truetype/ttgxvar.c (tt_hadvance_adjust): New function.
+	* src/truetype/ttgxvar.h: Updated.
+
+2016-12-15  Dave Arnold  <darnold@adobe.com>
+	    Werner Lemberg  <wl@gnu.org>
+
 	[truetype] Add `HVAR' table parsing.
 
 	Note that this is not complete yet; it only handles advance width
diff --git a/src/truetype/ttgxvar.c b/src/truetype/ttgxvar.c
index 8eb6454..c4eb125 100644
--- a/src/truetype/ttgxvar.c
+++ b/src/truetype/ttgxvar.c
@@ -748,6 +748,151 @@
   }
 
 
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_hadvance_adjust                                                 */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Apply HVAR advance width adjustment of a given glyph.              */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    gindex :: The glyph index.                                         */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    face   :: The font face.                                           */
+  /*                                                                       */
+  /*    adelta :: Points to width value that gets modified.                */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_hadvance_adjust( TT_Face  face,
+                      FT_UInt  gindex,
+                      FT_Int  *avalue )
+  {
+    FT_Error  error = FT_Err_Ok;
+
+    GX_HVarData  varData;
+
+    FT_UInt    innerIndex, outerIndex;
+    FT_UInt    master, j;
+    FT_Fixed   netAdjustment = 0;     /* accumulated adjustment */
+    FT_Fixed   scaledDelta;
+    FT_Short*  deltaSet;
+    FT_Fixed   delta;
+
+
+    if ( !face->blend )
+      goto Exit;
+
+    if ( !face->blend->hvar_loaded )
+    {
+      /* initialize hvar table */
+      face->blend->hvar_error = ft_var_load_hvar( face );
+    }
+
+    if ( !face->blend->hvar_checked )
+    {
+      error = face->blend->hvar_error;
+      goto Exit;
+    }
+
+    if ( gindex >= face->blend->hvar_table->widthMap.mapCount )
+    {
+      FT_TRACE2(( "gindex %d out of range\n", gindex ));
+      error = FT_THROW( Invalid_Argument );
+      goto Exit;
+    }
+
+    /* trust that HVAR parser has checked indices */
+    outerIndex = face->blend->hvar_table->widthMap.outerIndex[gindex];
+    innerIndex = face->blend->hvar_table->widthMap.innerIndex[gindex];
+    varData    = &face->blend->hvar_table->itemStore.varData[outerIndex];
+    deltaSet   = &varData->deltaSet[varData->regionIdxCount * innerIndex];
+
+    /* See pseudo code from `Font Variations Overview' */
+    /* in the OpenType specification.                  */
+
+    /* outer loop steps through master designs to be blended */
+    for ( master = 0; master < varData->regionIdxCount; master++ )
+    {
+      FT_Fixed  scalar      = FT_FIXED_ONE;
+      FT_UInt   regionIndex = varData->regionIndices[master];
+
+      GX_AxisCoords  axis = face->blend
+                              ->hvar_table
+                              ->itemStore.varRegionList[regionIndex]
+                                         .axisList;
+
+
+      /* inner loop steps through axes in this region */
+      for ( j = 0;
+            j < face->blend->hvar_table->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;
+
+        else if ( axis->startCoord < 0 &&
+                  axis->endCoord > 0   &&
+                  axis->peakCoord != 0 )
+          axisScalar = FT_FIXED_ONE;
+
+        /* peak of 0 means ignore this axis */
+        else if ( axis->peakCoord == 0 )
+          axisScalar = FT_FIXED_ONE;
+
+        /* 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;
+
+        /* calculate a proportional factor */
+        else
+        {
+          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 );
+        }
+
+        /* take product of all the axis scalars */
+        scalar = FT_MulFix( scalar, axisScalar );
+
+      } /* per-axis loop */
+
+      FT_TRACE4(( ", %f ", scalar / 65536.0 ));
+
+      /* 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;
+
+    } /* per-region loop */
+
+    FT_TRACE4(( "]\n" ));
+
+    /* apply the accumulated adjustment to derive the interpolated value */
+    *avalue += FT_fixedToInt( netAdjustment );
+
+  Exit:
+    return error;
+  }
+
+
   typedef struct  GX_GVar_Head_
   {
     FT_Long    version;
diff --git a/src/truetype/ttgxvar.h b/src/truetype/ttgxvar.h
index c5c98ea..95f991f 100644
--- a/src/truetype/ttgxvar.h
+++ b/src/truetype/ttgxvar.h
@@ -254,6 +254,10 @@ FT_BEGIN_HEADER
                               FT_Outline*  outline,
                               FT_UInt      n_points );
 
+  FT_LOCAL( FT_Error )
+  tt_hadvance_adjust( TT_Face  face,
+                      FT_UInt  gindex,
+                      FT_Int  *adelta );
 
   FT_LOCAL( FT_Error )
   tt_get_var_blend( TT_Face     face,