Home | History | Annotate | Download | only in autofit
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  afhints.c                                                              */
      4 /*                                                                         */
      5 /*    Auto-fitter hinting routines (body).                                 */
      6 /*                                                                         */
      7 /*  Copyright 2003-2018 by                                                 */
      8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
      9 /*                                                                         */
     10 /*  This file is part of the FreeType project, and may only be used,       */
     11 /*  modified, and distributed under the terms of the FreeType project      */
     12 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
     13 /*  this file you indicate that you have read the license and              */
     14 /*  understand and accept it fully.                                        */
     15 /*                                                                         */
     16 /***************************************************************************/
     17 
     18 
     19 #include "afhints.h"
     20 #include "aferrors.h"
     21 #include FT_INTERNAL_CALC_H
     22 #include FT_INTERNAL_DEBUG_H
     23 
     24 
     25   /*************************************************************************/
     26   /*                                                                       */
     27   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
     28   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
     29   /* messages during execution.                                            */
     30   /*                                                                       */
     31 #undef  FT_COMPONENT
     32 #define FT_COMPONENT  trace_afhints
     33 
     34 
     35   /* Get new segment for given axis. */
     36 
     37   FT_LOCAL_DEF( FT_Error )
     38   af_axis_hints_new_segment( AF_AxisHints  axis,
     39                              FT_Memory     memory,
     40                              AF_Segment   *asegment )
     41   {
     42     FT_Error    error   = FT_Err_Ok;
     43     AF_Segment  segment = NULL;
     44 
     45 
     46     if ( axis->num_segments < AF_SEGMENTS_EMBEDDED )
     47     {
     48       if ( !axis->segments )
     49       {
     50         axis->segments     = axis->embedded.segments;
     51         axis->max_segments = AF_SEGMENTS_EMBEDDED;
     52       }
     53     }
     54     else if ( axis->num_segments >= axis->max_segments )
     55     {
     56       FT_Int  old_max = axis->max_segments;
     57       FT_Int  new_max = old_max;
     58       FT_Int  big_max = (FT_Int)( FT_INT_MAX / sizeof ( *segment ) );
     59 
     60 
     61       if ( old_max >= big_max )
     62       {
     63         error = FT_THROW( Out_Of_Memory );
     64         goto Exit;
     65       }
     66 
     67       new_max += ( new_max >> 2 ) + 4;
     68       if ( new_max < old_max || new_max > big_max )
     69         new_max = big_max;
     70 
     71       if ( axis->segments == axis->embedded.segments )
     72       {
     73         if ( FT_NEW_ARRAY( axis->segments, new_max ) )
     74           goto Exit;
     75         ft_memcpy( axis->segments, axis->embedded.segments,
     76                    sizeof ( axis->embedded.segments ) );
     77       }
     78       else
     79       {
     80         if ( FT_RENEW_ARRAY( axis->segments, old_max, new_max ) )
     81           goto Exit;
     82       }
     83 
     84       axis->max_segments = new_max;
     85     }
     86 
     87     segment = axis->segments + axis->num_segments++;
     88 
     89   Exit:
     90     *asegment = segment;
     91     return error;
     92   }
     93 
     94 
     95   /* Get new edge for given axis, direction, and position, */
     96   /* without initializing the edge itself.                 */
     97 
     98   FT_LOCAL( FT_Error )
     99   af_axis_hints_new_edge( AF_AxisHints  axis,
    100                           FT_Int        fpos,
    101                           AF_Direction  dir,
    102                           FT_Bool       top_to_bottom_hinting,
    103                           FT_Memory     memory,
    104                           AF_Edge      *anedge )
    105   {
    106     FT_Error  error = FT_Err_Ok;
    107     AF_Edge   edge  = NULL;
    108     AF_Edge   edges;
    109 
    110 
    111     if ( axis->num_edges < AF_EDGES_EMBEDDED )
    112     {
    113       if ( !axis->edges )
    114       {
    115         axis->edges     = axis->embedded.edges;
    116         axis->max_edges = AF_EDGES_EMBEDDED;
    117       }
    118     }
    119     else if ( axis->num_edges >= axis->max_edges )
    120     {
    121       FT_Int  old_max = axis->max_edges;
    122       FT_Int  new_max = old_max;
    123       FT_Int  big_max = (FT_Int)( FT_INT_MAX / sizeof ( *edge ) );
    124 
    125 
    126       if ( old_max >= big_max )
    127       {
    128         error = FT_THROW( Out_Of_Memory );
    129         goto Exit;
    130       }
    131 
    132       new_max += ( new_max >> 2 ) + 4;
    133       if ( new_max < old_max || new_max > big_max )
    134         new_max = big_max;
    135 
    136       if ( axis->edges == axis->embedded.edges )
    137       {
    138         if ( FT_NEW_ARRAY( axis->edges, new_max ) )
    139           goto Exit;
    140         ft_memcpy( axis->edges, axis->embedded.edges,
    141                    sizeof ( axis->embedded.edges ) );
    142       }
    143       else
    144       {
    145         if ( FT_RENEW_ARRAY( axis->edges, old_max, new_max ) )
    146           goto Exit;
    147       }
    148 
    149       axis->max_edges = new_max;
    150     }
    151 
    152     edges = axis->edges;
    153     edge  = edges + axis->num_edges;
    154 
    155     while ( edge > edges )
    156     {
    157       if ( top_to_bottom_hinting ? ( edge[-1].fpos > fpos )
    158                                  : ( edge[-1].fpos < fpos ) )
    159         break;
    160 
    161       /* we want the edge with same position and minor direction */
    162       /* to appear before those in the major one in the list     */
    163       if ( edge[-1].fpos == fpos && dir == axis->major_dir )
    164         break;
    165 
    166       edge[0] = edge[-1];
    167       edge--;
    168     }
    169 
    170     axis->num_edges++;
    171 
    172   Exit:
    173     *anedge = edge;
    174     return error;
    175   }
    176 
    177 
    178 #ifdef FT_DEBUG_AUTOFIT
    179 
    180 #include FT_CONFIG_STANDARD_LIBRARY_H
    181 
    182   /* The dump functions are used in the `ftgrid' demo program, too. */
    183 #define AF_DUMP( varformat )          \
    184           do                          \
    185           {                           \
    186             if ( to_stdout )          \
    187               printf varformat;       \
    188             else                      \
    189               FT_TRACE7( varformat ); \
    190           } while ( 0 )
    191 
    192 
    193   static const char*
    194   af_dir_str( AF_Direction  dir )
    195   {
    196     const char*  result;
    197 
    198 
    199     switch ( dir )
    200     {
    201     case AF_DIR_UP:
    202       result = "up";
    203       break;
    204     case AF_DIR_DOWN:
    205       result = "down";
    206       break;
    207     case AF_DIR_LEFT:
    208       result = "left";
    209       break;
    210     case AF_DIR_RIGHT:
    211       result = "right";
    212       break;
    213     default:
    214       result = "none";
    215     }
    216 
    217     return result;
    218   }
    219 
    220 
    221 #define AF_INDEX_NUM( ptr, base )  (int)( (ptr) ? ( (ptr) - (base) ) : -1 )
    222 
    223 
    224   static char*
    225   af_print_idx( char* p,
    226                 int   idx )
    227   {
    228     if ( idx == -1 )
    229     {
    230       p[0] = '-';
    231       p[1] = '-';
    232       p[2] = '\0';
    233     }
    234     else
    235       ft_sprintf( p, "%d", idx );
    236 
    237     return p;
    238   }
    239 
    240 
    241   static int
    242   af_get_segment_index( AF_GlyphHints  hints,
    243                         int            point_idx,
    244                         int            dimension )
    245   {
    246     AF_AxisHints  axis     = &hints->axis[dimension];
    247     AF_Point      point    = hints->points + point_idx;
    248     AF_Segment    segments = axis->segments;
    249     AF_Segment    limit    = segments + axis->num_segments;
    250     AF_Segment    segment;
    251 
    252 
    253     for ( segment = segments; segment < limit; segment++ )
    254     {
    255       if ( segment->first <= segment->last )
    256       {
    257         if ( point >= segment->first && point <= segment->last )
    258           break;
    259       }
    260       else
    261       {
    262         AF_Point  p = segment->first;
    263 
    264 
    265         for (;;)
    266         {
    267           if ( point == p )
    268             goto Exit;
    269 
    270           if ( p == segment->last )
    271             break;
    272 
    273           p = p->next;
    274         }
    275       }
    276     }
    277 
    278   Exit:
    279     if ( segment == limit )
    280       return -1;
    281 
    282     return (int)( segment - segments );
    283   }
    284 
    285 
    286   static int
    287   af_get_edge_index( AF_GlyphHints  hints,
    288                      int            segment_idx,
    289                      int            dimension )
    290   {
    291     AF_AxisHints  axis    = &hints->axis[dimension];
    292     AF_Edge       edges   = axis->edges;
    293     AF_Segment    segment = axis->segments + segment_idx;
    294 
    295 
    296     return segment_idx == -1 ? -1 : AF_INDEX_NUM( segment->edge, edges );
    297   }
    298 
    299 
    300 #ifdef __cplusplus
    301   extern "C" {
    302 #endif
    303   void
    304   af_glyph_hints_dump_points( AF_GlyphHints  hints,
    305                               FT_Bool        to_stdout )
    306   {
    307     AF_Point   points  = hints->points;
    308     AF_Point   limit   = points + hints->num_points;
    309     AF_Point*  contour = hints->contours;
    310     AF_Point*  climit  = contour + hints->num_contours;
    311     AF_Point   point;
    312 
    313 
    314     AF_DUMP(( "Table of points:\n" ));
    315 
    316     if ( hints->num_points )
    317     {
    318       AF_DUMP(( "  index  hedge  hseg  vedge  vseg  flags "
    319              /* "  XXXXX  XXXXX XXXXX  XXXXX XXXXX  XXXXXX" */
    320                 "  xorg  yorg  xscale  yscale   xfit    yfit" ));
    321              /* " XXXXX XXXXX XXXX.XX XXXX.XX XXXX.XX XXXX.XX" */
    322     }
    323     else
    324       AF_DUMP(( "  (none)\n" ));
    325 
    326     for ( point = points; point < limit; point++ )
    327     {
    328       int  point_idx     = AF_INDEX_NUM( point, points );
    329       int  segment_idx_0 = af_get_segment_index( hints, point_idx, 0 );
    330       int  segment_idx_1 = af_get_segment_index( hints, point_idx, 1 );
    331 
    332       char  buf1[16], buf2[16], buf3[16], buf4[16];
    333 
    334 
    335       /* insert extra newline at the beginning of a contour */
    336       if ( contour < climit && *contour == point )
    337       {
    338         AF_DUMP(( "\n" ));
    339         contour++;
    340       }
    341 
    342       AF_DUMP(( "  %5d  %5s %5s  %5s %5s  %s"
    343                 " %5d %5d %7.2f %7.2f %7.2f %7.2f\n",
    344                 point_idx,
    345                 af_print_idx( buf1,
    346                               af_get_edge_index( hints, segment_idx_1, 1 ) ),
    347                 af_print_idx( buf2, segment_idx_1 ),
    348                 af_print_idx( buf3,
    349                               af_get_edge_index( hints, segment_idx_0, 0 ) ),
    350                 af_print_idx( buf4, segment_idx_0 ),
    351                 ( point->flags & AF_FLAG_NEAR )
    352                   ? " near "
    353                   : ( point->flags & AF_FLAG_WEAK_INTERPOLATION )
    354                     ? " weak "
    355                     : "strong",
    356 
    357                 point->fx,
    358                 point->fy,
    359                 point->ox / 64.0,
    360                 point->oy / 64.0,
    361                 point->x / 64.0,
    362                 point->y / 64.0 ));
    363     }
    364     AF_DUMP(( "\n" ));
    365   }
    366 #ifdef __cplusplus
    367   }
    368 #endif
    369 
    370 
    371   static const char*
    372   af_edge_flags_to_string( FT_UInt  flags )
    373   {
    374     static char  temp[32];
    375     int          pos = 0;
    376 
    377 
    378     if ( flags & AF_EDGE_ROUND )
    379     {
    380       ft_memcpy( temp + pos, "round", 5 );
    381       pos += 5;
    382     }
    383     if ( flags & AF_EDGE_SERIF )
    384     {
    385       if ( pos > 0 )
    386         temp[pos++] = ' ';
    387       ft_memcpy( temp + pos, "serif", 5 );
    388       pos += 5;
    389     }
    390     if ( pos == 0 )
    391       return "normal";
    392 
    393     temp[pos] = '\0';
    394 
    395     return temp;
    396   }
    397 
    398 
    399   /* Dump the array of linked segments. */
    400 
    401 #ifdef __cplusplus
    402   extern "C" {
    403 #endif
    404   void
    405   af_glyph_hints_dump_segments( AF_GlyphHints  hints,
    406                                 FT_Bool        to_stdout )
    407   {
    408     FT_Int  dimension;
    409 
    410 
    411     for ( dimension = 1; dimension >= 0; dimension-- )
    412     {
    413       AF_AxisHints  axis     = &hints->axis[dimension];
    414       AF_Point      points   = hints->points;
    415       AF_Edge       edges    = axis->edges;
    416       AF_Segment    segments = axis->segments;
    417       AF_Segment    limit    = segments + axis->num_segments;
    418       AF_Segment    seg;
    419 
    420       char  buf1[16], buf2[16], buf3[16];
    421 
    422 
    423       AF_DUMP(( "Table of %s segments:\n",
    424                 dimension == AF_DIMENSION_HORZ ? "vertical"
    425                                                : "horizontal" ));
    426       if ( axis->num_segments )
    427       {
    428         AF_DUMP(( "  index   pos   delta   dir   from   to "
    429                /* "  XXXXX  XXXXX  XXXXX  XXXXX  XXXX  XXXX" */
    430                   "  link  serif  edge"
    431                /* "  XXXX  XXXXX  XXXX" */
    432                   "  height  extra     flags\n" ));
    433                /* "  XXXXXX  XXXXX  XXXXXXXXXXX" */
    434       }
    435       else
    436         AF_DUMP(( "  (none)\n" ));
    437 
    438       for ( seg = segments; seg < limit; seg++ )
    439         AF_DUMP(( "  %5d  %5d  %5d  %5s  %4d  %4d"
    440                   "  %4s  %5s  %4s"
    441                   "  %6d  %5d  %11s\n",
    442                   AF_INDEX_NUM( seg, segments ),
    443                   seg->pos,
    444                   seg->delta,
    445                   af_dir_str( (AF_Direction)seg->dir ),
    446                   AF_INDEX_NUM( seg->first, points ),
    447                   AF_INDEX_NUM( seg->last, points ),
    448 
    449                   af_print_idx( buf1, AF_INDEX_NUM( seg->link, segments ) ),
    450                   af_print_idx( buf2, AF_INDEX_NUM( seg->serif, segments ) ),
    451                   af_print_idx( buf3, AF_INDEX_NUM( seg->edge, edges ) ),
    452 
    453                   seg->height,
    454                   seg->height - ( seg->max_coord - seg->min_coord ),
    455                   af_edge_flags_to_string( seg->flags ) ));
    456       AF_DUMP(( "\n" ));
    457     }
    458   }
    459 #ifdef __cplusplus
    460   }
    461 #endif
    462 
    463 
    464   /* Fetch number of segments. */
    465 
    466 #ifdef __cplusplus
    467   extern "C" {
    468 #endif
    469   FT_Error
    470   af_glyph_hints_get_num_segments( AF_GlyphHints  hints,
    471                                    FT_Int         dimension,
    472                                    FT_Int*        num_segments )
    473   {
    474     AF_Dimension  dim;
    475     AF_AxisHints  axis;
    476 
    477 
    478     dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT;
    479 
    480     axis          = &hints->axis[dim];
    481     *num_segments = axis->num_segments;
    482 
    483     return FT_Err_Ok;
    484   }
    485 #ifdef __cplusplus
    486   }
    487 #endif
    488 
    489 
    490   /* Fetch offset of segments into user supplied offset array. */
    491 
    492 #ifdef __cplusplus
    493   extern "C" {
    494 #endif
    495   FT_Error
    496   af_glyph_hints_get_segment_offset( AF_GlyphHints  hints,
    497                                      FT_Int         dimension,
    498                                      FT_Int         idx,
    499                                      FT_Pos        *offset,
    500                                      FT_Bool       *is_blue,
    501                                      FT_Pos        *blue_offset )
    502   {
    503     AF_Dimension  dim;
    504     AF_AxisHints  axis;
    505     AF_Segment    seg;
    506 
    507 
    508     if ( !offset )
    509       return FT_THROW( Invalid_Argument );
    510 
    511     dim = ( dimension == 0 ) ? AF_DIMENSION_HORZ : AF_DIMENSION_VERT;
    512 
    513     axis = &hints->axis[dim];
    514 
    515     if ( idx < 0 || idx >= axis->num_segments )
    516       return FT_THROW( Invalid_Argument );
    517 
    518     seg      = &axis->segments[idx];
    519     *offset  = ( dim == AF_DIMENSION_HORZ ) ? seg->first->fx
    520                                             : seg->first->fy;
    521     if ( seg->edge )
    522       *is_blue = (FT_Bool)( seg->edge->blue_edge != 0 );
    523     else
    524       *is_blue = FALSE;
    525 
    526     if ( *is_blue )
    527       *blue_offset = seg->edge->blue_edge->org;
    528     else
    529       *blue_offset = 0;
    530 
    531     return FT_Err_Ok;
    532   }
    533 #ifdef __cplusplus
    534   }
    535 #endif
    536 
    537 
    538   /* Dump the array of linked edges. */
    539 
    540 #ifdef __cplusplus
    541   extern "C" {
    542 #endif
    543   void
    544   af_glyph_hints_dump_edges( AF_GlyphHints  hints,
    545                              FT_Bool        to_stdout )
    546   {
    547     FT_Int  dimension;
    548 
    549 
    550     for ( dimension = 1; dimension >= 0; dimension-- )
    551     {
    552       AF_AxisHints  axis  = &hints->axis[dimension];
    553       AF_Edge       edges = axis->edges;
    554       AF_Edge       limit = edges + axis->num_edges;
    555       AF_Edge       edge;
    556 
    557       char  buf1[16], buf2[16];
    558 
    559 
    560       /*
    561        *  note: AF_DIMENSION_HORZ corresponds to _vertical_ edges
    562        *        since they have a constant X coordinate.
    563        */
    564       if ( dimension == AF_DIMENSION_HORZ )
    565         AF_DUMP(( "Table of %s edges (1px=%.2fu, 10u=%.2fpx):\n",
    566                   "vertical",
    567                   65536.0 * 64.0 / hints->x_scale,
    568                   10.0 * hints->x_scale / 65536.0 / 64.0 ));
    569       else
    570         AF_DUMP(( "Table of %s edges (1px=%.2fu, 10u=%.2fpx):\n",
    571                   "horizontal",
    572                   65536.0 * 64.0 / hints->y_scale,
    573                   10.0 * hints->y_scale / 65536.0 / 64.0 ));
    574 
    575       if ( axis->num_edges )
    576       {
    577         AF_DUMP(( "  index    pos     dir   link  serif"
    578                /* "  XXXXX  XXXX.XX  XXXXX  XXXX  XXXXX" */
    579                   "  blue    opos     pos       flags\n" ));
    580                /* "    X   XXXX.XX  XXXX.XX  XXXXXXXXXXX" */
    581       }
    582       else
    583         AF_DUMP(( "  (none)\n" ));
    584 
    585       for ( edge = edges; edge < limit; edge++ )
    586         AF_DUMP(( "  %5d  %7.2f  %5s  %4s  %5s"
    587                   "    %c   %7.2f  %7.2f  %11s\n",
    588                   AF_INDEX_NUM( edge, edges ),
    589                   (int)edge->opos / 64.0,
    590                   af_dir_str( (AF_Direction)edge->dir ),
    591                   af_print_idx( buf1, AF_INDEX_NUM( edge->link, edges ) ),
    592                   af_print_idx( buf2, AF_INDEX_NUM( edge->serif, edges ) ),
    593 
    594                   edge->blue_edge ? 'y' : 'n',
    595                   edge->opos / 64.0,
    596                   edge->pos / 64.0,
    597                   af_edge_flags_to_string( edge->flags ) ));
    598       AF_DUMP(( "\n" ));
    599     }
    600   }
    601 #ifdef __cplusplus
    602   }
    603 #endif
    604 
    605 #undef AF_DUMP
    606 
    607 #endif /* !FT_DEBUG_AUTOFIT */
    608 
    609 
    610   /* Compute the direction value of a given vector. */
    611 
    612   FT_LOCAL_DEF( AF_Direction )
    613   af_direction_compute( FT_Pos  dx,
    614                         FT_Pos  dy )
    615   {
    616     FT_Pos        ll, ss;  /* long and short arm lengths */
    617     AF_Direction  dir;     /* candidate direction        */
    618 
    619 
    620     if ( dy >= dx )
    621     {
    622       if ( dy >= -dx )
    623       {
    624         dir = AF_DIR_UP;
    625         ll  = dy;
    626         ss  = dx;
    627       }
    628       else
    629       {
    630         dir = AF_DIR_LEFT;
    631         ll  = -dx;
    632         ss  = dy;
    633       }
    634     }
    635     else /* dy < dx */
    636     {
    637       if ( dy >= -dx )
    638       {
    639         dir = AF_DIR_RIGHT;
    640         ll  = dx;
    641         ss  = dy;
    642       }
    643       else
    644       {
    645         dir = AF_DIR_DOWN;
    646         ll  = -dy;
    647         ss  = dx;
    648       }
    649     }
    650 
    651     /* return no direction if arm lengths do not differ enough       */
    652     /* (value 14 is heuristic, corresponding to approx. 4.1 degrees) */
    653     /* the long arm is never negative                                */
    654     if ( ll <= 14 * FT_ABS( ss ) )
    655       dir = AF_DIR_NONE;
    656 
    657     return dir;
    658   }
    659 
    660 
    661   FT_LOCAL_DEF( void )
    662   af_glyph_hints_init( AF_GlyphHints  hints,
    663                        FT_Memory      memory )
    664   {
    665     /* no need to initialize the embedded items */
    666     FT_MEM_ZERO( hints, sizeof ( *hints ) - sizeof ( hints->embedded ) );
    667     hints->memory = memory;
    668   }
    669 
    670 
    671   FT_LOCAL_DEF( void )
    672   af_glyph_hints_done( AF_GlyphHints  hints )
    673   {
    674     FT_Memory  memory;
    675     int        dim;
    676 
    677 
    678     if ( !( hints && hints->memory ) )
    679       return;
    680 
    681     memory = hints->memory;
    682 
    683     /*
    684      *  note that we don't need to free the segment and edge
    685      *  buffers since they are really within the hints->points array
    686      */
    687     for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
    688     {
    689       AF_AxisHints  axis = &hints->axis[dim];
    690 
    691 
    692       axis->num_segments = 0;
    693       axis->max_segments = 0;
    694       if ( axis->segments != axis->embedded.segments )
    695         FT_FREE( axis->segments );
    696 
    697       axis->num_edges = 0;
    698       axis->max_edges = 0;
    699       if ( axis->edges != axis->embedded.edges )
    700         FT_FREE( axis->edges );
    701     }
    702 
    703     if ( hints->contours != hints->embedded.contours )
    704       FT_FREE( hints->contours );
    705     hints->max_contours = 0;
    706     hints->num_contours = 0;
    707 
    708     if ( hints->points != hints->embedded.points )
    709       FT_FREE( hints->points );
    710     hints->max_points = 0;
    711     hints->num_points = 0;
    712 
    713     hints->memory = NULL;
    714   }
    715 
    716 
    717   /* Reset metrics. */
    718 
    719   FT_LOCAL_DEF( void )
    720   af_glyph_hints_rescale( AF_GlyphHints    hints,
    721                           AF_StyleMetrics  metrics )
    722   {
    723     hints->metrics      = metrics;
    724     hints->scaler_flags = metrics->scaler.flags;
    725   }
    726 
    727 
    728   /* Recompute all AF_Point in AF_GlyphHints from the definitions */
    729   /* in a source outline.                                         */
    730 
    731   FT_LOCAL_DEF( FT_Error )
    732   af_glyph_hints_reload( AF_GlyphHints  hints,
    733                          FT_Outline*    outline )
    734   {
    735     FT_Error   error   = FT_Err_Ok;
    736     AF_Point   points;
    737     FT_UInt    old_max, new_max;
    738     FT_Fixed   x_scale = hints->x_scale;
    739     FT_Fixed   y_scale = hints->y_scale;
    740     FT_Pos     x_delta = hints->x_delta;
    741     FT_Pos     y_delta = hints->y_delta;
    742     FT_Memory  memory  = hints->memory;
    743 
    744 
    745     hints->num_points   = 0;
    746     hints->num_contours = 0;
    747 
    748     hints->axis[0].num_segments = 0;
    749     hints->axis[0].num_edges    = 0;
    750     hints->axis[1].num_segments = 0;
    751     hints->axis[1].num_edges    = 0;
    752 
    753     /* first of all, reallocate the contours array if necessary */
    754     new_max = (FT_UInt)outline->n_contours;
    755     old_max = (FT_UInt)hints->max_contours;
    756 
    757     if ( new_max <= AF_CONTOURS_EMBEDDED )
    758     {
    759       if ( !hints->contours )
    760       {
    761         hints->contours     = hints->embedded.contours;
    762         hints->max_contours = AF_CONTOURS_EMBEDDED;
    763       }
    764     }
    765     else if ( new_max > old_max )
    766     {
    767       if ( hints->contours == hints->embedded.contours )
    768         hints->contours = NULL;
    769 
    770       new_max = ( new_max + 3 ) & ~3U; /* round up to a multiple of 4 */
    771 
    772       if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) )
    773         goto Exit;
    774 
    775       hints->max_contours = (FT_Int)new_max;
    776     }
    777 
    778     /*
    779      *  then reallocate the points arrays if necessary --
    780      *  note that we reserve two additional point positions, used to
    781      *  hint metrics appropriately
    782      */
    783     new_max = (FT_UInt)( outline->n_points + 2 );
    784     old_max = (FT_UInt)hints->max_points;
    785 
    786     if ( new_max <= AF_POINTS_EMBEDDED )
    787     {
    788       if ( !hints->points )
    789       {
    790         hints->points     = hints->embedded.points;
    791         hints->max_points = AF_POINTS_EMBEDDED;
    792       }
    793     }
    794     else if ( new_max > old_max )
    795     {
    796       if ( hints->points == hints->embedded.points )
    797         hints->points = NULL;
    798 
    799       new_max = ( new_max + 2 + 7 ) & ~7U; /* round up to a multiple of 8 */
    800 
    801       if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) )
    802         goto Exit;
    803 
    804       hints->max_points = (FT_Int)new_max;
    805     }
    806 
    807     hints->num_points   = outline->n_points;
    808     hints->num_contours = outline->n_contours;
    809 
    810     /* We can't rely on the value of `FT_Outline.flags' to know the fill   */
    811     /* direction used for a glyph, given that some fonts are broken (e.g., */
    812     /* the Arphic ones).  We thus recompute it each time we need to.       */
    813     /*                                                                     */
    814     hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_UP;
    815     hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_LEFT;
    816 
    817     if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT )
    818     {
    819       hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_DOWN;
    820       hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_RIGHT;
    821     }
    822 
    823     hints->x_scale = x_scale;
    824     hints->y_scale = y_scale;
    825     hints->x_delta = x_delta;
    826     hints->y_delta = y_delta;
    827 
    828     hints->xmin_delta = 0;
    829     hints->xmax_delta = 0;
    830 
    831     points = hints->points;
    832     if ( hints->num_points == 0 )
    833       goto Exit;
    834 
    835     {
    836       AF_Point  point;
    837       AF_Point  point_limit = points + hints->num_points;
    838 
    839       /* value 20 in `near_limit' is heuristic */
    840       FT_UInt  units_per_em = hints->metrics->scaler.face->units_per_EM;
    841       FT_Int   near_limit   = 20 * units_per_em / 2048;
    842 
    843 
    844       /* compute coordinates & Bezier flags, next and prev */
    845       {
    846         FT_Vector*  vec           = outline->points;
    847         char*       tag           = outline->tags;
    848         FT_Short    endpoint      = outline->contours[0];
    849         AF_Point    end           = points + endpoint;
    850         AF_Point    prev          = end;
    851         FT_Int      contour_index = 0;
    852 
    853 
    854         for ( point = points; point < point_limit; point++, vec++, tag++ )
    855         {
    856           FT_Pos  out_x, out_y;
    857 
    858 
    859           point->in_dir  = (FT_Char)AF_DIR_NONE;
    860           point->out_dir = (FT_Char)AF_DIR_NONE;
    861 
    862           point->fx = (FT_Short)vec->x;
    863           point->fy = (FT_Short)vec->y;
    864           point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta;
    865           point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta;
    866 
    867           end->fx = (FT_Short)outline->points[endpoint].x;
    868           end->fy = (FT_Short)outline->points[endpoint].y;
    869 
    870           switch ( FT_CURVE_TAG( *tag ) )
    871           {
    872           case FT_CURVE_TAG_CONIC:
    873             point->flags = AF_FLAG_CONIC;
    874             break;
    875           case FT_CURVE_TAG_CUBIC:
    876             point->flags = AF_FLAG_CUBIC;
    877             break;
    878           default:
    879             point->flags = AF_FLAG_NONE;
    880           }
    881 
    882           out_x = point->fx - prev->fx;
    883           out_y = point->fy - prev->fy;
    884 
    885           if ( FT_ABS( out_x ) + FT_ABS( out_y ) < near_limit )
    886             prev->flags |= AF_FLAG_NEAR;
    887 
    888           point->prev = prev;
    889           prev->next  = point;
    890           prev        = point;
    891 
    892           if ( point == end )
    893           {
    894             if ( ++contour_index < outline->n_contours )
    895             {
    896               endpoint = outline->contours[contour_index];
    897               end      = points + endpoint;
    898               prev     = end;
    899             }
    900           }
    901         }
    902       }
    903 
    904       /* set up the contours array */
    905       {
    906         AF_Point*  contour       = hints->contours;
    907         AF_Point*  contour_limit = contour + hints->num_contours;
    908         short*     end           = outline->contours;
    909         short      idx           = 0;
    910 
    911 
    912         for ( ; contour < contour_limit; contour++, end++ )
    913         {
    914           contour[0] = points + idx;
    915           idx        = (short)( end[0] + 1 );
    916         }
    917       }
    918 
    919       {
    920         /*
    921          *  Compute directions of `in' and `out' vectors.
    922          *
    923          *  Note that distances between points that are very near to each
    924          *  other are accumulated.  In other words, the auto-hinter either
    925          *  prepends the small vectors between near points to the first
    926          *  non-near vector, or the sum of small vector lengths exceeds a
    927          *  threshold, thus `grouping' the small vectors.  All intermediate
    928          *  points are tagged as weak; the directions are adjusted also to
    929          *  be equal to the accumulated one.
    930          */
    931 
    932         FT_Int  near_limit2 = 2 * near_limit - 1;
    933 
    934         AF_Point*  contour;
    935         AF_Point*  contour_limit = hints->contours + hints->num_contours;
    936 
    937 
    938         for ( contour = hints->contours; contour < contour_limit; contour++ )
    939         {
    940           AF_Point  first = *contour;
    941           AF_Point  next, prev, curr;
    942 
    943           FT_Pos  out_x, out_y;
    944 
    945 
    946           /* since the first point of a contour could be part of a */
    947           /* series of near points, go backwards to find the first */
    948           /* non-near point and adjust `first'                     */
    949 
    950           point = first;
    951           prev  = first->prev;
    952 
    953           while ( prev != first )
    954           {
    955             out_x = point->fx - prev->fx;
    956             out_y = point->fy - prev->fy;
    957 
    958             /*
    959              *  We use Taxicab metrics to measure the vector length.
    960              *
    961              *  Note that the accumulated distances so far could have the
    962              *  opposite direction of the distance measured here.  For this
    963              *  reason we use `near_limit2' for the comparison to get a
    964              *  non-near point even in the worst case.
    965              */
    966             if ( FT_ABS( out_x ) + FT_ABS( out_y ) >= near_limit2 )
    967               break;
    968 
    969             point = prev;
    970             prev  = prev->prev;
    971           }
    972 
    973           /* adjust first point */
    974           first = point;
    975 
    976           /* now loop over all points of the contour to get */
    977           /* `in' and `out' vector directions               */
    978 
    979           curr = first;
    980 
    981           /*
    982            *  We abuse the `u' and `v' fields to store index deltas to the
    983            *  next and previous non-near point, respectively.
    984            *
    985            *  To avoid problems with not having non-near points, we point to
    986            *  `first' by default as the next non-near point.
    987            *
    988            */
    989           curr->u  = (FT_Pos)( first - curr );
    990           first->v = -curr->u;
    991 
    992           out_x = 0;
    993           out_y = 0;
    994 
    995           next = first;
    996           do
    997           {
    998             AF_Direction  out_dir;
    999 
   1000 
   1001             point = next;
   1002             next  = point->next;
   1003 
   1004             out_x += next->fx - point->fx;
   1005             out_y += next->fy - point->fy;
   1006 
   1007             if ( FT_ABS( out_x ) + FT_ABS( out_y ) < near_limit )
   1008             {
   1009               next->flags |= AF_FLAG_WEAK_INTERPOLATION;
   1010               continue;
   1011             }
   1012 
   1013             curr->u = (FT_Pos)( next - curr );
   1014             next->v = -curr->u;
   1015 
   1016             out_dir = af_direction_compute( out_x, out_y );
   1017 
   1018             /* adjust directions for all points inbetween; */
   1019             /* the loop also updates position of `curr'    */
   1020             curr->out_dir = (FT_Char)out_dir;
   1021             for ( curr = curr->next; curr != next; curr = curr->next )
   1022             {
   1023               curr->in_dir  = (FT_Char)out_dir;
   1024               curr->out_dir = (FT_Char)out_dir;
   1025             }
   1026             next->in_dir = (FT_Char)out_dir;
   1027 
   1028             curr->u  = (FT_Pos)( first - curr );
   1029             first->v = -curr->u;
   1030 
   1031             out_x = 0;
   1032             out_y = 0;
   1033 
   1034           } while ( next != first );
   1035         }
   1036 
   1037         /*
   1038          *  The next step is to `simplify' an outline's topology so that we
   1039          *  can identify local extrema more reliably: A series of
   1040          *  non-horizontal or non-vertical vectors pointing into the same
   1041          *  quadrant are handled as a single, long vector.  From a
   1042          *  topological point of the view, the intermediate points are of no
   1043          *  interest and thus tagged as weak.
   1044          */
   1045 
   1046         for ( point = points; point < point_limit; point++ )
   1047         {
   1048           if ( point->flags & AF_FLAG_WEAK_INTERPOLATION )
   1049             continue;
   1050 
   1051           if ( point->in_dir  == AF_DIR_NONE &&
   1052                point->out_dir == AF_DIR_NONE )
   1053           {
   1054             /* check whether both vectors point into the same quadrant */
   1055 
   1056             FT_Pos  in_x, in_y;
   1057             FT_Pos  out_x, out_y;
   1058 
   1059             AF_Point  next_u = point + point->u;
   1060             AF_Point  prev_v = point + point->v;
   1061 
   1062 
   1063             in_x = point->fx - prev_v->fx;
   1064             in_y = point->fy - prev_v->fy;
   1065 
   1066             out_x = next_u->fx - point->fx;
   1067             out_y = next_u->fy - point->fy;
   1068 
   1069             if ( ( in_x ^ out_x ) >= 0 && ( in_y ^ out_y ) >= 0 )
   1070             {
   1071               /* yes, so tag current point as weak */
   1072               /* and update index deltas           */
   1073 
   1074               point->flags |= AF_FLAG_WEAK_INTERPOLATION;
   1075 
   1076               prev_v->u = (FT_Pos)( next_u - prev_v );
   1077               next_u->v = -prev_v->u;
   1078             }
   1079           }
   1080         }
   1081 
   1082         /*
   1083          *  Finally, check for remaining weak points.  Everything else not
   1084          *  collected in edges so far is then implicitly classified as strong
   1085          *  points.
   1086          */
   1087 
   1088         for ( point = points; point < point_limit; point++ )
   1089         {
   1090           if ( point->flags & AF_FLAG_WEAK_INTERPOLATION )
   1091             continue;
   1092 
   1093           if ( point->flags & AF_FLAG_CONTROL )
   1094           {
   1095             /* control points are always weak */
   1096           Is_Weak_Point:
   1097             point->flags |= AF_FLAG_WEAK_INTERPOLATION;
   1098           }
   1099           else if ( point->out_dir == point->in_dir )
   1100           {
   1101             if ( point->out_dir != AF_DIR_NONE )
   1102             {
   1103               /* current point lies on a horizontal or          */
   1104               /* vertical segment (but doesn't start or end it) */
   1105               goto Is_Weak_Point;
   1106             }
   1107 
   1108             {
   1109               AF_Point  next_u = point + point->u;
   1110               AF_Point  prev_v = point + point->v;
   1111 
   1112 
   1113               if ( ft_corner_is_flat( point->fx  - prev_v->fx,
   1114                                       point->fy  - prev_v->fy,
   1115                                       next_u->fx - point->fx,
   1116                                       next_u->fy - point->fy ) )
   1117               {
   1118                 /* either the `in' or the `out' vector is much more  */
   1119                 /* dominant than the other one, so tag current point */
   1120                 /* as weak and update index deltas                   */
   1121 
   1122                 prev_v->u = (FT_Pos)( next_u - prev_v );
   1123                 next_u->v = -prev_v->u;
   1124 
   1125                 goto Is_Weak_Point;
   1126               }
   1127             }
   1128           }
   1129           else if ( point->in_dir == -point->out_dir )
   1130           {
   1131             /* current point forms a spike */
   1132             goto Is_Weak_Point;
   1133           }
   1134         }
   1135       }
   1136     }
   1137 
   1138   Exit:
   1139     return error;
   1140   }
   1141 
   1142 
   1143   /* Store the hinted outline in an FT_Outline structure. */
   1144 
   1145   FT_LOCAL_DEF( void )
   1146   af_glyph_hints_save( AF_GlyphHints  hints,
   1147                        FT_Outline*    outline )
   1148   {
   1149     AF_Point    point = hints->points;
   1150     AF_Point    limit = point + hints->num_points;
   1151     FT_Vector*  vec   = outline->points;
   1152     char*       tag   = outline->tags;
   1153 
   1154 
   1155     for ( ; point < limit; point++, vec++, tag++ )
   1156     {
   1157       vec->x = point->x;
   1158       vec->y = point->y;
   1159 
   1160       if ( point->flags & AF_FLAG_CONIC )
   1161         tag[0] = FT_CURVE_TAG_CONIC;
   1162       else if ( point->flags & AF_FLAG_CUBIC )
   1163         tag[0] = FT_CURVE_TAG_CUBIC;
   1164       else
   1165         tag[0] = FT_CURVE_TAG_ON;
   1166     }
   1167   }
   1168 
   1169 
   1170   /****************************************************************
   1171    *
   1172    *                     EDGE POINT GRID-FITTING
   1173    *
   1174    ****************************************************************/
   1175 
   1176 
   1177   /* Align all points of an edge to the same coordinate value, */
   1178   /* either horizontally or vertically.                        */
   1179 
   1180   FT_LOCAL_DEF( void )
   1181   af_glyph_hints_align_edge_points( AF_GlyphHints  hints,
   1182                                     AF_Dimension   dim )
   1183   {
   1184     AF_AxisHints  axis          = & hints->axis[dim];
   1185     AF_Segment    segments      = axis->segments;
   1186     AF_Segment    segment_limit = segments + axis->num_segments;
   1187     AF_Segment    seg;
   1188 
   1189 
   1190     if ( dim == AF_DIMENSION_HORZ )
   1191     {
   1192       for ( seg = segments; seg < segment_limit; seg++ )
   1193       {
   1194         AF_Edge   edge = seg->edge;
   1195         AF_Point  point, first, last;
   1196 
   1197 
   1198         if ( !edge )
   1199           continue;
   1200 
   1201         first = seg->first;
   1202         last  = seg->last;
   1203         point = first;
   1204         for (;;)
   1205         {
   1206           point->x      = edge->pos;
   1207           point->flags |= AF_FLAG_TOUCH_X;
   1208 
   1209           if ( point == last )
   1210             break;
   1211 
   1212           point = point->next;
   1213         }
   1214       }
   1215     }
   1216     else
   1217     {
   1218       for ( seg = segments; seg < segment_limit; seg++ )
   1219       {
   1220         AF_Edge   edge = seg->edge;
   1221         AF_Point  point, first, last;
   1222 
   1223 
   1224         if ( !edge )
   1225           continue;
   1226 
   1227         first = seg->first;
   1228         last  = seg->last;
   1229         point = first;
   1230         for (;;)
   1231         {
   1232           point->y      = edge->pos;
   1233           point->flags |= AF_FLAG_TOUCH_Y;
   1234 
   1235           if ( point == last )
   1236             break;
   1237 
   1238           point = point->next;
   1239         }
   1240       }
   1241     }
   1242   }
   1243 
   1244 
   1245   /****************************************************************
   1246    *
   1247    *                    STRONG POINT INTERPOLATION
   1248    *
   1249    ****************************************************************/
   1250 
   1251 
   1252   /* Hint the strong points -- this is equivalent to the TrueType `IP' */
   1253   /* hinting instruction.                                              */
   1254 
   1255   FT_LOCAL_DEF( void )
   1256   af_glyph_hints_align_strong_points( AF_GlyphHints  hints,
   1257                                       AF_Dimension   dim )
   1258   {
   1259     AF_Point      points      = hints->points;
   1260     AF_Point      point_limit = points + hints->num_points;
   1261     AF_AxisHints  axis        = &hints->axis[dim];
   1262     AF_Edge       edges       = axis->edges;
   1263     AF_Edge       edge_limit  = edges + axis->num_edges;
   1264     FT_UInt       touch_flag;
   1265 
   1266 
   1267     if ( dim == AF_DIMENSION_HORZ )
   1268       touch_flag = AF_FLAG_TOUCH_X;
   1269     else
   1270       touch_flag  = AF_FLAG_TOUCH_Y;
   1271 
   1272     if ( edges < edge_limit )
   1273     {
   1274       AF_Point  point;
   1275       AF_Edge   edge;
   1276 
   1277 
   1278       for ( point = points; point < point_limit; point++ )
   1279       {
   1280         FT_Pos  u, ou, fu;  /* point position */
   1281         FT_Pos  delta;
   1282 
   1283 
   1284         if ( point->flags & touch_flag )
   1285           continue;
   1286 
   1287         /* if this point is candidate to weak interpolation, we       */
   1288         /* interpolate it after all strong points have been processed */
   1289 
   1290         if ( ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) )
   1291           continue;
   1292 
   1293         if ( dim == AF_DIMENSION_VERT )
   1294         {
   1295           u  = point->fy;
   1296           ou = point->oy;
   1297         }
   1298         else
   1299         {
   1300           u  = point->fx;
   1301           ou = point->ox;
   1302         }
   1303 
   1304         fu = u;
   1305 
   1306         /* is the point before the first edge? */
   1307         edge  = edges;
   1308         delta = edge->fpos - u;
   1309         if ( delta >= 0 )
   1310         {
   1311           u = edge->pos - ( edge->opos - ou );
   1312           goto Store_Point;
   1313         }
   1314 
   1315         /* is the point after the last edge? */
   1316         edge  = edge_limit - 1;
   1317         delta = u - edge->fpos;
   1318         if ( delta >= 0 )
   1319         {
   1320           u = edge->pos + ( ou - edge->opos );
   1321           goto Store_Point;
   1322         }
   1323 
   1324         {
   1325           FT_PtrDist  min, max, mid;
   1326           FT_Pos      fpos;
   1327 
   1328 
   1329           /* find enclosing edges */
   1330           min = 0;
   1331           max = edge_limit - edges;
   1332 
   1333 #if 1
   1334           /* for a small number of edges, a linear search is better */
   1335           if ( max <= 8 )
   1336           {
   1337             FT_PtrDist  nn;
   1338 
   1339 
   1340             for ( nn = 0; nn < max; nn++ )
   1341               if ( edges[nn].fpos >= u )
   1342                 break;
   1343 
   1344             if ( edges[nn].fpos == u )
   1345             {
   1346               u = edges[nn].pos;
   1347               goto Store_Point;
   1348             }
   1349             min = nn;
   1350           }
   1351           else
   1352 #endif
   1353           while ( min < max )
   1354           {
   1355             mid  = ( max + min ) >> 1;
   1356             edge = edges + mid;
   1357             fpos = edge->fpos;
   1358 
   1359             if ( u < fpos )
   1360               max = mid;
   1361             else if ( u > fpos )
   1362               min = mid + 1;
   1363             else
   1364             {
   1365               /* we are on the edge */
   1366               u = edge->pos;
   1367               goto Store_Point;
   1368             }
   1369           }
   1370 
   1371           /* point is not on an edge */
   1372           {
   1373             AF_Edge  before = edges + min - 1;
   1374             AF_Edge  after  = edges + min + 0;
   1375 
   1376 
   1377             /* assert( before && after && before != after ) */
   1378             if ( before->scale == 0 )
   1379               before->scale = FT_DivFix( after->pos - before->pos,
   1380                                          after->fpos - before->fpos );
   1381 
   1382             u = before->pos + FT_MulFix( fu - before->fpos,
   1383                                          before->scale );
   1384           }
   1385         }
   1386 
   1387       Store_Point:
   1388         /* save the point position */
   1389         if ( dim == AF_DIMENSION_HORZ )
   1390           point->x = u;
   1391         else
   1392           point->y = u;
   1393 
   1394         point->flags |= touch_flag;
   1395       }
   1396     }
   1397   }
   1398 
   1399 
   1400   /****************************************************************
   1401    *
   1402    *                    WEAK POINT INTERPOLATION
   1403    *
   1404    ****************************************************************/
   1405 
   1406 
   1407   /* Shift the original coordinates of all points between `p1' and */
   1408   /* `p2' to get hinted coordinates, using the same difference as  */
   1409   /* given by `ref'.                                               */
   1410 
   1411   static void
   1412   af_iup_shift( AF_Point  p1,
   1413                 AF_Point  p2,
   1414                 AF_Point  ref )
   1415   {
   1416     AF_Point  p;
   1417     FT_Pos    delta = ref->u - ref->v;
   1418 
   1419 
   1420     if ( delta == 0 )
   1421       return;
   1422 
   1423     for ( p = p1; p < ref; p++ )
   1424       p->u = p->v + delta;
   1425 
   1426     for ( p = ref + 1; p <= p2; p++ )
   1427       p->u = p->v + delta;
   1428   }
   1429 
   1430 
   1431   /* Interpolate the original coordinates of all points between `p1' and  */
   1432   /* `p2' to get hinted coordinates, using `ref1' and `ref2' as the       */
   1433   /* reference points.  The `u' and `v' members are the current and       */
   1434   /* original coordinate values, respectively.                            */
   1435   /*                                                                      */
   1436   /* Details can be found in the TrueType bytecode specification.         */
   1437 
   1438   static void
   1439   af_iup_interp( AF_Point  p1,
   1440                  AF_Point  p2,
   1441                  AF_Point  ref1,
   1442                  AF_Point  ref2 )
   1443   {
   1444     AF_Point  p;
   1445     FT_Pos    u, v1, v2, u1, u2, d1, d2;
   1446 
   1447 
   1448     if ( p1 > p2 )
   1449       return;
   1450 
   1451     if ( ref1->v > ref2->v )
   1452     {
   1453       p    = ref1;
   1454       ref1 = ref2;
   1455       ref2 = p;
   1456     }
   1457 
   1458     v1 = ref1->v;
   1459     v2 = ref2->v;
   1460     u1 = ref1->u;
   1461     u2 = ref2->u;
   1462     d1 = u1 - v1;
   1463     d2 = u2 - v2;
   1464 
   1465     if ( u1 == u2 || v1 == v2 )
   1466     {
   1467       for ( p = p1; p <= p2; p++ )
   1468       {
   1469         u = p->v;
   1470 
   1471         if ( u <= v1 )
   1472           u += d1;
   1473         else if ( u >= v2 )
   1474           u += d2;
   1475         else
   1476           u = u1;
   1477 
   1478         p->u = u;
   1479       }
   1480     }
   1481     else
   1482     {
   1483       FT_Fixed  scale = FT_DivFix( u2 - u1, v2 - v1 );
   1484 
   1485 
   1486       for ( p = p1; p <= p2; p++ )
   1487       {
   1488         u = p->v;
   1489 
   1490         if ( u <= v1 )
   1491           u += d1;
   1492         else if ( u >= v2 )
   1493           u += d2;
   1494         else
   1495           u = u1 + FT_MulFix( u - v1, scale );
   1496 
   1497         p->u = u;
   1498       }
   1499     }
   1500   }
   1501 
   1502 
   1503   /* Hint the weak points -- this is equivalent to the TrueType `IUP' */
   1504   /* hinting instruction.                                             */
   1505 
   1506   FT_LOCAL_DEF( void )
   1507   af_glyph_hints_align_weak_points( AF_GlyphHints  hints,
   1508                                     AF_Dimension   dim )
   1509   {
   1510     AF_Point   points        = hints->points;
   1511     AF_Point   point_limit   = points + hints->num_points;
   1512     AF_Point*  contour       = hints->contours;
   1513     AF_Point*  contour_limit = contour + hints->num_contours;
   1514     FT_UInt    touch_flag;
   1515     AF_Point   point;
   1516     AF_Point   end_point;
   1517     AF_Point   first_point;
   1518 
   1519 
   1520     /* PASS 1: Move segment points to edge positions */
   1521 
   1522     if ( dim == AF_DIMENSION_HORZ )
   1523     {
   1524       touch_flag = AF_FLAG_TOUCH_X;
   1525 
   1526       for ( point = points; point < point_limit; point++ )
   1527       {
   1528         point->u = point->x;
   1529         point->v = point->ox;
   1530       }
   1531     }
   1532     else
   1533     {
   1534       touch_flag = AF_FLAG_TOUCH_Y;
   1535 
   1536       for ( point = points; point < point_limit; point++ )
   1537       {
   1538         point->u = point->y;
   1539         point->v = point->oy;
   1540       }
   1541     }
   1542 
   1543     for ( ; contour < contour_limit; contour++ )
   1544     {
   1545       AF_Point  first_touched, last_touched;
   1546 
   1547 
   1548       point       = *contour;
   1549       end_point   = point->prev;
   1550       first_point = point;
   1551 
   1552       /* find first touched point */
   1553       for (;;)
   1554       {
   1555         if ( point > end_point )  /* no touched point in contour */
   1556           goto NextContour;
   1557 
   1558         if ( point->flags & touch_flag )
   1559           break;
   1560 
   1561         point++;
   1562       }
   1563 
   1564       first_touched = point;
   1565 
   1566       for (;;)
   1567       {
   1568         FT_ASSERT( point <= end_point                 &&
   1569                    ( point->flags & touch_flag ) != 0 );
   1570 
   1571         /* skip any touched neighbours */
   1572         while ( point < end_point                    &&
   1573                 ( point[1].flags & touch_flag ) != 0 )
   1574           point++;
   1575 
   1576         last_touched = point;
   1577 
   1578         /* find the next touched point, if any */
   1579         point++;
   1580         for (;;)
   1581         {
   1582           if ( point > end_point )
   1583             goto EndContour;
   1584 
   1585           if ( ( point->flags & touch_flag ) != 0 )
   1586             break;
   1587 
   1588           point++;
   1589         }
   1590 
   1591         /* interpolate between last_touched and point */
   1592         af_iup_interp( last_touched + 1, point - 1,
   1593                        last_touched, point );
   1594       }
   1595 
   1596     EndContour:
   1597       /* special case: only one point was touched */
   1598       if ( last_touched == first_touched )
   1599         af_iup_shift( first_point, end_point, first_touched );
   1600 
   1601       else /* interpolate the last part */
   1602       {
   1603         if ( last_touched < end_point )
   1604           af_iup_interp( last_touched + 1, end_point,
   1605                          last_touched, first_touched );
   1606 
   1607         if ( first_touched > points )
   1608           af_iup_interp( first_point, first_touched - 1,
   1609                          last_touched, first_touched );
   1610       }
   1611 
   1612     NextContour:
   1613       ;
   1614     }
   1615 
   1616     /* now save the interpolated values back to x/y */
   1617     if ( dim == AF_DIMENSION_HORZ )
   1618     {
   1619       for ( point = points; point < point_limit; point++ )
   1620         point->x = point->u;
   1621     }
   1622     else
   1623     {
   1624       for ( point = points; point < point_limit; point++ )
   1625         point->y = point->u;
   1626     }
   1627   }
   1628 
   1629 
   1630 #ifdef AF_CONFIG_OPTION_USE_WARPER
   1631 
   1632   /* Apply (small) warp scale and warp delta for given dimension. */
   1633 
   1634   FT_LOCAL_DEF( void )
   1635   af_glyph_hints_scale_dim( AF_GlyphHints  hints,
   1636                             AF_Dimension   dim,
   1637                             FT_Fixed       scale,
   1638                             FT_Pos         delta )
   1639   {
   1640     AF_Point  points       = hints->points;
   1641     AF_Point  points_limit = points + hints->num_points;
   1642     AF_Point  point;
   1643 
   1644 
   1645     if ( dim == AF_DIMENSION_HORZ )
   1646     {
   1647       for ( point = points; point < points_limit; point++ )
   1648         point->x = FT_MulFix( point->fx, scale ) + delta;
   1649     }
   1650     else
   1651     {
   1652       for ( point = points; point < points_limit; point++ )
   1653         point->y = FT_MulFix( point->fy, scale ) + delta;
   1654     }
   1655   }
   1656 
   1657 #endif /* AF_CONFIG_OPTION_USE_WARPER */
   1658 
   1659 /* END */
   1660