afhints.c

Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  afhints.c                                                              */
00004 /*                                                                         */
00005 /*    Auto-fitter hinting routines (body).                                 */
00006 /*                                                                         */
00007 /*  Copyright 2003, 2004, 2005, 2006, 2007, 2009 by                        */
00008 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
00009 /*                                                                         */
00010 /*  This file is part of the FreeType project, and may only be used,       */
00011 /*  modified, and distributed under the terms of the FreeType project      */
00012 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00013 /*  this file you indicate that you have read the license and              */
00014 /*  understand and accept it fully.                                        */
00015 /*                                                                         */
00016 /***************************************************************************/
00017 
00018 
00019 #include "afhints.h"
00020 #include "aferrors.h"
00021 #include FT_INTERNAL_CALC_H
00022 
00023 
00024   FT_LOCAL_DEF( FT_Error )
00025   af_axis_hints_new_segment( AF_AxisHints  axis,
00026                              FT_Memory     memory,
00027                              AF_Segment   *asegment )
00028   {
00029     FT_Error    error   = AF_Err_Ok;
00030     AF_Segment  segment = NULL;
00031 
00032 
00033     if ( axis->num_segments >= axis->max_segments )
00034     {
00035       FT_Int  old_max = axis->max_segments;
00036       FT_Int  new_max = old_max;
00037       FT_Int  big_max = (FT_Int)( FT_INT_MAX / sizeof ( *segment ) );
00038 
00039 
00040       if ( old_max >= big_max )
00041       {
00042         error = AF_Err_Out_Of_Memory;
00043         goto Exit;
00044       }
00045 
00046       new_max += ( new_max >> 2 ) + 4;
00047       if ( new_max < old_max || new_max > big_max )
00048         new_max = big_max;
00049 
00050       if ( FT_RENEW_ARRAY( axis->segments, old_max, new_max ) )
00051         goto Exit;
00052 
00053       axis->max_segments = new_max;
00054     }
00055 
00056     segment = axis->segments + axis->num_segments++;
00057 
00058   Exit:
00059     *asegment = segment;
00060     return error;
00061   }
00062 
00063 
00064   FT_LOCAL( FT_Error )
00065   af_axis_hints_new_edge( AF_AxisHints  axis,
00066                           FT_Int        fpos,
00067                           AF_Direction  dir,
00068                           FT_Memory     memory,
00069                           AF_Edge      *aedge )
00070   {
00071     FT_Error  error = AF_Err_Ok;
00072     AF_Edge   edge  = NULL;
00073     AF_Edge   edges;
00074 
00075 
00076     if ( axis->num_edges >= axis->max_edges )
00077     {
00078       FT_Int  old_max = axis->max_edges;
00079       FT_Int  new_max = old_max;
00080       FT_Int  big_max = (FT_Int)( FT_INT_MAX / sizeof ( *edge ) );
00081 
00082 
00083       if ( old_max >= big_max )
00084       {
00085         error = AF_Err_Out_Of_Memory;
00086         goto Exit;
00087       }
00088 
00089       new_max += ( new_max >> 2 ) + 4;
00090       if ( new_max < old_max || new_max > big_max )
00091         new_max = big_max;
00092 
00093       if ( FT_RENEW_ARRAY( axis->edges, old_max, new_max ) )
00094         goto Exit;
00095 
00096       axis->max_edges = new_max;
00097     }
00098 
00099     edges = axis->edges;
00100     edge  = edges + axis->num_edges;
00101 
00102     while ( edge > edges )
00103     {
00104       if ( edge[-1].fpos < fpos )
00105         break;
00106 
00107       /* we want the edge with same position and minor direction */
00108       /* to appear before those in the major one in the list     */
00109       if ( edge[-1].fpos == fpos && dir == axis->major_dir )
00110         break;
00111 
00112       edge[0] = edge[-1];
00113       edge--;
00114     }
00115 
00116     axis->num_edges++;
00117 
00118     FT_ZERO( edge );
00119     edge->fpos = (FT_Short)fpos;
00120     edge->dir  = (FT_Char)dir;
00121 
00122   Exit:
00123     *aedge = edge;
00124     return error;
00125   }
00126 
00127 
00128 #ifdef AF_DEBUG
00129 
00130 #include FT_CONFIG_STANDARD_LIBRARY_H
00131 
00132   static const char*
00133   af_dir_str( AF_Direction  dir )
00134   {
00135     const char*  result;
00136 
00137 
00138     switch ( dir )
00139     {
00140     case AF_DIR_UP:
00141       result = "up";
00142       break;
00143     case AF_DIR_DOWN:
00144       result = "down";
00145       break;
00146     case AF_DIR_LEFT:
00147       result = "left";
00148       break;
00149     case AF_DIR_RIGHT:
00150       result = "right";
00151       break;
00152     default:
00153       result = "none";
00154     }
00155 
00156     return result;
00157   }
00158 
00159 
00160 #define AF_INDEX_NUM( ptr, base )  ( (ptr) ? ( (ptr) - (base) ) : -1 )
00161 
00162 
00163   void
00164   af_glyph_hints_dump_points( AF_GlyphHints  hints )
00165   {
00166     AF_Point  points = hints->points;
00167     AF_Point  limit  = points + hints->num_points;
00168     AF_Point  point;
00169 
00170 
00171     printf( "Table of points:\n" );
00172     printf(   "  [ index |  xorg |  yorg |  xscale |  yscale "
00173               "|  xfit  |  yfit  |  flags ]\n" );
00174 
00175     for ( point = points; point < limit; point++ )
00176     {
00177       printf( "  [ %5d | %5d | %5d | %-5.2f | %-5.2f "
00178               "| %-5.2f | %-5.2f | %c%c%c%c%c%c ]\n",
00179               point - points,
00180               point->fx,
00181               point->fy,
00182               point->ox/64.0,
00183               point->oy/64.0,
00184               point->x/64.0,
00185               point->y/64.0,
00186               ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) ? 'w' : ' ',
00187               ( point->flags & AF_FLAG_INFLECTION )         ? 'i' : ' ',
00188               ( point->flags & AF_FLAG_EXTREMA_X )          ? '<' : ' ',
00189               ( point->flags & AF_FLAG_EXTREMA_Y )          ? 'v' : ' ',
00190               ( point->flags & AF_FLAG_ROUND_X )            ? '(' : ' ',
00191               ( point->flags & AF_FLAG_ROUND_Y )            ? 'u' : ' ');
00192     }
00193     printf( "\n" );
00194   }
00195 
00196 
00197   static const char*
00198   af_edge_flags_to_string( AF_Edge_Flags  flags )
00199   {
00200     static char  temp[32];
00201     int          pos = 0;
00202 
00203 
00204     if ( flags & AF_EDGE_ROUND )
00205     {
00206       ft_memcpy( temp + pos, "round", 5 );
00207       pos += 5;
00208     }
00209     if ( flags & AF_EDGE_SERIF )
00210     {
00211       if ( pos > 0 )
00212         temp[pos++] = ' ';
00213       ft_memcpy( temp + pos, "serif", 5 );
00214       pos += 5;
00215     }
00216     if ( pos == 0 )
00217       return "normal";
00218 
00219     temp[pos] = 0;
00220 
00221     return temp;
00222   }
00223 
00224 
00225   /* A function to dump the array of linked segments. */
00226   void
00227   af_glyph_hints_dump_segments( AF_GlyphHints  hints )
00228   {
00229     FT_Int  dimension;
00230 
00231 
00232     for ( dimension = 1; dimension >= 0; dimension-- )
00233     {
00234       AF_AxisHints  axis     = &hints->axis[dimension];
00235       AF_Segment    segments = axis->segments;
00236       AF_Segment    limit    = segments + axis->num_segments;
00237       AF_Segment    seg;
00238 
00239 
00240       printf ( "Table of %s segments:\n",
00241                dimension == AF_DIMENSION_HORZ ? "vertical" : "horizontal" );
00242       printf ( "  [ index |  pos  |  dir  | link | serif |"
00243                " height  | extra | flags    ]\n" );
00244 
00245       for ( seg = segments; seg < limit; seg++ )
00246       {
00247         printf ( "  [ %5d | %5.2g | %5s | %4d | %5d | %5d | %5d | %s ]\n",
00248                  seg - segments,
00249                  dimension == AF_DIMENSION_HORZ ? (int)seg->first->ox / 64.0
00250                                                 : (int)seg->first->oy / 64.0,
00251                  af_dir_str( (AF_Direction)seg->dir ),
00252                  AF_INDEX_NUM( seg->link, segments ),
00253                  AF_INDEX_NUM( seg->serif, segments ),
00254                  seg->height,
00255                  seg->height - ( seg->max_coord - seg->min_coord ),
00256                  af_edge_flags_to_string( seg->flags ) );
00257       }
00258       printf( "\n" );
00259     }
00260   }
00261 
00262 
00263   void
00264   af_glyph_hints_dump_edges( AF_GlyphHints  hints )
00265   {
00266     FT_Int  dimension;
00267 
00268 
00269     for ( dimension = 1; dimension >= 0; dimension-- )
00270     {
00271       AF_AxisHints  axis  = &hints->axis[dimension];
00272       AF_Edge       edges = axis->edges;
00273       AF_Edge       limit = edges + axis->num_edges;
00274       AF_Edge       edge;
00275 
00276 
00277       /*
00278        *  note: AF_DIMENSION_HORZ corresponds to _vertical_ edges
00279        *        since they have constant a X coordinate.
00280        */
00281       printf ( "Table of %s edges:\n",
00282                dimension == AF_DIMENSION_HORZ ? "vertical" : "horizontal" );
00283       printf ( "  [ index |  pos  |  dir  | link |"
00284                " serif | blue | opos  |  pos  | flags   ]\n" );
00285 
00286       for ( edge = edges; edge < limit; edge++ )
00287       {
00288         printf ( "  [ %5d | %5.2g | %5s | %4d |"
00289                  " %5d |   %c  | %5.2f | %5.2f | %s ]\n",
00290                  edge - edges,
00291                  (int)edge->opos / 64.0,
00292                  af_dir_str( (AF_Direction)edge->dir ),
00293                  AF_INDEX_NUM( edge->link, edges ),
00294                  AF_INDEX_NUM( edge->serif, edges ),
00295                  edge->blue_edge ? 'y' : 'n',
00296                  edge->opos / 64.0,
00297                  edge->pos / 64.0,
00298                  af_edge_flags_to_string( edge->flags ) );
00299       }
00300       printf( "\n" );
00301     }
00302   }
00303 
00304 #else /* !AF_DEBUG */
00305 
00306   /* these empty stubs are only used to link the `ftgrid' test program */
00307   /* when debugging is disabled                                        */
00308 
00309   void
00310   af_glyph_hints_dump_points( AF_GlyphHints  hints )
00311   {
00312     FT_UNUSED( hints );
00313   }
00314 
00315 
00316   void
00317   af_glyph_hints_dump_segments( AF_GlyphHints  hints )
00318   {
00319     FT_UNUSED( hints );
00320   }
00321 
00322 
00323   void
00324   af_glyph_hints_dump_edges( AF_GlyphHints  hints )
00325   {
00326     FT_UNUSED( hints );
00327   }
00328 
00329 #endif /* !AF_DEBUG */
00330 
00331 
00332   /* compute the direction value of a given vector */
00333   FT_LOCAL_DEF( AF_Direction )
00334   af_direction_compute( FT_Pos  dx,
00335                         FT_Pos  dy )
00336   {
00337     FT_Pos        ll, ss;  /* long and short arm lengths */
00338     AF_Direction  dir;     /* candidate direction        */
00339 
00340 
00341     if ( dy >= dx )
00342     {
00343       if ( dy >= -dx )
00344       {
00345         dir = AF_DIR_UP;
00346         ll  = dy;
00347         ss  = dx;
00348       }
00349       else
00350       {
00351         dir = AF_DIR_LEFT;
00352         ll  = -dx;
00353         ss  = dy;
00354       }
00355     }
00356     else /* dy < dx */
00357     {
00358       if ( dy >= -dx )
00359       {
00360         dir = AF_DIR_RIGHT;
00361         ll  = dx;
00362         ss  = dy;
00363       }
00364       else
00365       {
00366         dir = AF_DIR_DOWN;
00367         ll  = dy;
00368         ss  = dx;
00369       }
00370     }
00371 
00372     ss *= 14;
00373     if ( FT_ABS( ll ) <= FT_ABS( ss ) )
00374       dir = AF_DIR_NONE;
00375 
00376     return dir;
00377   }
00378 
00379 
00380   /* compute all inflex points in a given glyph */
00381 
00382   static void
00383   af_glyph_hints_compute_inflections( AF_GlyphHints  hints )
00384   {
00385     AF_Point*  contour       = hints->contours;
00386     AF_Point*  contour_limit = contour + hints->num_contours;
00387 
00388 
00389     /* do each contour separately */
00390     for ( ; contour < contour_limit; contour++ )
00391     {
00392       AF_Point  point = contour[0];
00393       AF_Point  first = point;
00394       AF_Point  start = point;
00395       AF_Point  end   = point;
00396       AF_Point  before;
00397       AF_Point  after;
00398       FT_Pos    in_x, in_y, out_x, out_y;
00399       AF_Angle  orient_prev, orient_cur;
00400       FT_Int    finished = 0;
00401 
00402 
00403       /* compute first segment in contour */
00404       first = point;
00405 
00406       start = end = first;
00407       do
00408       {
00409         end = end->next;
00410         if ( end == first )
00411           goto Skip;
00412 
00413         in_x = end->fx - start->fx;
00414         in_y = end->fy - start->fy;
00415 
00416       } while ( in_x == 0 && in_y == 0 );
00417 
00418       /* extend the segment start whenever possible */
00419       before = start;
00420       do
00421       {
00422         do
00423         {
00424           start  = before;
00425           before = before->prev;
00426           if ( before == first )
00427             goto Skip;
00428 
00429           out_x = start->fx - before->fx;
00430           out_y = start->fy - before->fy;
00431 
00432         } while ( out_x == 0 && out_y == 0 );
00433 
00434         orient_prev = ft_corner_orientation( in_x, in_y, out_x, out_y );
00435 
00436       } while ( orient_prev == 0 );
00437 
00438       first = start;
00439 
00440       in_x = out_x;
00441       in_y = out_y;
00442 
00443       /* now process all segments in the contour */
00444       do
00445       {
00446         /* first, extend current segment's end whenever possible */
00447         after = end;
00448         do
00449         {
00450           do
00451           {
00452             end   = after;
00453             after = after->next;
00454             if ( after == first )
00455               finished = 1;
00456 
00457             out_x = after->fx - end->fx;
00458             out_y = after->fy - end->fy;
00459 
00460           } while ( out_x == 0 && out_y == 0 );
00461 
00462           orient_cur = ft_corner_orientation( in_x, in_y, out_x, out_y );
00463 
00464         } while ( orient_cur == 0 );
00465 
00466         if ( ( orient_prev + orient_cur ) == 0 )
00467         {
00468           /* we have an inflection point here */
00469           do
00470           {
00471             start->flags |= AF_FLAG_INFLECTION;
00472             start = start->next;
00473 
00474           } while ( start != end );
00475 
00476           start->flags |= AF_FLAG_INFLECTION;
00477         }
00478 
00479         start = end;
00480         end   = after;
00481 
00482         orient_prev = orient_cur;
00483         in_x        = out_x;
00484         in_y        = out_y;
00485 
00486       } while ( !finished );
00487 
00488     Skip:
00489       ;
00490     }
00491   }
00492 
00493 
00494   FT_LOCAL_DEF( void )
00495   af_glyph_hints_init( AF_GlyphHints  hints,
00496                        FT_Memory      memory )
00497   {
00498     FT_ZERO( hints );
00499     hints->memory = memory;
00500   }
00501 
00502 
00503   FT_LOCAL_DEF( void )
00504   af_glyph_hints_done( AF_GlyphHints  hints )
00505   {
00506     if ( hints && hints->memory )
00507     {
00508       FT_Memory  memory = hints->memory;
00509       int        dim;
00510 
00511 
00512       /*
00513        *  note that we don't need to free the segment and edge
00514        *  buffers, since they are really within the hints->points array
00515        */
00516       for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
00517       {
00518         AF_AxisHints  axis = &hints->axis[dim];
00519 
00520 
00521         axis->num_segments = 0;
00522         axis->max_segments = 0;
00523         FT_FREE( axis->segments );
00524 
00525         axis->num_edges    = 0;
00526         axis->max_edges    = 0;
00527         FT_FREE( axis->edges );
00528       }
00529 
00530       FT_FREE( hints->contours );
00531       hints->max_contours = 0;
00532       hints->num_contours = 0;
00533 
00534       FT_FREE( hints->points );
00535       hints->num_points = 0;
00536       hints->max_points = 0;
00537 
00538       hints->memory = NULL;
00539     }
00540   }
00541 
00542 
00543   FT_LOCAL_DEF( void )
00544   af_glyph_hints_rescale( AF_GlyphHints     hints,
00545                           AF_ScriptMetrics  metrics )
00546   {
00547     hints->metrics      = metrics;
00548     hints->scaler_flags = metrics->scaler.flags;
00549   }
00550 
00551 
00552   FT_LOCAL_DEF( FT_Error )
00553   af_glyph_hints_reload( AF_GlyphHints  hints,
00554                          FT_Outline*    outline,
00555                          FT_Bool        get_inflections )
00556   {
00557     FT_Error   error   = AF_Err_Ok;
00558     AF_Point   points;
00559     FT_UInt    old_max, new_max;
00560     FT_Fixed   x_scale = hints->x_scale;
00561     FT_Fixed   y_scale = hints->y_scale;
00562     FT_Pos     x_delta = hints->x_delta;
00563     FT_Pos     y_delta = hints->y_delta;
00564     FT_Memory  memory  = hints->memory;
00565 
00566 
00567     hints->num_points   = 0;
00568     hints->num_contours = 0;
00569 
00570     hints->axis[0].num_segments = 0;
00571     hints->axis[0].num_edges    = 0;
00572     hints->axis[1].num_segments = 0;
00573     hints->axis[1].num_edges    = 0;
00574 
00575     /* first of all, reallocate the contours array when necessary */
00576     new_max = (FT_UInt)outline->n_contours;
00577     old_max = hints->max_contours;
00578     if ( new_max > old_max )
00579     {
00580       new_max = ( new_max + 3 ) & ~3;
00581 
00582       if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) )
00583         goto Exit;
00584 
00585       hints->max_contours = new_max;
00586     }
00587 
00588     /*
00589      *  then reallocate the points arrays if necessary --
00590      *  note that we reserve two additional point positions, used to
00591      *  hint metrics appropriately
00592      */
00593     new_max = (FT_UInt)( outline->n_points + 2 );
00594     old_max = hints->max_points;
00595     if ( new_max > old_max )
00596     {
00597       new_max = ( new_max + 2 + 7 ) & ~7;
00598 
00599       if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) )
00600         goto Exit;
00601 
00602       hints->max_points = new_max;
00603     }
00604 
00605     hints->num_points   = outline->n_points;
00606     hints->num_contours = outline->n_contours;
00607 
00608     /* We can't rely on the value of `FT_Outline.flags' to know the fill   */
00609     /* direction used for a glyph, given that some fonts are broken (e.g., */
00610     /* the Arphic ones).  We thus recompute it each time we need to.       */
00611     /*                                                                     */
00612     hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_UP;
00613     hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_LEFT;
00614 
00615     if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT )
00616     {
00617       hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_DOWN;
00618       hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_RIGHT;
00619     }
00620 
00621     hints->x_scale = x_scale;
00622     hints->y_scale = y_scale;
00623     hints->x_delta = x_delta;
00624     hints->y_delta = y_delta;
00625 
00626     hints->xmin_delta = 0;
00627     hints->xmax_delta = 0;
00628 
00629     points = hints->points;
00630     if ( hints->num_points == 0 )
00631       goto Exit;
00632 
00633     {
00634       AF_Point  point;
00635       AF_Point  point_limit = points + hints->num_points;
00636 
00637 
00638       /* compute coordinates & Bezier flags, next and prev */
00639       {
00640         FT_Vector*  vec           = outline->points;
00641         char*       tag           = outline->tags;
00642         AF_Point    first         = points;
00643         AF_Point    end           = points + outline->contours[0];
00644         AF_Point    prev          = end;
00645         FT_Int      contour_index = 0;
00646 
00647 
00648         FT_UNUSED( first );
00649         for ( point = points; point < point_limit; point++, vec++, tag++ )
00650         {
00651           point->fx = (FT_Short)vec->x;
00652           point->fy = (FT_Short)vec->y;
00653           point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta;
00654           point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta;
00655 
00656           switch ( FT_CURVE_TAG( *tag ) )
00657           {
00658           case FT_CURVE_TAG_CONIC:
00659             point->flags = AF_FLAG_CONIC;
00660             break;
00661           case FT_CURVE_TAG_CUBIC:
00662             point->flags = AF_FLAG_CUBIC;
00663             break;
00664           default:
00665             point->flags = 0;
00666           }
00667 
00668           point->prev = prev;
00669           prev->next  = point;
00670           prev        = point;
00671 
00672           if ( point == end )
00673           {
00674             if ( ++contour_index < outline->n_contours )
00675             {
00676               first = point + 1;
00677               end   = points + outline->contours[contour_index];
00678               prev  = end;
00679             }
00680           }
00681         }
00682       }
00683 
00684       /* set-up the contours array */
00685       {
00686         AF_Point*  contour       = hints->contours;
00687         AF_Point*  contour_limit = contour + hints->num_contours;
00688         short*     end           = outline->contours;
00689         short      idx           = 0;
00690 
00691 
00692         for ( ; contour < contour_limit; contour++, end++ )
00693         {
00694           contour[0] = points + idx;
00695           idx        = (short)( end[0] + 1 );
00696         }
00697       }
00698 
00699       /* compute directions of in & out vectors */
00700       {
00701         AF_Point      first  = points;
00702         AF_Point      prev   = NULL;
00703         FT_Pos        in_x   = 0;
00704         FT_Pos        in_y   = 0;
00705         AF_Direction  in_dir = AF_DIR_NONE;
00706 
00707 
00708         for ( point = points; point < point_limit; point++ )
00709         {
00710           AF_Point  next;
00711           FT_Pos    out_x, out_y;
00712 
00713 
00714           if ( point == first )
00715           {
00716             prev   = first->prev;
00717             in_x   = first->fx - prev->fx;
00718             in_y   = first->fy - prev->fy;
00719             in_dir = af_direction_compute( in_x, in_y );
00720             first  = prev + 1;
00721           }
00722 
00723           point->in_dir = (FT_Char)in_dir;
00724 
00725           next  = point->next;
00726           out_x = next->fx - point->fx;
00727           out_y = next->fy - point->fy;
00728 
00729           in_dir         = af_direction_compute( out_x, out_y );
00730           point->out_dir = (FT_Char)in_dir;
00731 
00732           if ( point->flags & ( AF_FLAG_CONIC | AF_FLAG_CUBIC ) )
00733           {
00734           Is_Weak_Point:
00735             point->flags |= AF_FLAG_WEAK_INTERPOLATION;
00736           }
00737           else if ( point->out_dir == point->in_dir )
00738           {
00739             if ( point->out_dir != AF_DIR_NONE )
00740               goto Is_Weak_Point;
00741 
00742             if ( ft_corner_is_flat( in_x, in_y, out_x, out_y ) )
00743               goto Is_Weak_Point;
00744           }
00745           else if ( point->in_dir == -point->out_dir )
00746             goto Is_Weak_Point;
00747 
00748           in_x = out_x;
00749           in_y = out_y;
00750           prev = point;
00751         }
00752       }
00753     }
00754 
00755     /* compute inflection points --                 */
00756     /* disabled due to no longer perceived benefits */
00757     if ( 0 && get_inflections )
00758       af_glyph_hints_compute_inflections( hints );
00759 
00760   Exit:
00761     return error;
00762   }
00763 
00764 
00765   FT_LOCAL_DEF( void )
00766   af_glyph_hints_save( AF_GlyphHints  hints,
00767                        FT_Outline*    outline )
00768   {
00769     AF_Point    point = hints->points;
00770     AF_Point    limit = point + hints->num_points;
00771     FT_Vector*  vec   = outline->points;
00772     char*       tag   = outline->tags;
00773 
00774 
00775     for ( ; point < limit; point++, vec++, tag++ )
00776     {
00777       vec->x = point->x;
00778       vec->y = point->y;
00779 
00780       if ( point->flags & AF_FLAG_CONIC )
00781         tag[0] = FT_CURVE_TAG_CONIC;
00782       else if ( point->flags & AF_FLAG_CUBIC )
00783         tag[0] = FT_CURVE_TAG_CUBIC;
00784       else
00785         tag[0] = FT_CURVE_TAG_ON;
00786     }
00787   }
00788 
00789 
00790   /****************************************************************
00791    *
00792    *                     EDGE POINT GRID-FITTING
00793    *
00794    ****************************************************************/
00795 
00796 
00797   FT_LOCAL_DEF( void )
00798   af_glyph_hints_align_edge_points( AF_GlyphHints  hints,
00799                                     AF_Dimension   dim )
00800   {
00801     AF_AxisHints  axis          = & hints->axis[dim];
00802     AF_Segment    segments      = axis->segments;
00803     AF_Segment    segment_limit = segments + axis->num_segments;
00804     AF_Segment    seg;
00805 
00806 
00807     if ( dim == AF_DIMENSION_HORZ )
00808     {
00809       for ( seg = segments; seg < segment_limit; seg++ )
00810       {
00811         AF_Edge   edge = seg->edge;
00812         AF_Point  point, first, last;
00813 
00814 
00815         if ( edge == NULL )
00816           continue;
00817 
00818         first = seg->first;
00819         last  = seg->last;
00820         point = first;
00821         for (;;)
00822         {
00823           point->x      = edge->pos;
00824           point->flags |= AF_FLAG_TOUCH_X;
00825 
00826           if ( point == last )
00827             break;
00828 
00829           point = point->next;
00830 
00831         }
00832       }
00833     }
00834     else
00835     {
00836       for ( seg = segments; seg < segment_limit; seg++ )
00837       {
00838         AF_Edge   edge = seg->edge;
00839         AF_Point  point, first, last;
00840 
00841 
00842         if ( edge == NULL )
00843           continue;
00844 
00845         first = seg->first;
00846         last  = seg->last;
00847         point = first;
00848         for (;;)
00849         {
00850           point->y      = edge->pos;
00851           point->flags |= AF_FLAG_TOUCH_Y;
00852 
00853           if ( point == last )
00854             break;
00855 
00856           point = point->next;
00857         }
00858       }
00859     }
00860   }
00861 
00862 
00863   /****************************************************************
00864    *
00865    *                    STRONG POINT INTERPOLATION
00866    *
00867    ****************************************************************/
00868 
00869 
00870   /* hint the strong points -- this is equivalent to the TrueType `IP' */
00871   /* hinting instruction                                               */
00872 
00873   FT_LOCAL_DEF( void )
00874   af_glyph_hints_align_strong_points( AF_GlyphHints  hints,
00875                                       AF_Dimension   dim )
00876   {
00877     AF_Point      points      = hints->points;
00878     AF_Point      point_limit = points + hints->num_points;
00879     AF_AxisHints  axis        = &hints->axis[dim];
00880     AF_Edge       edges       = axis->edges;
00881     AF_Edge       edge_limit  = edges + axis->num_edges;
00882     AF_Flags      touch_flag;
00883 
00884 
00885     if ( dim == AF_DIMENSION_HORZ )
00886       touch_flag = AF_FLAG_TOUCH_X;
00887     else
00888       touch_flag  = AF_FLAG_TOUCH_Y;
00889 
00890     if ( edges < edge_limit )
00891     {
00892       AF_Point  point;
00893       AF_Edge   edge;
00894 
00895 
00896       for ( point = points; point < point_limit; point++ )
00897       {
00898         FT_Pos  u, ou, fu;  /* point position */
00899         FT_Pos  delta;
00900 
00901 
00902         if ( point->flags & touch_flag )
00903           continue;
00904 
00905         /* if this point is candidate to weak interpolation, we       */
00906         /* interpolate it after all strong points have been processed */
00907 
00908         if (  ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) &&
00909              !( point->flags & AF_FLAG_INFLECTION )         )
00910           continue;
00911 
00912         if ( dim == AF_DIMENSION_VERT )
00913         {
00914           u  = point->fy;
00915           ou = point->oy;
00916         }
00917         else
00918         {
00919           u  = point->fx;
00920           ou = point->ox;
00921         }
00922 
00923         fu = u;
00924 
00925         /* is the point before the first edge? */
00926         edge  = edges;
00927         delta = edge->fpos - u;
00928         if ( delta >= 0 )
00929         {
00930           u = edge->pos - ( edge->opos - ou );
00931           goto Store_Point;
00932         }
00933 
00934         /* is the point after the last edge? */
00935         edge  = edge_limit - 1;
00936         delta = u - edge->fpos;
00937         if ( delta >= 0 )
00938         {
00939           u = edge->pos + ( ou - edge->opos );
00940           goto Store_Point;
00941         }
00942 
00943         {
00944           FT_PtrDist  min, max, mid;
00945           FT_Pos      fpos;
00946 
00947 
00948           /* find enclosing edges */
00949           min = 0;
00950           max = edge_limit - edges;
00951 
00952 #if 1
00953           /* for small edge counts, a linear search is better */
00954           if ( max <= 8 )
00955           {
00956             FT_PtrDist  nn;
00957 
00958             for ( nn = 0; nn < max; nn++ )
00959               if ( edges[nn].fpos >= u )
00960                 break;
00961 
00962             if ( edges[nn].fpos == u )
00963             {
00964               u = edges[nn].pos;
00965               goto Store_Point;
00966             }
00967             min = nn;
00968           }
00969           else
00970 #endif
00971           while ( min < max )
00972           {
00973             mid  = ( max + min ) >> 1;
00974             edge = edges + mid;
00975             fpos = edge->fpos;
00976 
00977             if ( u < fpos )
00978               max = mid;
00979             else if ( u > fpos )
00980               min = mid + 1;
00981             else
00982             {
00983               /* we are on the edge */
00984               u = edge->pos;
00985               goto Store_Point;
00986             }
00987           }
00988 
00989           {
00990             AF_Edge  before = edges + min - 1;
00991             AF_Edge  after  = edges + min + 0;
00992 
00993 
00994             /* assert( before && after && before != after ) */
00995             if ( before->scale == 0 )
00996               before->scale = FT_DivFix( after->pos - before->pos,
00997                                          after->fpos - before->fpos );
00998 
00999             u = before->pos + FT_MulFix( fu - before->fpos,
01000                                          before->scale );
01001           }
01002         }
01003 
01004       Store_Point:
01005         /* save the point position */
01006         if ( dim == AF_DIMENSION_HORZ )
01007           point->x = u;
01008         else
01009           point->y = u;
01010 
01011         point->flags |= touch_flag;
01012       }
01013     }
01014   }
01015 
01016 
01017   /****************************************************************
01018    *
01019    *                    WEAK POINT INTERPOLATION
01020    *
01021    ****************************************************************/
01022 
01023 
01024   static void
01025   af_iup_shift( AF_Point  p1,
01026                 AF_Point  p2,
01027                 AF_Point  ref )
01028   {
01029     AF_Point  p;
01030     FT_Pos    delta = ref->u - ref->v;
01031 
01032     if ( delta == 0 )
01033       return;
01034 
01035     for ( p = p1; p < ref; p++ )
01036       p->u = p->v + delta;
01037 
01038     for ( p = ref + 1; p <= p2; p++ )
01039       p->u = p->v + delta;
01040   }
01041 
01042 
01043   static void
01044   af_iup_interp( AF_Point  p1,
01045                  AF_Point  p2,
01046                  AF_Point  ref1,
01047                  AF_Point  ref2 )
01048   {
01049     AF_Point  p;
01050     FT_Pos    u;
01051     FT_Pos    v1 = ref1->v;
01052     FT_Pos    v2 = ref2->v;
01053     FT_Pos    d1 = ref1->u - v1;
01054     FT_Pos    d2 = ref2->u - v2;
01055 
01056 
01057     if ( p1 > p2 )
01058       return;
01059 
01060     if ( v1 == v2 )
01061     {
01062       for ( p = p1; p <= p2; p++ )
01063       {
01064         u = p->v;
01065 
01066         if ( u <= v1 )
01067           u += d1;
01068         else
01069           u += d2;
01070 
01071         p->u = u;
01072       }
01073       return;
01074     }
01075 
01076     if ( v1 < v2 )
01077     {
01078       for ( p = p1; p <= p2; p++ )
01079       {
01080         u = p->v;
01081 
01082         if ( u <= v1 )
01083           u += d1;
01084         else if ( u >= v2 )
01085           u += d2;
01086         else
01087           u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
01088 
01089         p->u = u;
01090       }
01091     }
01092     else
01093     {
01094       for ( p = p1; p <= p2; p++ )
01095       {
01096         u = p->v;
01097 
01098         if ( u <= v2 )
01099           u += d2;
01100         else if ( u >= v1 )
01101           u += d1;
01102         else
01103           u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
01104 
01105         p->u = u;
01106       }
01107     }
01108   }
01109 
01110 
01111   FT_LOCAL_DEF( void )
01112   af_glyph_hints_align_weak_points( AF_GlyphHints  hints,
01113                                     AF_Dimension   dim )
01114   {
01115     AF_Point   points        = hints->points;
01116     AF_Point   point_limit   = points + hints->num_points;
01117     AF_Point*  contour       = hints->contours;
01118     AF_Point*  contour_limit = contour + hints->num_contours;
01119     AF_Flags   touch_flag;
01120     AF_Point   point;
01121     AF_Point   end_point;
01122     AF_Point   first_point;
01123 
01124 
01125     /* PASS 1: Move segment points to edge positions */
01126 
01127     if ( dim == AF_DIMENSION_HORZ )
01128     {
01129       touch_flag = AF_FLAG_TOUCH_X;
01130 
01131       for ( point = points; point < point_limit; point++ )
01132       {
01133         point->u = point->x;
01134         point->v = point->ox;
01135       }
01136     }
01137     else
01138     {
01139       touch_flag = AF_FLAG_TOUCH_Y;
01140 
01141       for ( point = points; point < point_limit; point++ )
01142       {
01143         point->u = point->y;
01144         point->v = point->oy;
01145       }
01146     }
01147 
01148     point = points;
01149 
01150     for ( ; contour < contour_limit; contour++ )
01151     {
01152       AF_Point  first_touched, last_touched;
01153 
01154 
01155       point       = *contour;
01156       end_point   = point->prev;
01157       first_point = point;
01158 
01159       /* find first touched point */
01160       for (;;)
01161       {
01162         if ( point > end_point )  /* no touched point in contour */
01163           goto NextContour;
01164 
01165         if ( point->flags & touch_flag )
01166           break;
01167 
01168         point++;
01169       }
01170 
01171       first_touched = point;
01172       last_touched  = point;
01173 
01174       for (;;)
01175       {
01176         FT_ASSERT( point <= end_point &&
01177                    ( point->flags & touch_flag ) != 0 );
01178 
01179         /* skip any touched neighbhours */
01180         while ( point < end_point && ( point[1].flags & touch_flag ) != 0 )
01181           point++;
01182 
01183         last_touched = point;
01184 
01185         /* find the next touched point, if any */
01186         point ++;
01187         for (;;)
01188         {
01189           if ( point > end_point )
01190             goto EndContour;
01191 
01192           if ( ( point->flags & touch_flag ) != 0 )
01193             break;
01194 
01195           point++;
01196         }
01197 
01198         /* interpolate between last_touched and point */
01199         af_iup_interp( last_touched + 1, point - 1,
01200                        last_touched, point );
01201       }
01202 
01203     EndContour:
01204       /* special case: only one point was touched */
01205       if ( last_touched == first_touched )
01206       {
01207         af_iup_shift( first_point, end_point, first_touched );
01208       }
01209       else /* interpolate the last part */
01210       {
01211         if ( last_touched < end_point )
01212           af_iup_interp( last_touched + 1, end_point,
01213                          last_touched, first_touched );
01214 
01215         if ( first_touched > points )
01216           af_iup_interp( first_point, first_touched - 1,
01217                          last_touched, first_touched );
01218       }
01219 
01220     NextContour:
01221       ;
01222     }
01223 
01224     /* now save the interpolated values back to x/y */
01225     if ( dim == AF_DIMENSION_HORZ )
01226     {
01227       for ( point = points; point < point_limit; point++ )
01228         point->x = point->u;
01229     }
01230     else
01231     {
01232       for ( point = points; point < point_limit; point++ )
01233         point->y = point->u;
01234     }
01235   }
01236 
01237 
01238 #ifdef AF_USE_WARPER
01239 
01240   FT_LOCAL_DEF( void )
01241   af_glyph_hints_scale_dim( AF_GlyphHints  hints,
01242                             AF_Dimension   dim,
01243                             FT_Fixed       scale,
01244                             FT_Pos         delta )
01245   {
01246     AF_Point  points       = hints->points;
01247     AF_Point  points_limit = points + hints->num_points;
01248     AF_Point  point;
01249 
01250 
01251     if ( dim == AF_DIMENSION_HORZ )
01252     {
01253       for ( point = points; point < points_limit; point++ )
01254         point->x = FT_MulFix( point->fx, scale ) + delta;
01255     }
01256     else
01257     {
01258       for ( point = points; point < points_limit; point++ )
01259         point->y = FT_MulFix( point->fy, scale ) + delta;
01260     }
01261   }
01262 
01263 #endif /* AF_USE_WARPER */
01264 
01265 /* END */

Generated on Tue Jul 5 14:13:41 2011 for ROOT_528-00b_version by  doxygen 1.5.1