shithub: freetype+ttf2subf

Download patch

ref: e9df4e47e3d80e18680d38a0f54746da517ab96b
parent: 9845c1d4e96215483fd3409222690335f6052e55
author: Werner Lemberg <[email protected]>
date: Sun May 31 08:21:34 EDT 2015

[truetype] In GX, make private point numbers work correctly.

This is completely missing in Apple's documentation: If a `gvar'
tuple uses private point numbers (this is, deltas are specified for
some points only), the uncovered points must be interpolated for
this tuple similar to the IUP bytecode instruction.  Examples that
need this functionality are glyphs `Oslash' and `Q' in Skia.ttf.

* src/truetype/ttgxvar.c (tt_delta_shift, tt_delta_interpolate,
tt_handle_deltas): New functions.
(TT_Vary_Get_Glyph_Deltas): Renamed to...
(TT_Vary_Apply_Glyph_Deltas): ... this; it directly processes the
points and does no longer return an array of deltas.
Add tracing information.
Call `tt_handle_deltas' to interpolate missing deltas.
Also fix a minor memory leak in case of error.

* src/truetype/ttgxvar.h: Updated.

* src/truetype/ttgload.c (TT_Process_Simple_Glyph,
load_truetype_glyph): Updated.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,29 @@
 2015-05-31  Werner Lemberg  <[email protected]>
 
+	[truetype] In GX, make private point numbers work correctly.
+
+	This is completely missing in Apple's documentation: If a `gvar'
+	tuple uses private point numbers (this is, deltas are specified for
+	some points only), the uncovered points must be interpolated for
+	this tuple similar to the IUP bytecode instruction.  Examples that
+	need this functionality are glyphs `Oslash' and `Q' in Skia.ttf.
+
+	* src/truetype/ttgxvar.c (tt_delta_shift, tt_delta_interpolate,
+	tt_handle_deltas): New functions.
+	(TT_Vary_Get_Glyph_Deltas): Renamed to...
+	(TT_Vary_Apply_Glyph_Deltas): ... this; it directly processes the
+	points and does no longer return an array of deltas.
+	Add tracing information.
+	Call `tt_handle_deltas' to interpolate missing deltas.
+	Also fix a minor memory leak in case of error.
+
+	* src/truetype/ttgxvar.h: Updated.
+
+	* src/truetype/ttgload.c (TT_Process_Simple_Glyph,
+	load_truetype_glyph): Updated.
+
+2015-05-31  Werner Lemberg  <[email protected]>
+
 	[truetype] In GX, make intermediate tuplets work at extrema.
 
 	* src/truetype/ttgxvar.c (ft_var_apply_tuple): Fix range condition.
--- a/src/truetype/ttgload.c
+++ b/src/truetype/ttgload.c
@@ -900,25 +900,12 @@
     if ( ((TT_Face)loader->face)->doblend )
     {
       /* Deltas apply to the unscaled data. */
-      FT_Vector*  deltas;
-      FT_Memory   memory = loader->face->memory;
-      FT_Int      i;
-
-
-      error = TT_Vary_Get_Glyph_Deltas( (TT_Face)(loader->face),
-                                        loader->glyph_index,
-                                        &deltas,
-                                        (FT_UInt)n_points );
+      error = TT_Vary_Apply_Glyph_Deltas( (TT_Face)(loader->face),
+                                           loader->glyph_index,
+                                           outline,
+                                           (FT_UInt)n_points );
       if ( error )
         return error;
-
-      for ( i = 0; i < n_points; ++i )
-      {
-        outline->points[i].x += deltas[i].x;
-        outline->points[i].y += deltas[i].y;
-      }
-
-      FT_FREE( deltas );
     }
 
 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
@@ -1429,10 +1416,6 @@
     FT_GlyphLoader  gloader      = loader->gloader;
     FT_Bool         opened_frame = 0;
 
-#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
-    FT_Vector*      deltas       = NULL;
-#endif
-
 #ifdef FT_CONFIG_OPTION_INCREMENTAL
     FT_StreamRec    inc_stream;
     FT_Data         glyph_data;
@@ -1571,26 +1554,47 @@
 
       if ( ((TT_Face)(loader->face))->doblend )
       {
-        /* this must be done before scaling */
-        FT_Memory  memory = loader->face->memory;
+        /* a small outline structure with four elements for */
+        /* communication with `TT_Vary_Apply_Glyph_Deltas'  */
+        FT_Vector   points[4];
+        char        tags[4]     = { 1, 1, 1, 1 };
+        short       contours[4] = { 0, 1, 2, 3 };
+        FT_Outline  outline;
 
 
-        error = TT_Vary_Get_Glyph_Deltas( (TT_Face)(loader->face),
-                                          glyph_index, &deltas, 4 );
+        points[0].x = loader->pp1.x;
+        points[0].y = loader->pp1.y;
+        points[1].x = loader->pp2.x;
+        points[1].y = loader->pp2.y;
+
+        points[2].x = loader->pp3.x;
+        points[2].y = loader->pp3.y;
+        points[3].x = loader->pp4.x;
+        points[3].y = loader->pp4.y;
+
+        outline.n_points   = 4;
+        outline.n_contours = 4;
+        outline.points     = points;
+        outline.tags       = tags;
+        outline.contours   = contours;
+
+        /* this must be done before scaling */
+        error = TT_Vary_Apply_Glyph_Deltas( (TT_Face)(loader->face),
+                                             glyph_index,
+                                             &outline,
+                                             outline.n_points );
         if ( error )
           goto Exit;
 
-        loader->pp1.x += deltas[0].x;
-        loader->pp1.y += deltas[0].y;
-        loader->pp2.x += deltas[1].x;
-        loader->pp2.y += deltas[1].y;
+        loader->pp1.x = points[0].x;
+        loader->pp1.y = points[0].y;
+        loader->pp2.x = points[1].x;
+        loader->pp2.y = points[1].y;
 
-        loader->pp3.x += deltas[2].x;
-        loader->pp3.y += deltas[2].y;
-        loader->pp4.x += deltas[3].x;
-        loader->pp4.y += deltas[3].y;
-
-        FT_FREE( deltas );
+        loader->pp3.x = points[2].x;
+        loader->pp3.y = points[2].y;
+        loader->pp4.x = points[3].x;
+        loader->pp4.y = points[3].y;
       }
 
 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
@@ -1677,45 +1681,104 @@
       {
         FT_UInt      i, limit;
         FT_SubGlyph  subglyph;
-        FT_Memory    memory = face->root.memory;
 
+        FT_Outline  outline;
+        FT_Vector*  points   = NULL;
+        char*       tags     = NULL;
+        short*      contours = NULL;
 
-        /* this provides additional offsets */
-        /* for each component's translation */
+        FT_Memory  memory = face->root.memory;
 
-        if ( ( error = TT_Vary_Get_Glyph_Deltas(
+
+        limit = gloader->current.num_subglyphs;
+
+        /* construct an outline structure for              */
+        /* communication with `TT_Vary_Apply_Glyph_Deltas' */
+        outline.n_points   = gloader->current.num_subglyphs + 4;
+        outline.n_contours = outline.n_points;
+
+        if ( FT_NEW_ARRAY( points, outline.n_points )   ||
+             FT_NEW_ARRAY( tags, outline.n_points )     ||
+             FT_NEW_ARRAY( contours, outline.n_points ) )
+          goto Exit1;
+
+        subglyph = gloader->current.subglyphs + gloader->base.num_subglyphs;
+
+        for ( i = 0; i < limit; i++, subglyph++ )
+        {
+          /* applying deltas for anchor points doesn't make sense, */
+          /* but we don't have to specially check this since       */
+          /* unused delta values are zero anyways                  */
+          points[i].x = subglyph->arg1;
+          points[i].y = subglyph->arg2;
+          tags[i]     = 1;
+          contours[i] = i;
+        }
+
+        points[i].x = loader->pp1.x;
+        points[i].y = loader->pp1.y;
+        tags[i]     = 1;
+        contours[i] = i;
+
+        i++;
+        points[i].x = loader->pp2.x;
+        points[i].y = loader->pp2.y;
+        tags[i]     = 1;
+        contours[i] = i;
+
+        i++;
+        points[i].x = loader->pp3.x;
+        points[i].y = loader->pp3.y;
+        tags[i]     = 1;
+        contours[i] = i;
+
+        i++;
+        points[i].x = loader->pp4.x;
+        points[i].y = loader->pp4.y;
+        tags[i]     = 1;
+        contours[i] = i;
+
+        outline.points   = points;
+        outline.tags     = tags;
+        outline.contours = contours;
+
+        /* this call provides additional offsets */
+        /* for each component's translation      */
+        if ( ( error = TT_Vary_Apply_Glyph_Deltas(
                          face,
                          glyph_index,
-                         &deltas,
-                         gloader->current.num_subglyphs + 4 ) ) != 0 )
-          goto Exit;
+                         &outline,
+                         outline.n_points ) ) != 0 )
+          goto Exit1;
 
         subglyph = gloader->current.subglyphs + gloader->base.num_subglyphs;
-        limit    = gloader->current.num_subglyphs;
 
-        for ( i = 0; i < limit; ++i, ++subglyph )
+        for ( i = 0; i < limit; i++, subglyph++ )
         {
-          if ( subglyph->flags & ARGS_ARE_XY_VALUES )
-          {
-            /* XXX: overflow check for subglyph->{arg1,arg2}.   */
-            /* deltas[i].{x,y} must be within signed 16-bit,    */
-            /* but the restriction of summed delta is not clear */
-            subglyph->arg1 += (FT_Int16)deltas[i].x;
-            subglyph->arg2 += (FT_Int16)deltas[i].y;
-          }
+          /* XXX: overflow check for subglyph->{arg1,arg2}.         */
+          /*      Deltas must be within signed 16-bit,              */
+          /*      but the restriction of summed deltas is not clear */
+          subglyph->arg1 = (FT_Int16)points[i].x;
+          subglyph->arg2 = (FT_Int16)points[i].y;
         }
 
-        loader->pp1.x += deltas[i + 0].x;
-        loader->pp1.y += deltas[i + 0].y;
-        loader->pp2.x += deltas[i + 1].x;
-        loader->pp2.y += deltas[i + 1].y;
+        loader->pp1.x = points[i + 0].x;
+        loader->pp1.y = points[i + 0].y;
+        loader->pp2.x = points[i + 1].x;
+        loader->pp2.y = points[i + 1].y;
 
-        loader->pp3.x += deltas[i + 2].x;
-        loader->pp3.y += deltas[i + 2].y;
-        loader->pp4.x += deltas[i + 3].x;
-        loader->pp4.y += deltas[i + 3].y;
+        loader->pp3.x = points[i + 2].x;
+        loader->pp3.y = points[i + 2].y;
+        loader->pp4.x = points[i + 3].x;
+        loader->pp4.y = points[i + 3].y;
 
-        FT_FREE( deltas );
+      Exit1:
+        FT_FREE( outline.points );
+        FT_FREE( outline.tags );
+        FT_FREE( outline.contours );
+
+        if ( error )
+          goto Exit;
       }
 
 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
--- a/src/truetype/ttgxvar.c
+++ b/src/truetype/ttgxvar.c
@@ -1518,13 +1518,230 @@
   }
 
 
+  /* Shift the original coordinates of all points between indices `p1' */
+  /* and `p2', using the same difference as given by index `ref'.      */
+
+  /* modeled after `af_iup_shift' */
+
+  static void
+  tt_delta_shift( int         p1,
+                  int         p2,
+                  int         ref,
+                  FT_Vector*  in_points,
+                  FT_Vector*  out_points )
+  {
+    int        p;
+    FT_Vector  delta;
+
+
+    delta.x = out_points[ref].x - in_points[ref].x;
+    delta.y = out_points[ref].y - in_points[ref].y;
+
+    if ( delta.x == 0 && delta.y == 0 )
+      return;
+
+    for ( p = p1; p < ref; p++ )
+    {
+      out_points[p].x += delta.x;
+      out_points[p].y += delta.y;
+    }
+
+    for ( p = ref + 1; p <= p2; p++ )
+    {
+      out_points[p].x += delta.x;
+      out_points[p].y += delta.y;
+    }
+  }
+
+
+  /* Interpolate the original coordinates of all points with indices */
+  /* between `p1' and `p2', using `ref1' and `ref2' as the reference */
+  /* point indices.                                                  */
+
+  /* modeled after `af_iup_interp', `_iup_worker_interpolate', and */
+  /* `Ins_IUP'                                                     */
+
+  static void
+  tt_delta_interpolate( int         p1,
+                        int         p2,
+                        int         ref1,
+                        int         ref2,
+                        FT_Vector*  in_points,
+                        FT_Vector*  out_points )
+  {
+    int  p, i;
+
+    FT_Pos  out, in1, in2, out1, out2, d1, d2;
+
+
+    if ( p1 > p2 )
+      return;
+
+    /* handle both horizontal and vertical coordinates */
+    for ( i = 0; i <= 1; i++ )
+    {
+      /* shift array pointers so that we can access `foo.y' as `foo.x' */
+      in_points  = (FT_Vector*)( (FT_Pos*)in_points + i );
+      out_points = (FT_Vector*)( (FT_Pos*)out_points + i );
+
+      if ( in_points[ref1].x > in_points[ref2].x )
+      {
+        p    = ref1;
+        ref1 = ref2;
+        ref2 = p;
+      }
+
+      in1  = in_points[ref1].x;
+      in2  = in_points[ref2].x;
+      out1 = out_points[ref1].x;
+      out2 = out_points[ref2].x;
+      d1   = out1 - in1;
+      d2   = out2 - in2;
+
+      if ( out1 == out2 || in1 == in2 )
+      {
+        for ( p = p1; p <= p2; p++ )
+        {
+          out = in_points[p].x;
+
+          if ( out <= in1 )
+            out += d1;
+          else if ( out >= in2 )
+            out += d2;
+          else
+            out = out1;
+
+          out_points[p].x = out;
+        }
+      }
+      else
+      {
+        FT_Fixed  scale = FT_DivFix( out2 - out1, in2 - in1 );
+
+
+        for ( p = p1; p <= p2; p++ )
+        {
+          out = in_points[p].x;
+
+          if ( out <= in1 )
+            out += d1;
+          else if ( out >= in2 )
+            out += d2;
+          else
+            out = out1 + FT_MulFix( out - in1, scale );
+
+          out_points[p].x = out;
+        }
+      }
+    }
+  }
+
+
+  /* Interpolate points without delta values, similar to */
+  /* the `IUP' hinting instruction.                      */
+
+  /* modeled after `Ins_IUP */
+
+  static void
+  tt_handle_deltas( FT_Outline*  outline,
+                    FT_Vector*   in_points,
+                    FT_Bool*     has_delta )
+  {
+    FT_Vector*  out_points;
+
+    FT_UInt  first_point;
+    FT_UInt  end_point;
+
+    FT_UInt  first_delta;
+    FT_UInt  cur_delta;
+
+    FT_UInt   point;
+    FT_Short  contour;
+
+
+    /* ignore empty outlines */
+    if ( !outline->n_contours )
+      return;
+
+    out_points = outline->points;
+
+    contour = 0;
+    point   = 0;
+
+    do
+    {
+      end_point   = outline->contours[contour];
+      first_point = point;
+
+      /* search first point that has a delta */
+      while ( point <= end_point && !has_delta[point] )
+        point++;
+
+      if ( point <= end_point )
+      {
+        first_delta = point;
+        cur_delta   = point;
+
+        point++;
+
+        while ( point <= end_point )
+        {
+          /* search next point that has a delta  */
+          /* and interpolate intermediate points */
+          if ( has_delta[point] )
+          {
+            tt_delta_interpolate( cur_delta + 1,
+                                  point - 1,
+                                  cur_delta,
+                                  point,
+                                  in_points,
+                                  out_points );
+            cur_delta = point;
+          }
+
+          point++;
+        }
+
+        /* shift contour if we only have a single delta */
+        if ( cur_delta == first_delta )
+          tt_delta_shift( first_point,
+                          end_point,
+                          cur_delta,
+                          in_points,
+                          out_points );
+        else
+        {
+          /* otherwise handle remaining points       */
+          /* at the end and beginning of the contour */
+          tt_delta_interpolate( cur_delta + 1,
+                                end_point,
+                                cur_delta,
+                                first_delta,
+                                in_points,
+                                out_points );
+
+          if ( first_delta > 0 )
+            tt_delta_interpolate( first_point,
+                                  first_delta - 1,
+                                  cur_delta,
+                                  first_delta,
+                                  in_points,
+                                  out_points );
+        }
+      }
+      contour++;
+
+    } while ( contour < outline->n_contours );
+  }
+
+
   /*************************************************************************/
   /*                                                                       */
   /* <Function>                                                            */
-  /*    TT_Vary_Get_Glyph_Deltas                                           */
+  /*    TT_Vary_Apply_Glyph_Deltas                                         */
   /*                                                                       */
   /* <Description>                                                         */
-  /*    Load the appropriate deltas for the current glyph.                 */
+  /*    Apply the appropriate deltas to the current glyph.                 */
   /*                                                                       */
   /* <Input>                                                               */
   /*    face        :: A handle to the target face object.                 */
@@ -1534,23 +1751,25 @@
   /*    n_points    :: The number of the points in the glyph, including    */
   /*                   phantom points.                                     */
   /*                                                                       */
-  /* <Output>                                                              */
-  /*    deltas      :: The array of points to change.                      */
+  /* <InOut>                                                               */
+  /*    outline     :: The outline to change.                              */
   /*                                                                       */
   /* <Return>                                                              */
   /*    FreeType error code.  0 means success.                             */
   /*                                                                       */
   FT_LOCAL_DEF( FT_Error )
-  TT_Vary_Get_Glyph_Deltas( TT_Face      face,
-                            FT_UInt      glyph_index,
-                            FT_Vector*  *deltas,
-                            FT_UInt      n_points )
+  TT_Vary_Apply_Glyph_Deltas( TT_Face      face,
+                              FT_UInt      glyph_index,
+                              FT_Outline*  outline,
+                              FT_UInt      n_points )
   {
     FT_Stream   stream = face->root.stream;
     FT_Memory   memory = stream->memory;
     GX_Blend    blend  = face->blend;
-    FT_Vector*  delta_xy = NULL;
 
+    FT_Vector*  points_org = NULL;
+    FT_Bool*    has_delta  = NULL;
+
     FT_Error    error;
     FT_ULong    glyph_start;
     FT_UInt     tupleCount;
@@ -1570,16 +1789,19 @@
     if ( !face->doblend || blend == NULL )
       return FT_THROW( Invalid_Argument );
 
-    /* to be freed by the caller */
-    if ( FT_NEW_ARRAY( delta_xy, n_points ) )
-      goto Exit;
-    *deltas = delta_xy;
-
     if ( glyph_index >= blend->gv_glyphcnt      ||
          blend->glyphoffsets[glyph_index] ==
            blend->glyphoffsets[glyph_index + 1] )
-      return FT_Err_Ok;               /* no variation data for this glyph */
+    {
+      FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
+                  " no variation data for this glyph\n" ));
+      return FT_Err_Ok;
+    }
 
+    if ( FT_NEW_ARRAY( points_org, n_points ) ||
+         FT_NEW_ARRAY( has_delta, n_points )  )
+      goto Fail1;
+
     if ( FT_STREAM_SEEK( blend->glyphoffsets[glyph_index] )   ||
          FT_FRAME_ENTER( blend->glyphoffsets[glyph_index + 1] -
                            blend->glyphoffsets[glyph_index] ) )
@@ -1610,6 +1832,8 @@
       FT_Stream_SeekSet( stream, here );
     }
 
+    FT_TRACE5(( "gvar: there are %d tuples:\n", tupleCount ));
+
     for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ )
     {
       FT_UInt   tupleDataSize;
@@ -1617,6 +1841,8 @@
       FT_Fixed  apply;
 
 
+      FT_TRACE6(( "  tuple %d:\n", i ));
+
       tupleDataSize = FT_GET_USHORT();
       tupleIndex    = FT_GET_USHORT();
 
@@ -1629,7 +1855,7 @@
       else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount )
       {
         error = FT_THROW( Invalid_Table );
-        goto Fail3;
+        goto Fail2;
       }
       else
         FT_MEM_COPY(
@@ -1684,24 +1910,101 @@
 
       else if ( points == ALL_POINTS )
       {
+#ifdef FT_DEBUG_LEVEL_TRACE
+        int  count = 0;
+#endif
+
+
+        FT_TRACE7(( "    point deltas:\n" ));
+
         /* this means that there are deltas for every point in the glyph */
         for ( j = 0; j < n_points; j++ )
         {
-          delta_xy[j].x += FT_MulFix( deltas_x[j], apply );
-          delta_xy[j].y += FT_MulFix( deltas_y[j], apply );
+#ifdef FT_DEBUG_LEVEL_TRACE
+          FT_Vector  point_org = outline->points[j];
+#endif
+
+
+          outline->points[j].x += FT_MulFix( deltas_x[j], apply );
+          outline->points[j].y += FT_MulFix( deltas_y[j], apply );
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+          if ( ( point_org.x != outline->points[j].x ) ||
+               ( point_org.y != outline->points[j].y ) )
+          {
+            FT_TRACE7(( "      %d: (%d, %d) -> (%d, %d)\n",
+                        j,
+                        point_org.x,
+                        point_org.y,
+                        outline->points[j].x,
+                        outline->points[j].y ));
+            count++;
+          }
+#endif
         }
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+        if ( !count )
+          FT_TRACE7(( "      none\n" ));
+#endif
       }
 
       else
       {
+#ifdef FT_DEBUG_LEVEL_TRACE
+        int  count = 0;
+#endif
+
+
+        /* we have to interpolate the missing deltas similar to the */
+        /* IUP bytecode instruction                                 */
+        for ( j = 0; j < n_points; j++ )
+        {
+          points_org[j] = outline->points[j];
+          has_delta[j]  = FALSE;
+        }
+
         for ( j = 0; j < point_count; j++ )
         {
-          if ( localpoints[j] >= n_points )
+          FT_UShort  idx = localpoints[j];
+
+
+          if ( idx >= n_points )
             continue;
 
-          delta_xy[localpoints[j]].x += FT_MulFix( deltas_x[j], apply );
-          delta_xy[localpoints[j]].y += FT_MulFix( deltas_y[j], apply );
+          has_delta[idx] = TRUE;
+
+          outline->points[idx].x += FT_MulFix( deltas_x[j], apply );
+          outline->points[idx].y += FT_MulFix( deltas_y[j], apply );
         }
+
+        /* no need to handle phantom points here,      */
+        /* since solitary points can't be interpolated */
+        tt_handle_deltas( outline,
+                          points_org,
+                          has_delta );
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+        FT_TRACE7(( "    point deltas:\n" ));
+
+        for ( j = 0; j < n_points; j++)
+        {
+          if ( ( points_org[j].x != outline->points[j].x ) ||
+               ( points_org[j].y != outline->points[j].y ) )
+          {
+            FT_TRACE7(( "      %d: (%d, %d) -> (%d, %d)\n",
+                        j,
+                        points_org[j].x,
+                        points_org[j].y,
+                        outline->points[j].x,
+                        outline->points[j].y ));
+            count++;
+          }
+        }
+
+        if ( !count )
+          FT_TRACE7(( "      none\n" ));
+#endif
       }
 
       if ( localpoints != ALL_POINTS )
@@ -1714,22 +2017,19 @@
       FT_Stream_SeekSet( stream, here );
     }
 
-  Fail3:
+    FT_TRACE5(( "\n" ));
+
+  Fail2:
     FT_FREE( tuple_coords );
     FT_FREE( im_start_coords );
     FT_FREE( im_end_coords );
 
-  Fail2:
     FT_FRAME_EXIT();
 
   Fail1:
-    if ( error )
-    {
-      FT_FREE( delta_xy );
-      *deltas = NULL;
-    }
+    FT_FREE( points_org );
+    FT_FREE( has_delta );
 
-  Exit:
     return error;
   }
 
--- a/src/truetype/ttgxvar.h
+++ b/src/truetype/ttgxvar.h
@@ -162,10 +162,10 @@
 
 
   FT_LOCAL( FT_Error )
-  TT_Vary_Get_Glyph_Deltas( TT_Face      face,
-                            FT_UInt      glyph_index,
-                            FT_Vector*  *deltas,
-                            FT_UInt      n_points );
+  TT_Vary_Apply_Glyph_Deltas( TT_Face      face,
+                              FT_UInt      glyph_index,
+                              FT_Outline*  outline,
+                              FT_UInt      n_points );
 
 
   FT_LOCAL( void )