aflatin.c

Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  aflatin.c                                                              */
00004 /*                                                                         */
00005 /*    Auto-fitter hinting routines for latin script (body).                */
00006 /*                                                                         */
00007 /*  Copyright 2003, 2004, 2005, 2006, 2007, 2008, 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 <ft2build.h>
00020 #include FT_ADVANCES_H
00021 
00022 #include "aflatin.h"
00023 #include "aferrors.h"
00024 
00025 
00026 #ifdef AF_USE_WARPER
00027 #include "afwarp.h"
00028 #endif
00029 
00030 
00031   /*************************************************************************/
00032   /*************************************************************************/
00033   /*****                                                               *****/
00034   /*****            L A T I N   G L O B A L   M E T R I C S            *****/
00035   /*****                                                               *****/
00036   /*************************************************************************/
00037   /*************************************************************************/
00038 
00039   FT_LOCAL_DEF( void )
00040   af_latin_metrics_init_widths( AF_LatinMetrics  metrics,
00041                                 FT_Face          face,
00042                                 FT_ULong         charcode )
00043   {
00044     /* scan the array of segments in each direction */
00045     AF_GlyphHintsRec  hints[1];
00046 
00047 
00048     af_glyph_hints_init( hints, face->memory );
00049 
00050     metrics->axis[AF_DIMENSION_HORZ].width_count = 0;
00051     metrics->axis[AF_DIMENSION_VERT].width_count = 0;
00052 
00053     {
00054       FT_Error             error;
00055       FT_UInt              glyph_index;
00056       int                  dim;
00057       AF_LatinMetricsRec   dummy[1];
00058       AF_Scaler            scaler = &dummy->root.scaler;
00059 
00060 
00061       glyph_index = FT_Get_Char_Index( face, charcode );
00062       if ( glyph_index == 0 )
00063         goto Exit;
00064 
00065       error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
00066       if ( error || face->glyph->outline.n_points <= 0 )
00067         goto Exit;
00068 
00069       FT_ZERO( dummy );
00070 
00071       dummy->units_per_em = metrics->units_per_em;
00072       scaler->x_scale     = scaler->y_scale = 0x10000L;
00073       scaler->x_delta     = scaler->y_delta = 0;
00074       scaler->face        = face;
00075       scaler->render_mode = FT_RENDER_MODE_NORMAL;
00076       scaler->flags       = 0;
00077 
00078       af_glyph_hints_rescale( hints, (AF_ScriptMetrics)dummy );
00079 
00080       error = af_glyph_hints_reload( hints, &face->glyph->outline, 0 );
00081       if ( error )
00082         goto Exit;
00083 
00084       for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
00085       {
00086         AF_LatinAxis  axis    = &metrics->axis[dim];
00087         AF_AxisHints  axhints = &hints->axis[dim];
00088         AF_Segment    seg, limit, link;
00089         FT_UInt       num_widths = 0;
00090 
00091 
00092         error = af_latin_hints_compute_segments( hints,
00093                                                  (AF_Dimension)dim );
00094         if ( error )
00095           goto Exit;
00096 
00097         af_latin_hints_link_segments( hints,
00098                                       (AF_Dimension)dim );
00099 
00100         seg   = axhints->segments;
00101         limit = seg + axhints->num_segments;
00102 
00103         for ( ; seg < limit; seg++ )
00104         {
00105           link = seg->link;
00106 
00107           /* we only consider stem segments there! */
00108           if ( link && link->link == seg && link > seg )
00109           {
00110             FT_Pos  dist;
00111 
00112 
00113             dist = seg->pos - link->pos;
00114             if ( dist < 0 )
00115               dist = -dist;
00116 
00117             if ( num_widths < AF_LATIN_MAX_WIDTHS )
00118               axis->widths[ num_widths++ ].org = dist;
00119           }
00120         }
00121 
00122         af_sort_widths( num_widths, axis->widths );
00123         axis->width_count = num_widths;
00124       }
00125 
00126   Exit:
00127       for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
00128       {
00129         AF_LatinAxis  axis = &metrics->axis[dim];
00130         FT_Pos        stdw;
00131 
00132 
00133         stdw = ( axis->width_count > 0 )
00134                  ? axis->widths[0].org
00135                  : AF_LATIN_CONSTANT( metrics, 50 );
00136 
00137         /* let's try 20% of the smallest width */
00138         axis->edge_distance_threshold = stdw / 5;
00139         axis->standard_width          = stdw;
00140         axis->extra_light             = 0;
00141       }
00142     }
00143 
00144     af_glyph_hints_done( hints );
00145   }
00146 
00147 
00148 
00149 #define AF_LATIN_MAX_TEST_CHARACTERS  12
00150 
00151 
00152   static const char af_latin_blue_chars[AF_LATIN_MAX_BLUES]
00153                                        [AF_LATIN_MAX_TEST_CHARACTERS + 1] =
00154   {
00155     "THEZOCQS",
00156     "HEZLOCUS",
00157     "fijkdbh",
00158     "xzroesc",
00159     "xzroesc",
00160     "pqgjy"
00161   };
00162 
00163 
00164   static void
00165   af_latin_metrics_init_blues( AF_LatinMetrics  metrics,
00166                                FT_Face          face )
00167   {
00168     FT_Pos        flats [AF_LATIN_MAX_TEST_CHARACTERS];
00169     FT_Pos        rounds[AF_LATIN_MAX_TEST_CHARACTERS];
00170     FT_Int        num_flats;
00171     FT_Int        num_rounds;
00172     FT_Int        bb;
00173     AF_LatinBlue  blue;
00174     FT_Error      error;
00175     AF_LatinAxis  axis  = &metrics->axis[AF_DIMENSION_VERT];
00176     FT_GlyphSlot  glyph = face->glyph;
00177 
00178 
00179     /* we compute the blues simply by loading each character from the    */
00180     /* 'af_latin_blue_chars[blues]' string, then compute its top-most or */
00181     /* bottom-most points (depending on `AF_IS_TOP_BLUE')                */
00182 
00183     AF_LOG(( "blue zones computation\n" ));
00184     AF_LOG(( "------------------------------------------------\n" ));
00185 
00186     for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ )
00187     {
00188       const char*  p     = af_latin_blue_chars[bb];
00189       const char*  limit = p + AF_LATIN_MAX_TEST_CHARACTERS;
00190       FT_Pos*      blue_ref;
00191       FT_Pos*      blue_shoot;
00192 
00193 
00194       AF_LOG(( "blue %3d: ", bb ));
00195 
00196       num_flats  = 0;
00197       num_rounds = 0;
00198 
00199       for ( ; p < limit && *p; p++ )
00200       {
00201         FT_UInt     glyph_index;
00202         FT_Pos      best_y; /* same as points.y */
00203         FT_Int      best_point, best_first, best_last;
00204         FT_Vector*  points;
00205         FT_Bool     round = 0;
00206 
00207 
00208         AF_LOG(( "'%c'", *p ));
00209 
00210         /* load the character in the face -- skip unknown or empty ones */
00211         glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p );
00212         if ( glyph_index == 0 )
00213           continue;
00214 
00215         error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
00216         if ( error || glyph->outline.n_points <= 0 )
00217           continue;
00218 
00219         /* now compute min or max point indices and coordinates */
00220         points      = glyph->outline.points;
00221         best_point  = -1;
00222         best_y      = 0;  /* make compiler happy */
00223         best_first  = 0;  /* ditto */
00224         best_last   = 0;  /* ditto */
00225 
00226         {
00227           FT_Int  nn;
00228           FT_Int  first = 0;
00229           FT_Int  last  = -1;
00230 
00231 
00232           for ( nn = 0; nn < glyph->outline.n_contours; first = last+1, nn++ )
00233           {
00234             FT_Int  old_best_point = best_point;
00235             FT_Int  pp;
00236 
00237 
00238             last = glyph->outline.contours[nn];
00239 
00240             /* Avoid single-point contours since they are never rasterized. */
00241             /* In some fonts, they correspond to mark attachment points     */
00242             /* which are way outside of the glyph's real outline.           */
00243             if ( last <= first )
00244                 continue;
00245 
00246             if ( AF_LATIN_IS_TOP_BLUE( bb ) )
00247             {
00248               for ( pp = first; pp <= last; pp++ )
00249                 if ( best_point < 0 || points[pp].y > best_y )
00250                 {
00251                   best_point = pp;
00252                   best_y     = points[pp].y;
00253                 }
00254             }
00255             else
00256             {
00257               for ( pp = first; pp <= last; pp++ )
00258                 if ( best_point < 0 || points[pp].y < best_y )
00259                 {
00260                   best_point = pp;
00261                   best_y     = points[pp].y;
00262                 }
00263             }
00264 
00265             if ( best_point != old_best_point )
00266             {
00267               best_first = first;
00268               best_last  = last;
00269             }
00270           }
00271           AF_LOG(( "%5d", best_y ));
00272         }
00273 
00274         /* now check whether the point belongs to a straight or round   */
00275         /* segment; we first need to find in which contour the extremum */
00276         /* lies, then inspect its previous and next points              */
00277         if ( best_point >= 0 )
00278         {
00279           FT_Int  prev, next;
00280           FT_Pos  dist;
00281 
00282 
00283           /* now look for the previous and next points that are not on the */
00284           /* same Y coordinate.  Threshold the `closeness'...              */
00285           prev = best_point;
00286           next = prev;
00287 
00288           do
00289           {
00290             if ( prev > best_first )
00291               prev--;
00292             else
00293               prev = best_last;
00294 
00295             dist = points[prev].y - best_y;
00296             if ( dist < -5 || dist > 5 )
00297               break;
00298 
00299           } while ( prev != best_point );
00300 
00301           do
00302           {
00303             if ( next < best_last )
00304               next++;
00305             else
00306               next = best_first;
00307 
00308             dist = points[next].y - best_y;
00309             if ( dist < -5 || dist > 5 )
00310               break;
00311 
00312           } while ( next != best_point );
00313 
00314           /* now, set the `round' flag depending on the segment's kind */
00315           round = FT_BOOL(
00316             FT_CURVE_TAG( glyph->outline.tags[prev] ) != FT_CURVE_TAG_ON ||
00317             FT_CURVE_TAG( glyph->outline.tags[next] ) != FT_CURVE_TAG_ON );
00318 
00319           AF_LOG(( "%c ", round ? 'r' : 'f' ));
00320         }
00321 
00322         if ( round )
00323           rounds[num_rounds++] = best_y;
00324         else
00325           flats[num_flats++]   = best_y;
00326       }
00327 
00328       AF_LOG(( "\n" ));
00329 
00330       if ( num_flats == 0 && num_rounds == 0 )
00331       {
00332         /*
00333          *  we couldn't find a single glyph to compute this blue zone,
00334          *  we will simply ignore it then
00335          */
00336         AF_LOG(( "empty\n" ));
00337         continue;
00338       }
00339 
00340       /* we have computed the contents of the `rounds' and `flats' tables, */
00341       /* now determine the reference and overshoot position of the blue -- */
00342       /* we simply take the median value after a simple sort               */
00343       af_sort_pos( num_rounds, rounds );
00344       af_sort_pos( num_flats,  flats );
00345 
00346       blue       = & axis->blues[axis->blue_count];
00347       blue_ref   = & blue->ref.org;
00348       blue_shoot = & blue->shoot.org;
00349 
00350       axis->blue_count++;
00351 
00352       if ( num_flats == 0 )
00353       {
00354         *blue_ref   =
00355         *blue_shoot = rounds[num_rounds / 2];
00356       }
00357       else if ( num_rounds == 0 )
00358       {
00359         *blue_ref   =
00360         *blue_shoot = flats[num_flats / 2];
00361       }
00362       else
00363       {
00364         *blue_ref   = flats[num_flats / 2];
00365         *blue_shoot = rounds[num_rounds / 2];
00366       }
00367 
00368       /* there are sometimes problems: if the overshoot position of top     */
00369       /* zones is under its reference position, or the opposite for bottom  */
00370       /* zones.  We must thus check everything there and correct the errors */
00371       if ( *blue_shoot != *blue_ref )
00372       {
00373         FT_Pos   ref      = *blue_ref;
00374         FT_Pos   shoot    = *blue_shoot;
00375         FT_Bool  over_ref = FT_BOOL( shoot > ref );
00376 
00377 
00378         if ( AF_LATIN_IS_TOP_BLUE( bb ) ^ over_ref )
00379           *blue_shoot = *blue_ref = ( shoot + ref ) / 2;
00380       }
00381 
00382       blue->flags = 0;
00383       if ( AF_LATIN_IS_TOP_BLUE( bb ) )
00384         blue->flags |= AF_LATIN_BLUE_TOP;
00385 
00386       /*
00387        * The following flag is used later to adjust the y and x scales
00388        * in order to optimize the pixel grid alignment of the top of small
00389        * letters.
00390        */
00391       if ( bb == AF_LATIN_BLUE_SMALL_TOP )
00392         blue->flags |= AF_LATIN_BLUE_ADJUSTMENT;
00393 
00394       AF_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot ));
00395     }
00396 
00397     return;
00398   }
00399 
00400 
00401   FT_LOCAL_DEF( void )
00402   af_latin_metrics_check_digits( AF_LatinMetrics  metrics,
00403                                  FT_Face          face )
00404   {
00405     FT_UInt   i;
00406     FT_Bool   started = 0, same_width = 1;
00407     FT_Fixed  advance, old_advance = 0;
00408 
00409 
00410     /* check whether all ASCII digits have the same advance width; */
00411     /* digit `0' is 0x30 in all supported charmaps                 */
00412     for ( i = 0x30; i <= 0x39; i++ )
00413     {
00414       FT_UInt  glyph_index;
00415 
00416 
00417       glyph_index = FT_Get_Char_Index( face, i );
00418       if ( glyph_index == 0 )
00419         continue;
00420 
00421       if ( FT_Get_Advance( face, glyph_index,
00422                            FT_LOAD_NO_SCALE         |
00423                            FT_LOAD_NO_HINTING       |
00424                            FT_LOAD_IGNORE_TRANSFORM,
00425                            &advance ) )
00426         continue;
00427 
00428       if ( started )
00429       {
00430         if ( advance != old_advance )
00431         {
00432           same_width = 0;
00433           break;
00434         }
00435       }
00436       else
00437       {
00438         old_advance = advance;
00439         started     = 1;
00440       }
00441     }
00442 
00443     metrics->root.digits_have_same_width = same_width;
00444   }
00445 
00446 
00447   FT_LOCAL_DEF( FT_Error )
00448   af_latin_metrics_init( AF_LatinMetrics  metrics,
00449                          FT_Face          face )
00450   {
00451     FT_Error    error = AF_Err_Ok;
00452     FT_CharMap  oldmap = face->charmap;
00453     FT_UInt     ee;
00454 
00455     static const FT_Encoding  latin_encodings[] =
00456     {
00457       FT_ENCODING_UNICODE,
00458       FT_ENCODING_APPLE_ROMAN,
00459       FT_ENCODING_ADOBE_STANDARD,
00460       FT_ENCODING_ADOBE_LATIN_1,
00461       FT_ENCODING_NONE  /* end of list */
00462     };
00463 
00464 
00465     metrics->units_per_em = face->units_per_EM;
00466 
00467     /* do we have a latin charmap in there? */
00468     for ( ee = 0; latin_encodings[ee] != FT_ENCODING_NONE; ee++ )
00469     {
00470       error = FT_Select_Charmap( face, latin_encodings[ee] );
00471       if ( !error )
00472         break;
00473     }
00474 
00475     if ( !error )
00476     {
00477       /* For now, compute the standard width and height from the `o'. */
00478       af_latin_metrics_init_widths( metrics, face, 'o' );
00479       af_latin_metrics_init_blues( metrics, face );
00480       af_latin_metrics_check_digits( metrics, face );
00481     }
00482 
00483     FT_Set_Charmap( face, oldmap );
00484     return AF_Err_Ok;
00485   }
00486 
00487 
00488   static void
00489   af_latin_metrics_scale_dim( AF_LatinMetrics  metrics,
00490                               AF_Scaler        scaler,
00491                               AF_Dimension     dim )
00492   {
00493     FT_Fixed      scale;
00494     FT_Pos        delta;
00495     AF_LatinAxis  axis;
00496     FT_UInt       nn;
00497 
00498 
00499     if ( dim == AF_DIMENSION_HORZ )
00500     {
00501       scale = scaler->x_scale;
00502       delta = scaler->x_delta;
00503     }
00504     else
00505     {
00506       scale = scaler->y_scale;
00507       delta = scaler->y_delta;
00508     }
00509 
00510     axis = &metrics->axis[dim];
00511 
00512     if ( axis->org_scale == scale && axis->org_delta == delta )
00513       return;
00514 
00515     axis->org_scale = scale;
00516     axis->org_delta = delta;
00517 
00518     /*
00519      * correct X and Y scale to optimize the alignment of the top of small
00520      * letters to the pixel grid
00521      */
00522     {
00523       AF_LatinAxis  Axis = &metrics->axis[AF_DIMENSION_VERT];
00524       AF_LatinBlue  blue = NULL;
00525 
00526 
00527       for ( nn = 0; nn < Axis->blue_count; nn++ )
00528       {
00529         if ( Axis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT )
00530         {
00531           blue = &Axis->blues[nn];
00532           break;
00533         }
00534       }
00535 
00536       if ( blue )
00537       {
00538         FT_Pos  scaled = FT_MulFix( blue->shoot.org, scaler->y_scale );
00539         FT_Pos  fitted = ( scaled + 40 ) & ~63;
00540 
00541 
00542         if ( scaled != fitted )
00543         {
00544 #if 0
00545           if ( dim == AF_DIMENSION_HORZ )
00546           {
00547             if ( fitted < scaled )
00548               scale -= scale / 50;  /* scale *= 0.98 */
00549           }
00550           else
00551 #endif
00552           if ( dim == AF_DIMENSION_VERT )
00553           {
00554             scale = FT_MulDiv( scale, fitted, scaled );
00555           }
00556         }
00557       }
00558     }
00559 
00560     axis->scale = scale;
00561     axis->delta = delta;
00562 
00563     if ( dim == AF_DIMENSION_HORZ )
00564     {
00565       metrics->root.scaler.x_scale = scale;
00566       metrics->root.scaler.x_delta = delta;
00567     }
00568     else
00569     {
00570       metrics->root.scaler.y_scale = scale;
00571       metrics->root.scaler.y_delta = delta;
00572     }
00573 
00574     /* scale the standard widths */
00575     for ( nn = 0; nn < axis->width_count; nn++ )
00576     {
00577       AF_Width  width = axis->widths + nn;
00578 
00579 
00580       width->cur = FT_MulFix( width->org, scale );
00581       width->fit = width->cur;
00582     }
00583 
00584     /* an extra-light axis corresponds to a standard width that is */
00585     /* smaller than 0.75 pixels                                    */
00586     axis->extra_light =
00587       (FT_Bool)( FT_MulFix( axis->standard_width, scale ) < 32 + 8 );
00588 
00589     if ( dim == AF_DIMENSION_VERT )
00590     {
00591       /* scale the blue zones */
00592       for ( nn = 0; nn < axis->blue_count; nn++ )
00593       {
00594         AF_LatinBlue  blue = &axis->blues[nn];
00595         FT_Pos        dist;
00596 
00597 
00598         blue->ref.cur   = FT_MulFix( blue->ref.org, scale ) + delta;
00599         blue->ref.fit   = blue->ref.cur;
00600         blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta;
00601         blue->shoot.fit = blue->shoot.cur;
00602         blue->flags    &= ~AF_LATIN_BLUE_ACTIVE;
00603 
00604         /* a blue zone is only active if it is less than 3/4 pixels tall */
00605         dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
00606         if ( dist <= 48 && dist >= -48 )
00607         {
00608           FT_Pos  delta1, delta2;
00609 
00610 
00611           delta1 = blue->shoot.org - blue->ref.org;
00612           delta2 = delta1;
00613           if ( delta1 < 0 )
00614             delta2 = -delta2;
00615 
00616           delta2 = FT_MulFix( delta2, scale );
00617 
00618           if ( delta2 < 32 )
00619             delta2 = 0;
00620           else if ( delta2 < 64 )
00621             delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 );
00622           else
00623             delta2 = FT_PIX_ROUND( delta2 );
00624 
00625           if ( delta1 < 0 )
00626             delta2 = -delta2;
00627 
00628           blue->ref.fit   = FT_PIX_ROUND( blue->ref.cur );
00629           blue->shoot.fit = blue->ref.fit + delta2;
00630 
00631           blue->flags |= AF_LATIN_BLUE_ACTIVE;
00632         }
00633       }
00634     }
00635   }
00636 
00637 
00638   FT_LOCAL_DEF( void )
00639   af_latin_metrics_scale( AF_LatinMetrics  metrics,
00640                           AF_Scaler        scaler )
00641   {
00642     metrics->root.scaler.render_mode = scaler->render_mode;
00643     metrics->root.scaler.face        = scaler->face;
00644 
00645     af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ );
00646     af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT );
00647   }
00648 
00649 
00650   /*************************************************************************/
00651   /*************************************************************************/
00652   /*****                                                               *****/
00653   /*****           L A T I N   G L Y P H   A N A L Y S I S             *****/
00654   /*****                                                               *****/
00655   /*************************************************************************/
00656   /*************************************************************************/
00657 
00658   FT_LOCAL_DEF( FT_Error )
00659   af_latin_hints_compute_segments( AF_GlyphHints  hints,
00660                                    AF_Dimension   dim )
00661   {
00662     AF_AxisHints  axis          = &hints->axis[dim];
00663     FT_Memory     memory        = hints->memory;
00664     FT_Error      error         = AF_Err_Ok;
00665     AF_Segment    segment       = NULL;
00666     AF_SegmentRec seg0;
00667     AF_Point*     contour       = hints->contours;
00668     AF_Point*     contour_limit = contour + hints->num_contours;
00669     AF_Direction  major_dir, segment_dir;
00670 
00671 
00672     FT_ZERO( &seg0 );
00673     seg0.score = 32000;
00674     seg0.flags = AF_EDGE_NORMAL;
00675 
00676     major_dir   = (AF_Direction)FT_ABS( axis->major_dir );
00677     segment_dir = major_dir;
00678 
00679     axis->num_segments = 0;
00680 
00681     /* set up (u,v) in each point */
00682     if ( dim == AF_DIMENSION_HORZ )
00683     {
00684       AF_Point  point = hints->points;
00685       AF_Point  limit = point + hints->num_points;
00686 
00687 
00688       for ( ; point < limit; point++ )
00689       {
00690         point->u = point->fx;
00691         point->v = point->fy;
00692       }
00693     }
00694     else
00695     {
00696       AF_Point  point = hints->points;
00697       AF_Point  limit = point + hints->num_points;
00698 
00699 
00700       for ( ; point < limit; point++ )
00701       {
00702         point->u = point->fy;
00703         point->v = point->fx;
00704       }
00705     }
00706 
00707     /* do each contour separately */
00708     for ( ; contour < contour_limit; contour++ )
00709     {
00710       AF_Point  point   =  contour[0];
00711       AF_Point  last    =  point->prev;
00712       int       on_edge =  0;
00713       FT_Pos    min_pos =  32000;  /* minimum segment pos != min_coord */
00714       FT_Pos    max_pos = -32000;  /* maximum segment pos != max_coord */
00715       FT_Bool   passed;
00716 
00717 
00718       if ( point == last )  /* skip singletons -- just in case */
00719         continue;
00720 
00721       if ( FT_ABS( last->out_dir )  == major_dir &&
00722            FT_ABS( point->out_dir ) == major_dir )
00723       {
00724         /* we are already on an edge, try to locate its start */
00725         last = point;
00726 
00727         for (;;)
00728         {
00729           point = point->prev;
00730           if ( FT_ABS( point->out_dir ) != major_dir )
00731           {
00732             point = point->next;
00733             break;
00734           }
00735           if ( point == last )
00736             break;
00737         }
00738       }
00739 
00740       last   = point;
00741       passed = 0;
00742 
00743       for (;;)
00744       {
00745         FT_Pos  u, v;
00746 
00747 
00748         if ( on_edge )
00749         {
00750           u = point->u;
00751           if ( u < min_pos )
00752             min_pos = u;
00753           if ( u > max_pos )
00754             max_pos = u;
00755 
00756           if ( point->out_dir != segment_dir || point == last )
00757           {
00758             /* we are just leaving an edge; record a new segment! */
00759             segment->last = point;
00760             segment->pos  = (FT_Short)( ( min_pos + max_pos ) >> 1 );
00761 
00762             /* a segment is round if either its first or last point */
00763             /* is a control point                                   */
00764             if ( ( segment->first->flags | point->flags ) &
00765                    AF_FLAG_CONTROL                        )
00766               segment->flags |= AF_EDGE_ROUND;
00767 
00768             /* compute segment size */
00769             min_pos = max_pos = point->v;
00770 
00771             v = segment->first->v;
00772             if ( v < min_pos )
00773               min_pos = v;
00774             if ( v > max_pos )
00775               max_pos = v;
00776 
00777             segment->min_coord = (FT_Short)min_pos;
00778             segment->max_coord = (FT_Short)max_pos;
00779             segment->height    = (FT_Short)( segment->max_coord -
00780                                              segment->min_coord );
00781 
00782             on_edge = 0;
00783             segment = NULL;
00784             /* fallthrough */
00785           }
00786         }
00787 
00788         /* now exit if we are at the start/end point */
00789         if ( point == last )
00790         {
00791           if ( passed )
00792             break;
00793           passed = 1;
00794         }
00795 
00796         if ( !on_edge && FT_ABS( point->out_dir ) == major_dir )
00797         {
00798           /* this is the start of a new segment! */
00799           segment_dir = (AF_Direction)point->out_dir;
00800 
00801           /* clear all segment fields */
00802           error = af_axis_hints_new_segment( axis, memory, &segment );
00803           if ( error )
00804             goto Exit;
00805 
00806           segment[0]        = seg0;
00807           segment->dir      = (FT_Char)segment_dir;
00808           min_pos = max_pos = point->u;
00809           segment->first    = point;
00810           segment->last     = point;
00811           segment->contour  = contour;
00812           on_edge           = 1;
00813         }
00814 
00815         point = point->next;
00816       }
00817 
00818     } /* contours */
00819 
00820 
00821     /* now slightly increase the height of segments when this makes */
00822     /* sense -- this is used to better detect and ignore serifs     */
00823     {
00824       AF_Segment  segments     = axis->segments;
00825       AF_Segment  segments_end = segments + axis->num_segments;
00826 
00827 
00828       for ( segment = segments; segment < segments_end; segment++ )
00829       {
00830         AF_Point  first   = segment->first;
00831         AF_Point  last    = segment->last;
00832         FT_Pos    first_v = first->v;
00833         FT_Pos    last_v  = last->v;
00834 
00835 
00836         if ( first == last )
00837           continue;
00838 
00839         if ( first_v < last_v )
00840         {
00841           AF_Point  p;
00842 
00843 
00844           p = first->prev;
00845           if ( p->v < first_v )
00846             segment->height = (FT_Short)( segment->height +
00847                                           ( ( first_v - p->v ) >> 1 ) );
00848 
00849           p = last->next;
00850           if ( p->v > last_v )
00851             segment->height = (FT_Short)( segment->height +
00852                                           ( ( p->v - last_v ) >> 1 ) );
00853         }
00854         else
00855         {
00856           AF_Point  p;
00857 
00858 
00859           p = first->prev;
00860           if ( p->v > first_v )
00861             segment->height = (FT_Short)( segment->height +
00862                                           ( ( p->v - first_v ) >> 1 ) );
00863 
00864           p = last->next;
00865           if ( p->v < last_v )
00866             segment->height = (FT_Short)( segment->height +
00867                                           ( ( last_v - p->v ) >> 1 ) );
00868         }
00869       }
00870     }
00871 
00872   Exit:
00873     return error;
00874   }
00875 
00876 
00877   FT_LOCAL_DEF( void )
00878   af_latin_hints_link_segments( AF_GlyphHints  hints,
00879                                 AF_Dimension   dim )
00880   {
00881     AF_AxisHints  axis          = &hints->axis[dim];
00882     AF_Segment    segments      = axis->segments;
00883     AF_Segment    segment_limit = segments + axis->num_segments;
00884     FT_Pos        len_threshold, len_score;
00885     AF_Segment    seg1, seg2;
00886 
00887 
00888     len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 );
00889     if ( len_threshold == 0 )
00890       len_threshold = 1;
00891 
00892     len_score = AF_LATIN_CONSTANT( hints->metrics, 6000 );
00893 
00894     /* now compare each segment to the others */
00895     for ( seg1 = segments; seg1 < segment_limit; seg1++ )
00896     {
00897       /* the fake segments are introduced to hint the metrics -- */
00898       /* we must never link them to anything                     */
00899       if ( seg1->dir != axis->major_dir || seg1->first == seg1->last )
00900         continue;
00901 
00902       for ( seg2 = segments; seg2 < segment_limit; seg2++ )
00903         if ( seg1->dir + seg2->dir == 0 && seg2->pos > seg1->pos )
00904         {
00905           FT_Pos  pos1 = seg1->pos;
00906           FT_Pos  pos2 = seg2->pos;
00907           FT_Pos  dist = pos2 - pos1;
00908 
00909 
00910           if ( dist < 0 )
00911             dist = -dist;
00912 
00913           {
00914             FT_Pos  min = seg1->min_coord;
00915             FT_Pos  max = seg1->max_coord;
00916             FT_Pos  len, score;
00917 
00918 
00919             if ( min < seg2->min_coord )
00920               min = seg2->min_coord;
00921 
00922             if ( max > seg2->max_coord )
00923               max = seg2->max_coord;
00924 
00925             len = max - min;
00926             if ( len >= len_threshold )
00927             {
00928               score = dist + len_score / len;
00929 
00930               if ( score < seg1->score )
00931               {
00932                 seg1->score = score;
00933                 seg1->link  = seg2;
00934               }
00935 
00936               if ( score < seg2->score )
00937               {
00938                 seg2->score = score;
00939                 seg2->link  = seg1;
00940               }
00941             }
00942           }
00943         }
00944     }
00945 
00946     /* now, compute the `serif' segments */
00947     for ( seg1 = segments; seg1 < segment_limit; seg1++ )
00948     {
00949       seg2 = seg1->link;
00950 
00951       if ( seg2 )
00952       {
00953         if ( seg2->link != seg1 )
00954         {
00955           seg1->link  = 0;
00956           seg1->serif = seg2->link;
00957         }
00958       }
00959     }
00960   }
00961 
00962 
00963   FT_LOCAL_DEF( FT_Error )
00964   af_latin_hints_compute_edges( AF_GlyphHints  hints,
00965                                 AF_Dimension   dim )
00966   {
00967     AF_AxisHints  axis   = &hints->axis[dim];
00968     FT_Error      error  = AF_Err_Ok;
00969     FT_Memory     memory = hints->memory;
00970     AF_LatinAxis  laxis  = &((AF_LatinMetrics)hints->metrics)->axis[dim];
00971 
00972     AF_Segment    segments      = axis->segments;
00973     AF_Segment    segment_limit = segments + axis->num_segments;
00974     AF_Segment    seg;
00975 
00976     AF_Direction  up_dir;
00977     FT_Fixed      scale;
00978     FT_Pos        edge_distance_threshold;
00979     FT_Pos        segment_length_threshold;
00980 
00981 
00982     axis->num_edges = 0;
00983 
00984     scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
00985                                          : hints->y_scale;
00986 
00987     up_dir = ( dim == AF_DIMENSION_HORZ ) ? AF_DIR_UP
00988                                           : AF_DIR_RIGHT;
00989 
00990     /*
00991      *  We ignore all segments that are less than 1 pixels in length,
00992      *  to avoid many problems with serif fonts.  We compute the
00993      *  corresponding threshold in font units.
00994      */
00995     if ( dim == AF_DIMENSION_HORZ )
00996         segment_length_threshold = FT_DivFix( 64, hints->y_scale );
00997     else
00998         segment_length_threshold = 0;
00999 
01000     /*********************************************************************/
01001     /*                                                                   */
01002     /* We will begin by generating a sorted table of edges for the       */
01003     /* current direction.  To do so, we simply scan each segment and try */
01004     /* to find an edge in our table that corresponds to its position.    */
01005     /*                                                                   */
01006     /* If no edge is found, we create and insert a new edge in the       */
01007     /* sorted table.  Otherwise, we simply add the segment to the edge's */
01008     /* list which will be processed in the second step to compute the    */
01009     /* edge's properties.                                                */
01010     /*                                                                   */
01011     /* Note that the edges table is sorted along the segment/edge        */
01012     /* position.                                                         */
01013     /*                                                                   */
01014     /*********************************************************************/
01015 
01016     edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold,
01017                                          scale );
01018     if ( edge_distance_threshold > 64 / 4 )
01019       edge_distance_threshold = 64 / 4;
01020 
01021     edge_distance_threshold = FT_DivFix( edge_distance_threshold,
01022                                          scale );
01023 
01024     for ( seg = segments; seg < segment_limit; seg++ )
01025     {
01026       AF_Edge  found = 0;
01027       FT_Int   ee;
01028 
01029 
01030       if ( seg->height < segment_length_threshold )
01031         continue;
01032 
01033       /* A special case for serif edges: If they are smaller than */
01034       /* 1.5 pixels we ignore them.                               */
01035       if ( seg->serif                                     &&
01036            2 * seg->height < 3 * segment_length_threshold )
01037         continue;
01038 
01039       /* look for an edge corresponding to the segment */
01040       for ( ee = 0; ee < axis->num_edges; ee++ )
01041       {
01042         AF_Edge  edge = axis->edges + ee;
01043         FT_Pos   dist;
01044 
01045 
01046         dist = seg->pos - edge->fpos;
01047         if ( dist < 0 )
01048           dist = -dist;
01049 
01050         if ( dist < edge_distance_threshold && edge->dir == seg->dir )
01051         {
01052           found = edge;
01053           break;
01054         }
01055       }
01056 
01057       if ( !found )
01058       {
01059         AF_Edge  edge;
01060 
01061 
01062         /* insert a new edge in the list and */
01063         /* sort according to the position    */
01064         error = af_axis_hints_new_edge( axis, seg->pos,
01065                                         (AF_Direction)seg->dir,
01066                                         memory, &edge );
01067         if ( error )
01068           goto Exit;
01069 
01070         /* add the segment to the new edge's list */
01071         FT_ZERO( edge );
01072 
01073         edge->first    = seg;
01074         edge->last     = seg;
01075         edge->fpos     = seg->pos;
01076         edge->dir      = seg->dir;
01077         edge->opos     = edge->pos = FT_MulFix( seg->pos, scale );
01078         seg->edge_next = seg;
01079       }
01080       else
01081       {
01082         /* if an edge was found, simply add the segment to the edge's */
01083         /* list                                                       */
01084         seg->edge_next         = found->first;
01085         found->last->edge_next = seg;
01086         found->last            = seg;
01087       }
01088     }
01089 
01090 
01091     /*********************************************************************/
01092     /*                                                                   */
01093     /* Good, we will now compute each edge's properties according to     */
01094     /* segments found on its position.  Basically, these are:            */
01095     /*                                                                   */
01096     /*  - edge's main direction                                          */
01097     /*  - stem edge, serif edge or both (which defaults to stem then)    */
01098     /*  - rounded edge, straight or both (which defaults to straight)    */
01099     /*  - link for edge                                                  */
01100     /*                                                                   */
01101     /*********************************************************************/
01102 
01103     /* first of all, set the `edge' field in each segment -- this is */
01104     /* required in order to compute edge links                       */
01105 
01106     /*
01107      * Note that removing this loop and setting the `edge' field of each
01108      * segment directly in the code above slows down execution speed for
01109      * some reasons on platforms like the Sun.
01110      */
01111     {
01112       AF_Edge  edges      = axis->edges;
01113       AF_Edge  edge_limit = edges + axis->num_edges;
01114       AF_Edge  edge;
01115 
01116 
01117       for ( edge = edges; edge < edge_limit; edge++ )
01118       {
01119         seg = edge->first;
01120         if ( seg )
01121           do
01122           {
01123             seg->edge = edge;
01124             seg       = seg->edge_next;
01125 
01126           } while ( seg != edge->first );
01127       }
01128 
01129       /* now, compute each edge properties */
01130       for ( edge = edges; edge < edge_limit; edge++ )
01131       {
01132         FT_Int  is_round    = 0;  /* does it contain round segments?    */
01133         FT_Int  is_straight = 0;  /* does it contain straight segments? */
01134         FT_Pos  ups         = 0;  /* number of upwards segments         */
01135         FT_Pos  downs       = 0;  /* number of downwards segments       */
01136 
01137 
01138         seg = edge->first;
01139 
01140         do
01141         {
01142           FT_Bool  is_serif;
01143 
01144 
01145           /* check for roundness of segment */
01146           if ( seg->flags & AF_EDGE_ROUND )
01147             is_round++;
01148           else
01149             is_straight++;
01150 
01151           /* check for segment direction */
01152           if ( seg->dir == up_dir )
01153             ups   += seg->max_coord-seg->min_coord;
01154           else
01155             downs += seg->max_coord-seg->min_coord;
01156 
01157           /* check for links -- if seg->serif is set, then seg->link must */
01158           /* be ignored                                                   */
01159           is_serif = (FT_Bool)( seg->serif               &&
01160                                 seg->serif->edge         &&
01161                                 seg->serif->edge != edge );
01162 
01163           if ( ( seg->link && seg->link->edge != NULL ) || is_serif )
01164           {
01165             AF_Edge     edge2;
01166             AF_Segment  seg2;
01167 
01168 
01169             edge2 = edge->link;
01170             seg2  = seg->link;
01171 
01172             if ( is_serif )
01173             {
01174               seg2  = seg->serif;
01175               edge2 = edge->serif;
01176             }
01177 
01178             if ( edge2 )
01179             {
01180               FT_Pos  edge_delta;
01181               FT_Pos  seg_delta;
01182 
01183 
01184               edge_delta = edge->fpos - edge2->fpos;
01185               if ( edge_delta < 0 )
01186                 edge_delta = -edge_delta;
01187 
01188               seg_delta = seg->pos - seg2->pos;
01189               if ( seg_delta < 0 )
01190                 seg_delta = -seg_delta;
01191 
01192               if ( seg_delta < edge_delta )
01193                 edge2 = seg2->edge;
01194             }
01195             else
01196               edge2 = seg2->edge;
01197 
01198             if ( is_serif )
01199             {
01200               edge->serif   = edge2;
01201               edge2->flags |= AF_EDGE_SERIF;
01202             }
01203             else
01204               edge->link  = edge2;
01205           }
01206 
01207           seg = seg->edge_next;
01208 
01209         } while ( seg != edge->first );
01210 
01211         /* set the round/straight flags */
01212         edge->flags = AF_EDGE_NORMAL;
01213 
01214         if ( is_round > 0 && is_round >= is_straight )
01215           edge->flags |= AF_EDGE_ROUND;
01216 
01217 #if 0
01218         /* set the edge's main direction */
01219         edge->dir = AF_DIR_NONE;
01220 
01221         if ( ups > downs )
01222           edge->dir = (FT_Char)up_dir;
01223 
01224         else if ( ups < downs )
01225           edge->dir = (FT_Char)-up_dir;
01226 
01227         else if ( ups == downs )
01228           edge->dir = 0;  /* both up and down! */
01229 #endif
01230 
01231         /* gets rid of serifs if link is set                */
01232         /* XXX: This gets rid of many unpleasant artefacts! */
01233         /*      Example: the `c' in cour.pfa at size 13     */
01234 
01235         if ( edge->serif && edge->link )
01236           edge->serif = 0;
01237       }
01238     }
01239 
01240   Exit:
01241     return error;
01242   }
01243 
01244 
01245   FT_LOCAL_DEF( FT_Error )
01246   af_latin_hints_detect_features( AF_GlyphHints  hints,
01247                                   AF_Dimension   dim )
01248   {
01249     FT_Error  error;
01250 
01251 
01252     error = af_latin_hints_compute_segments( hints, dim );
01253     if ( !error )
01254     {
01255       af_latin_hints_link_segments( hints, dim );
01256 
01257       error = af_latin_hints_compute_edges( hints, dim );
01258     }
01259     return error;
01260   }
01261 
01262 
01263   FT_LOCAL_DEF( void )
01264   af_latin_hints_compute_blue_edges( AF_GlyphHints    hints,
01265                                      AF_LatinMetrics  metrics )
01266   {
01267     AF_AxisHints  axis       = &hints->axis[ AF_DIMENSION_VERT ];
01268     AF_Edge       edge       = axis->edges;
01269     AF_Edge       edge_limit = edge + axis->num_edges;
01270     AF_LatinAxis  latin      = &metrics->axis[ AF_DIMENSION_VERT ];
01271     FT_Fixed      scale      = latin->scale;
01272 
01273 
01274     /* compute which blue zones are active, i.e. have their scaled */
01275     /* size < 3/4 pixels                                           */
01276 
01277     /* for each horizontal edge search the blue zone which is closest */
01278     for ( ; edge < edge_limit; edge++ )
01279     {
01280       FT_Int    bb;
01281       AF_Width  best_blue = NULL;
01282       FT_Pos    best_dist;  /* initial threshold */
01283 
01284 
01285       /* compute the initial threshold as a fraction of the EM size */
01286       best_dist = FT_MulFix( metrics->units_per_em / 40, scale );
01287 
01288       if ( best_dist > 64 / 2 )
01289         best_dist = 64 / 2;
01290 
01291       for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ )
01292       {
01293         AF_LatinBlue  blue = latin->blues + bb;
01294         FT_Bool       is_top_blue, is_major_dir;
01295 
01296 
01297         /* skip inactive blue zones (i.e., those that are too small) */
01298         if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) )
01299           continue;
01300 
01301         /* if it is a top zone, check for right edges -- if it is a bottom */
01302         /* zone, check for left edges                                      */
01303         /*                                                                 */
01304         /* of course, that's for TrueType                                  */
01305         is_top_blue  = (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_TOP ) != 0 );
01306         is_major_dir = FT_BOOL( edge->dir == axis->major_dir );
01307 
01308         /* if it is a top zone, the edge must be against the major    */
01309         /* direction; if it is a bottom zone, it must be in the major */
01310         /* direction                                                  */
01311         if ( is_top_blue ^ is_major_dir )
01312         {
01313           FT_Pos  dist;
01314 
01315 
01316           /* first of all, compare it to the reference position */
01317           dist = edge->fpos - blue->ref.org;
01318           if ( dist < 0 )
01319             dist = -dist;
01320 
01321           dist = FT_MulFix( dist, scale );
01322           if ( dist < best_dist )
01323           {
01324             best_dist = dist;
01325             best_blue = & blue->ref;
01326           }
01327 
01328           /* now, compare it to the overshoot position if the edge is     */
01329           /* rounded, and if the edge is over the reference position of a */
01330           /* top zone, or under the reference position of a bottom zone   */
01331           if ( edge->flags & AF_EDGE_ROUND && dist != 0 )
01332           {
01333             FT_Bool  is_under_ref = FT_BOOL( edge->fpos < blue->ref.org );
01334 
01335 
01336             if ( is_top_blue ^ is_under_ref )
01337             {
01338               blue = latin->blues + bb;
01339               dist = edge->fpos - blue->shoot.org;
01340               if ( dist < 0 )
01341                 dist = -dist;
01342 
01343               dist = FT_MulFix( dist, scale );
01344               if ( dist < best_dist )
01345               {
01346                 best_dist = dist;
01347                 best_blue = & blue->shoot;
01348               }
01349             }
01350           }
01351         }
01352       }
01353 
01354       if ( best_blue )
01355         edge->blue_edge = best_blue;
01356     }
01357   }
01358 
01359 
01360   static FT_Error
01361   af_latin_hints_init( AF_GlyphHints    hints,
01362                        AF_LatinMetrics  metrics )
01363   {
01364     FT_Render_Mode  mode;
01365     FT_UInt32       scaler_flags, other_flags;
01366     FT_Face         face = metrics->root.scaler.face;
01367 
01368 
01369     af_glyph_hints_rescale( hints, (AF_ScriptMetrics)metrics );
01370 
01371     /*
01372      *  correct x_scale and y_scale if needed, since they may have
01373      *  been modified `af_latin_metrics_scale_dim' above
01374      */
01375     hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale;
01376     hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta;
01377     hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale;
01378     hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta;
01379 
01380     /* compute flags depending on render mode, etc. */
01381     mode = metrics->root.scaler.render_mode;
01382 
01383 #if 0 /* #ifdef AF_USE_WARPER */
01384     if ( mode == FT_RENDER_MODE_LCD || mode == FT_RENDER_MODE_LCD_V )
01385     {
01386       metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL;
01387     }
01388 #endif
01389 
01390     scaler_flags = hints->scaler_flags;
01391     other_flags  = 0;
01392 
01393     /*
01394      *  We snap the width of vertical stems for the monochrome and
01395      *  horizontal LCD rendering targets only.
01396      */
01397     if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD )
01398       other_flags |= AF_LATIN_HINTS_HORZ_SNAP;
01399 
01400     /*
01401      *  We snap the width of horizontal stems for the monochrome and
01402      *  vertical LCD rendering targets only.
01403      */
01404     if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V )
01405       other_flags |= AF_LATIN_HINTS_VERT_SNAP;
01406 
01407     /*
01408      *  We adjust stems to full pixels only if we don't use the `light' mode.
01409      */
01410     if ( mode != FT_RENDER_MODE_LIGHT )
01411       other_flags |= AF_LATIN_HINTS_STEM_ADJUST;
01412 
01413     if ( mode == FT_RENDER_MODE_MONO )
01414       other_flags |= AF_LATIN_HINTS_MONO;
01415 
01416     /*
01417      *  In `light' hinting mode we disable horizontal hinting completely.
01418      *  We also do it if the face is italic.
01419      */
01420     if ( mode == FT_RENDER_MODE_LIGHT                    ||
01421          (face->style_flags & FT_STYLE_FLAG_ITALIC) != 0 )
01422       scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL;
01423 
01424     hints->scaler_flags = scaler_flags;
01425     hints->other_flags  = other_flags;
01426 
01427     return 0;
01428   }
01429 
01430 
01431   /*************************************************************************/
01432   /*************************************************************************/
01433   /*****                                                               *****/
01434   /*****        L A T I N   G L Y P H   G R I D - F I T T I N G        *****/
01435   /*****                                                               *****/
01436   /*************************************************************************/
01437   /*************************************************************************/
01438 
01439   /* snap a given width in scaled coordinates to one of the */
01440   /* current standard widths                                */
01441 
01442   static FT_Pos
01443   af_latin_snap_width( AF_Width  widths,
01444                        FT_Int    count,
01445                        FT_Pos    width )
01446   {
01447     int     n;
01448     FT_Pos  best      = 64 + 32 + 2;
01449     FT_Pos  reference = width;
01450     FT_Pos  scaled;
01451 
01452 
01453     for ( n = 0; n < count; n++ )
01454     {
01455       FT_Pos  w;
01456       FT_Pos  dist;
01457 
01458 
01459       w = widths[n].cur;
01460       dist = width - w;
01461       if ( dist < 0 )
01462         dist = -dist;
01463       if ( dist < best )
01464       {
01465         best      = dist;
01466         reference = w;
01467       }
01468     }
01469 
01470     scaled = FT_PIX_ROUND( reference );
01471 
01472     if ( width >= reference )
01473     {
01474       if ( width < scaled + 48 )
01475         width = reference;
01476     }
01477     else
01478     {
01479       if ( width > scaled - 48 )
01480         width = reference;
01481     }
01482 
01483     return width;
01484   }
01485 
01486 
01487   /* compute the snapped width of a given stem */
01488 
01489   static FT_Pos
01490   af_latin_compute_stem_width( AF_GlyphHints  hints,
01491                                AF_Dimension   dim,
01492                                FT_Pos         width,
01493                                AF_Edge_Flags  base_flags,
01494                                AF_Edge_Flags  stem_flags )
01495   {
01496     AF_LatinMetrics  metrics  = (AF_LatinMetrics) hints->metrics;
01497     AF_LatinAxis     axis     = & metrics->axis[dim];
01498     FT_Pos           dist     = width;
01499     FT_Int           sign     = 0;
01500     FT_Int           vertical = ( dim == AF_DIMENSION_VERT );
01501 
01502 
01503     if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ||
01504           axis->extra_light                      )
01505       return width;
01506 
01507     if ( dist < 0 )
01508     {
01509       dist = -width;
01510       sign = 1;
01511     }
01512 
01513     if ( (  vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
01514          ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
01515     {
01516       /* smooth hinting process: very lightly quantize the stem width */
01517 
01518       /* leave the widths of serifs alone */
01519 
01520       if ( ( stem_flags & AF_EDGE_SERIF ) && vertical && ( dist < 3 * 64 ) )
01521         goto Done_Width;
01522 
01523       else if ( ( base_flags & AF_EDGE_ROUND ) )
01524       {
01525         if ( dist < 80 )
01526           dist = 64;
01527       }
01528       else if ( dist < 56 )
01529         dist = 56;
01530 
01531       if ( axis->width_count > 0 )
01532       {
01533         FT_Pos  delta;
01534 
01535 
01536         /* compare to standard width */
01537         if ( axis->width_count > 0 )
01538         {
01539           delta = dist - axis->widths[0].cur;
01540 
01541           if ( delta < 0 )
01542             delta = -delta;
01543 
01544           if ( delta < 40 )
01545           {
01546             dist = axis->widths[0].cur;
01547             if ( dist < 48 )
01548               dist = 48;
01549 
01550             goto Done_Width;
01551           }
01552         }
01553 
01554         if ( dist < 3 * 64 )
01555         {
01556           delta  = dist & 63;
01557           dist  &= -64;
01558 
01559           if ( delta < 10 )
01560             dist += delta;
01561 
01562           else if ( delta < 32 )
01563             dist += 10;
01564 
01565           else if ( delta < 54 )
01566             dist += 54;
01567 
01568           else
01569             dist += delta;
01570         }
01571         else
01572           dist = ( dist + 32 ) & ~63;
01573       }
01574     }
01575     else
01576     {
01577       /* strong hinting process: snap the stem width to integer pixels */
01578       FT_Pos  org_dist = dist;
01579 
01580 
01581       dist = af_latin_snap_width( axis->widths, axis->width_count, dist );
01582 
01583       if ( vertical )
01584       {
01585         /* in the case of vertical hinting, always round */
01586         /* the stem heights to integer pixels            */
01587 
01588         if ( dist >= 64 )
01589           dist = ( dist + 16 ) & ~63;
01590         else
01591           dist = 64;
01592       }
01593       else
01594       {
01595         if ( AF_LATIN_HINTS_DO_MONO( hints ) )
01596         {
01597           /* monochrome horizontal hinting: snap widths to integer pixels */
01598           /* with a different threshold                                   */
01599 
01600           if ( dist < 64 )
01601             dist = 64;
01602           else
01603             dist = ( dist + 32 ) & ~63;
01604         }
01605         else
01606         {
01607           /* for horizontal anti-aliased hinting, we adopt a more subtle */
01608           /* approach: we strengthen small stems, round stems whose size */
01609           /* is between 1 and 2 pixels to an integer, otherwise nothing  */
01610 
01611           if ( dist < 48 )
01612             dist = ( dist + 64 ) >> 1;
01613 
01614           else if ( dist < 128 )
01615           {
01616             /* We only round to an integer width if the corresponding */
01617             /* distortion is less than 1/4 pixel.  Otherwise this     */
01618             /* makes everything worse since the diagonals, which are  */
01619             /* not hinted, appear a lot bolder or thinner than the    */
01620             /* vertical stems.                                        */
01621 
01622             FT_Pos  delta;
01623 
01624 
01625             dist = ( dist + 22 ) & ~63;
01626             delta = dist - org_dist;
01627             if ( delta < 0 )
01628               delta = -delta;
01629 
01630             if (delta >= 16)
01631             {
01632               dist = org_dist;
01633               if ( dist < 48 )
01634                 dist = ( dist + 64 ) >> 1;
01635             }
01636           }
01637           else
01638             /* round otherwise to prevent color fringes in LCD mode */
01639             dist = ( dist + 32 ) & ~63;
01640         }
01641       }
01642     }
01643 
01644   Done_Width:
01645     if ( sign )
01646       dist = -dist;
01647 
01648     return dist;
01649   }
01650 
01651 
01652   /* align one stem edge relative to the previous stem edge */
01653 
01654   static void
01655   af_latin_align_linked_edge( AF_GlyphHints  hints,
01656                               AF_Dimension   dim,
01657                               AF_Edge        base_edge,
01658                               AF_Edge        stem_edge )
01659   {
01660     FT_Pos  dist = stem_edge->opos - base_edge->opos;
01661 
01662     FT_Pos  fitted_width = af_latin_compute_stem_width(
01663                              hints, dim, dist,
01664                              (AF_Edge_Flags)base_edge->flags,
01665                              (AF_Edge_Flags)stem_edge->flags );
01666 
01667 
01668     stem_edge->pos = base_edge->pos + fitted_width;
01669 
01670     AF_LOG(( "LINK: edge %d (opos=%.2f) linked to (%.2f), "
01671              "dist was %.2f, now %.2f\n",
01672              stem_edge-hints->axis[dim].edges, stem_edge->opos / 64.0,
01673              stem_edge->pos / 64.0, dist / 64.0, fitted_width / 64.0 ));
01674   }
01675 
01676 
01677   static void
01678   af_latin_align_serif_edge( AF_GlyphHints  hints,
01679                              AF_Edge        base,
01680                              AF_Edge        serif )
01681   {
01682     FT_UNUSED( hints );
01683 
01684     serif->pos = base->pos + (serif->opos - base->opos);
01685   }
01686 
01687 
01688   /*************************************************************************/
01689   /*************************************************************************/
01690   /*************************************************************************/
01691   /****                                                                 ****/
01692   /****                    E D G E   H I N T I N G                      ****/
01693   /****                                                                 ****/
01694   /*************************************************************************/
01695   /*************************************************************************/
01696   /*************************************************************************/
01697 
01698 
01699   FT_LOCAL_DEF( void )
01700   af_latin_hint_edges( AF_GlyphHints  hints,
01701                        AF_Dimension   dim )
01702   {
01703     AF_AxisHints  axis       = &hints->axis[dim];
01704     AF_Edge       edges      = axis->edges;
01705     AF_Edge       edge_limit = edges + axis->num_edges;
01706     FT_PtrDist    n_edges;
01707     AF_Edge       edge;
01708     AF_Edge       anchor     = 0;
01709     FT_Int        has_serifs = 0;
01710 
01711 
01712     /* we begin by aligning all stems relative to the blue zone */
01713     /* if needed -- that's only for horizontal edges            */
01714 
01715     if ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_BLUES( hints ) )
01716     {
01717       for ( edge = edges; edge < edge_limit; edge++ )
01718       {
01719         AF_Width  blue;
01720         AF_Edge   edge1, edge2;
01721 
01722 
01723         if ( edge->flags & AF_EDGE_DONE )
01724           continue;
01725 
01726         blue  = edge->blue_edge;
01727         edge1 = NULL;
01728         edge2 = edge->link;
01729 
01730         if ( blue )
01731         {
01732           edge1 = edge;
01733         }
01734         else if ( edge2 && edge2->blue_edge )
01735         {
01736           blue  = edge2->blue_edge;
01737           edge1 = edge2;
01738           edge2 = edge;
01739         }
01740 
01741         if ( !edge1 )
01742           continue;
01743 
01744         AF_LOG(( "BLUE: edge %d (opos=%.2f) snapped to (%.2f), "
01745                  "was (%.2f)\n",
01746                  edge1-edges, edge1->opos / 64.0, blue->fit / 64.0,
01747                  edge1->pos / 64.0 ));
01748 
01749         edge1->pos    = blue->fit;
01750         edge1->flags |= AF_EDGE_DONE;
01751 
01752         if ( edge2 && !edge2->blue_edge )
01753         {
01754           af_latin_align_linked_edge( hints, dim, edge1, edge2 );
01755           edge2->flags |= AF_EDGE_DONE;
01756         }
01757 
01758         if ( !anchor )
01759           anchor = edge;
01760       }
01761     }
01762 
01763     /* now we will align all stem edges, trying to maintain the */
01764     /* relative order of stems in the glyph                     */
01765     for ( edge = edges; edge < edge_limit; edge++ )
01766     {
01767       AF_Edge  edge2;
01768 
01769 
01770       if ( edge->flags & AF_EDGE_DONE )
01771         continue;
01772 
01773       /* skip all non-stem edges */
01774       edge2 = edge->link;
01775       if ( !edge2 )
01776       {
01777         has_serifs++;
01778         continue;
01779       }
01780 
01781       /* now align the stem */
01782 
01783       /* this should not happen, but it's better to be safe */
01784       if ( edge2->blue_edge )
01785       {
01786         AF_LOG(( "ASSERTION FAILED for edge %d\n", edge2-edges ));
01787 
01788         af_latin_align_linked_edge( hints, dim, edge2, edge );
01789         edge->flags |= AF_EDGE_DONE;
01790         continue;
01791       }
01792 
01793       if ( !anchor )
01794       {
01795         FT_Pos  org_len, org_center, cur_len;
01796         FT_Pos  cur_pos1, error1, error2, u_off, d_off;
01797 
01798 
01799         org_len = edge2->opos - edge->opos;
01800         cur_len = af_latin_compute_stem_width(
01801                     hints, dim, org_len,
01802                     (AF_Edge_Flags)edge->flags,
01803                     (AF_Edge_Flags)edge2->flags );
01804         if ( cur_len <= 64 )
01805           u_off = d_off = 32;
01806         else
01807         {
01808           u_off = 38;
01809           d_off = 26;
01810         }
01811 
01812         if ( cur_len < 96 )
01813         {
01814           org_center = edge->opos + ( org_len >> 1 );
01815 
01816           cur_pos1   = FT_PIX_ROUND( org_center );
01817 
01818           error1 = org_center - ( cur_pos1 - u_off );
01819           if ( error1 < 0 )
01820             error1 = -error1;
01821 
01822           error2 = org_center - ( cur_pos1 + d_off );
01823           if ( error2 < 0 )
01824             error2 = -error2;
01825 
01826           if ( error1 < error2 )
01827             cur_pos1 -= u_off;
01828           else
01829             cur_pos1 += d_off;
01830 
01831           edge->pos  = cur_pos1 - cur_len / 2;
01832           edge2->pos = edge->pos + cur_len;
01833         }
01834         else
01835           edge->pos = FT_PIX_ROUND( edge->opos );
01836 
01837         AF_LOG(( "ANCHOR: edge %d (opos=%.2f) and %d (opos=%.2f) "
01838                  "snapped to (%.2f) (%.2f)\n",
01839                  edge-edges, edge->opos / 64.0,
01840                  edge2-edges, edge2->opos / 64.0,
01841                  edge->pos / 64.0, edge2->pos / 64.0 ));
01842         anchor = edge;
01843 
01844         edge->flags |= AF_EDGE_DONE;
01845 
01846         af_latin_align_linked_edge( hints, dim, edge, edge2 );
01847       }
01848       else
01849       {
01850         FT_Pos  org_pos, org_len, org_center, cur_len;
01851         FT_Pos  cur_pos1, cur_pos2, delta1, delta2;
01852 
01853 
01854         org_pos    = anchor->pos + ( edge->opos - anchor->opos );
01855         org_len    = edge2->opos - edge->opos;
01856         org_center = org_pos + ( org_len >> 1 );
01857 
01858         cur_len = af_latin_compute_stem_width(
01859                    hints, dim, org_len,
01860                    (AF_Edge_Flags)edge->flags,
01861                    (AF_Edge_Flags)edge2->flags );
01862 
01863         if ( edge2->flags & AF_EDGE_DONE )
01864           edge->pos = edge2->pos - cur_len;
01865 
01866         else if ( cur_len < 96 )
01867         {
01868           FT_Pos  u_off, d_off;
01869 
01870 
01871           cur_pos1 = FT_PIX_ROUND( org_center );
01872 
01873           if (cur_len <= 64 )
01874             u_off = d_off = 32;
01875           else
01876           {
01877             u_off = 38;
01878             d_off = 26;
01879           }
01880 
01881           delta1 = org_center - ( cur_pos1 - u_off );
01882           if ( delta1 < 0 )
01883             delta1 = -delta1;
01884 
01885           delta2 = org_center - ( cur_pos1 + d_off );
01886           if ( delta2 < 0 )
01887             delta2 = -delta2;
01888 
01889           if ( delta1 < delta2 )
01890             cur_pos1 -= u_off;
01891           else
01892             cur_pos1 += d_off;
01893 
01894           edge->pos  = cur_pos1 - cur_len / 2;
01895           edge2->pos = cur_pos1 + cur_len / 2;
01896 
01897           AF_LOG(( "STEM: %d (opos=%.2f) to %d (opos=%.2f) "
01898                    "snapped to (%.2f) and (%.2f)\n",
01899                    edge-edges, edge->opos / 64.0,
01900                    edge2-edges, edge2->opos / 64.0,
01901                    edge->pos / 64.0, edge2->pos / 64.0 ));
01902         }
01903         else
01904         {
01905           org_pos    = anchor->pos + ( edge->opos - anchor->opos );
01906           org_len    = edge2->opos - edge->opos;
01907           org_center = org_pos + ( org_len >> 1 );
01908 
01909           cur_len    = af_latin_compute_stem_width(
01910                          hints, dim, org_len,
01911                          (AF_Edge_Flags)edge->flags,
01912                          (AF_Edge_Flags)edge2->flags );
01913 
01914           cur_pos1   = FT_PIX_ROUND( org_pos );
01915           delta1     = cur_pos1 + ( cur_len >> 1 ) - org_center;
01916           if ( delta1 < 0 )
01917             delta1 = -delta1;
01918 
01919           cur_pos2   = FT_PIX_ROUND( org_pos + org_len ) - cur_len;
01920           delta2     = cur_pos2 + ( cur_len >> 1 ) - org_center;
01921           if ( delta2 < 0 )
01922             delta2 = -delta2;
01923 
01924           edge->pos  = ( delta1 < delta2 ) ? cur_pos1 : cur_pos2;
01925           edge2->pos = edge->pos + cur_len;
01926 
01927           AF_LOG(( "STEM: %d (opos=%.2f) to %d (opos=%.2f) "
01928                    "snapped to (%.2f) and (%.2f)\n",
01929                    edge-edges, edge->opos / 64.0,
01930                    edge2-edges, edge2->opos / 64.0,
01931                    edge->pos / 64.0, edge2->pos / 64.0 ));
01932         }
01933 
01934         edge->flags  |= AF_EDGE_DONE;
01935         edge2->flags |= AF_EDGE_DONE;
01936 
01937         if ( edge > edges && edge->pos < edge[-1].pos )
01938         {
01939           AF_LOG(( "BOUND: %d (pos=%.2f) to (%.2f)\n",
01940                    edge-edges, edge->pos / 64.0, edge[-1].pos / 64.0 ));
01941           edge->pos = edge[-1].pos;
01942         }
01943       }
01944     }
01945 
01946     /* make sure that lowercase m's maintain their symmetry */
01947 
01948     /* In general, lowercase m's have six vertical edges if they are sans */
01949     /* serif, or twelve if they are with serifs.  This implementation is  */
01950     /* based on that assumption, and seems to work very well with most    */
01951     /* faces.  However, if for a certain face this assumption is not      */
01952     /* true, the m is just rendered like before.  In addition, any stem   */
01953     /* correction will only be applied to symmetrical glyphs (even if the */
01954     /* glyph is not an m), so the potential for unwanted distortion is    */
01955     /* relatively low.                                                    */
01956 
01957     /* We don't handle horizontal edges since we can't easily assure that */
01958     /* the third (lowest) stem aligns with the base line; it might end up */
01959     /* one pixel higher or lower.                                         */
01960 
01961     n_edges = edge_limit - edges;
01962     if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) )
01963     {
01964       AF_Edge  edge1, edge2, edge3;
01965       FT_Pos   dist1, dist2, span, delta;
01966 
01967 
01968       if ( n_edges == 6 )
01969       {
01970         edge1 = edges;
01971         edge2 = edges + 2;
01972         edge3 = edges + 4;
01973       }
01974       else
01975       {
01976         edge1 = edges + 1;
01977         edge2 = edges + 5;
01978         edge3 = edges + 9;
01979       }
01980 
01981       dist1 = edge2->opos - edge1->opos;
01982       dist2 = edge3->opos - edge2->opos;
01983 
01984       span = dist1 - dist2;
01985       if ( span < 0 )
01986         span = -span;
01987 
01988       if ( span < 8 )
01989       {
01990         delta = edge3->pos - ( 2 * edge2->pos - edge1->pos );
01991         edge3->pos -= delta;
01992         if ( edge3->link )
01993           edge3->link->pos -= delta;
01994 
01995         /* move the serifs along with the stem */
01996         if ( n_edges == 12 )
01997         {
01998           ( edges + 8 )->pos -= delta;
01999           ( edges + 11 )->pos -= delta;
02000         }
02001 
02002         edge3->flags |= AF_EDGE_DONE;
02003         if ( edge3->link )
02004           edge3->link->flags |= AF_EDGE_DONE;
02005       }
02006     }
02007 
02008     if ( has_serifs || !anchor )
02009     {
02010       /*
02011        *  now hint the remaining edges (serifs and single) in order
02012        *  to complete our processing
02013        */
02014       for ( edge = edges; edge < edge_limit; edge++ )
02015       {
02016         FT_Pos  delta;
02017 
02018 
02019         if ( edge->flags & AF_EDGE_DONE )
02020           continue;
02021 
02022         delta = 1000;
02023 
02024         if ( edge->serif )
02025         {
02026           delta = edge->serif->opos - edge->opos;
02027           if ( delta < 0 )
02028             delta = -delta;
02029         }
02030 
02031         if ( delta < 64 + 16 )
02032         {
02033           af_latin_align_serif_edge( hints, edge->serif, edge );
02034           AF_LOG(( "SERIF: edge %d (opos=%.2f) serif to %d (opos=%.2f) "
02035                    "aligned to (%.2f)\n",
02036                    edge-edges, edge->opos / 64.0,
02037                    edge->serif - edges, edge->serif->opos / 64.0,
02038                    edge->pos / 64.0 ));
02039         }
02040         else if ( !anchor )
02041         {
02042           AF_LOG(( "SERIF_ANCHOR: edge %d (opos=%.2f) snapped to (%.2f)\n",
02043                    edge-edges, edge->opos / 64.0, edge->pos / 64.0 ));
02044           edge->pos = FT_PIX_ROUND( edge->opos );
02045           anchor    = edge;
02046         }
02047         else
02048         {
02049           AF_Edge  before, after;
02050 
02051 
02052           for ( before = edge - 1; before >= edges; before-- )
02053             if ( before->flags & AF_EDGE_DONE )
02054               break;
02055 
02056           for ( after = edge + 1; after < edge_limit; after++ )
02057             if ( after->flags & AF_EDGE_DONE )
02058               break;
02059 
02060           if ( before >= edges && before < edge   &&
02061                after < edge_limit && after > edge )
02062           {
02063             if ( after->opos == before->opos )
02064               edge->pos = before->pos;
02065             else
02066               edge->pos = before->pos +
02067                           FT_MulDiv( edge->opos - before->opos,
02068                                      after->pos - before->pos,
02069                                      after->opos - before->opos );
02070             AF_LOG(( "SERIF_LINK1: edge %d (opos=%.2f) snapped to (%.2f) "
02071                      "from %d (opos=%.2f)\n",
02072                      edge-edges, edge->opos / 64.0,
02073                      edge->pos / 64.0, before - edges,
02074                      before->opos / 64.0 ));
02075           }
02076           else
02077           {
02078             edge->pos = anchor->pos +
02079                         ( ( edge->opos - anchor->opos + 16 ) & ~31 );
02080             AF_LOG(( "SERIF_LINK2: edge %d (opos=%.2f) snapped to (%.2f)\n",
02081                      edge-edges, edge->opos / 64.0, edge->pos / 64.0 ));
02082           }
02083         }
02084 
02085         edge->flags |= AF_EDGE_DONE;
02086 
02087         if ( edge > edges && edge->pos < edge[-1].pos )
02088           edge->pos = edge[-1].pos;
02089 
02090         if ( edge + 1 < edge_limit        &&
02091              edge[1].flags & AF_EDGE_DONE &&
02092              edge->pos > edge[1].pos      )
02093           edge->pos = edge[1].pos;
02094       }
02095     }
02096   }
02097 
02098 
02099   static FT_Error
02100   af_latin_hints_apply( AF_GlyphHints    hints,
02101                         FT_Outline*      outline,
02102                         AF_LatinMetrics  metrics )
02103   {
02104     FT_Error  error;
02105     int       dim;
02106 
02107 
02108     error = af_glyph_hints_reload( hints, outline, 1 );
02109     if ( error )
02110       goto Exit;
02111 
02112     /* analyze glyph outline */
02113 #ifdef AF_USE_WARPER
02114     if ( metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT ||
02115          AF_HINTS_DO_HORIZONTAL( hints ) )
02116 #else
02117     if ( AF_HINTS_DO_HORIZONTAL( hints ) )
02118 #endif
02119     {
02120       error = af_latin_hints_detect_features( hints, AF_DIMENSION_HORZ );
02121       if ( error )
02122         goto Exit;
02123     }
02124 
02125     if ( AF_HINTS_DO_VERTICAL( hints ) )
02126     {
02127       error = af_latin_hints_detect_features( hints, AF_DIMENSION_VERT );
02128       if ( error )
02129         goto Exit;
02130 
02131       af_latin_hints_compute_blue_edges( hints, metrics );
02132     }
02133 
02134     /* grid-fit the outline */
02135     for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
02136     {
02137 #ifdef AF_USE_WARPER
02138       if ( ( dim == AF_DIMENSION_HORZ &&
02139              metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT ) )
02140       {
02141         AF_WarperRec  warper;
02142         FT_Fixed      scale;
02143         FT_Pos        delta;
02144 
02145 
02146         af_warper_compute( &warper, hints, dim, &scale, &delta );
02147         af_glyph_hints_scale_dim( hints, dim, scale, delta );
02148         continue;
02149       }
02150 #endif
02151 
02152       if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) ||
02153            ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) )   )
02154       {
02155         af_latin_hint_edges( hints, (AF_Dimension)dim );
02156         af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim );
02157         af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim );
02158         af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim );
02159       }
02160     }
02161     af_glyph_hints_save( hints, outline );
02162 
02163   Exit:
02164     return error;
02165   }
02166 
02167 
02168   /*************************************************************************/
02169   /*************************************************************************/
02170   /*****                                                               *****/
02171   /*****              L A T I N   S C R I P T   C L A S S              *****/
02172   /*****                                                               *****/
02173   /*************************************************************************/
02174   /*************************************************************************/
02175 
02176 
02177   /* XXX: this should probably fine tuned to differentiate better between */
02178   /*      scripts...                                                      */
02179 
02180   static const AF_Script_UniRangeRec  af_latin_uniranges[] =
02181   {
02182     AF_UNIRANGE_REC(  0x0020UL,  0x007FUL ),  /* Basic Latin (no control chars) */
02183     AF_UNIRANGE_REC(  0x00A0UL,  0x00FFUL ),  /* Latin-1 Supplement (no control chars) */
02184     AF_UNIRANGE_REC(  0x0100UL,  0x017FUL ),  /* Latin Extended-A */
02185     AF_UNIRANGE_REC(  0x0180UL,  0x024FUL ),  /* Latin Extended-B */
02186     AF_UNIRANGE_REC(  0x0250UL,  0x02AFUL ),  /* IPA Extensions */
02187     AF_UNIRANGE_REC(  0x02B0UL,  0x02FFUL ),  /* Spacing Modifier Letters */
02188     AF_UNIRANGE_REC(  0x0300UL,  0x036FUL ),  /* Combining Diacritical Marks */
02189     AF_UNIRANGE_REC(  0x0370UL,  0x03FFUL ),  /* Greek and Coptic */
02190     AF_UNIRANGE_REC(  0x0400UL,  0x04FFUL ),  /* Cyrillic */
02191     AF_UNIRANGE_REC(  0x0500UL,  0x052FUL ),  /* Cyrillic Supplement */
02192     AF_UNIRANGE_REC(  0x1D00UL,  0x1D7FUL ),  /* Phonetic Extensions */
02193     AF_UNIRANGE_REC(  0x1D80UL,  0x1DBFUL ),  /* Phonetic Extensions Supplement */
02194     AF_UNIRANGE_REC(  0x1DC0UL,  0x1DFFUL ),  /* Combining Diacritical Marks Supplement */
02195     AF_UNIRANGE_REC(  0x1E00UL,  0x1EFFUL ),  /* Latin Extended Additional */
02196     AF_UNIRANGE_REC(  0x1F00UL,  0x1FFFUL ),  /* Greek Extended */
02197     AF_UNIRANGE_REC(  0x2000UL,  0x206FUL ),  /* General Punctuation */
02198     AF_UNIRANGE_REC(  0x2070UL,  0x209FUL ),  /* Superscripts and Subscripts */
02199     AF_UNIRANGE_REC(  0x20A0UL,  0x20CFUL ),  /* Currency Symbols */
02200     AF_UNIRANGE_REC(  0x2150UL,  0x218FUL ),  /* Number Forms */
02201     AF_UNIRANGE_REC(  0x2460UL,  0x24FFUL ),  /* Enclosed Alphanumerics */
02202     AF_UNIRANGE_REC(  0x2C60UL,  0x2C7FUL ),  /* Latin Extended-C */
02203     AF_UNIRANGE_REC(  0x2DE0UL,  0x2DFFUL ),  /* Cyrillic Extended-A */
02204     AF_UNIRANGE_REC(  0xA640UL,  0xA69FUL ),  /* Cyrillic Extended-B */
02205     AF_UNIRANGE_REC(  0xA720UL,  0xA7FFUL ),  /* Latin Extended-D */
02206     AF_UNIRANGE_REC(  0xFB00UL,  0xFB06UL ),  /* Alphab. Present. Forms (Latin Ligs) */
02207     AF_UNIRANGE_REC( 0x1D400UL, 0x1D7FFUL ),  /* Mathematical Alphanumeric Symbols */
02208     AF_UNIRANGE_REC(       0UL,       0UL )
02209   };
02210 
02211 
02212   AF_DEFINE_SCRIPT_CLASS(af_latin_script_class,  
02213     AF_SCRIPT_LATIN,
02214     af_latin_uniranges,
02215 
02216     sizeof( AF_LatinMetricsRec ),
02217 
02218     (AF_Script_InitMetricsFunc) af_latin_metrics_init,
02219     (AF_Script_ScaleMetricsFunc)af_latin_metrics_scale,
02220     (AF_Script_DoneMetricsFunc) NULL,
02221 
02222     (AF_Script_InitHintsFunc)   af_latin_hints_init,
02223     (AF_Script_ApplyHintsFunc)  af_latin_hints_apply
02224   )
02225 
02226 
02227 /* END */

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