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