diff --git a/include/freetype/internal/ftobjs.h b/include/freetype/internal/ftobjs.h index 28bc9b65f..ceb4251df 100644 --- a/include/freetype/internal/ftobjs.h +++ b/include/freetype/internal/ftobjs.h @@ -275,6 +275,26 @@ FT_BEGIN_HEADER FT_GlyphSlot slot, FT_Render_Mode mode ); + /************************************************************************** + * + * @Function: + * find_unicode_charmap + * + * @Description: + * This function finds a Unicode charmap, if there is one. + * And if there is more than one, it tries to favour the more + * extensive one, i.e., one that supports UCS-4 against those which + * are limited to the BMP ( UCS-2 encoding.) + * + * If a unicode charmap is found, face->charmap is set to it. + * + * This function is called from open_face(), + * from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ), + * and also from afadjust.c in the autofit module. + */ + FT_BASE( FT_Error ) + find_unicode_charmap( FT_Face face ); + #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING typedef void (*FT_Bitmap_LcdFilterFunc)( FT_Bitmap* bitmap, diff --git a/src/autofit/afadjust.c b/src/autofit/afadjust.c index d48e06883..5ebffa470 100644 --- a/src/autofit/afadjust.c +++ b/src/autofit/afadjust.c @@ -136,3 +136,222 @@ adjustment_database[] = {0x17D, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0}, {0x17E, AF_VERTICAL_ADJUSTMENT_TOP_CONTOUR_UP, 0} }; + +/*Helper function: get the adjustment database entry for a codepoint*/ +FT_LOCAL_DEF( const AF_AdjustmentDatabaseEntry* ) +af_adjustment_database_lookup( FT_UInt32 codepoint ) { + /* Binary search for database entry */ + FT_Int low = 0; + FT_Int high = AF_ADJUSTMENT_DATABASE_LENGTH - 1; + while ( high >= low ) + { + FT_Int mid = ( low + high ) / 2; + FT_UInt32 mid_codepoint = adjustment_database[mid].codepoint; + if ( mid_codepoint < codepoint ) + { + low = mid + 1; + } + else if ( mid_codepoint > codepoint ) + { + high = mid - 1; + } + else + { + return &adjustment_database[mid]; + } + } + + return NULL; +} + +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 ) + { + return AF_VERTICAL_ADJUSTMENT_NONE; + } + return entry->vertical_separation_adjustment_type; +} + +/*1 if tilde correction should be applied to the topmost contour +else 0*/ +FT_LOCAL_DEF( FT_Bool ) +af_lookup_tilde_correction_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 ) + { + return 0; + } + return entry->apply_tilde; +} + +typedef struct AF_ReverseMapEntry_ +{ + FT_Int glyph_index; + FT_UInt32 codepoint; +} AF_ReverseMapEntry; + +typedef struct AF_ReverseCharacterMap_ +{ + FT_Long length; + AF_ReverseMapEntry *entries; +} AF_ReverseCharacterMap_Rec; + +/* qsort compare function for reverse character map */ +FT_LOCAL_DEF( FT_Int ) +af_reverse_character_map_entry_compare( const void *a, const void *b ) { + const AF_ReverseMapEntry entry_a = *((const AF_ReverseMapEntry *)a); + const AF_ReverseMapEntry entry_b = *((const AF_ReverseMapEntry *)b); + return entry_a.glyph_index < entry_b.glyph_index ? -1 : entry_a.glyph_index > entry_b.glyph_index ? 1 : 0; +} + +FT_LOCAL_DEF( FT_UInt32 ) +af_reverse_character_map_lookup_( AF_ReverseCharacterMap map, FT_Int glyph_index, FT_Long length ) +{ + if ( map == NULL ) + { + return 0; + } + /* Binary search for reverse character map entry */ + FT_Int low = 0; + FT_Int high = length - 1; + while ( high >= low ) + { + FT_Int mid = ( high + low ) / 2; + FT_Int mid_glyph_index = map->entries[mid].glyph_index; + if ( glyph_index < mid_glyph_index ) + { + high = mid - 1; + } + else if ( glyph_index > mid_glyph_index ) + { + low = mid + 1; + } + else + { + return map->entries[mid].codepoint; + } + } + + return 0; +} + +FT_LOCAL_DEF( FT_UInt32 ) +af_reverse_character_map_lookup( AF_ReverseCharacterMap map, FT_Int glyph_index ) +{ + return af_reverse_character_map_lookup_( map, glyph_index, map->length ); +} + +/*prepare to add one more entry to the reverse character map + this is a helper for af_reverse_character_map_new*/ +FT_LOCAL_DEF( FT_Error ) +af_reverse_character_map_expand( AF_ReverseCharacterMap map, FT_Long *capacity, FT_Memory memory ) +{ + FT_Error error; + if ( map->length < *capacity ) + { + return FT_Err_Ok; + } + + if ( map->length == *capacity ) + { + FT_Long new_capacity = *capacity + *capacity / 2; + if ( FT_RENEW_ARRAY( map->entries, map->length, new_capacity ) ) { + return error; + } + *capacity = new_capacity; + } + + return FT_Err_Ok; +} + +FT_LOCAL_DEF( FT_Error ) +af_reverse_character_map_new( AF_ReverseCharacterMap *map, AF_FaceGlobals globals ) +{ + FT_Face face = globals->face; + FT_Memory memory = face->memory; + /* Search for a unicode charmap */ + /* If there isn't one, create a blank map */ + + FT_TRACE4(( "af_reverse_character_map_new: building reverse character map\n" )); + + FT_Error error; + /* backup face->charmap because find_unicode_charmap sets it */ + FT_CharMap old_charmap = face->charmap; + if ( ( error = find_unicode_charmap( face ) ) ) + { + *map = NULL; + goto Exit; + } + + if ( FT_NEW( *map ) ) + { + goto Exit; + } + + FT_Long capacity = 10; + ( *map )->length = 0; + + if ( FT_NEW_ARRAY( ( *map )->entries, capacity) ) + { + goto Exit; + } + +#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 = FT_Get_Char_Index( face, codepoint ); + if ( glyph == 0 ) + { +#ifdef FT_DEBUG_LEVEL_TRACE + failed_lookups++; +#endif + continue; + } + error = af_reverse_character_map_expand( *map, &capacity, memory ); + if ( error ) { + goto Exit; + } + + ( *map )->length++; + ( *map )->entries[i].glyph_index = glyph; + ( *map )->entries[i].codepoint = codepoint; + } + + ft_qsort( + ( *map )->entries, + ( *map )->length, + sizeof( AF_ReverseMapEntry ), + af_reverse_character_map_entry_compare + ); + + FT_TRACE4(( " reverse character map built successfully"\ + " with %d entries\n", (*map)->length )); + +Exit: + face->charmap = old_charmap; + 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; + } + + return FT_Err_Ok; +} + +FT_LOCAL_DEF( FT_Error ) +af_reverse_character_map_done( AF_ReverseCharacterMap map, FT_Memory memory ) { + FT_FREE( map->entries ); + return FT_Err_Ok; +} diff --git a/src/autofit/afadjust.h b/src/autofit/afadjust.h index 6b67703d0..5f9c01ed1 100644 --- a/src/autofit/afadjust.h +++ b/src/autofit/afadjust.h @@ -2,6 +2,7 @@ #define AFADJUST_H_ #include +#include "afglobal.h" FT_BEGIN_HEADER @@ -20,10 +21,29 @@ typedef enum AF_VerticalSeparationAdjustmentType_ AF_VERTICAL_ADJUSTMENT_NONE } 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; + FT_Bool apply_tilde; +} AF_AdjustmentDatabaseEntry; + +FT_LOCAL(AF_VerticalSeparationAdjustmentType) +af_lookup_vertical_seperation_type( AF_ReverseCharacterMap map, FT_Int glyph_index ); + +FT_LOCAL( FT_Bool ) +af_lookup_tilde_correction_type( AF_ReverseCharacterMap map, FT_Int glyph_index ); + +FT_LOCAL( FT_UInt32 ) +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( AF_ReverseCharacterMap *map, AF_FaceGlobals globals ); + +/*free the reverse character map*/ +FT_LOCAL( FT_Error ) +af_reverse_character_map_done( AF_ReverseCharacterMap map, FT_Memory memory ); struct AF_ReverseCharacterMap_; diff --git a/src/autofit/aftypes.h b/src/autofit/aftypes.h index 661519449..dd96f47c3 100644 --- a/src/autofit/aftypes.h +++ b/src/autofit/aftypes.h @@ -406,6 +406,12 @@ extern void* af_debug_hints_; typedef struct AF_FaceGlobalsRec_* AF_FaceGlobals; + /*stores a mapping from glyphs to unicode codepoints + see afadjust.c for details */ + struct AF_ReverseCharacterMap_; + + typedef struct AF_ReverseCharacterMap_ *AF_ReverseCharacterMap; + /* This is the main structure that combines everything. Autofit modules */ /* specific to writing systems derive their structures from it, for */ /* example `AF_LatinMetrics'. */ diff --git a/src/autofit/autofit.c b/src/autofit/autofit.c index 8bd609b5e..55017186d 100644 --- a/src/autofit/autofit.c +++ b/src/autofit/autofit.c @@ -30,6 +30,7 @@ #include "afmodule.c" #include "afranges.c" #include "afshaper.c" +#include "afadjust.c" /* END */ diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c index 759b95c73..1a642140d 100644 --- a/src/base/ftobjs.c +++ b/src/base/ftobjs.c @@ -1358,22 +1358,7 @@ driver ); } - - /************************************************************************** - * - * @Function: - * find_unicode_charmap - * - * @Description: - * This function finds a Unicode charmap, if there is one. - * And if there is more than one, it tries to favour the more - * extensive one, i.e., one that supports UCS-4 against those which - * are limited to the BMP (said UCS-2 encoding.) - * - * This function is called from open_face() (just below), and also - * from FT_Select_Charmap( ..., FT_ENCODING_UNICODE ). - */ - static FT_Error + FT_Error find_unicode_charmap( FT_Face face ) { FT_CharMap* first;