Commit b9c22aff61a90a17d8ace2dfda5094df31ac860c

David Turner 2005-03-01T15:48:29

* 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
diff --git a/ChangeLog b/ChangeLog
index dc0b1e0..82d7a8b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2005-03-01  David Turner  <david@freetype.org>
+
+    * 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  <wl@gnu.org>
 
 	* src/truetype/ttpload.c (tt_face_load_loca): Fix typo.
diff --git a/include/freetype/config/ftmodule.h b/include/freetype/config/ftmodule.h
index 762d4af..74782f0 100644
--- 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)
diff --git a/include/freetype/config/ftstdlib.h b/include/freetype/config/ftstdlib.h
index 448ae4b..4b9b398 100644
--- 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
 
 
diff --git a/src/autofit/afhints.c b/src/autofit/afhints.c
index a1a50dc..9e85ae1 100644
--- 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,59 +461,17 @@
     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. */
     /* the Arphic ones).  We thus recompute it each time we need to.      */
diff --git a/src/autofit/afhints.h b/src/autofit/afhints.h
index a570cc8..9b71c8c 100644
--- a/src/autofit/afhints.h
+++ b/src/autofit/afhints.h
@@ -84,15 +84,15 @@ FT_BEGIN_HEADER
 
   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 @@ FT_BEGIN_HEADER
 
   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 @@ FT_BEGIN_HEADER
   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;
@@ -205,6 +207,17 @@ FT_BEGIN_HEADER
                         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,
                        FT_Memory      memory );
diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c
index ce0f8c9..fa5d565 100644
--- 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,15 +755,16 @@
         segment->score = 32000;
         segment->link  = NULL;
 
-        num_segments++;
-        segment++;
+        segment = NULL;
       }
 
       /* insert maximum segment */
       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++;
-
-        /* clear all edge fields */
-        FT_ZERO( edge );
+        error = af_axis_hints_new_edge( axis, seg->pos, memory, &edge );
+        if ( error )
+          goto Exit;
 
         /* 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 );
-    }
-
-    /* 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       */
+      AF_Edge  edges      = axis->edges;
+      AF_Edge  edge_limit = edges + axis->num_edges;
+      AF_Edge  edge;
 
+      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;
+
+            if ( is_serif )
+            {
+              seg2  = seg->serif;
+              edge2 = edge->serif;
+            }
+
+            if ( edge2 )
+            {
+              FT_Pos  edge_delta;
+              FT_Pos  seg_delta;
 
 
-            edge_delta = edge->fpos - edge2->fpos;
-            if ( edge_delta < 0 )
-              edge_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;
+              seg_delta = seg->pos - seg2->pos;
+              if ( seg_delta < 0 )
+                seg_delta = -seg_delta;
 
-            if ( seg_delta < edge_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 );
     }
 
diff --git a/src/autofit/aflatin.h b/src/autofit/aflatin.h
index e7e8e48..9b7f8fe 100644
--- a/src/autofit/aflatin.h
+++ b/src/autofit/aflatin.h
@@ -140,7 +140,7 @@ FT_BEGIN_HEADER
  /* 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 @@ FT_BEGIN_HEADER
  /* 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 );
 
diff --git a/src/autofit/afloader.c b/src/autofit/afloader.c
index acd11c1..c03a9f3 100644
--- 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;