"Fossies" - the Fresh Open Source Software Archive

Member "SDL2_ttf-2.20.2/external/freetype/src/autofit/afhints.c" (25 May 2022, 46934 Bytes) of package /linux/misc/SDL2_ttf-2.20.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "afhints.c" see the Fossies "Dox" file reference documentation.

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