diff --git a/include/freetype/internal/fttrace.h b/include/freetype/internal/fttrace.h index 319fe56fd..156fb21dc 100644 --- a/include/freetype/internal/fttrace.h +++ b/include/freetype/internal/fttrace.h @@ -164,6 +164,7 @@ FT_TRACE_DEF( afhints ) FT_TRACE_DEF( afmodule ) FT_TRACE_DEF( aflatin ) FT_TRACE_DEF( afshaper ) +FT_TRACE_DEF( afadjust ) /* SDF components */ FT_TRACE_DEF( sdf ) /* signed distance raster for outlines (ftsdf.c) */ diff --git a/src/autofit/afadjust.c b/src/autofit/afadjust.c index 00a21a447..cf2a59671 100644 --- a/src/autofit/afadjust.c +++ b/src/autofit/afadjust.c @@ -2,34 +2,52 @@ #include #include #include +#include -#define AF_ADJUSTMENT_DATABASE_LENGTH 12 +#define AF_ADJUSTMENT_DATABASE_LENGTH (sizeof(adjustment_database)/sizeof(adjustment_database[0])) +#undef FT_COMPONENT +#define FT_COMPONENT afadjust /*TODO: find out whether capital u/U with accent entries are needed*/ /*the accent won't merge with the rest of the glyph because the accent mark is sitting above empty space*/ FT_LOCAL_ARRAY_DEF( AF_AdjustmentDatabaseEntry ) -adjustment_database[AF_ADJUSTMENT_DATABASE_LENGTH] = { - {'i', AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE}, - {'j', AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE}, - {0xC8, AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE}, /*E with grave*/ - {0xCC, AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE}, /*I with grave*/ - {0xD9, AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE}, /*U with grave*/ - {0xE0, AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE}, /*a with grave*/ - {0xEC, AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE}, /*i with grave*/ - {0x114, AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE}, /*E with macron*/ - {0x12A, AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE}, /*I with macron*/ - {0x12B, AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE}, /*i with macron*/ - {0x16A, AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE}, /*U with macron*/ - {0x16B, AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE} /*u with macron*/ - /*TODO: find out why E won't work, even though it appears to be one-on-one*/ +adjustment_database[] = +{ + {0x21, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /* ! */ + {0x69, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /* i */ + {0x6A, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /* j */ + {0xA1, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /*Inverted Exclamation Mark*/ + {0xBF, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /*Inverted Question Mark*/ + {0xC0, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /*A with grave*/ + {0xC1, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /*A with acute*/ + {0xC2, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /*A with circumflex*/ + {0xC3, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /*A with tilde*/ + {0xC8, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /*E with grave*/ + {0xCC, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /*I with grave*/ + {0xD9, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /*U with grave*/ + {0xE0, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /*a with grave*/ + {0xEC, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /*i with grave*/ + {0x114, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /*E with macron*/ + {0x12A, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /*I with macron*/ + {0x12B, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /*i with macron*/ + {0x16A, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP}, /*U with macron*/ + {0x16B, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP} /*u with macron*/ }; /*Helper function: get the adjustment database entry for a codepoint*/ FT_LOCAL_DEF( const AF_AdjustmentDatabaseEntry* ) af_adjustment_database_lookup( FT_UInt32 codepoint ) { - for ( FT_Int entry = 0; entry < AF_ADJUSTMENT_DATABASE_LENGTH; entry++ ) { - if ( adjustment_database[entry].codepoint == codepoint ) { - return &adjustment_database[entry]; + /* Binary search for database entry */ + FT_UInt low = 0; + FT_UInt high = AF_ADJUSTMENT_DATABASE_LENGTH - 1; + while (high > low) { + FT_UInt mid = (low + high) / 2; + if (adjustment_database[mid].codepoint < codepoint) { + low = mid + 1; + } else if (adjustment_database[mid].codepoint > codepoint) { + high = mid - 1; + } else { + return &adjustment_database[mid]; } } @@ -40,30 +58,37 @@ FT_LOCAL_DEF( AF_VerticalSeparationAdjustmentType ) af_lookup_vertical_seperation_type( AF_ReverseCharacterMap map, FT_Int glyph_index ) { FT_UInt32 codepoint = af_reverse_character_map_lookup( map, glyph_index ); const AF_AdjustmentDatabaseEntry *entry = af_adjustment_database_lookup( codepoint ); - if ( entry == NULL ) { + if ( entry == NULL ) + { return AF_VERTICAL_ADJUSTMENT_NONE; } return entry->vertical_separation_adjustment_type; } -typedef struct AF_ReverseMapEntry_ { +typedef struct AF_ReverseMapEntry_ +{ FT_Int glyph_index; FT_UInt32 codepoint; } AF_ReverseMapEntry; -typedef struct AF_ReverseCharacterMap_ { +typedef struct AF_ReverseCharacterMap_ +{ FT_UInt length; AF_ReverseMapEntry *entries; } AF_ReverseCharacterMap_Rec; FT_LOCAL_DEF(FT_UInt32) -af_reverse_character_map_lookup( AF_ReverseCharacterMap map, FT_Int glyph_index ) { - if ( map == NULL ) { +af_reverse_character_map_lookup( AF_ReverseCharacterMap map, FT_Int glyph_index ) +{ + if ( map == NULL ) + { return 0; } - for ( FT_UInt entry = 0; entry < map->length; entry++ ) { - if ( map->entries[entry].glyph_index == glyph_index ) { + for ( FT_UInt entry = 0; entry < map->length; entry++ ) + { + if ( map->entries[entry].glyph_index == glyph_index ) + { return map->entries[entry].codepoint; } } @@ -72,64 +97,87 @@ af_reverse_character_map_lookup( AF_ReverseCharacterMap map, FT_Int glyph_index } FT_LOCAL_DEF( FT_Error ) -af_reverse_character_map_new( FT_Face face, AF_ReverseCharacterMap *map, FT_Memory memory ) { +af_reverse_character_map_new( FT_Face face, AF_ReverseCharacterMap *map, FT_Memory memory ) +{ /* Search for a unicode charmap */ /* If there isn't one, create a blank map */ - + /*TODO: change this to logic that searches for a "preferred" unicode charmap that maps the most codepoints*/ /*see find_unicode_charmap*/ /*TODO: use GSUB lookups */ + FT_TRACE4(( "af_reverse_character_map_new: building reverse character map\n" )); FT_CMap unicode_charmap = NULL; - for ( FT_UInt i = 0; i < face->num_charmaps; i++ ) { - if ( face->charmaps[i]->encoding == FT_ENCODING_UNICODE ) { + for ( FT_UInt i = 0; i < face->num_charmaps; i++ ) + { + if ( face->charmaps[i]->encoding == FT_ENCODING_UNICODE ) + { unicode_charmap = FT_CMAP( face->charmaps[i] ); } } - - if ( unicode_charmap == NULL ) { + + if ( unicode_charmap == NULL ) + { *map = NULL; return FT_Err_Ok; } FT_Error error; - if ( FT_NEW( *map ) ) { + if ( FT_NEW( *map ) ) + { goto Exit; } FT_Int capacity = 10; FT_Int size = 0; - - if ( FT_NEW_ARRAY((*map)->entries, capacity) ) { + + if ( FT_NEW_ARRAY((*map)->entries, capacity) ) + { goto Exit; } - for ( FT_Int i = 0; i < AF_ADJUSTMENT_DATABASE_LENGTH; i++ ) { +#ifdef FT_DEBUG_LEVEL_TRACE + int failed_lookups = 0; +#endif + for ( FT_Int i = 0; i < AF_ADJUSTMENT_DATABASE_LENGTH; i++ ) + { FT_UInt32 codepoint = adjustment_database[i].codepoint; FT_Int glyph = unicode_charmap->clazz->char_index(unicode_charmap, codepoint); - if ( glyph == 0 ) { + if ( glyph == 0 ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + failed_lookups++; +#endif continue; } - if (size == capacity) { + if ( size == capacity ) + { capacity += capacity / 2; - if ( FT_RENEW_ARRAY((*map)->entries, size, capacity) ) { + if ( FT_RENEW_ARRAY((*map)->entries, size, capacity) ) + { goto Exit; } } size++; - (*map)->entries[i].glyph_index = glyph; - (*map)->entries[i].codepoint = codepoint; + ( *map )->entries[i].glyph_index = glyph; + ( *map )->entries[i].codepoint = codepoint; } - (*map)->length = size; + ( *map )->length = size; Exit: - if ( error ) { - if ( *map ) { + if ( error ) + { + FT_TRACE4(( " error while building reverse character map. Using blank map.\n" )); + if ( *map ) + { FT_FREE( ( *map )->entries ); } FT_FREE( *map ); return error; } - +#ifdef FT_DEBUG_LEVEL_TRACE + FT_TRACE4(( " reverse character map built successfully"\ + " with %d entries and %d failed lookups.\n", size, failed_lookups )); +#endif return FT_Err_Ok; } @@ -137,4 +185,4 @@ FT_LOCAL_DEF( FT_Error ) af_reverse_character_map_done( AF_ReverseCharacterMap map, FT_Memory memory ) { FT_FREE( map->entries ); return FT_Err_Ok; -} \ No newline at end of file +} diff --git a/src/autofit/afadjust.h b/src/autofit/afadjust.h index f1c8c47d3..65cdfaa66 100644 --- a/src/autofit/afadjust.h +++ b/src/autofit/afadjust.h @@ -7,11 +7,11 @@ FT_BEGIN_HEADER /*The type of adjustment that should be done to prevent cases where 2 parts of a character*/ /*stacked vertically merge, even though they should be separate*/ -typedef enum AF_VerticalSeparationAdjustmentType_ { - AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE, - /*"One on one" means that the character is expected to be one contour on top of another, where the contours should not touch*/ - /*the hinter will force the contours to have a gap of at least 1 pixel between them*/ - /*by moving the top contour up */ +typedef enum AF_VerticalSeparationAdjustmentType_ +{ + AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, + /*This means that the hinter should find the topmost contour and push it up until its lowest point is 1 pixel*/ + /*above the highest point not part of that contour.*/ AF_VERTICAL_ADJUSTMENT_NONE /*others will be needed, such as the case where the lower contour should be moved in the adjustment instead of the upper one*/ @@ -19,10 +19,11 @@ typedef enum AF_VerticalSeparationAdjustmentType_ { /*and a way of handling A and O, where the letter consists of 2 contours*/ } AF_VerticalSeparationAdjustmentType; -typedef struct AF_AdjustmentDatabaseEntry_ { - FT_UInt32 codepoint; - AF_VerticalSeparationAdjustmentType vertical_separation_adjustment_type; - } AF_AdjustmentDatabaseEntry; +typedef struct AF_AdjustmentDatabaseEntry_ +{ + FT_UInt32 codepoint; + AF_VerticalSeparationAdjustmentType vertical_separation_adjustment_type; +} AF_AdjustmentDatabaseEntry; struct AF_ReverseCharacterMap_; @@ -37,11 +38,11 @@ af_reverse_character_map_lookup( AF_ReverseCharacterMap map, FT_Int glyph_index /*allocate and populate the reverse character map, using the character map within the face*/ FT_LOCAL( FT_Error ) af_reverse_character_map_new( FT_Face face, AF_ReverseCharacterMap *map, FT_Memory memory ); - + /*free the reverse character map*/ FT_LOCAL( FT_Error ) af_reverse_character_map_done( AF_ReverseCharacterMap map, FT_Memory memory ); FT_END_HEADER -#endif \ No newline at end of file +#endif diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c index 8177c66f1..2e870f59e 100644 --- a/src/autofit/aflatin.c +++ b/src/autofit/aflatin.c @@ -1153,7 +1153,7 @@ goto Exit; } af_latin_metrics_check_digits( metrics, face ); - + af_reverse_character_map_new( face, &metrics->root.reverse_charmap, face->memory ); } @@ -2745,13 +2745,25 @@ } -void af_glyph_hints_apply_adjustments(AF_GlyphHints hints, AF_Dimension dim, FT_Int glyph_index, AF_ReverseCharacterMap reverse_charmap) { - if ( dim != AF_DIMENSION_VERT ) { +#undef FT_COMPONENT +#define FT_COMPONENT afadjust + +void +af_glyph_hints_apply_vertical_separation_adjustments( AF_GlyphHints hints, + AF_Dimension dim, + FT_Int glyph_index, + AF_ReverseCharacterMap reverse_charmap ) +{ + if ( dim != AF_DIMENSION_VERT ) + { return; } - if ( af_lookup_vertical_seperation_type( reverse_charmap, glyph_index ) == AF_VERTICAL_ADJUSTMENT_ONE_ON_ONE && - hints->num_contours == 2 ) { - + + if ( af_lookup_vertical_seperation_type( reverse_charmap, glyph_index ) == AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP + && hints->num_contours >= 2 ) + { + FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments: Applying vertical adjustment: AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP\n" )); + /* Figure out which contout is the higher one by finding the one */ /* with the highest minimum y value */ @@ -2759,22 +2771,27 @@ void af_glyph_hints_apply_adjustments(AF_GlyphHints hints, AF_Dimension dim, FT_ FT_Pos highest_min_y = 0; FT_Pos current_min_y = 0; - for ( FT_Int contour = 0; contour < hints->num_contours; contour++ ) { + for ( FT_Int contour = 0; contour < hints->num_contours; contour++ ) + { AF_Point point = hints->contours[contour]; AF_Point first_point = point; - if ( point == NULL ) { /*TODO: is this necessary?*/ + if ( point == NULL ) + { /*TODO: is this necessary?*/ continue; } current_min_y = point->y; - do { - if ( point->y < current_min_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 ) { + if ( highest_contour == -1 || current_min_y > highest_min_y ) + { highest_min_y = current_min_y; highest_contour = contour; } @@ -2785,42 +2802,57 @@ void af_glyph_hints_apply_adjustments(AF_GlyphHints hints, AF_Dimension dim, FT_ /* contour, bump the high contour up until the distance is one pixel */ FT_Int adjustment_amount = 0; - for ( FT_Int contour = 0; contour < hints->num_contours; contour++ ) { - if (contour == highest_contour) { + for ( FT_Int contour = 0; contour < hints->num_contours; contour++ ) + { + if ( contour == highest_contour ) + { continue; } AF_Point point = hints->contours[contour]; AF_Point first_point = point; - if ( point == NULL ) { + if ( point == NULL ) + { continue; } FT_Pos max_y = point->y; - do { - if ( point->y > max_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 ( max_y >= highest_min_y - 64 ) + { + adjustment_amount = 64 - ( highest_min_y - max_y ); } } + FT_TRACE4(( " Pushing top contour %d units up\n", adjustment_amount )); if ( adjustment_amount > 0 ) { AF_Point point = hints->contours[highest_contour]; AF_Point first_point = point; - if ( point != NULL ) { - do { + if ( point != NULL ) + { + do + { point->y += adjustment_amount; point = point->next; } while ( point != first_point ); } } + } else { + FT_TRACE4(( "af_glyph_hints_apply_vertical_separation_adjustments: No vertical adjustment needed\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 */ @@ -3689,7 +3721,7 @@ void af_glyph_hints_apply_adjustments(AF_GlyphHints hints, AF_Dimension dim, FT_ 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_adjustments(hints, (AF_Dimension) dim, glyph_index, metrics->root.reverse_charmap); + af_glyph_hints_apply_vertical_separation_adjustments(hints, (AF_Dimension) dim, glyph_index, metrics->root.reverse_charmap); } }