Home | History | Annotate | Download | only in autofit
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  afhints.c                                                              */
      4 /*                                                                         */
      5 /*    Auto-fitter hinting routines (body).                                 */
      6 /*                                                                         */
      7 /*  Copyright 2003, 2004, 2005, 2006, 2007, 2009, 2010 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 
     23 
     24   FT_LOCAL_DEF( FT_Error )
     25   af_axis_hints_new_segment( AF_AxisHints  axis,
     26                              FT_Memory     memory,
     27                              AF_Segment   *asegment )
     28   {
     29     FT_Error    error   = AF_Err_Ok;
     30     AF_Segment  segment = NULL;
     31 
     32 
     33     if ( axis->num_segments >= axis->max_segments )
     34     {
     35       FT_Int  old_max = axis->max_segments;
     36       FT_Int  new_max = old_max;
     37       FT_Int  big_max = (FT_Int)( FT_INT_MAX / sizeof ( *segment ) );
     38 
     39 
     40       if ( old_max >= big_max )
     41       {
     42         error = AF_Err_Out_Of_Memory;
     43         goto Exit;
     44       }
     45 
     46       new_max += ( new_max >> 2 ) + 4;
     47       if ( new_max < old_max || new_max > big_max )
     48         new_max = big_max;
     49 
     50       if ( FT_RENEW_ARRAY( axis->segments, old_max, new_max ) )
     51         goto Exit;
     52 
     53       axis->max_segments = new_max;
     54     }
     55 
     56     segment = axis->segments + axis->num_segments++;
     57 
     58   Exit:
     59     *asegment = segment;
     60     return error;
     61   }
     62 
     63 
     64   FT_LOCAL( FT_Error )
     65   af_axis_hints_new_edge( AF_AxisHints  axis,
     66                           FT_Int        fpos,
     67                           AF_Direction  dir,
     68                           FT_Memory     memory,
     69                           AF_Edge      *aedge )
     70   {
     71     FT_Error  error = AF_Err_Ok;
     72     AF_Edge   edge  = NULL;
     73     AF_Edge   edges;
     74 
     75 
     76     if ( axis->num_edges >= axis->max_edges )
     77     {
     78       FT_Int  old_max = axis->max_edges;
     79       FT_Int  new_max = old_max;
     80       FT_Int  big_max = (FT_Int)( FT_INT_MAX / sizeof ( *edge ) );
     81 
     82 
     83       if ( old_max >= big_max )
     84       {
     85         error = AF_Err_Out_Of_Memory;
     86         goto Exit;
     87       }
     88 
     89       new_max += ( new_max >> 2 ) + 4;
     90       if ( new_max < old_max || new_max > big_max )
     91         new_max = big_max;
     92 
     93       if ( FT_RENEW_ARRAY( axis->edges, old_max, new_max ) )
     94         goto Exit;
     95 
     96       axis->max_edges = new_max;
     97     }
     98 
     99     edges = axis->edges;
    100     edge  = edges + axis->num_edges;
    101 
    102     while ( edge > edges )
    103     {
    104       if ( edge[-1].fpos < fpos )
    105         break;
    106 
    107       /* we want the edge with same position and minor direction */
    108       /* to appear before those in the major one in the list     */
    109       if ( edge[-1].fpos == fpos && dir == axis->major_dir )
    110         break;
    111 
    112       edge[0] = edge[-1];
    113       edge--;
    114     }
    115 
    116     axis->num_edges++;
    117 
    118     FT_ZERO( edge );
    119     edge->fpos = (FT_Short)fpos;
    120     edge->dir  = (FT_Char)dir;
    121 
    122   Exit:
    123     *aedge = edge;
    124     return error;
    125   }
    126 
    127 
    128 #ifdef AF_DEBUG
    129 
    130 #include FT_CONFIG_STANDARD_LIBRARY_H
    131 
    132   static const char*
    133   af_dir_str( AF_Direction  dir )
    134   {
    135     const char*  result;
    136 
    137 
    138     switch ( dir )
    139     {
    140     case AF_DIR_UP:
    141       result = "up";
    142       break;
    143     case AF_DIR_DOWN:
    144       result = "down";
    145       break;
    146     case AF_DIR_LEFT:
    147       result = "left";
    148       break;
    149     case AF_DIR_RIGHT:
    150       result = "right";
    151       break;
    152     default:
    153       result = "none";
    154     }
    155 
    156     return result;
    157   }
    158 
    159 
    160 #define AF_INDEX_NUM( ptr, base )  ( (ptr) ? ( (ptr) - (base) ) : -1 )
    161 
    162 
    163   void
    164   af_glyph_hints_dump_points( AF_GlyphHints  hints )
    165   {
    166     AF_Point  points = hints->points;
    167     AF_Point  limit  = points + hints->num_points;
    168     AF_Point  point;
    169 
    170 
    171     printf( "Table of points:\n" );
    172     printf(   "  [ index |  xorg |  yorg |  xscale |  yscale "
    173               "|  xfit  |  yfit  |  flags ]\n" );
    174 
    175     for ( point = points; point < limit; point++ )
    176     {
    177       printf( "  [ %5d | %5d | %5d | %-5.2f | %-5.2f "
    178               "| %-5.2f | %-5.2f | %c%c%c%c%c%c ]\n",
    179               point - points,
    180               point->fx,
    181               point->fy,
    182               point->ox/64.0,
    183               point->oy/64.0,
    184               point->x/64.0,
    185               point->y/64.0,
    186               ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) ? 'w' : ' ',
    187               ( point->flags & AF_FLAG_INFLECTION )         ? 'i' : ' ',
    188               ( point->flags & AF_FLAG_EXTREMA_X )          ? '<' : ' ',
    189               ( point->flags & AF_FLAG_EXTREMA_Y )          ? 'v' : ' ',
    190               ( point->flags & AF_FLAG_ROUND_X )            ? '(' : ' ',
    191               ( point->flags & AF_FLAG_ROUND_Y )            ? 'u' : ' ');
    192     }
    193     printf( "\n" );
    194   }
    195 
    196 
    197   static const char*
    198   af_edge_flags_to_string( AF_Edge_Flags  flags )
    199   {
    200     static char  temp[32];
    201     int          pos = 0;
    202 
    203 
    204     if ( flags & AF_EDGE_ROUND )
    205     {
    206       ft_memcpy( temp + pos, "round", 5 );
    207       pos += 5;
    208     }
    209     if ( flags & AF_EDGE_SERIF )
    210     {
    211       if ( pos > 0 )
    212         temp[pos++] = ' ';
    213       ft_memcpy( temp + pos, "serif", 5 );
    214       pos += 5;
    215     }
    216     if ( pos == 0 )
    217       return "normal";
    218 
    219     temp[pos] = 0;
    220 
    221     return temp;
    222   }
    223 
    224 
    225   /* A function to dump the array of linked segments. */
    226   void
    227   af_glyph_hints_dump_segments( AF_GlyphHints  hints )
    228   {
    229     FT_Int  dimension;
    230 
    231 
    232     for ( dimension = 1; dimension >= 0; dimension-- )
    233     {
    234       AF_AxisHints  axis     = &hints->axis[dimension];
    235       AF_Segment    segments = axis->segments;
    236       AF_Segment    limit    = segments + axis->num_segments;
    237       AF_Segment    seg;
    238 
    239 
    240       printf ( "Table of %s segments:\n",
    241                dimension == AF_DIMENSION_HORZ ? "vertical" : "horizontal" );
    242       printf ( "  [ index |  pos  |  dir  | link | serif |"
    243                " height  | extra | flags    ]\n" );
    244 
    245       for ( seg = segments; seg < limit; seg++ )
    246       {
    247         printf ( "  [ %5d | %5.2g | %5s | %4d | %5d | %5d | %5d | %s ]\n",
    248                  seg - segments,
    249                  dimension == AF_DIMENSION_HORZ ? (int)seg->first->ox / 64.0
    250                                                 : (int)seg->first->oy / 64.0,
    251                  af_dir_str( (AF_Direction)seg->dir ),
    252                  AF_INDEX_NUM( seg->link, segments ),
    253                  AF_INDEX_NUM( seg->serif, segments ),
    254                  seg->height,
    255                  seg->height - ( seg->max_coord - seg->min_coord ),
    256                  af_edge_flags_to_string( seg->flags ) );
    257       }
    258       printf( "\n" );
    259     }
    260   }
    261 
    262 
    263   void
    264   af_glyph_hints_dump_edges( AF_GlyphHints  hints )
    265   {
    266     FT_Int  dimension;
    267 
    268 
    269     for ( dimension = 1; dimension >= 0; dimension-- )
    270     {
    271       AF_AxisHints  axis  = &hints->axis[dimension];
    272       AF_Edge       edges = axis->edges;
    273       AF_Edge       limit = edges + axis->num_edges;
    274       AF_Edge       edge;
    275 
    276 
    277       /*
    278        *  note: AF_DIMENSION_HORZ corresponds to _vertical_ edges
    279        *        since they have constant a X coordinate.
    280        */
    281       printf ( "Table of %s edges:\n",
    282                dimension == AF_DIMENSION_HORZ ? "vertical" : "horizontal" );
    283       printf ( "  [ index |  pos  |  dir  | link |"
    284                " serif | blue | opos  |  pos  | flags   ]\n" );
    285 
    286       for ( edge = edges; edge < limit; edge++ )
    287       {
    288         printf ( "  [ %5d | %5.2g | %5s | %4d |"
    289                  " %5d |   %c  | %5.2f | %5.2f | %s ]\n",
    290                  edge - edges,
    291                  (int)edge->opos / 64.0,
    292                  af_dir_str( (AF_Direction)edge->dir ),
    293                  AF_INDEX_NUM( edge->link, edges ),
    294                  AF_INDEX_NUM( edge->serif, edges ),
    295                  edge->blue_edge ? 'y' : 'n',
    296                  edge->opos / 64.0,
    297                  edge->pos / 64.0,
    298                  af_edge_flags_to_string( edge->flags ) );
    299       }
    300       printf( "\n" );
    301     }
    302   }
    303 
    304 #else /* !AF_DEBUG */
    305 
    306   /* these empty stubs are only used to link the `ftgrid' test program */
    307   /* when debugging is disabled                                        */
    308 
    309   void
    310   af_glyph_hints_dump_points( AF_GlyphHints  hints )
    311   {
    312     FT_UNUSED( hints );
    313   }
    314 
    315 
    316   void
    317   af_glyph_hints_dump_segments( AF_GlyphHints  hints )
    318   {
    319     FT_UNUSED( hints );
    320   }
    321 
    322 
    323   void
    324   af_glyph_hints_dump_edges( AF_GlyphHints  hints )
    325   {
    326     FT_UNUSED( hints );
    327   }
    328 
    329 #endif /* !AF_DEBUG */
    330 
    331 
    332   /* compute the direction value of a given vector */
    333   FT_LOCAL_DEF( AF_Direction )
    334   af_direction_compute( FT_Pos  dx,
    335                         FT_Pos  dy )
    336   {
    337     FT_Pos        ll, ss;  /* long and short arm lengths */
    338     AF_Direction  dir;     /* candidate direction        */
    339 
    340 
    341     if ( dy >= dx )
    342     {
    343       if ( dy >= -dx )
    344       {
    345         dir = AF_DIR_UP;
    346         ll  = dy;
    347         ss  = dx;
    348       }
    349       else
    350       {
    351         dir = AF_DIR_LEFT;
    352         ll  = -dx;
    353         ss  = dy;
    354       }
    355     }
    356     else /* dy < dx */
    357     {
    358       if ( dy >= -dx )
    359       {
    360         dir = AF_DIR_RIGHT;
    361         ll  = dx;
    362         ss  = dy;
    363       }
    364       else
    365       {
    366         dir = AF_DIR_DOWN;
    367         ll  = dy;
    368         ss  = dx;
    369       }
    370     }
    371 
    372     ss *= 14;
    373     if ( FT_ABS( ll ) <= FT_ABS( ss ) )
    374       dir = AF_DIR_NONE;
    375 
    376     return dir;
    377   }
    378 
    379 
    380   FT_LOCAL_DEF( void )
    381   af_glyph_hints_init( AF_GlyphHints  hints,
    382                        FT_Memory      memory )
    383   {
    384     FT_ZERO( hints );
    385     hints->memory = memory;
    386   }
    387 
    388 
    389   FT_LOCAL_DEF( void )
    390   af_glyph_hints_done( AF_GlyphHints  hints )
    391   {
    392     if ( hints && hints->memory )
    393     {
    394       FT_Memory  memory = hints->memory;
    395       int        dim;
    396 
    397 
    398       /*
    399        *  note that we don't need to free the segment and edge
    400        *  buffers, since they are really within the hints->points array
    401        */
    402       for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
    403       {
    404         AF_AxisHints  axis = &hints->axis[dim];
    405 
    406 
    407         axis->num_segments = 0;
    408         axis->max_segments = 0;
    409         FT_FREE( axis->segments );
    410 
    411         axis->num_edges    = 0;
    412         axis->max_edges    = 0;
    413         FT_FREE( axis->edges );
    414       }
    415 
    416       FT_FREE( hints->contours );
    417       hints->max_contours = 0;
    418       hints->num_contours = 0;
    419 
    420       FT_FREE( hints->points );
    421       hints->num_points = 0;
    422       hints->max_points = 0;
    423 
    424       hints->memory = NULL;
    425     }
    426   }
    427 
    428 
    429   FT_LOCAL_DEF( void )
    430   af_glyph_hints_rescale( AF_GlyphHints     hints,
    431                           AF_ScriptMetrics  metrics )
    432   {
    433     hints->metrics      = metrics;
    434     hints->scaler_flags = metrics->scaler.flags;
    435   }
    436 
    437 
    438   FT_LOCAL_DEF( FT_Error )
    439   af_glyph_hints_reload( AF_GlyphHints  hints,
    440                          FT_Outline*    outline )
    441   {
    442     FT_Error   error   = AF_Err_Ok;
    443     AF_Point   points;
    444     FT_UInt    old_max, new_max;
    445     FT_Fixed   x_scale = hints->x_scale;
    446     FT_Fixed   y_scale = hints->y_scale;
    447     FT_Pos     x_delta = hints->x_delta;
    448     FT_Pos     y_delta = hints->y_delta;
    449     FT_Memory  memory  = hints->memory;
    450 
    451 
    452     hints->num_points   = 0;
    453     hints->num_contours = 0;
    454 
    455     hints->axis[0].num_segments = 0;
    456     hints->axis[0].num_edges    = 0;
    457     hints->axis[1].num_segments = 0;
    458     hints->axis[1].num_edges    = 0;
    459 
    460     /* first of all, reallocate the contours array when necessary */
    461     new_max = (FT_UInt)outline->n_contours;
    462     old_max = hints->max_contours;
    463     if ( new_max > old_max )
    464     {
    465       new_max = ( new_max + 3 ) & ~3;
    466 
    467       if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) )
    468         goto Exit;
    469 
    470       hints->max_contours = new_max;
    471     }
    472 
    473     /*
    474      *  then reallocate the points arrays if necessary --
    475      *  note that we reserve two additional point positions, used to
    476      *  hint metrics appropriately
    477      */
    478     new_max = (FT_UInt)( outline->n_points + 2 );
    479     old_max = hints->max_points;
    480     if ( new_max > old_max )
    481     {
    482       new_max = ( new_max + 2 + 7 ) & ~7;
    483 
    484       if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) )
    485         goto Exit;
    486 
    487       hints->max_points = new_max;
    488     }
    489 
    490     hints->num_points   = outline->n_points;
    491     hints->num_contours = outline->n_contours;
    492 
    493     /* We can't rely on the value of `FT_Outline.flags' to know the fill   */
    494     /* direction used for a glyph, given that some fonts are broken (e.g., */
    495     /* the Arphic ones).  We thus recompute it each time we need to.       */
    496     /*                                                                     */
    497     hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_UP;
    498     hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_LEFT;
    499 
    500     if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT )
    501     {
    502       hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_DOWN;
    503       hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_RIGHT;
    504     }
    505 
    506     hints->x_scale = x_scale;
    507     hints->y_scale = y_scale;
    508     hints->x_delta = x_delta;
    509     hints->y_delta = y_delta;
    510 
    511     hints->xmin_delta = 0;
    512     hints->xmax_delta = 0;
    513 
    514     points = hints->points;
    515     if ( hints->num_points == 0 )
    516       goto Exit;
    517 
    518     {
    519       AF_Point  point;
    520       AF_Point  point_limit = points + hints->num_points;
    521 
    522 
    523       /* compute coordinates & Bezier flags, next and prev */
    524       {
    525         FT_Vector*  vec           = outline->points;
    526         char*       tag           = outline->tags;
    527         AF_Point    end           = points + outline->contours[0];
    528         AF_Point    prev          = end;
    529         FT_Int      contour_index = 0;
    530 
    531 
    532         for ( point = points; point < point_limit; point++, vec++, tag++ )
    533         {
    534           point->fx = (FT_Short)vec->x;
    535           point->fy = (FT_Short)vec->y;
    536           point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta;
    537           point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta;
    538 
    539           switch ( FT_CURVE_TAG( *tag ) )
    540           {
    541           case FT_CURVE_TAG_CONIC:
    542             point->flags = AF_FLAG_CONIC;
    543             break;
    544           case FT_CURVE_TAG_CUBIC:
    545             point->flags = AF_FLAG_CUBIC;
    546             break;
    547           default:
    548             point->flags = 0;
    549           }
    550 
    551           point->prev = prev;
    552           prev->next  = point;
    553           prev        = point;
    554 
    555           if ( point == end )
    556           {
    557             if ( ++contour_index < outline->n_contours )
    558             {
    559               end  = points + outline->contours[contour_index];
    560               prev = end;
    561             }
    562           }
    563         }
    564       }
    565 
    566       /* set-up the contours array */
    567       {
    568         AF_Point*  contour       = hints->contours;
    569         AF_Point*  contour_limit = contour + hints->num_contours;
    570         short*     end           = outline->contours;
    571         short      idx           = 0;
    572 
    573 
    574         for ( ; contour < contour_limit; contour++, end++ )
    575         {
    576           contour[0] = points + idx;
    577           idx        = (short)( end[0] + 1 );
    578         }
    579       }
    580 
    581       /* compute directions of in & out vectors */
    582       {
    583         AF_Point      first  = points;
    584         AF_Point      prev   = NULL;
    585         FT_Pos        in_x   = 0;
    586         FT_Pos        in_y   = 0;
    587         AF_Direction  in_dir = AF_DIR_NONE;
    588 
    589 
    590         for ( point = points; point < point_limit; point++ )
    591         {
    592           AF_Point  next;
    593           FT_Pos    out_x, out_y;
    594 
    595 
    596           if ( point == first )
    597           {
    598             prev   = first->prev;
    599             in_x   = first->fx - prev->fx;
    600             in_y   = first->fy - prev->fy;
    601             in_dir = af_direction_compute( in_x, in_y );
    602             first  = prev + 1;
    603           }
    604 
    605           point->in_dir = (FT_Char)in_dir;
    606 
    607           next  = point->next;
    608           out_x = next->fx - point->fx;
    609           out_y = next->fy - point->fy;
    610 
    611           in_dir         = af_direction_compute( out_x, out_y );
    612           point->out_dir = (FT_Char)in_dir;
    613 
    614           if ( point->flags & ( AF_FLAG_CONIC | AF_FLAG_CUBIC ) )
    615           {
    616           Is_Weak_Point:
    617             point->flags |= AF_FLAG_WEAK_INTERPOLATION;
    618           }
    619           else if ( point->out_dir == point->in_dir )
    620           {
    621             if ( point->out_dir != AF_DIR_NONE )
    622               goto Is_Weak_Point;
    623 
    624             if ( ft_corner_is_flat( in_x, in_y, out_x, out_y ) )
    625               goto Is_Weak_Point;
    626           }
    627           else if ( point->in_dir == -point->out_dir )
    628             goto Is_Weak_Point;
    629 
    630           in_x = out_x;
    631           in_y = out_y;
    632           prev = point;
    633         }
    634       }
    635     }
    636 
    637   Exit:
    638     return error;
    639   }
    640 
    641 
    642   FT_LOCAL_DEF( void )
    643   af_glyph_hints_save( AF_GlyphHints  hints,
    644                        FT_Outline*    outline )
    645   {
    646     AF_Point    point = hints->points;
    647     AF_Point    limit = point + hints->num_points;
    648     FT_Vector*  vec   = outline->points;
    649     char*       tag   = outline->tags;
    650 
    651 
    652     for ( ; point < limit; point++, vec++, tag++ )
    653     {
    654       vec->x = point->x;
    655       vec->y = point->y;
    656 
    657       if ( point->flags & AF_FLAG_CONIC )
    658         tag[0] = FT_CURVE_TAG_CONIC;
    659       else if ( point->flags & AF_FLAG_CUBIC )
    660         tag[0] = FT_CURVE_TAG_CUBIC;
    661       else
    662         tag[0] = FT_CURVE_TAG_ON;
    663     }
    664   }
    665 
    666 
    667   /****************************************************************
    668    *
    669    *                     EDGE POINT GRID-FITTING
    670    *
    671    ****************************************************************/
    672 
    673 
    674   FT_LOCAL_DEF( void )
    675   af_glyph_hints_align_edge_points( AF_GlyphHints  hints,
    676                                     AF_Dimension   dim )
    677   {
    678     AF_AxisHints  axis          = & hints->axis[dim];
    679     AF_Segment    segments      = axis->segments;
    680     AF_Segment    segment_limit = segments + axis->num_segments;
    681     AF_Segment    seg;
    682 
    683 
    684     if ( dim == AF_DIMENSION_HORZ )
    685     {
    686       for ( seg = segments; seg < segment_limit; seg++ )
    687       {
    688         AF_Edge   edge = seg->edge;
    689         AF_Point  point, first, last;
    690 
    691 
    692         if ( edge == NULL )
    693           continue;
    694 
    695         first = seg->first;
    696         last  = seg->last;
    697         point = first;
    698         for (;;)
    699         {
    700           point->x      = edge->pos;
    701           point->flags |= AF_FLAG_TOUCH_X;
    702 
    703           if ( point == last )
    704             break;
    705 
    706           point = point->next;
    707 
    708         }
    709       }
    710     }
    711     else
    712     {
    713       for ( seg = segments; seg < segment_limit; seg++ )
    714       {
    715         AF_Edge   edge = seg->edge;
    716         AF_Point  point, first, last;
    717 
    718 
    719         if ( edge == NULL )
    720           continue;
    721 
    722         first = seg->first;
    723         last  = seg->last;
    724         point = first;
    725         for (;;)
    726         {
    727           point->y      = edge->pos;
    728           point->flags |= AF_FLAG_TOUCH_Y;
    729 
    730           if ( point == last )
    731             break;
    732 
    733           point = point->next;
    734         }
    735       }
    736     }
    737   }
    738 
    739 
    740   /****************************************************************
    741    *
    742    *                    STRONG POINT INTERPOLATION
    743    *
    744    ****************************************************************/
    745 
    746 
    747   /* hint the strong points -- this is equivalent to the TrueType `IP' */
    748   /* hinting instruction                                               */
    749 
    750   FT_LOCAL_DEF( void )
    751   af_glyph_hints_align_strong_points( AF_GlyphHints  hints,
    752                                       AF_Dimension   dim )
    753   {
    754     AF_Point      points      = hints->points;
    755     AF_Point      point_limit = points + hints->num_points;
    756     AF_AxisHints  axis        = &hints->axis[dim];
    757     AF_Edge       edges       = axis->edges;
    758     AF_Edge       edge_limit  = edges + axis->num_edges;
    759     AF_Flags      touch_flag;
    760 
    761 
    762     if ( dim == AF_DIMENSION_HORZ )
    763       touch_flag = AF_FLAG_TOUCH_X;
    764     else
    765       touch_flag  = AF_FLAG_TOUCH_Y;
    766 
    767     if ( edges < edge_limit )
    768     {
    769       AF_Point  point;
    770       AF_Edge   edge;
    771 
    772 
    773       for ( point = points; point < point_limit; point++ )
    774       {
    775         FT_Pos  u, ou, fu;  /* point position */
    776         FT_Pos  delta;
    777 
    778 
    779         if ( point->flags & touch_flag )
    780           continue;
    781 
    782         /* if this point is candidate to weak interpolation, we       */
    783         /* interpolate it after all strong points have been processed */
    784 
    785         if (  ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) &&
    786              !( point->flags & AF_FLAG_INFLECTION )         )
    787           continue;
    788 
    789         if ( dim == AF_DIMENSION_VERT )
    790         {
    791           u  = point->fy;
    792           ou = point->oy;
    793         }
    794         else
    795         {
    796           u  = point->fx;
    797           ou = point->ox;
    798         }
    799 
    800         fu = u;
    801 
    802         /* is the point before the first edge? */
    803         edge  = edges;
    804         delta = edge->fpos - u;
    805         if ( delta >= 0 )
    806         {
    807           u = edge->pos - ( edge->opos - ou );
    808           goto Store_Point;
    809         }
    810 
    811         /* is the point after the last edge? */
    812         edge  = edge_limit - 1;
    813         delta = u - edge->fpos;
    814         if ( delta >= 0 )
    815         {
    816           u = edge->pos + ( ou - edge->opos );
    817           goto Store_Point;
    818         }
    819 
    820         {
    821           FT_PtrDist  min, max, mid;
    822           FT_Pos      fpos;
    823 
    824 
    825           /* find enclosing edges */
    826           min = 0;
    827           max = edge_limit - edges;
    828 
    829 #if 1
    830           /* for small edge counts, a linear search is better */
    831           if ( max <= 8 )
    832           {
    833             FT_PtrDist  nn;
    834 
    835             for ( nn = 0; nn < max; nn++ )
    836               if ( edges[nn].fpos >= u )
    837                 break;
    838 
    839             if ( edges[nn].fpos == u )
    840             {
    841               u = edges[nn].pos;
    842               goto Store_Point;
    843             }
    844             min = nn;
    845           }
    846           else
    847 #endif
    848           while ( min < max )
    849           {
    850             mid  = ( max + min ) >> 1;
    851             edge = edges + mid;
    852             fpos = edge->fpos;
    853 
    854             if ( u < fpos )
    855               max = mid;
    856             else if ( u > fpos )
    857               min = mid + 1;
    858             else
    859             {
    860               /* we are on the edge */
    861               u = edge->pos;
    862               goto Store_Point;
    863             }
    864           }
    865 
    866           {
    867             AF_Edge  before = edges + min - 1;
    868             AF_Edge  after  = edges + min + 0;
    869 
    870 
    871             /* assert( before && after && before != after ) */
    872             if ( before->scale == 0 )
    873               before->scale = FT_DivFix( after->pos - before->pos,
    874                                          after->fpos - before->fpos );
    875 
    876             u = before->pos + FT_MulFix( fu - before->fpos,
    877                                          before->scale );
    878           }
    879         }
    880 
    881       Store_Point:
    882         /* save the point position */
    883         if ( dim == AF_DIMENSION_HORZ )
    884           point->x = u;
    885         else
    886           point->y = u;
    887 
    888         point->flags |= touch_flag;
    889       }
    890     }
    891   }
    892 
    893 
    894   /****************************************************************
    895    *
    896    *                    WEAK POINT INTERPOLATION
    897    *
    898    ****************************************************************/
    899 
    900 
    901   static void
    902   af_iup_shift( AF_Point  p1,
    903                 AF_Point  p2,
    904                 AF_Point  ref )
    905   {
    906     AF_Point  p;
    907     FT_Pos    delta = ref->u - ref->v;
    908 
    909     if ( delta == 0 )
    910       return;
    911 
    912     for ( p = p1; p < ref; p++ )
    913       p->u = p->v + delta;
    914 
    915     for ( p = ref + 1; p <= p2; p++ )
    916       p->u = p->v + delta;
    917   }
    918 
    919 
    920   static void
    921   af_iup_interp( AF_Point  p1,
    922                  AF_Point  p2,
    923                  AF_Point  ref1,
    924                  AF_Point  ref2 )
    925   {
    926     AF_Point  p;
    927     FT_Pos    u;
    928     FT_Pos    v1 = ref1->v;
    929     FT_Pos    v2 = ref2->v;
    930     FT_Pos    d1 = ref1->u - v1;
    931     FT_Pos    d2 = ref2->u - v2;
    932 
    933 
    934     if ( p1 > p2 )
    935       return;
    936 
    937     if ( v1 == v2 )
    938     {
    939       for ( p = p1; p <= p2; p++ )
    940       {
    941         u = p->v;
    942 
    943         if ( u <= v1 )
    944           u += d1;
    945         else
    946           u += d2;
    947 
    948         p->u = u;
    949       }
    950       return;
    951     }
    952 
    953     if ( v1 < v2 )
    954     {
    955       for ( p = p1; p <= p2; p++ )
    956       {
    957         u = p->v;
    958 
    959         if ( u <= v1 )
    960           u += d1;
    961         else if ( u >= v2 )
    962           u += d2;
    963         else
    964           u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
    965 
    966         p->u = u;
    967       }
    968     }
    969     else
    970     {
    971       for ( p = p1; p <= p2; p++ )
    972       {
    973         u = p->v;
    974 
    975         if ( u <= v2 )
    976           u += d2;
    977         else if ( u >= v1 )
    978           u += d1;
    979         else
    980           u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
    981 
    982         p->u = u;
    983       }
    984     }
    985   }
    986 
    987 
    988   FT_LOCAL_DEF( void )
    989   af_glyph_hints_align_weak_points( AF_GlyphHints  hints,
    990                                     AF_Dimension   dim )
    991   {
    992     AF_Point   points        = hints->points;
    993     AF_Point   point_limit   = points + hints->num_points;
    994     AF_Point*  contour       = hints->contours;
    995     AF_Point*  contour_limit = contour + hints->num_contours;
    996     AF_Flags   touch_flag;
    997     AF_Point   point;
    998     AF_Point   end_point;
    999     AF_Point   first_point;
   1000 
   1001 
   1002     /* PASS 1: Move segment points to edge positions */
   1003 
   1004     if ( dim == AF_DIMENSION_HORZ )
   1005     {
   1006       touch_flag = AF_FLAG_TOUCH_X;
   1007 
   1008       for ( point = points; point < point_limit; point++ )
   1009       {
   1010         point->u = point->x;
   1011         point->v = point->ox;
   1012       }
   1013     }
   1014     else
   1015     {
   1016       touch_flag = AF_FLAG_TOUCH_Y;
   1017 
   1018       for ( point = points; point < point_limit; point++ )
   1019       {
   1020         point->u = point->y;
   1021         point->v = point->oy;
   1022       }
   1023     }
   1024 
   1025     point = points;
   1026 
   1027     for ( ; contour < contour_limit; contour++ )
   1028     {
   1029       AF_Point  first_touched, last_touched;
   1030 
   1031 
   1032       point       = *contour;
   1033       end_point   = point->prev;
   1034       first_point = point;
   1035 
   1036       /* find first touched point */
   1037       for (;;)
   1038       {
   1039         if ( point > end_point )  /* no touched point in contour */
   1040           goto NextContour;
   1041 
   1042         if ( point->flags & touch_flag )
   1043           break;
   1044 
   1045         point++;
   1046       }
   1047 
   1048       first_touched = point;
   1049       last_touched  = point;
   1050 
   1051       for (;;)
   1052       {
   1053         FT_ASSERT( point <= end_point &&
   1054                    ( point->flags & touch_flag ) != 0 );
   1055 
   1056         /* skip any touched neighbhours */
   1057         while ( point < end_point && ( point[1].flags & touch_flag ) != 0 )
   1058           point++;
   1059 
   1060         last_touched = point;
   1061 
   1062         /* find the next touched point, if any */
   1063         point ++;
   1064         for (;;)
   1065         {
   1066           if ( point > end_point )
   1067             goto EndContour;
   1068 
   1069           if ( ( point->flags & touch_flag ) != 0 )
   1070             break;
   1071 
   1072           point++;
   1073         }
   1074 
   1075         /* interpolate between last_touched and point */
   1076         af_iup_interp( last_touched + 1, point - 1,
   1077                        last_touched, point );
   1078       }
   1079 
   1080     EndContour:
   1081       /* special case: only one point was touched */
   1082       if ( last_touched == first_touched )
   1083       {
   1084         af_iup_shift( first_point, end_point, first_touched );
   1085       }
   1086       else /* interpolate the last part */
   1087       {
   1088         if ( last_touched < end_point )
   1089           af_iup_interp( last_touched + 1, end_point,
   1090                          last_touched, first_touched );
   1091 
   1092         if ( first_touched > points )
   1093           af_iup_interp( first_point, first_touched - 1,
   1094                          last_touched, first_touched );
   1095       }
   1096 
   1097     NextContour:
   1098       ;
   1099     }
   1100 
   1101     /* now save the interpolated values back to x/y */
   1102     if ( dim == AF_DIMENSION_HORZ )
   1103     {
   1104       for ( point = points; point < point_limit; point++ )
   1105         point->x = point->u;
   1106     }
   1107     else
   1108     {
   1109       for ( point = points; point < point_limit; point++ )
   1110         point->y = point->u;
   1111     }
   1112   }
   1113 
   1114 
   1115 #ifdef AF_USE_WARPER
   1116 
   1117   FT_LOCAL_DEF( void )
   1118   af_glyph_hints_scale_dim( AF_GlyphHints  hints,
   1119                             AF_Dimension   dim,
   1120                             FT_Fixed       scale,
   1121                             FT_Pos         delta )
   1122   {
   1123     AF_Point  points       = hints->points;
   1124     AF_Point  points_limit = points + hints->num_points;
   1125     AF_Point  point;
   1126 
   1127 
   1128     if ( dim == AF_DIMENSION_HORZ )
   1129     {
   1130       for ( point = points; point < points_limit; point++ )
   1131         point->x = FT_MulFix( point->fx, scale ) + delta;
   1132     }
   1133     else
   1134     {
   1135       for ( point = points; point < points_limit; point++ )
   1136         point->y = FT_MulFix( point->fy, scale ) + delta;
   1137     }
   1138   }
   1139 
   1140 #endif /* AF_USE_WARPER */
   1141 
   1142 /* END */
   1143