|
|
|
@ -36,6 +36,10 @@ |
|
|
|
|
/*************************************************************************/ |
|
|
|
|
/*************************************************************************/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Find segments and links, compute all stem widths, and initialize */ |
|
|
|
|
/* standard width and height for the glyph with given charcode. */ |
|
|
|
|
|
|
|
|
|
FT_LOCAL_DEF( void ) |
|
|
|
|
af_latin_metrics_init_widths( AF_LatinMetrics metrics, |
|
|
|
|
FT_Face face, |
|
|
|
@ -69,8 +73,12 @@ |
|
|
|
|
FT_ZERO( dummy ); |
|
|
|
|
|
|
|
|
|
dummy->units_per_em = metrics->units_per_em; |
|
|
|
|
scaler->x_scale = scaler->y_scale = 0x10000L; |
|
|
|
|
scaler->x_delta = scaler->y_delta = 0; |
|
|
|
|
|
|
|
|
|
scaler->x_scale = 0x10000L; |
|
|
|
|
scaler->y_scale = 0x10000L; |
|
|
|
|
scaler->x_delta = 0; |
|
|
|
|
scaler->y_delta = 0; |
|
|
|
|
|
|
|
|
|
scaler->face = face; |
|
|
|
|
scaler->render_mode = FT_RENDER_MODE_NORMAL; |
|
|
|
|
scaler->flags = 0; |
|
|
|
@ -161,6 +169,9 @@ |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Find all blue zones. Flat segments give the reference points, */ |
|
|
|
|
/* round segments the overshoot positions. */ |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
af_latin_metrics_init_blues( AF_LatinMetrics metrics, |
|
|
|
|
FT_Face face ) |
|
|
|
@ -177,7 +188,7 @@ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* we compute the blues simply by loading each character from the */ |
|
|
|
|
/* 'af_latin_blue_chars[blues]' string, then compute its top-most or */ |
|
|
|
|
/* `af_latin_blue_chars[blues]' string, then finding its top-most or */ |
|
|
|
|
/* bottom-most points (depending on `AF_IS_TOP_BLUE') */ |
|
|
|
|
|
|
|
|
|
AF_LOG(( "blue zones computation\n" )); |
|
|
|
@ -199,7 +210,7 @@ |
|
|
|
|
for ( ; p < limit && *p; p++ ) |
|
|
|
|
{ |
|
|
|
|
FT_UInt glyph_index; |
|
|
|
|
FT_Pos best_y; /* same as points.y */ |
|
|
|
|
FT_Pos best_y; /* same as points.y */ |
|
|
|
|
FT_Int best_point, best_first, best_last; |
|
|
|
|
FT_Vector* points; |
|
|
|
|
FT_Bool round = 0; |
|
|
|
@ -229,7 +240,9 @@ |
|
|
|
|
FT_Int last = -1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for ( nn = 0; nn < glyph->outline.n_contours; first = last+1, nn++ ) |
|
|
|
|
for ( nn = 0; |
|
|
|
|
nn < glyph->outline.n_contours; |
|
|
|
|
first = last + 1, nn++ ) |
|
|
|
|
{ |
|
|
|
|
FT_Int old_best_point = best_point; |
|
|
|
|
FT_Int pp; |
|
|
|
@ -241,7 +254,7 @@ |
|
|
|
|
/* In some fonts, they correspond to mark attachment points */ |
|
|
|
|
/* which are way outside of the glyph's real outline. */ |
|
|
|
|
if ( last <= first ) |
|
|
|
|
continue; |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
if ( AF_LATIN_IS_TOP_BLUE( bb ) ) |
|
|
|
|
{ |
|
|
|
@ -311,7 +324,7 @@ |
|
|
|
|
|
|
|
|
|
} while ( next != best_point ); |
|
|
|
|
|
|
|
|
|
/* now, set the `round' flag depending on the segment's kind */ |
|
|
|
|
/* now set the `round' flag depending on the segment's kind */ |
|
|
|
|
round = FT_BOOL( |
|
|
|
|
FT_CURVE_TAG( glyph->outline.tags[prev] ) != FT_CURVE_TAG_ON || |
|
|
|
|
FT_CURVE_TAG( glyph->outline.tags[next] ) != FT_CURVE_TAG_ON ); |
|
|
|
@ -343,9 +356,9 @@ |
|
|
|
|
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; |
|
|
|
|
blue = &axis->blues[axis->blue_count]; |
|
|
|
|
blue_ref = &blue->ref.org; |
|
|
|
|
blue_shoot = &blue->shoot.org; |
|
|
|
|
|
|
|
|
|
axis->blue_count++; |
|
|
|
|
|
|
|
|
@ -376,7 +389,8 @@ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ( AF_LATIN_IS_TOP_BLUE( bb ) ^ over_ref ) |
|
|
|
|
*blue_shoot = *blue_ref = ( shoot + ref ) / 2; |
|
|
|
|
*blue_ref = |
|
|
|
|
*blue_shoot = ( shoot + ref ) / 2; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
blue->flags = 0; |
|
|
|
@ -398,6 +412,8 @@ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Check whether all ASCII digits have the same advance width. */ |
|
|
|
|
|
|
|
|
|
FT_LOCAL_DEF( void ) |
|
|
|
|
af_latin_metrics_check_digits( AF_LatinMetrics metrics, |
|
|
|
|
FT_Face face ) |
|
|
|
@ -407,8 +423,7 @@ |
|
|
|
|
FT_Fixed advance, old_advance = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* check whether all ASCII digits have the same advance width; */ |
|
|
|
|
/* digit `0' is 0x30 in all supported charmaps */ |
|
|
|
|
/* digit `0' is 0x30 in all supported charmaps */ |
|
|
|
|
for ( i = 0x30; i <= 0x39; i++ ) |
|
|
|
|
{ |
|
|
|
|
FT_UInt glyph_index; |
|
|
|
@ -444,6 +459,8 @@ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Initialize global metrics. */ |
|
|
|
|
|
|
|
|
|
FT_LOCAL_DEF( FT_Error ) |
|
|
|
|
af_latin_metrics_init( AF_LatinMetrics metrics, |
|
|
|
|
FT_Face face ) |
|
|
|
@ -458,6 +475,7 @@ |
|
|
|
|
FT_ENCODING_APPLE_ROMAN, |
|
|
|
|
FT_ENCODING_ADOBE_STANDARD, |
|
|
|
|
FT_ENCODING_ADOBE_LATIN_1, |
|
|
|
|
|
|
|
|
|
FT_ENCODING_NONE /* end of list */ |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -485,6 +503,9 @@ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Adjust scaling value, then scale and shift widths */ |
|
|
|
|
/* and blue zones (if applicable) for given dimension. */ |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
af_latin_metrics_scale_dim( AF_LatinMetrics metrics, |
|
|
|
|
AF_Scaler scaler, |
|
|
|
@ -550,9 +571,7 @@ |
|
|
|
|
else |
|
|
|
|
#endif |
|
|
|
|
if ( dim == AF_DIMENSION_VERT ) |
|
|
|
|
{ |
|
|
|
|
scale = FT_MulDiv( scale, fitted, scaled ); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -571,7 +590,7 @@ |
|
|
|
|
metrics->root.scaler.y_delta = delta; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* scale the standard widths */ |
|
|
|
|
/* scale the widths */ |
|
|
|
|
for ( nn = 0; nn < axis->width_count; nn++ ) |
|
|
|
|
{ |
|
|
|
|
AF_Width width = axis->widths + nn; |
|
|
|
@ -635,6 +654,8 @@ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Scale global values in both directions. */ |
|
|
|
|
|
|
|
|
|
FT_LOCAL_DEF( void ) |
|
|
|
|
af_latin_metrics_scale( AF_LatinMetrics metrics, |
|
|
|
|
AF_Scaler scaler ) |
|
|
|
@ -655,18 +676,21 @@ |
|
|
|
|
/*************************************************************************/ |
|
|
|
|
/*************************************************************************/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Walk over all contours and compute its segments. */ |
|
|
|
|
|
|
|
|
|
FT_LOCAL_DEF( FT_Error ) |
|
|
|
|
af_latin_hints_compute_segments( AF_GlyphHints hints, |
|
|
|
|
AF_Dimension dim ) |
|
|
|
|
{ |
|
|
|
|
AF_AxisHints axis = &hints->axis[dim]; |
|
|
|
|
FT_Memory memory = hints->memory; |
|
|
|
|
FT_Error error = AF_Err_Ok; |
|
|
|
|
AF_Segment segment = NULL; |
|
|
|
|
AF_SegmentRec seg0; |
|
|
|
|
AF_Point* contour = hints->contours; |
|
|
|
|
AF_Point* contour_limit = contour + hints->num_contours; |
|
|
|
|
AF_Direction major_dir, segment_dir; |
|
|
|
|
AF_AxisHints axis = &hints->axis[dim]; |
|
|
|
|
FT_Memory memory = hints->memory; |
|
|
|
|
FT_Error error = AF_Err_Ok; |
|
|
|
|
AF_Segment segment = NULL; |
|
|
|
|
AF_SegmentRec seg0; |
|
|
|
|
AF_Point* contour = hints->contours; |
|
|
|
|
AF_Point* contour_limit = contour + hints->num_contours; |
|
|
|
|
AF_Direction major_dir, segment_dir; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FT_ZERO( &seg0 ); |
|
|
|
@ -762,7 +786,7 @@ |
|
|
|
|
/* a segment is round if either its first or last point */ |
|
|
|
|
/* is a control point */ |
|
|
|
|
if ( ( segment->first->flags | point->flags ) & |
|
|
|
|
AF_FLAG_CONTROL ) |
|
|
|
|
AF_FLAG_CONTROL ) |
|
|
|
|
segment->flags |= AF_EDGE_ROUND; |
|
|
|
|
|
|
|
|
|
/* compute segment size */ |
|
|
|
@ -874,6 +898,8 @@ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Link segments to form stems and serifs. */ |
|
|
|
|
|
|
|
|
|
FT_LOCAL_DEF( void ) |
|
|
|
|
af_latin_hints_link_segments( AF_GlyphHints hints, |
|
|
|
|
AF_Dimension dim ) |
|
|
|
@ -899,6 +925,8 @@ |
|
|
|
|
if ( seg1->dir != axis->major_dir || seg1->first == seg1->last ) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
/* search for stems having opposite directions, */ |
|
|
|
|
/* with seg1 to the `left' of seg2 */ |
|
|
|
|
for ( seg2 = segments; seg2 < segment_limit; seg2++ ) |
|
|
|
|
{ |
|
|
|
|
FT_Pos pos1 = seg1->pos; |
|
|
|
@ -907,6 +935,7 @@ |
|
|
|
|
|
|
|
|
|
if ( seg1->dir + seg2->dir == 0 && pos2 > pos1 ) |
|
|
|
|
{ |
|
|
|
|
/* compute distance between the two segments */ |
|
|
|
|
FT_Pos dist = pos2 - pos1; |
|
|
|
|
FT_Pos min = seg1->min_coord; |
|
|
|
|
FT_Pos max = seg1->max_coord; |
|
|
|
@ -919,11 +948,16 @@ |
|
|
|
|
if ( max > seg2->max_coord ) |
|
|
|
|
max = seg2->max_coord; |
|
|
|
|
|
|
|
|
|
/* compute maximum coordinate difference of the two segments */ |
|
|
|
|
len = max - min; |
|
|
|
|
if ( len >= len_threshold ) |
|
|
|
|
{ |
|
|
|
|
/* small coordinate differences cause a higher score, and */ |
|
|
|
|
/* segments with a greater distance cause a higher score also */ |
|
|
|
|
score = dist + len_score / len; |
|
|
|
|
|
|
|
|
|
/* and we search for the smallest score */ |
|
|
|
|
/* of the sum of the two values */ |
|
|
|
|
if ( score < seg1->score ) |
|
|
|
|
{ |
|
|
|
|
seg1->score = score; |
|
|
|
@ -940,7 +974,7 @@ |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* now, compute the `serif' segments */ |
|
|
|
|
/* now compute the `serif' segments, cf. explanations in `afhints.h' */ |
|
|
|
|
for ( seg1 = segments; seg1 < segment_limit; seg1++ ) |
|
|
|
|
{ |
|
|
|
|
seg2 = seg1->link; |
|
|
|
@ -957,6 +991,8 @@ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Link segments to edges, using feature analysis for selection. */ |
|
|
|
|
|
|
|
|
|
FT_LOCAL_DEF( FT_Error ) |
|
|
|
|
af_latin_hints_compute_edges( AF_GlyphHints hints, |
|
|
|
|
AF_Dimension dim ) |
|
|
|
@ -985,7 +1021,7 @@ |
|
|
|
|
: AF_DIR_RIGHT; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We ignore all segments that are less than 1 pixels in length, |
|
|
|
|
* We ignore all segments that are less than 1 pixel in length |
|
|
|
|
* to avoid many problems with serif fonts. We compute the |
|
|
|
|
* corresponding threshold in font units. |
|
|
|
|
*/ |
|
|
|
@ -996,20 +1032,21 @@ |
|
|
|
|
|
|
|
|
|
/*********************************************************************/ |
|
|
|
|
/* */ |
|
|
|
|
/* We will begin by generating a sorted table of edges for the */ |
|
|
|
|
/* current direction. To do so, we simply scan each segment and try */ |
|
|
|
|
/* to find an edge in our table that corresponds to its position. */ |
|
|
|
|
/* We begin by generating a sorted table of edges for the current */ |
|
|
|
|
/* direction. To do so, we simply scan each segment and try to find */ |
|
|
|
|
/* an edge in our table that corresponds to its position. */ |
|
|
|
|
/* */ |
|
|
|
|
/* If no edge is found, we create and insert a new edge in the */ |
|
|
|
|
/* sorted table. Otherwise, we simply add the segment to the edge's */ |
|
|
|
|
/* list which will be processed in the second step to compute the */ |
|
|
|
|
/* list which gets processed in the second step to compute the */ |
|
|
|
|
/* edge's properties. */ |
|
|
|
|
/* */ |
|
|
|
|
/* Note that the edges table is sorted along the segment/edge */ |
|
|
|
|
/* Note that the table of edges is sorted along the segment/edge */ |
|
|
|
|
/* position. */ |
|
|
|
|
/* */ |
|
|
|
|
/*********************************************************************/ |
|
|
|
|
|
|
|
|
|
/* assure that edge distance threshold is at least 0.25px */ |
|
|
|
|
edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold, |
|
|
|
|
scale ); |
|
|
|
|
if ( edge_distance_threshold > 64 / 4 ) |
|
|
|
@ -1020,7 +1057,7 @@ |
|
|
|
|
|
|
|
|
|
for ( seg = segments; seg < segment_limit; seg++ ) |
|
|
|
|
{ |
|
|
|
|
AF_Edge found = 0; |
|
|
|
|
AF_Edge found = NULL; |
|
|
|
|
FT_Int ee; |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -1069,9 +1106,10 @@ |
|
|
|
|
|
|
|
|
|
edge->first = seg; |
|
|
|
|
edge->last = seg; |
|
|
|
|
edge->fpos = seg->pos; |
|
|
|
|
edge->dir = seg->dir; |
|
|
|
|
edge->opos = edge->pos = FT_MulFix( seg->pos, scale ); |
|
|
|
|
edge->fpos = seg->pos; |
|
|
|
|
edge->opos = FT_MulFix( seg->pos, scale ); |
|
|
|
|
edge->pos = edge->opos; |
|
|
|
|
seg->edge_next = seg; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
@ -1088,9 +1126,9 @@ |
|
|
|
|
/*********************************************************************/ |
|
|
|
|
/* */ |
|
|
|
|
/* Good, we will now compute each edge's properties according to */ |
|
|
|
|
/* segments found on its position. Basically, these are: */ |
|
|
|
|
/* the segments found on its position. Basically, these are */ |
|
|
|
|
/* */ |
|
|
|
|
/* - edge's main direction */ |
|
|
|
|
/* - the edge's main direction */ |
|
|
|
|
/* - stem edge, serif edge or both (which defaults to stem then) */ |
|
|
|
|
/* - rounded edge, straight or both (which defaults to straight) */ |
|
|
|
|
/* - link for edge */ |
|
|
|
@ -1123,7 +1161,7 @@ |
|
|
|
|
} while ( seg != edge->first ); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* now, compute each edge properties */ |
|
|
|
|
/* now compute each edge properties */ |
|
|
|
|
for ( edge = edges; edge < edge_limit; edge++ ) |
|
|
|
|
{ |
|
|
|
|
FT_Int is_round = 0; /* does it contain round segments? */ |
|
|
|
@ -1150,9 +1188,9 @@ |
|
|
|
|
#if 0 |
|
|
|
|
/* check for segment direction */ |
|
|
|
|
if ( seg->dir == up_dir ) |
|
|
|
|
ups += seg->max_coord-seg->min_coord; |
|
|
|
|
ups += seg->max_coord - seg->min_coord; |
|
|
|
|
else |
|
|
|
|
downs += seg->max_coord-seg->min_coord; |
|
|
|
|
downs += seg->max_coord - seg->min_coord; |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/* check for links -- if seg->serif is set, then seg->link must */ |
|
|
|
@ -1229,7 +1267,7 @@ |
|
|
|
|
edge->dir = 0; /* both up and down! */ |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/* gets rid of serifs if link is set */ |
|
|
|
|
/* get rid of serifs if link is set */ |
|
|
|
|
/* XXX: This gets rid of many unpleasant artefacts! */ |
|
|
|
|
/* Example: the `c' in cour.pfa at size 13 */ |
|
|
|
|
|
|
|
|
@ -1243,6 +1281,8 @@ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Detect segments and edges for given dimension. */ |
|
|
|
|
|
|
|
|
|
FT_LOCAL_DEF( FT_Error ) |
|
|
|
|
af_latin_hints_detect_features( AF_GlyphHints hints, |
|
|
|
|
AF_Dimension dim ) |
|
|
|
@ -1257,10 +1297,13 @@ |
|
|
|
|
|
|
|
|
|
error = af_latin_hints_compute_edges( hints, dim ); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return error; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Compute all edges which lie within blue zones. */ |
|
|
|
|
|
|
|
|
|
FT_LOCAL_DEF( void ) |
|
|
|
|
af_latin_hints_compute_blue_edges( AF_GlyphHints hints, |
|
|
|
|
AF_LatinMetrics metrics ) |
|
|
|
@ -1284,8 +1327,10 @@ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* compute the initial threshold as a fraction of the EM size */ |
|
|
|
|
/* (the value 40 is heuristic) */ |
|
|
|
|
best_dist = FT_MulFix( metrics->units_per_em / 40, scale ); |
|
|
|
|
|
|
|
|
|
/* assure a minumum distance of 0.5px */ |
|
|
|
|
if ( best_dist > 64 / 2 ) |
|
|
|
|
best_dist = 64 / 2; |
|
|
|
|
|
|
|
|
@ -1295,7 +1340,7 @@ |
|
|
|
|
FT_Bool is_top_blue, is_major_dir; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* skip inactive blue zones (i.e., those that are too small) */ |
|
|
|
|
/* skip inactive blue zones (i.e., those that are too large) */ |
|
|
|
|
if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) ) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
@ -1323,12 +1368,13 @@ |
|
|
|
|
if ( dist < best_dist ) |
|
|
|
|
{ |
|
|
|
|
best_dist = dist; |
|
|
|
|
best_blue = & blue->ref; |
|
|
|
|
best_blue = &blue->ref; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* now, compare it to the overshoot position if the edge is */ |
|
|
|
|
/* rounded, and if the edge is over the reference position of a */ |
|
|
|
|
/* top zone, or under the reference position of a bottom zone */ |
|
|
|
|
/* now compare it to the overshoot position and check whether */ |
|
|
|
|
/* the edge is rounded, and whether the edge is over the */ |
|
|
|
|
/* reference position of a top zone, or under the reference */ |
|
|
|
|
/* position of a bottom zone */ |
|
|
|
|
if ( edge->flags & AF_EDGE_ROUND && dist != 0 ) |
|
|
|
|
{ |
|
|
|
|
FT_Bool is_under_ref = FT_BOOL( edge->fpos < blue->ref.org ); |
|
|
|
@ -1344,7 +1390,7 @@ |
|
|
|
|
if ( dist < best_dist ) |
|
|
|
|
{ |
|
|
|
|
best_dist = dist; |
|
|
|
|
best_blue = & blue->shoot; |
|
|
|
|
best_blue = &blue->shoot; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1357,6 +1403,8 @@ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Initalize hinting engine. */ |
|
|
|
|
|
|
|
|
|
static FT_Error |
|
|
|
|
af_latin_hints_init( AF_GlyphHints hints, |
|
|
|
|
AF_LatinMetrics metrics ) |
|
|
|
@ -1370,7 +1418,7 @@ |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* correct x_scale and y_scale if needed, since they may have |
|
|
|
|
* been modified `af_latin_metrics_scale_dim' above |
|
|
|
|
* been modified by `af_latin_metrics_scale_dim' above |
|
|
|
|
*/ |
|
|
|
|
hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale; |
|
|
|
|
hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta; |
|
|
|
@ -1417,8 +1465,8 @@ |
|
|
|
|
* In `light' hinting mode we disable horizontal hinting completely. |
|
|
|
|
* We also do it if the face is italic. |
|
|
|
|
*/ |
|
|
|
|
if ( mode == FT_RENDER_MODE_LIGHT || |
|
|
|
|
(face->style_flags & FT_STYLE_FLAG_ITALIC) != 0 ) |
|
|
|
|
if ( mode == FT_RENDER_MODE_LIGHT || |
|
|
|
|
( face->style_flags & FT_STYLE_FLAG_ITALIC ) != 0 ) |
|
|
|
|
scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL; |
|
|
|
|
|
|
|
|
|
hints->scaler_flags = scaler_flags; |
|
|
|
@ -1436,8 +1484,8 @@ |
|
|
|
|
/*************************************************************************/ |
|
|
|
|
/*************************************************************************/ |
|
|
|
|
|
|
|
|
|
/* snap a given width in scaled coordinates to one of the */ |
|
|
|
|
/* current standard widths */ |
|
|
|
|
/* Snap a given width in scaled coordinates to one of the */ |
|
|
|
|
/* current standard widths. */ |
|
|
|
|
|
|
|
|
|
static FT_Pos |
|
|
|
|
af_latin_snap_width( AF_Width widths, |
|
|
|
@ -1484,7 +1532,9 @@ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* compute the snapped width of a given stem */ |
|
|
|
|
/* Compute the snapped width of a given stem, ignoring very thin ones. */ |
|
|
|
|
/* There is a lot of voodoo in this function; changing the hard-coded */ |
|
|
|
|
/* parameters influence the whole hinting process. */ |
|
|
|
|
|
|
|
|
|
static FT_Pos |
|
|
|
|
af_latin_compute_stem_width( AF_GlyphHints hints, |
|
|
|
@ -1501,7 +1551,7 @@ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) || |
|
|
|
|
axis->extra_light ) |
|
|
|
|
axis->extra_light ) |
|
|
|
|
return width; |
|
|
|
|
|
|
|
|
|
if ( dist < 0 ) |
|
|
|
@ -1516,8 +1566,9 @@ |
|
|
|
|
/* smooth hinting process: very lightly quantize the stem width */ |
|
|
|
|
|
|
|
|
|
/* leave the widths of serifs alone */ |
|
|
|
|
|
|
|
|
|
if ( ( stem_flags & AF_EDGE_SERIF ) && vertical && ( dist < 3 * 64 ) ) |
|
|
|
|
if ( ( stem_flags & AF_EDGE_SERIF ) && |
|
|
|
|
vertical && |
|
|
|
|
( dist < 3 * 64 ) ) |
|
|
|
|
goto Done_Width; |
|
|
|
|
|
|
|
|
|
else if ( ( base_flags & AF_EDGE_ROUND ) ) |
|
|
|
@ -1572,6 +1623,7 @@ |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
/* strong hinting process: snap the stem width to integer pixels */ |
|
|
|
|
|
|
|
|
|
FT_Pos org_dist = dist; |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -1646,7 +1698,7 @@ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* align one stem edge relative to the previous stem edge */ |
|
|
|
|
/* Align one stem edge relative to the previous stem edge. */ |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
af_latin_align_linked_edge( AF_GlyphHints hints, |
|
|
|
@ -1664,13 +1716,16 @@ |
|
|
|
|
|
|
|
|
|
stem_edge->pos = base_edge->pos + fitted_width; |
|
|
|
|
|
|
|
|
|
AF_LOG(( "LINK: edge %d (opos=%.2f) linked to (%.2f), " |
|
|
|
|
"dist was %.2f, now %.2f\n", |
|
|
|
|
AF_LOG(( "LINK: edge %d (opos=%.2f) linked to (%.2f)," |
|
|
|
|
" dist was %.2f, now %.2f\n", |
|
|
|
|
stem_edge-hints->axis[dim].edges, stem_edge->opos / 64.0, |
|
|
|
|
stem_edge->pos / 64.0, dist / 64.0, fitted_width / 64.0 )); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Shift the coordinates of the `serif' edge by the same amount */ |
|
|
|
|
/* as the corresponding `base' edge has been moved already. */ |
|
|
|
|
|
|
|
|
|
static void |
|
|
|
|
af_latin_align_serif_edge( AF_GlyphHints hints, |
|
|
|
|
AF_Edge base, |
|
|
|
@ -1678,7 +1733,7 @@ |
|
|
|
|
{ |
|
|
|
|
FT_UNUSED( hints ); |
|
|
|
|
|
|
|
|
|
serif->pos = base->pos + (serif->opos - base->opos); |
|
|
|
|
serif->pos = base->pos + ( serif->opos - base->opos ); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -1693,6 +1748,8 @@ |
|
|
|
|
/*************************************************************************/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* The main grid-fitting routine. */ |
|
|
|
|
|
|
|
|
|
FT_LOCAL_DEF( void ) |
|
|
|
|
af_latin_hint_edges( AF_GlyphHints hints, |
|
|
|
|
AF_Dimension dim ) |
|
|
|
@ -1702,7 +1759,7 @@ |
|
|
|
|
AF_Edge edge_limit = edges + axis->num_edges; |
|
|
|
|
FT_PtrDist n_edges; |
|
|
|
|
AF_Edge edge; |
|
|
|
|
AF_Edge anchor = 0; |
|
|
|
|
AF_Edge anchor = NULL; |
|
|
|
|
FT_Int has_serifs = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -1725,9 +1782,8 @@ |
|
|
|
|
edge2 = edge->link; |
|
|
|
|
|
|
|
|
|
if ( blue ) |
|
|
|
|
{ |
|
|
|
|
edge1 = edge; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
else if ( edge2 && edge2->blue_edge ) |
|
|
|
|
{ |
|
|
|
|
blue = edge2->blue_edge; |
|
|
|
@ -1738,9 +1794,9 @@ |
|
|
|
|
if ( !edge1 ) |
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
AF_LOG(( "BLUE: edge %d (opos=%.2f) snapped to (%.2f), " |
|
|
|
|
"was (%.2f)\n", |
|
|
|
|
edge1-edges, edge1->opos / 64.0, blue->fit / 64.0, |
|
|
|
|
AF_LOG(( "BLUE: edge %d (opos=%.2f) snapped to (%.2f)," |
|
|
|
|
" was (%.2f)\n", |
|
|
|
|
edge1 - edges, edge1->opos / 64.0, blue->fit / 64.0, |
|
|
|
|
edge1->pos / 64.0 )); |
|
|
|
|
|
|
|
|
|
edge1->pos = blue->fit; |
|
|
|
@ -1757,8 +1813,8 @@ |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* now we will align all stem edges, trying to maintain the */ |
|
|
|
|
/* relative order of stems in the glyph */ |
|
|
|
|
/* now we align all stem edges, trying to maintain the */ |
|
|
|
|
/* relative order of stems in the glyph */ |
|
|
|
|
for ( edge = edges; edge < edge_limit; edge++ ) |
|
|
|
|
{ |
|
|
|
|
AF_Edge edge2; |
|
|
|
@ -1798,8 +1854,13 @@ |
|
|
|
|
hints, dim, org_len, |
|
|
|
|
(AF_Edge_Flags)edge->flags, |
|
|
|
|
(AF_Edge_Flags)edge2->flags ); |
|
|
|
|
|
|
|
|
|
/* some voodoo to specially round edges for small stem widths */ |
|
|
|
|
if ( cur_len <= 64 ) |
|
|
|
|
u_off = d_off = 32; |
|
|
|
|
{ |
|
|
|
|
u_off = 32; |
|
|
|
|
d_off = 32; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
u_off = 38; |
|
|
|
@ -1809,7 +1870,6 @@ |
|
|
|
|
if ( cur_len < 96 ) |
|
|
|
|
{ |
|
|
|
|
org_center = edge->opos + ( org_len >> 1 ); |
|
|
|
|
|
|
|
|
|
cur_pos1 = FT_PIX_ROUND( org_center ); |
|
|
|
|
|
|
|
|
|
error1 = org_center - ( cur_pos1 - u_off ); |
|
|
|
@ -1831,10 +1891,10 @@ |
|
|
|
|
else |
|
|
|
|
edge->pos = FT_PIX_ROUND( edge->opos ); |
|
|
|
|
|
|
|
|
|
AF_LOG(( "ANCHOR: edge %d (opos=%.2f) and %d (opos=%.2f) " |
|
|
|
|
"snapped to (%.2f) (%.2f)\n", |
|
|
|
|
edge-edges, edge->opos / 64.0, |
|
|
|
|
edge2-edges, edge2->opos / 64.0, |
|
|
|
|
AF_LOG(( "ANCHOR: edge %d (opos=%.2f) and %d (opos=%.2f)" |
|
|
|
|
" snapped to (%.2f) (%.2f)\n", |
|
|
|
|
edge - edges, edge->opos / 64.0, |
|
|
|
|
edge2 - edges, edge2->opos / 64.0, |
|
|
|
|
edge->pos / 64.0, edge2->pos / 64.0 )); |
|
|
|
|
anchor = edge; |
|
|
|
|
|
|
|
|
@ -1853,9 +1913,9 @@ |
|
|
|
|
org_center = org_pos + ( org_len >> 1 ); |
|
|
|
|
|
|
|
|
|
cur_len = af_latin_compute_stem_width( |
|
|
|
|
hints, dim, org_len, |
|
|
|
|
(AF_Edge_Flags)edge->flags, |
|
|
|
|
(AF_Edge_Flags)edge2->flags ); |
|
|
|
|
hints, dim, org_len, |
|
|
|
|
(AF_Edge_Flags)edge->flags, |
|
|
|
|
(AF_Edge_Flags)edge2->flags ); |
|
|
|
|
|
|
|
|
|
if ( edge2->flags & AF_EDGE_DONE ) |
|
|
|
|
edge->pos = edge2->pos - cur_len; |
|
|
|
@ -1868,7 +1928,10 @@ |
|
|
|
|
cur_pos1 = FT_PIX_ROUND( org_center ); |
|
|
|
|
|
|
|
|
|
if (cur_len <= 64 ) |
|
|
|
|
u_off = d_off = 32; |
|
|
|
|
{ |
|
|
|
|
u_off = 32; |
|
|
|
|
d_off = 32; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
u_off = 38; |
|
|
|
@ -1891,10 +1954,10 @@ |
|
|
|
|
edge->pos = cur_pos1 - cur_len / 2; |
|
|
|
|
edge2->pos = cur_pos1 + cur_len / 2; |
|
|
|
|
|
|
|
|
|
AF_LOG(( "STEM: %d (opos=%.2f) to %d (opos=%.2f) " |
|
|
|
|
"snapped to (%.2f) and (%.2f)\n", |
|
|
|
|
edge-edges, edge->opos / 64.0, |
|
|
|
|
edge2-edges, edge2->opos / 64.0, |
|
|
|
|
AF_LOG(( "STEM: %d (opos=%.2f) to %d (opos=%.2f)" |
|
|
|
|
" snapped to (%.2f) and (%.2f)\n", |
|
|
|
|
edge - edges, edge->opos / 64.0, |
|
|
|
|
edge2 - edges, edge2->opos / 64.0, |
|
|
|
|
edge->pos / 64.0, edge2->pos / 64.0 )); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
@ -1908,23 +1971,23 @@ |
|
|
|
|
(AF_Edge_Flags)edge->flags, |
|
|
|
|
(AF_Edge_Flags)edge2->flags ); |
|
|
|
|
|
|
|
|
|
cur_pos1 = FT_PIX_ROUND( org_pos ); |
|
|
|
|
delta1 = cur_pos1 + ( cur_len >> 1 ) - org_center; |
|
|
|
|
cur_pos1 = FT_PIX_ROUND( org_pos ); |
|
|
|
|
delta1 = cur_pos1 + ( cur_len >> 1 ) - org_center; |
|
|
|
|
if ( delta1 < 0 ) |
|
|
|
|
delta1 = -delta1; |
|
|
|
|
|
|
|
|
|
cur_pos2 = FT_PIX_ROUND( org_pos + org_len ) - cur_len; |
|
|
|
|
delta2 = cur_pos2 + ( cur_len >> 1 ) - org_center; |
|
|
|
|
cur_pos2 = FT_PIX_ROUND( org_pos + org_len ) - cur_len; |
|
|
|
|
delta2 = cur_pos2 + ( cur_len >> 1 ) - org_center; |
|
|
|
|
if ( delta2 < 0 ) |
|
|
|
|
delta2 = -delta2; |
|
|
|
|
|
|
|
|
|
edge->pos = ( delta1 < delta2 ) ? cur_pos1 : cur_pos2; |
|
|
|
|
edge2->pos = edge->pos + cur_len; |
|
|
|
|
|
|
|
|
|
AF_LOG(( "STEM: %d (opos=%.2f) to %d (opos=%.2f) " |
|
|
|
|
"snapped to (%.2f) and (%.2f)\n", |
|
|
|
|
edge-edges, edge->opos / 64.0, |
|
|
|
|
edge2-edges, edge2->opos / 64.0, |
|
|
|
|
AF_LOG(( "STEM: %d (opos=%.2f) to %d (opos=%.2f)" |
|
|
|
|
" snapped to (%.2f) and (%.2f)\n", |
|
|
|
|
edge - edges, edge->opos / 64.0, |
|
|
|
|
edge2 - edges, edge2->opos / 64.0, |
|
|
|
|
edge->pos / 64.0, edge2->pos / 64.0 )); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1934,7 +1997,7 @@ |
|
|
|
|
if ( edge > edges && edge->pos < edge[-1].pos ) |
|
|
|
|
{ |
|
|
|
|
AF_LOG(( "BOUND: %d (pos=%.2f) to (%.2f)\n", |
|
|
|
|
edge-edges, edge->pos / 64.0, edge[-1].pos / 64.0 )); |
|
|
|
|
edge - edges, edge->pos / 64.0, edge[-1].pos / 64.0 )); |
|
|
|
|
edge->pos = edge[-1].pos; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -2028,9 +2091,9 @@ |
|
|
|
|
if ( delta < 64 + 16 ) |
|
|
|
|
{ |
|
|
|
|
af_latin_align_serif_edge( hints, edge->serif, edge ); |
|
|
|
|
AF_LOG(( "SERIF: edge %d (opos=%.2f) serif to %d (opos=%.2f) " |
|
|
|
|
"aligned to (%.2f)\n", |
|
|
|
|
edge-edges, edge->opos / 64.0, |
|
|
|
|
AF_LOG(( "SERIF: edge %d (opos=%.2f) serif to %d (opos=%.2f)" |
|
|
|
|
" aligned to (%.2f)\n", |
|
|
|
|
edge - edges, edge->opos / 64.0, |
|
|
|
|
edge->serif - edges, edge->serif->opos / 64.0, |
|
|
|
|
edge->pos / 64.0 )); |
|
|
|
|
} |
|
|
|
@ -2064,18 +2127,20 @@ |
|
|
|
|
FT_MulDiv( edge->opos - before->opos, |
|
|
|
|
after->pos - before->pos, |
|
|
|
|
after->opos - before->opos ); |
|
|
|
|
AF_LOG(( "SERIF_LINK1: edge %d (opos=%.2f) snapped to (%.2f) " |
|
|
|
|
"from %d (opos=%.2f)\n", |
|
|
|
|
edge-edges, edge->opos / 64.0, |
|
|
|
|
edge->pos / 64.0, before - edges, |
|
|
|
|
before->opos / 64.0 )); |
|
|
|
|
|
|
|
|
|
AF_LOG(( "SERIF_LINK1: edge %d (opos=%.2f) snapped to (%.2f)" |
|
|
|
|
" from %d (opos=%.2f)\n", |
|
|
|
|
edge - edges, edge->opos / 64.0, |
|
|
|
|
edge->pos / 64.0, |
|
|
|
|
before - edges, before->opos / 64.0 )); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
edge->pos = anchor->pos + |
|
|
|
|
( ( edge->opos - anchor->opos + 16 ) & ~31 ); |
|
|
|
|
|
|
|
|
|
AF_LOG(( "SERIF_LINK2: edge %d (opos=%.2f) snapped to (%.2f)\n", |
|
|
|
|
edge-edges, edge->opos / 64.0, edge->pos / 64.0 )); |
|
|
|
|
edge - edges, edge->opos / 64.0, edge->pos / 64.0 )); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -2093,6 +2158,8 @@ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Apply the complete hinting algorithm to a latin glyph. */ |
|
|
|
|
|
|
|
|
|
static FT_Error |
|
|
|
|
af_latin_hints_apply( AF_GlyphHints hints, |
|
|
|
|
FT_Outline* outline, |
|
|
|
@ -2109,7 +2176,7 @@ |
|
|
|
|
/* analyze glyph outline */ |
|
|
|
|
#ifdef AF_USE_WARPER |
|
|
|
|
if ( metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT || |
|
|
|
|
AF_HINTS_DO_HORIZONTAL( hints ) ) |
|
|
|
|
AF_HINTS_DO_HORIZONTAL( hints ) ) |
|
|
|
|
#else |
|
|
|
|
if ( AF_HINTS_DO_HORIZONTAL( hints ) ) |
|
|
|
|
#endif |
|
|
|
@ -2132,8 +2199,8 @@ |
|
|
|
|
for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) |
|
|
|
|
{ |
|
|
|
|
#ifdef AF_USE_WARPER |
|
|
|
|
if ( ( dim == AF_DIMENSION_HORZ && |
|
|
|
|
metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT ) ) |
|
|
|
|
if ( dim == AF_DIMENSION_HORZ && |
|
|
|
|
metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT ) |
|
|
|
|
{ |
|
|
|
|
AF_WarperRec warper; |
|
|
|
|
FT_Fixed scale; |
|
|
|
@ -2206,7 +2273,7 @@ |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AF_DEFINE_SCRIPT_CLASS(af_latin_script_class,
|
|
|
|
|
AF_DEFINE_SCRIPT_CLASS(af_latin_script_class, |
|
|
|
|
AF_SCRIPT_LATIN, |
|
|
|
|
af_latin_uniranges, |
|
|
|
|
|
|
|
|
|