shithub: freetype+ttf2subf

Download patch

ref: b9c22aff61a90a17d8ace2dfda5094df31ac860c
parent: e793092d0a9f4d4d383315bcefd485dcbe4804b3
author: David Turner <[email protected]>
date: Tue Mar 1 10:48:29 EST 2005

* src/autofit/{afhints.h,afhints.c,aflatin.h,aflatin.c,afloader.c}:
    various bug-fixes and drastic heap usage reduction improvements.

    * include/freetype/config/ftmodule.h: the auto-fitter is now the
    only supported auto-hinting module

    * include/freetype/config/ftstdlib.h: adding FT_INT_MAX definition

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2005-03-01  David Turner  <[email protected]>
+
+    * src/autofit/{afhints.h,afhints.c,aflatin.h,aflatin.c,afloader.c}:
+    various bug-fixes and drastic heap usage reduction improvements.
+
+    * include/freetype/config/ftmodule.h: the auto-fitter is now the
+    only supported auto-hinting module
+
+    * include/freetype/config/ftstdlib.h: adding FT_INT_MAX definition
+
 2005-02-28  Werner Lemberg  <[email protected]>
 
 	* src/truetype/ttpload.c (tt_face_load_loca): Fix typo.
--- a/include/freetype/config/ftmodule.h
+++ b/include/freetype/config/ftmodule.h
@@ -1,4 +1,4 @@
-FT_USE_MODULE(autohint_module_class)
+FT_USE_MODULE(autofit_module_class)
 FT_USE_MODULE(tt_driver_class)
 FT_USE_MODULE(t1_driver_class)
 FT_USE_MODULE(cff_driver_class)
--- a/include/freetype/config/ftstdlib.h
+++ b/include/freetype/config/ftstdlib.h
@@ -66,6 +66,7 @@
 #include <limits.h>
 
 #define FT_UINT_MAX   UINT_MAX
+#define FT_INT_MAX    INT_MAX
 #define FT_ULONG_MAX  ULONG_MAX
 
 
--- a/src/autofit/afhints.c
+++ b/src/autofit/afhints.c
@@ -1,5 +1,96 @@
 #include "afhints.h"
 
+
+  FT_LOCAL_DEF( FT_Error )
+  af_axis_hints_new_segment( AF_AxisHints  axis,
+                             FT_Memory     memory,
+                             AF_Segment   *asegment )
+  {
+    FT_Error    error   = 0;
+    AF_Segment  segment = NULL;
+
+    if ( axis->num_segments >= axis->max_segments )
+    {
+      FT_Int  old_max = axis->max_segments;
+      FT_Int  new_max = old_max;
+      FT_Int  big_max = FT_INT_MAX / sizeof(*segment);
+
+      if ( old_max >= big_max )
+      {
+        error = FT_Err_Out_Of_Memory;
+        goto Exit;
+      }
+
+      new_max += (new_max >> 1) + 4;
+      if ( new_max < old_max || new_max > big_max )
+        new_max = big_max;
+
+      if ( FT_RENEW_ARRAY( axis->segments, old_max, new_max ) )
+        goto Exit;
+
+      axis->max_segments = new_max;
+    }
+
+    segment = axis->segments + axis->num_segments++;
+    FT_ZERO( segment );
+
+  Exit:
+    *asegment = segment;
+    return error;
+  }
+
+  FT_LOCAL( FT_Error)
+  af_axis_hints_new_edge( AF_AxisHints  axis,
+                          FT_Int        fpos,
+                          FT_Memory     memory,
+                          AF_Edge      *aedge )
+  {
+    FT_Error    error = 0;
+    AF_Edge     edge  = NULL;
+    AF_Edge     edges;
+
+    if ( axis->num_edges >= axis->max_edges )
+    {
+      FT_Int  old_max = axis->max_edges;
+      FT_Int  new_max = old_max;
+      FT_Int  big_max = FT_INT_MAX / sizeof(*edge);
+
+      if ( old_max >= big_max )
+      {
+        error = FT_Err_Out_Of_Memory;
+        goto Exit;
+      }
+
+      new_max += (new_max >> 1) + 4;
+      if ( new_max < old_max || new_max > big_max )
+        new_max = big_max;
+
+      if ( FT_RENEW_ARRAY( axis->edges, old_max, new_max ) )
+        goto Exit;
+
+      axis->max_edges = new_max;
+    }
+
+    edges = axis->edges;
+    edge  = edges + axis->num_edges;
+
+    while ( edge > edges && edge[-1].fpos > fpos )
+    {
+      edge[0] = edge[-1];
+      edge--;
+    }
+
+    axis->num_edges++;
+
+    FT_ZERO(edge);
+    edge->fpos = (FT_Short) fpos;
+
+  Exit:
+    *aedge = edge;
+    return error;
+  }
+
+
 #ifdef AF_DEBUG
 
 #include <stdio.h>
@@ -295,9 +386,12 @@
         AF_AxisHints  axis = &hints->axis[ dim ];
 
         axis->num_segments = 0;
+        axis->max_segments = 0;
+        FT_FREE( axis->segments );
+
         axis->num_edges    = 0;
-        axis->segments     = NULL;
-        axis->edges        = NULL;
+        axis->max_edges    = 0;
+        FT_FREE( axis->edges );
       }
 
       FT_FREE( hints->contours );
@@ -359,7 +453,7 @@
       hints->max_contours = new_max;
     }
 
-   /* then, reallocate the points, segments & edges arrays if needed --
+   /* then, reallocate the points arrays if needed --
     * note that we reserved two additional point positions, used to
     * hint metrics appropriately
     */
@@ -367,58 +461,16 @@
     old_max = hints->max_points;
     if ( new_max > old_max )
     {
-      FT_Byte*    items;
-      FT_ULong    off1, off2, off3;
-
-     /* we store in a single buffer the following arrays:
-      *
-      *  - an array of   N  AF_PointRec   items
-      *  - an array of 2*N  AF_SegmentRec items
-      *  - an array of 2*N  AF_EdgeRec    items
-      *
-      */
-
       new_max = ( new_max + 2 + 7 ) & ~7;
 
-#define OFF_PAD2(x,y)   (((x)+(y)-1) & ~((y)-1))
-#define OFF_PADX(x,y)   ((((x)+(y)-1)/(y))*(y))
-#define OFF_PAD(x,y)    ( ((y) & ((y)-1)) ? OFF_PADX(x,y) : OFF_PAD2(x,y) )
-
-#undef  OFF_INCREMENT
-#define OFF_INCREMENT( _off, _type, _count )   \
-     ( OFF_PAD( _off, sizeof(_type) ) + (_count)*sizeof(_type))
-
-      off1 = OFF_INCREMENT( 0, AF_PointRec, new_max );
-      off2 = OFF_INCREMENT( off1, AF_SegmentRec, new_max*2 );
-      off3 = OFF_INCREMENT( off2, AF_EdgeRec, new_max*2 );
-
-      FT_FREE( hints->points );
-
-      if ( FT_ALLOC( items, off3 ) )
-      {
-        hints->max_points       = 0;
-        hints->axis[0].segments = NULL;
-        hints->axis[0].edges    = NULL;
-        hints->axis[1].segments = NULL;
-        hints->axis[1].edges    = NULL;
+      if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) )
         goto Exit;
-      }
 
-     /* readjust some pointers
-      */
-      hints->max_points       = new_max;
-      hints->points           = (AF_Point) items;
-
-      hints->axis[0].segments = (AF_Segment)( items + off1 );
-      hints->axis[1].segments = hints->axis[0].segments + new_max;
-
-      hints->axis[0].edges    = (AF_Edge)   ( items + off2 );
-      hints->axis[1].edges    = hints->axis[0].edges + new_max;
+      hints->max_points = new_max;
     }
 
     hints->num_points   = outline->n_points;
     hints->num_contours = outline->n_contours;
-
 
     /* We can't rely on the value of `FT_Outline.flags' to know the fill  */
     /* direction used for a glyph, given that some fonts are broken (e.g. */
--- a/src/autofit/afhints.h
+++ b/src/autofit/afhints.h
@@ -84,15 +84,15 @@
 
   typedef struct  AF_PointRec_
   {
-    AF_Flags      flags;    /* point flags used by hinter */
+    FT_UShort     flags;    /* point flags used by hinter */
+    FT_Char       in_dir;   /* direction of inwards vector  */
+    FT_Char       out_dir;  /* direction of outwards vector */
+
     FT_Pos        ox, oy;   /* original, scaled position  */
     FT_Short      fx, fy;   /* original, unscaled position (font units) */
     FT_Pos        x,  y;    /* current position */
     FT_Pos        u,  v;    /* current (x,y) or (y,x) depending on context */
 
-    FT_Char       in_dir;   /* direction of inwards vector  */
-    FT_Char       out_dir;  /* direction of outwards vector */
-
     AF_Point      next;     /* next point in contour     */
     AF_Point      prev;     /* previous point in contour */
 
@@ -101,7 +101,7 @@
 
   typedef struct  AF_SegmentRec_
   {
-    AF_Edge_Flags  flags;       /* edge/segment flags for this segment */
+    FT_Byte        flags;       /* edge/segment flags for this segment */
     FT_Char        dir;         /* segment direction                   */
     FT_Short       pos;         /* position of segment                 */
     FT_Short       min_coord;   /* minimum coordinate of segment       */
@@ -148,9 +148,11 @@
   typedef struct AF_AxisHintsRec_
   {
     FT_Int        num_segments;
+    FT_Int        max_segments;
     AF_Segment    segments;
 
     FT_Int        num_edges;
+    FT_Int        max_edges;
     AF_Edge       edges;
 
     AF_Direction  major_dir;
@@ -204,6 +206,17 @@
   af_direction_compute( FT_Pos  dx,
                         FT_Pos  dy );
 
+
+  FT_LOCAL( FT_Error )
+  af_axis_hints_new_segment( AF_AxisHints  axis,
+                             FT_Memory     memory,
+                             AF_Segment   *asegment );
+
+  FT_LOCAL( FT_Error)
+  af_axis_hints_new_edge( AF_AxisHints  axis,
+                          FT_Int        fpos,
+                          FT_Memory     memory,
+                          AF_Edge      *edge );
 
   FT_LOCAL( void )
   af_glyph_hints_init( AF_GlyphHints  hints,
--- a/src/autofit/aflatin.c
+++ b/src/autofit/aflatin.c
@@ -58,7 +58,10 @@
         FT_UInt       num_widths = 0;
         FT_Pos        edge_distance_threshold = 32000;
 
-        af_latin_hints_compute_segments( hints, dim );
+        error = af_latin_hints_compute_segments( hints, dim );
+        if ( error )
+          goto Exit;
+
         af_latin_hints_link_segments   ( hints, dim );
 
         seg   = axhints->segments;
@@ -506,9 +509,6 @@
   af_latin_metrics_scale( AF_LatinMetrics  metrics,
                           AF_Scaler        scaler )
   {
-    if ( AF_SCALER_EQUAL_SCALES( scaler, &metrics->root.scaler ) )
-      return;
-
     af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ );
     af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT );
   }
@@ -522,14 +522,14 @@
  /***************************************************************************/
  /***************************************************************************/
 
-  FT_LOCAL_DEF( void )
+  FT_LOCAL_DEF( FT_Error )
   af_latin_hints_compute_segments( AF_GlyphHints  hints,
                                    AF_Dimension   dim )
   {
-    AF_AxisHints  axis = &hints->axis[dim];
-    AF_Segment    segments = axis->segments;
-    AF_Segment    segment       =  segments;
-    FT_Int        num_segments  =  0;
+    AF_AxisHints  axis          = &hints->axis[dim];
+    FT_Memory     memory        = hints->memory;
+    FT_Error      error         = 0;
+    AF_Segment    segment       =  NULL;
     AF_Point*     contour       =  hints->contours;
     AF_Point*     contour_limit =  contour + hints->num_contours;
     AF_Direction  major_dir, segment_dir;
@@ -544,6 +544,8 @@
     major_dir   = FT_ABS( axis->major_dir );
     segment_dir = major_dir;
 
+    axis->num_segments = 0;
+
     /* set up (u,v) in each point */
     if ( dim == AF_DIMENSION_HORZ )
     {
@@ -656,8 +658,7 @@
             segment->max_coord = max_pos;
 
             on_edge = 0;
-            num_segments++;
-            segment++;
+            segment = NULL;
             /* fallthrough */
           }
         }
@@ -676,7 +677,9 @@
           segment_dir = point->out_dir;
 
           /* clear all segment fields */
-          FT_ZERO( segment );
+          error = af_axis_hints_new_segment( axis, memory, &segment );
+          if ( error )
+            goto Exit;
 
           segment->dir      = segment_dir;
           segment->flags    = AF_EDGE_NORMAL;
@@ -740,7 +743,9 @@
       if ( min_point )
       {
         /* clear all segment fields */
-        FT_ZERO( segment );
+        error = af_axis_hints_new_segment( axis, memory, &segment );
+        if ( error )
+          goto Exit;
 
         segment->dir   = segment_dir;
         segment->flags = AF_EDGE_NORMAL;
@@ -750,8 +755,7 @@
         segment->score = 32000;
         segment->link  = NULL;
 
-        num_segments++;
-        segment++;
+        segment = NULL;
       }
 
       /* insert maximum segment */
@@ -758,7 +762,9 @@
       if ( max_point )
       {
         /* clear all segment fields */
-        FT_ZERO( segment );
+        error = af_axis_hints_new_segment( axis, memory, &segment );
+        if ( error)
+          goto Exit;
 
         segment->dir   = segment_dir;
         segment->flags = AF_EDGE_NORMAL;
@@ -768,13 +774,13 @@
         segment->score = 32000;
         segment->link  = NULL;
 
-        num_segments++;
-        segment++;
+        segment = NULL;
       }
     }
 #endif /* AF_HINT_METRICS */
 
-    axis->num_segments = num_segments;
+  Exit:
+    return error;
   }
 
 
@@ -858,14 +864,14 @@
   }
 
 
-  FT_LOCAL_DEF( void )
+  FT_LOCAL_DEF( FT_Error )
   af_latin_hints_compute_edges( AF_GlyphHints  hints,
                                 AF_Dimension   dim )
   {
-    AF_AxisHints  axis = &hints->axis[dim];
+    AF_AxisHints  axis   = &hints->axis[dim];
+    FT_Error      error  = 0;
+    FT_Memory     memory = hints->memory;
     AF_LatinAxis  laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim];
-    AF_Edge       edges = axis->edges;
-    AF_Edge       edge, edge_limit;
 
     AF_Segment    segments = axis->segments;
     AF_Segment    segment_limit = segments + axis->num_segments;
@@ -875,6 +881,7 @@
     FT_Fixed      scale;
     FT_Pos        edge_distance_threshold;
 
+    axis->num_edges = 0;
 
     scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
                                          : hints->y_scale;
@@ -906,16 +913,16 @@
     edge_distance_threshold = FT_DivFix( edge_distance_threshold,
                                          scale );
 
-    edge_limit = edges;
     for ( seg = segments; seg < segment_limit; seg++ )
     {
       AF_Edge  found = 0;
+      FT_Int   ee;
 
-
       /* look for an edge corresponding to the segment */
-      for ( edge = edges; edge < edge_limit; edge++ )
+      for ( ee = 0; ee < axis->num_edges; ee++ )
       {
-        FT_Pos  dist;
+        AF_Edge  edge = axis->edges + ee;
+        FT_Pos   dist;
 
 
         dist = seg->pos - edge->fpos;
@@ -931,19 +938,17 @@
 
       if ( !found )
       {
+        AF_Edge   edge;
+
         /* insert a new edge in the list and */
         /* sort according to the position    */
-        while ( edge > edges && edge[-1].fpos > seg->pos )
-        {
-          edge[0] = edge[-1];
-          edge--;
-        }
-        edge_limit++;
+        error = af_axis_hints_new_edge( axis, seg->pos, memory, &edge );
+        if ( error )
+          goto Exit;
 
-        /* clear all edge fields */
-        FT_ZERO( edge );
-
         /* add the segment to the new edge's list */
+        FT_ZERO(edge);
+
         edge->first    = seg;
         edge->last     = seg;
         edge->fpos     = seg->pos;
@@ -954,12 +959,11 @@
       {
         /* if an edge was found, simply add the segment to the edge's */
         /* list                                                       */
-        seg->edge_next        = edge->first;
-        edge->last->edge_next = seg;
-        edge->last            = seg;
+        seg->edge_next         = found->first;
+        found->last->edge_next = seg;
+        found->last            = seg;
       }
     }
-    axis->num_edges = (FT_Int)( edge_limit - edges );
 
 
     /*********************************************************************/
@@ -982,133 +986,148 @@
      * code above.  For some reason, it slows down execution
      * speed -- on a Sun.
      */
-    for ( edge = edges; edge < edge_limit; edge++ )
     {
-      seg = edge->first;
-      if ( seg )
-        do
-        {
-          seg->edge = edge;
-          seg       = seg->edge_next;
-        }
-        while ( seg != edge->first );
-    }
+      AF_Edge  edges      = axis->edges;
+      AF_Edge  edge_limit = edges + axis->num_edges;
+      AF_Edge  edge;
 
-    /* now, compute each edge properties */
-    for ( edge = edges; edge < edge_limit; edge++ )
-    {
-      FT_Int  is_round    = 0;  /* does it contain round segments?    */
-      FT_Int  is_straight = 0;  /* does it contain straight segments? */
-      FT_Pos  ups         = 0;  /* number of upwards segments         */
-      FT_Pos  downs       = 0;  /* number of downwards segments       */
+      for ( edge = edges; edge < edge_limit; edge++ )
+      {
+        seg = edge->first;
+        if ( seg )
+          do
+          {
+            seg->edge = edge;
+            seg       = seg->edge_next;
+          }
+          while ( seg != edge->first );
+      }
 
-
-      seg = edge->first;
-
-      do
+      /* now, compute each edge properties */
+      for ( edge = edges; edge < edge_limit; edge++ )
       {
-        FT_Bool  is_serif;
+        FT_Int  is_round    = 0;  /* does it contain round segments?    */
+        FT_Int  is_straight = 0;  /* does it contain straight segments? */
+        FT_Pos  ups         = 0;  /* number of upwards segments         */
+        FT_Pos  downs       = 0;  /* number of downwards segments       */
 
 
-        /* check for roundness of segment */
-        if ( seg->flags & AF_EDGE_ROUND )
-          is_round++;
-        else
-          is_straight++;
+        seg = edge->first;
 
-        /* check for segment direction */
-        if ( seg->dir == up_dir )
-          ups   += seg->max_coord-seg->min_coord;
-        else
-          downs += seg->max_coord-seg->min_coord;
+        do
+        {
+          FT_Bool  is_serif;
 
-        /* check for links -- if seg->serif is set, then seg->link must */
-        /* be ignored                                                   */
-        is_serif = (FT_Bool)( seg->serif && seg->serif->edge != edge );
 
-        if ( seg->link || is_serif )
-        {
-          AF_Edge     edge2;
-          AF_Segment  seg2;
+          /* check for roundness of segment */
+          if ( seg->flags & AF_EDGE_ROUND )
+            is_round++;
+          else
+            is_straight++;
 
+          /* check for segment direction */
+          if ( seg->dir == up_dir )
+            ups   += seg->max_coord-seg->min_coord;
+          else
+            downs += seg->max_coord-seg->min_coord;
 
-          edge2 = edge->link;
-          seg2  = seg->link;
+          /* check for links -- if seg->serif is set, then seg->link must */
+          /* be ignored                                                   */
+          is_serif = (FT_Bool)( seg->serif && seg->serif->edge != edge );
 
-          if ( is_serif )
+          if ( seg->link || is_serif )
           {
-            seg2  = seg->serif;
-            edge2 = edge->serif;
-          }
+            AF_Edge     edge2;
+            AF_Segment  seg2;
 
-          if ( edge2 )
-          {
-            FT_Pos  edge_delta;
-            FT_Pos  seg_delta;
 
+            edge2 = edge->link;
+            seg2  = seg->link;
 
-            edge_delta = edge->fpos - edge2->fpos;
-            if ( edge_delta < 0 )
-              edge_delta = -edge_delta;
+            if ( is_serif )
+            {
+              seg2  = seg->serif;
+              edge2 = edge->serif;
+            }
 
-            seg_delta = seg->pos - seg2->pos;
-            if ( seg_delta < 0 )
-              seg_delta = -seg_delta;
+            if ( edge2 )
+            {
+              FT_Pos  edge_delta;
+              FT_Pos  seg_delta;
 
-            if ( seg_delta < edge_delta )
+
+              edge_delta = edge->fpos - edge2->fpos;
+              if ( edge_delta < 0 )
+                edge_delta = -edge_delta;
+
+              seg_delta = seg->pos - seg2->pos;
+              if ( seg_delta < 0 )
+                seg_delta = -seg_delta;
+
+              if ( seg_delta < edge_delta )
+                edge2 = seg2->edge;
+            }
+            else
               edge2 = seg2->edge;
-          }
-          else
-            edge2 = seg2->edge;
 
-          if ( is_serif )
-          {
-            edge->serif   = edge2;
-            edge2->flags |= AF_EDGE_SERIF;
+            if ( is_serif )
+            {
+              edge->serif   = edge2;
+              edge2->flags |= AF_EDGE_SERIF;
+            }
+            else
+              edge->link  = edge2;
           }
-          else
-            edge->link  = edge2;
-        }
 
-        seg = seg->edge_next;
+          seg = seg->edge_next;
 
-      } while ( seg != edge->first );
+        } while ( seg != edge->first );
 
-      /* set the round/straight flags */
-      edge->flags = AF_EDGE_NORMAL;
+        /* set the round/straight flags */
+        edge->flags = AF_EDGE_NORMAL;
 
-      if ( is_round > 0 && is_round >= is_straight )
-        edge->flags |= AF_EDGE_ROUND;
+        if ( is_round > 0 && is_round >= is_straight )
+          edge->flags |= AF_EDGE_ROUND;
 
-      /* set the edge's main direction */
-      edge->dir = AF_DIR_NONE;
+        /* set the edge's main direction */
+        edge->dir = AF_DIR_NONE;
 
-      if ( ups > downs )
-        edge->dir = up_dir;
+        if ( ups > downs )
+          edge->dir = up_dir;
 
-      else if ( ups < downs )
-        edge->dir = -up_dir;
+        else if ( ups < downs )
+          edge->dir = -up_dir;
 
-      else if ( ups == downs )
-        edge->dir = 0;  /* both up and down! */
+        else if ( ups == downs )
+          edge->dir = 0;  /* both up and down! */
 
-      /* gets rid of serifs if link is set                */
-      /* XXX: This gets rid of many unpleasant artefacts! */
-      /*      Example: the `c' in cour.pfa at size 13     */
+        /* gets rid of serifs if link is set                */
+        /* XXX: This gets rid of many unpleasant artefacts! */
+        /*      Example: the `c' in cour.pfa at size 13     */
 
-      if ( edge->serif && edge->link )
-        edge->serif = 0;
+        if ( edge->serif && edge->link )
+          edge->serif = 0;
+      }
     }
+
+  Exit:
+    return error;
   }
 
 
-  FT_LOCAL_DEF( void )
+  FT_LOCAL_DEF( FT_Error )
   af_latin_hints_detect_features( AF_GlyphHints  hints,
                                   AF_Dimension   dim )
   {
-    af_latin_hints_compute_segments( hints, dim );
-    af_latin_hints_link_segments   ( hints, dim );
-    af_latin_hints_compute_edges   ( hints, dim );
+    FT_Error  error;
+
+    error = af_latin_hints_compute_segments( hints, dim );
+    if ( !error )
+    {
+      af_latin_hints_link_segments   ( hints, dim );
+      error = af_latin_hints_compute_edges   ( hints, dim );
+    }
+    return error;
   }
 
 
@@ -1812,11 +1831,18 @@
    /* analyze glyph outline
     */
     if ( AF_HINTS_DO_HORIZONTAL(hints) )
-      af_latin_hints_detect_features( hints, AF_DIMENSION_HORZ );
+    {
+      error = af_latin_hints_detect_features( hints, AF_DIMENSION_HORZ );
+      if ( error )
+        goto Exit;
+    }
 
     if ( AF_HINTS_DO_VERTICAL(hints) )
     {
-      af_latin_hints_detect_features( hints, AF_DIMENSION_VERT );
+      error =  af_latin_hints_detect_features( hints, AF_DIMENSION_VERT );
+      if ( error )
+        goto Exit;
+
       af_latin_hints_compute_blue_edges( hints, metrics );
     }
 
--- a/src/autofit/aflatin.h
+++ b/src/autofit/aflatin.h
@@ -140,7 +140,7 @@
  /* this shouldn't normally be exported. However, other scripts might
   * like to use this function as-is
   */
-  FT_LOCAL( void )
+  FT_LOCAL( FT_Error )
   af_latin_hints_compute_segments( AF_GlyphHints  hints,
                                    AF_Dimension   dim );
 
@@ -154,11 +154,11 @@
  /* this shouldn't normally be exported. However, other scripts might
   * want to use this function as-is
   */
-  FT_LOCAL( void )
+  FT_LOCAL( FT_Error )
   af_latin_hints_compute_edges( AF_GlyphHints  hints,
                                 AF_Dimension   dim );
 
-  FT_LOCAL( void )
+  FT_LOCAL( FT_Error )
   af_latin_hints_detect_features( AF_GlyphHints  hints,
                                   AF_Dimension   dim );
 
--- a/src/autofit/afloader.c
+++ b/src/autofit/afloader.c
@@ -449,10 +449,10 @@
       {
         loader->metrics = metrics;
 
-        metrics->scaler = scaler;
-
         if ( metrics->clazz->script_metrics_scale )
           metrics->clazz->script_metrics_scale( metrics, &scaler );
+        else
+          metrics->scaler = scaler;
 
         load_flags |=  FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM;
         load_flags &= ~FT_LOAD_RENDER;