ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

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

Generated on Sat May 26 2012 04:32:29 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.