diff --git a/src/autofit/afadjust.c b/src/autofit/afadjust.c index a340716e6..536956eba 100644 --- a/src/autofit/afadjust.c +++ b/src/autofit/afadjust.c @@ -52,7 +52,7 @@ adjustment_database[] = {0xEC, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0}, {0xED, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0}, {0xEE, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0}, - {0xF1, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0}, /*n with tilde*/ + {0xF1, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 1}, /*n with tilde*/ {0xF2, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0}, {0xF3, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0}, {0xF4, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0}, diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c index 20d49f5fe..2331eaef1 100644 --- a/src/autofit/aflatin.c +++ b/src/autofit/aflatin.c @@ -2798,6 +2798,221 @@ af_find_highest_contour( AF_GlyphHints hints ) { return highest_contour; } +static void +af_remove_segments_containing_point(AF_GlyphHints hints, AF_Point point) +{ + AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT]; + AF_Segment segments = axis->segments; + for ( FT_Int i = 0; i < axis->num_segments; i++ ) + { + AF_Segment seg = &segments[i]; + FT_Bool remove = 0; + AF_Point p = seg->first; + while ( 1 ) + { + if ( p == point ) + { + remove = 1; + break; + } + if (p == seg->last) { + break; + } + p = p->next; + } + + if ( remove ) + { + /* first, check the first and last fields of the edge */ + AF_Edge edge = seg->edge; + if ( edge->first == seg && edge->last == seg ) + { + /* The edge only consists of the segment to be removed. remove the edge*/ + *edge = axis->edges[--axis->num_edges]; + } + else + { + if ( edge->first == seg ) + { + edge->first = seg->edge_next; + } + if ( edge->last == seg ) + { + edge->last = edge->first; + while ( edge->last->edge_next != seg ) + { + edge->last = edge->last->edge_next; + } + } + } + + /* Now, delete the segment */ + *seg = axis->segments[--axis->num_segments]; + + i--; /* we have to check the new segment at this position */ + } + } +} + +/*remove all segments containing points on the tilde contour*/ +static void +af_latin_remove_tilde_points_from_edges( AF_GlyphHints hints, + FT_Int glyph_index ) +{ + FT_Int highest_contour = af_find_highest_contour(hints); + AF_Point first_point = hints->contours[highest_contour]; + + /* search for any curve tips that are on a y extrema, and delete any + segments that contain this point.*/ + AF_Point p = first_point; + + do + { + p = p->next; + if ( /*!(p->flags & AF_FLAG_CONTROL) + && p->prev->y == p->y && p->next->y == p->y + && p->prev->flags & AF_FLAG_CONTROL + && p->next->flags & AF_FLAG_CONTROL*/ 1 ) + { + FT_TRACE4(("%p", p)); + af_remove_segments_containing_point( hints, p ); + } + } while ( p != first_point ); +} + +/* +The tilde unflattening algorithm sometimes goes too far and makes an +unusually high tilde, where decreasing the ppem will increase the height +instead of a steady decrease in height as less pixels are used. + +The n tilde on times new roman with forced autofitting on, +16.5-18 ppem font size exhibits this behaviour. +*/ +void +af_latin_stretch_tildes( AF_GlyphHints hints, + FT_Int glyph_index ) +{ + FT_Int highest_contour = af_find_highest_contour( hints ); + AF_Point p = hints->contours[highest_contour]; + AF_Point first_point = p; + + FT_Pos min_y, max_y; + min_y = max_y = p->y; + + FT_Short min_fy, max_fy; + min_fy = max_fy = p->fy; + + do + { + p = p->next; + if ( p->y < min_y ) + { + min_y = p->y; + } + if ( p->y > max_y ) + { + max_y = p->y; + } + + if ( p->fy < min_fy ) + { + min_fy = p->fy; + } + + if ( p->fy > max_fy ) + { + max_fy = p->fy; + } + + } + while ( p != first_point ); + + FT_Pos min_measurement = 32000; + FT_UInt measurements_taken = 0; + + do + { + p = p->next; + if ( !(p->flags & AF_FLAG_CONTROL) + && p->prev->y == p->y && p->next->y == p->y + && p->y != min_y && p->y != max_y + && p->prev->flags & AF_FLAG_CONTROL + && p->next->flags & AF_FLAG_CONTROL ) + { + /* This point could be a candidate. Find the next and previous on-curve */ + /* points, and make sure they are both either above or below the point, */ + /* Then make the measurement */ + AF_Point prevOn = p->prev; + AF_Point nextOn = p->next; + while ( prevOn->flags & AF_FLAG_CONTROL ) + { + prevOn = prevOn->prev; + } + while ( nextOn->flags & AF_FLAG_CONTROL ) + { + nextOn = nextOn->next; + } + FT_Pos measurement; + if ( nextOn->y > p->y && prevOn->y > p->y ) + { + measurement = p->y - min_y; + } + else if ( nextOn->y < p->y && prevOn->y < p->y ) + { + measurement = max_y - p->y; + } + else + { + continue; + } + + if (measurement < min_measurement) + { + min_measurement = measurement; + } + measurements_taken++; + } + + } + while ( p != first_point ); + + FT_Pos height = max_y - min_y; + + FT_Pos target_height = min_measurement + 64; + if ( height >= target_height ) + { + return; + } + + p = first_point; + do + { + p = p->next; + p->y = ((p->y - min_y) * target_height / height) + min_y; + p->fy = ((p->fy - min_fy) * target_height / height) + min_fy; + p->oy = p->y; + if ( !(p->flags & AF_FLAG_CONTROL) ) + p->flags |= AF_FLAG_TOUCH_Y; + } + while ( p != first_point ); + + FT_Pos new_min_y, new_max_y; + new_min_y = new_max_y = first_point->y; + p = first_point; + do { + p = p->next; + if ( p->y < new_min_y ) + { + new_min_y = p->y; + } + if ( p->y > new_max_y ) + { + new_max_y = p->y; + } + } + while ( p != first_point ); +} + /*True if the given contour overlaps horizontally with the bounding box Of all other contours combined. This is a helper for af_glyph_hints_apply_vertical_separation_adjustments */ @@ -3886,11 +4101,18 @@ af_glyph_hints_apply_vertical_separation_adjustments( AF_GlyphHints hints, if ( AF_HINTS_DO_VERTICAL( hints ) ) { + FT_Bool is_tilde = af_lookup_tilde_correction_type( metrics->root.reverse_charmap, glyph_index ); + if ( is_tilde ) { + af_latin_stretch_tildes( hints, glyph_index ); + } axis = &metrics->axis[AF_DIMENSION_VERT]; error = af_latin_hints_detect_features( hints, axis->width_count, axis->widths, AF_DIMENSION_VERT ); + if ( is_tilde ) { + af_latin_remove_tilde_points_from_edges( hints, glyph_index ); + } if ( error ) goto Exit;