/***************************************************************************/ /* */ /* ttsubpix.c */ /* */ /* TrueType Subpixel Hinting. */ /* */ /* Copyright 2010-2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ /* modified, and distributed under the terms of the FreeType project */ /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ /* this file you indicate that you have read the license and */ /* understand and accept it fully. */ /* */ /***************************************************************************/ #include #include FT_INTERNAL_DEBUG_H #include FT_INTERNAL_CALC_H #include FT_INTERNAL_STREAM_H #include FT_INTERNAL_SFNT_H #include FT_TRUETYPE_TAGS_H #include FT_OUTLINE_H #include "ttsubpix.h" #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING FT_LOCAL_DEF( FT_Bool ) is_member_of_family_class( const FT_String* detected_font_name, const FT_String* rule_font_name ) { FT_UInt i, j; /* If font name matches rule family */ if ( strcmp( detected_font_name, rule_font_name ) == 0 ) return TRUE; /* If font name is a wildcard "" */ if ( strcmp( rule_font_name, "" ) == 0 ) return TRUE; /* If font name is contained in a class list */ for ( i = 0; i < FAMILY_CLASS_RULES_SIZE; i++ ) { if ( strcmp( FAMILY_CLASS_Rules[i].name, rule_font_name ) == 0 ) { for ( j = 0; j < MAX_CLASS_MEMBERS; j++ ) { if ( strcmp( FAMILY_CLASS_Rules[i].member[j], "" ) == 0 ) continue; if ( strcmp( FAMILY_CLASS_Rules[i].member[j], detected_font_name ) == 0 ) return TRUE; } } } return FALSE; } FT_LOCAL_DEF( FT_Bool ) is_member_of_style_class( const FT_String* detected_font_style, const FT_String* rule_font_style ) { FT_UInt i, j; /* If font style matches rule style */ if ( strcmp( detected_font_style, rule_font_style ) == 0 ) return TRUE; /* If font style is a wildcard "" */ if ( strcmp( rule_font_style, "" ) == 0 ) return TRUE; /* If font style is contained in a class list */ for ( i = 0; i < STYLE_CLASS_RULES_SIZE; i++ ) { if ( strcmp( STYLE_CLASS_Rules[i].name, rule_font_style ) == 0 ) { for ( j = 0; j < MAX_CLASS_MEMBERS; j++ ) { if ( strcmp( STYLE_CLASS_Rules[i].member[j], "" ) == 0 ) continue; if ( strcmp( STYLE_CLASS_Rules[i].member[j], detected_font_style ) == 0 ) return TRUE; } } } return FALSE; } FT_LOCAL_DEF( FT_Bool ) sph_test_tweak( TT_Face face, FT_String* family, int ppem, FT_String* style, FT_UInt glyph_index, SPH_TweakRule* rule, FT_UInt num_rules ) { FT_UInt i; /* rule checks may be able to be optimized further */ for ( i = 0; i < num_rules; i++ ) { if ( family && ( is_member_of_family_class ( family, rule[i].family ) ) ) if ( rule[i].ppem == 0 || rule[i].ppem == ppem ) if ( style && is_member_of_style_class ( style, rule[i].style ) ) if ( rule[i].glyph == 0 || FT_Get_Char_Index( (FT_Face)face, rule[i].glyph ) == glyph_index ) return TRUE; } return FALSE; } FT_LOCAL_DEF( float ) scale_test_tweak( TT_Face face, FT_String* family, int ppem, FT_String* style, FT_UInt glyph_index, SPH_ScaleRule* rule, FT_UInt num_rules ) { FT_UInt i; /* rule checks may be able to be optimized further */ for ( i = 0; i < num_rules; i++ ) { if ( family && ( is_member_of_family_class ( family, rule[i].family ) ) ) if ( rule[i].ppem == 0 || rule[i].ppem == ppem ) if ( style && is_member_of_style_class( style, rule[i].style ) ) if ( rule[i].glyph == 0 || FT_Get_Char_Index( (FT_Face)face, rule[i].glyph ) == glyph_index ) return rule[i].scale; } return 1.0; } #define TWEAK_RULES( x ) \ if ( sph_test_tweak( face, family, ppem, style, glyph_index, \ x##_Rules, x##_RULES_SIZE ) ) \ loader->exec->sph_tweak_flags |= SPH_TWEAK_##x; #define TWEAK_RULES_EXCEPTIONS( x ) \ if ( sph_test_tweak( face, family, ppem, style, glyph_index, \ x##_Rules_Exceptions, x##_RULES_EXCEPTIONS_SIZE ) ) \ loader->exec->sph_tweak_flags &= ~SPH_TWEAK_##x; FT_LOCAL_DEF( void ) sph_set_tweaks( TT_Loader loader, FT_UInt glyph_index ) { TT_Face face = (TT_Face)loader->face; FT_String* family = face->root.family_name; int ppem = loader->size->metrics.x_ppem; FT_String* style = face->root.style_name; /* Don't apply rules if style isn't set */ if ( !face->root.style_name ) return; #ifdef SPH_DEBUG_MORE_VERBOSE printf( "%s,%d,%s,%c=%d ", family, ppem, style, glyph_index, glyph_index ); #endif TWEAK_RULES( PIXEL_HINTING ); if ( loader->exec->sph_tweak_flags & SPH_TWEAK_PIXEL_HINTING ) { loader->exec->ignore_x_mode = FALSE; return; } TWEAK_RULES( ALLOW_X_DMOVE ); TWEAK_RULES( ALLOW_X_DMOVEX ); TWEAK_RULES( ALLOW_X_MOVE_ZP2 ); TWEAK_RULES( ALWAYS_DO_DELTAP ); TWEAK_RULES( ALWAYS_SKIP_DELTAP ); TWEAK_RULES( DEEMBOLDEN ); TWEAK_RULES( DELTAP_SKIP_EXAGGERATED_VALUES ); TWEAK_RULES( DO_SHPIX ); TWEAK_RULES( EMBOLDEN ); TWEAK_RULES( MIAP_HACK ); TWEAK_RULES( NORMAL_ROUND ); TWEAK_RULES( NO_ALIGNRP_AFTER_IUP ); TWEAK_RULES( NO_CALL_AFTER_IUP ); TWEAK_RULES( NO_DELTAP_AFTER_IUP ); TWEAK_RULES( RASTERIZER_35 ); TWEAK_RULES( SKIP_INLINE_DELTAS ); TWEAK_RULES( SKIP_IUP ); TWEAK_RULES( MIRP_CVT_ZERO ); TWEAK_RULES( SKIP_OFFPIXEL_Y_MOVES ); TWEAK_RULES_EXCEPTIONS( SKIP_OFFPIXEL_Y_MOVES ); TWEAK_RULES( SKIP_NONPIXEL_Y_MOVES ); TWEAK_RULES_EXCEPTIONS( SKIP_NONPIXEL_Y_MOVES ); TWEAK_RULES( ROUND_NONPIXEL_Y_MOVES ); TWEAK_RULES_EXCEPTIONS( ROUND_NONPIXEL_Y_MOVES ); if ( loader->exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 ) { if ( loader->exec->rasterizer_version != 35 ) { loader->exec->rasterizer_version = 35; /* must re-execute fpgm */ loader->exec->size->cvt_ready = FALSE; tt_size_ready_bytecode( loader->exec->size, FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) ); } } else { if ( loader->exec->rasterizer_version == 35 ) { loader->exec->rasterizer_version = 37; /* must re-execute fpgm */ loader->exec->size->cvt_ready = FALSE; tt_size_ready_bytecode( loader->exec->size, FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) ); } } if ( IS_HINTED( loader->load_flags ) ) { TWEAK_RULES( TIMES_NEW_ROMAN_HACK ); TWEAK_RULES( COURIER_NEW_2_HACK ); } if ( sph_test_tweak( face, family, ppem, style, glyph_index, COMPATIBILITY_MODE_Rules, COMPATIBILITY_MODE_RULES_SIZE ) ) { loader->exec->compatibility_mode |= TRUE; loader->exec->ignore_x_mode |= TRUE; } else loader->exec->compatibility_mode &= FALSE; if ( IS_HINTED( loader->load_flags ) ) { if ( sph_test_tweak( face, family, ppem, style, glyph_index, COMPATIBLE_WIDTHS_Rules, COMPATIBLE_WIDTHS_RULES_SIZE ) ) loader->exec->compatible_widths |= TRUE; } } #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ /* END */