{
FT_Pos flats [AF_LATIN_MAX_TEST_CHARACTERS];
FT_Pos rounds[AF_LATIN_MAX_TEST_CHARACTERS];
FT_Int num_flats;
FT_Int num_rounds;
FT_Int bb;
AF_LatinBlue blue;
FT_Errorerror;
AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT];
FT_GlyphSlot glyph = face->glyph;
/* we compute the blues simply by loading each character from the *//* 'af_latin2_blue_chars[blues]' string, then compute its top-most or *//* bottom-most points (depending on `AF_IS_TOP_BLUE') */AF_LOG(( "blue zones computation\n" ));
AF_LOG(( "------------------------------------------------\n" ));
for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ )
{
constchar* p = af_latin2_blue_chars[bb];
constchar* limit = p + AF_LATIN_MAX_TEST_CHARACTERS;
FT_Pos* blue_ref;
FT_Pos* blue_shoot;
AF_LOG(( "blue %3d: ", bb ));
num_flats = 0;
num_rounds = 0;
for ( ; p < limit && *p; p++ )
{
FT_UInt glyph_index;
FT_Int best_point, best_y, best_first, best_last;
FT_Vector* points;
FT_Boolround;
AF_LOG(( "'%c'", *p ));
/* load the character in the face -- skip unknown or empty ones */
glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p );
if ( glyph_index == 0 )
continue;
error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
if ( error || glyph->outline.n_points <= 0 )
continue;
/* now compute min or max point indices and coordinates */
points = glyph->outline.points;
best_point = -1;
best_y = 0; /* make compiler happy */
best_first = 0; /* ditto */
best_last = 0; /* ditto */
{
FT_Int nn;
FT_Intfirst = 0;
FT_Intlast = -1;
for ( nn = 0; nn < glyph->outline.n_contours; first = last+1, nn++ )
{
FT_Int old_best_point = best_point;
FT_Int pp;
last = glyph->outline.contours[nn];
/* Avoid single-point contours since they are never rasterized. *//* In some fonts, they correspond to mark attachment points *//* which are way outside of the glyph's real outline. */if ( last == first )
continue;
if ( AF_LATIN_IS_TOP_BLUE( bb ) )
{
for ( pp = first; pp <= last; pp++ )
if ( best_point < 0 || points[pp].y > best_y )
{
best_point = pp;
best_y = points[pp].y;
}
}
else
{
for ( pp = first; pp <= last; pp++ )
if ( best_point < 0 || points[pp].y < best_y )
{
best_point = pp;
best_y = points[pp].y;
}
}
if ( best_point != old_best_point )
{
best_first = first;
best_last = last;
}
}
AF_LOG(( "%5d", best_y ));
}
/* now check whether the point belongs to a straight or round *//* segment; we first need to find in which contour the extremum *//* lies, then inspect its previous and next points */
{
FT_Intstart, end, prev, next;
FT_Posdist;
/* now look for the previous and next points that are not on the *//* same Y coordinate. Threshold the `closeness'... */
start = end = best_point;
do
{
prev = start-1;
if ( prev < best_first )
prev = best_last;
dist = points[prev].y - best_y;
if ( dist < -5 || dist > 5 )
break;
start = prev;
} while ( start != best_point );
do
{
next = end+1;
if ( next > best_last )
next = best_first;
dist = points[next].y - best_y;
if ( dist < -5 || dist > 5 )
break;
end = next;
} while ( end != best_point );
/* now, set the `round' flag depending on the segment's kind */
round = FT_BOOL(
FT_CURVE_TAG( glyph->outline.tags[start] ) != FT_CURVE_TAG_ON ||
FT_CURVE_TAG( glyph->outline.tags[ end ] ) != FT_CURVE_TAG_ON );
AF_LOG(( "%c ", round ? 'r' : 'f' ));
}
if ( round )
rounds[num_rounds++] = best_y;
else
flats[num_flats++] = best_y;
}
AF_LOG(( "\n" ));
if ( num_flats == 0 && num_rounds == 0 )
{
/* * we couldn't find a single glyph to compute this blue zone, * we will simply ignore it then */AF_LOG(( "empty\n" ));
continue;
}
/* we have computed the contents of the `rounds' and `flats' tables, *//* now determine the reference and overshoot position of the blue -- *//* we simply take the median value after a simple sort */af_sort_pos( num_rounds, rounds );
af_sort_pos( num_flats, flats );
blue = & axis->blues[axis->blue_count];
blue_ref = & blue->ref.org;
blue_shoot = & blue->shoot.org;
axis->blue_count++;
if ( num_flats == 0 )
{
*blue_ref =
*blue_shoot = rounds[num_rounds / 2];
}
elseif ( num_rounds == 0 )
{
*blue_ref =
*blue_shoot = flats[num_flats / 2];
}
else
{
*blue_ref = flats[num_flats / 2];
*blue_shoot = rounds[num_rounds / 2];
}
/* there are sometimes problems: if the overshoot position of top *//* zones is under its reference position, or the opposite for bottom *//* zones. We must thus check everything there and correct the errors */if ( *blue_shoot != *blue_ref )
{
FT_Posref = *blue_ref;
FT_Pos shoot = *blue_shoot;
FT_Bool over_ref = FT_BOOL( shoot > ref );
if ( AF_LATIN_IS_TOP_BLUE( bb ) ^ over_ref )
*blue_shoot = *blue_ref = ( shoot + ref ) / 2;
}
blue->flags = 0;
if ( AF_LATIN_IS_TOP_BLUE( bb ) )
blue->flags |= AF_LATIN_BLUE_TOP;
/* * The following flags is used later to adjust the y and x scales * in order to optimize the pixel grid alignment of the top of small * letters. */if ( bb == AF_LATIN_BLUE_SMALL_TOP )
blue->flags |= AF_LATIN_BLUE_ADJUSTMENT;
AF_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot ));
}
return;
}
Generated on Sat May 26 2012 05:59:02 for ReactOS by
1.7.6.1
ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.