diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c index 89287f7ea..c2e373455 100644 --- a/src/autofit/aflatin.c +++ b/src/autofit/aflatin.c @@ -22,6 +22,7 @@ #include "afglobal.h" #include "aflatin.h" #include "aferrors.h" +#include "afadjust.h" /************************************************************************** @@ -1155,6 +1156,9 @@ af_latin_metrics_check_digits( metrics, face ); } + af_reverse_character_map_new( &metrics->root.reverse_charmap, + metrics->root.globals ); + Exit: face->charmap = oldmap; return error; @@ -1484,6 +1488,17 @@ } + FT_CALLBACK_DEF( void ) + af_latin_metrics_done( AF_StyleMetrics metrics_ ) + { + AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_; + + + af_reverse_character_map_done( metrics->root.reverse_charmap, + metrics->root.globals->face->memory ); + } + + /* Scale global values in both directions. */ FT_LOCAL_DEF( void ) @@ -2737,6 +2752,304 @@ } +#undef FT_COMPONENT +#define FT_COMPONENT afadjust + + + static void + af_move_contour_vertically( AF_Point contour, + FT_Int movement ) + { + AF_Point point = contour; + AF_Point first_point = point; + + + if ( point ) + { + do + { + point->y += movement; + point = point->next; + + } while ( point != first_point ); + } + } + + + /* Return 1 if the given contour overlaps horizontally with the bounding */ + /* box of all other contours combined. This is a helper for function */ + /* `af_glyph_hints_apply_vertical_separation_adjustments`. */ + static FT_Bool + af_check_contour_horizontal_overlap( AF_GlyphHints hints, + FT_Int contour_index ) + { + FT_Pos contour_max_x = -32000; + FT_Pos contour_min_x = 32000; + FT_Pos others_max_x = -32000; + FT_Pos others_min_x = 32000; + + FT_Int contour; + + FT_Bool horizontal_overlap; + + + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + AF_Point first_point = hints->contours[contour]; + AF_Point p = first_point; + + + do + { + p = p->next; + + if ( contour == contour_index ) + { + if ( p->x < contour_min_x ) + contour_min_x = p->x; + if ( p->x > contour_max_x ) + contour_max_x = p->x; + } + else + { + if ( p->x < others_min_x ) + others_min_x = p->x; + if ( p->x > others_max_x ) + others_max_x = p->x; + } + } while ( p != first_point ); + } + + horizontal_overlap = + ( others_min_x <= contour_max_x && contour_max_x <= others_max_x ) || + ( others_min_x <= contour_min_x && contour_min_x <= others_max_x ) || + ( contour_max_x >= others_max_x && contour_min_x <= others_min_x ); + + return horizontal_overlap; + } + + + static void + af_glyph_hints_apply_vertical_separation_adjustments( + AF_GlyphHints hints, + AF_Dimension dim, + FT_Int glyph_index, + AF_ReverseCharacterMap reverse_charmap ) + { + FT_TRACE4(( "Entering" + " af_glyph_hints_apply_vertical_separation_adjustments\n" )); + + if ( dim != AF_DIMENSION_VERT ) + return; + + if ( af_lookup_vertical_separation_type( reverse_charmap, + glyph_index ) == + AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP && + hints->num_contours >= 2 ) + { + FT_Int highest_contour = -1; + FT_Pos highest_min_y = 0; + FT_Pos current_min_y = 0; + + FT_Int contour; + FT_Bool horizontal_overlap; + FT_Int adjustment_amount; + + FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments:\n" + " Applying vertical adjustment:" + " AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP\n" )); + + /* Figure out which contour is the higher one by finding the one */ + /* with the highest minimum y value. */ + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + AF_Point point = hints->contours[contour]; + AF_Point first_point = point; + + + if ( !point ) + continue; + + current_min_y = point->y; + + do + { + if ( point->y < current_min_y ) + current_min_y = point->y; + point = point->next; + + } while ( point != first_point ); + + if ( highest_contour == -1 || current_min_y > highest_min_y ) + { + highest_min_y = current_min_y; + highest_contour = contour; + } + } + + /* Check for a horizontal overlap between the top contour and the */ + /* rest. If there is no overlap, do not adjust. */ + horizontal_overlap = + af_check_contour_horizontal_overlap( hints, highest_contour ); + if ( !horizontal_overlap ) + { + FT_TRACE4(( " Top contour does not horizontally overlap" + " with other contours.\n" + " Skipping adjustment.\n" )); + return; + } + + /* If there are any contours that have a maximum y coordinate */ + /* greater than or equal to the minimum y coordinate of the */ + /* previously found highest contour, bump the high contour up until */ + /* the distance is one pixel. */ + adjustment_amount = 0; + + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + AF_Point point; + AF_Point first_point; + + FT_Pos max_y; + + + if ( contour == highest_contour ) + continue; + + point = hints->contours[contour]; + first_point = point; + if ( !point ) + continue; + + max_y = point->y; + do + { + if ( point->y > max_y ) + max_y = point->y; + point = point->next; + + } while ( point != first_point ); + + if ( max_y >= highest_min_y - 64 ) + adjustment_amount = 64 - ( highest_min_y - max_y ); + } + + if ( adjustment_amount > 64 ) + FT_TRACE4(( " Calculated adjustment amount %d" + " was more than threshold of 64. Not adjusting\n", + adjustment_amount )); + else if ( adjustment_amount > 0 ) + { + FT_TRACE4(( " Pushing top contour %d units up\n", + adjustment_amount )); + + af_move_contour_vertically( hints->contours[highest_contour], + adjustment_amount ); + } + } + + else if ( af_lookup_vertical_separation_type( reverse_charmap, + glyph_index ) == + AF_VERTICAL_ADJUSTMENT_BOTTOM_CONTOUR_DOWN && + hints->num_contours >= 2 ) + { + FT_Int lowest_contour = -1; + FT_Pos lowest_max_y = 0; + FT_Pos current_max_y = 0; + + FT_Int contour; + FT_Int adjustment_amount; + + + FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments:\n" + " Applying vertical adjustment:" + " AF_VERTICAL_ADJUSTMENT_BOTTOM_CONTOUR_DOWN\n" )); + + /* Find lowest contour. */ + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + AF_Point point = hints->contours[contour]; + AF_Point first_point = point; + + + if ( !point ) + continue; + + current_max_y = point->y; + + do + { + if ( point->y > current_max_y ) + current_max_y = point->y; + point = point->next; + + } while ( point != first_point ); + + if ( lowest_contour == -1 || current_max_y < lowest_max_y ) + { + lowest_max_y = current_max_y; + lowest_contour = contour; + } + } + + adjustment_amount = 0; + + for ( contour = 0; contour < hints->num_contours; contour++ ) + { + AF_Point point; + AF_Point first_point; + + FT_Pos min_y; + + + if ( contour == lowest_contour ) + continue; + + point = hints->contours[contour]; + first_point = point; + if ( !point ) + continue; + + min_y = point->y; + do + { + if ( point->y < min_y ) + min_y = point->y; + point = point->next; + + } while ( point != first_point ); + + if ( min_y <= lowest_max_y - 64 ) + adjustment_amount = 64 - ( min_y - lowest_max_y ); + } + + if ( adjustment_amount > 64 ) + FT_TRACE4(( " Calculated adjustment amount %d" + " was more than threshold of 64. Not adjusting\n", + adjustment_amount )); + else if ( adjustment_amount > 0 ) + { + FT_TRACE4(( " Pushing bottom contour %d units down\n", + adjustment_amount )); + + af_move_contour_vertically( hints->contours[lowest_contour], + -adjustment_amount ); + } + } + + else + FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments:\n" + " No vertical adjustment needed\n" )); + + FT_TRACE4(( "Exiting" + " af_glyph_hints_apply_vertical_separation_adjustments\n" )); + } + + +#undef FT_COMPONENT +#define FT_COMPONENT aflatin + + /* 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. */ @@ -3604,6 +3917,11 @@ af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim ); af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim ); af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim ); + af_glyph_hints_apply_vertical_separation_adjustments( + hints, + (AF_Dimension)dim, + glyph_index, + metrics->root.reverse_charmap ); } } @@ -3632,7 +3950,7 @@ (AF_WritingSystem_InitMetricsFunc) af_latin_metrics_init, /* style_metrics_init */ (AF_WritingSystem_ScaleMetricsFunc)af_latin_metrics_scale, /* style_metrics_scale */ - (AF_WritingSystem_DoneMetricsFunc) NULL, /* style_metrics_done */ + (AF_WritingSystem_DoneMetricsFunc) af_latin_metrics_done, /* style_metrics_done */ (AF_WritingSystem_GetStdWidthsFunc)af_latin_get_standard_widths, /* style_metrics_getstdw */ (AF_WritingSystem_InitHintsFunc) af_latin_hints_init, /* style_hints_init */ diff --git a/src/autofit/aftypes.h b/src/autofit/aftypes.h index 5d4aaa9ba..259b555be 100644 --- a/src/autofit/aftypes.h +++ b/src/autofit/aftypes.h @@ -439,6 +439,8 @@ extern void* af_debug_hints_; AF_FaceGlobals globals; /* to access properties */ + AF_ReverseCharacterMap reverse_charmap; + } AF_StyleMetricsRec;