Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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