diff options
Diffstat (limited to '0002-infinality-2.10.1-2019.08.21.patch')
-rw-r--r-- | 0002-infinality-2.10.1-2019.08.21.patch | 6310 |
1 files changed, 6310 insertions, 0 deletions
diff --git a/0002-infinality-2.10.1-2019.08.21.patch b/0002-infinality-2.10.1-2019.08.21.patch new file mode 100644 index 000000000000..2eb0f0d44e48 --- /dev/null +++ b/0002-infinality-2.10.1-2019.08.21.patch @@ -0,0 +1,6310 @@ +diff --git a/builds/freetype.mk b/builds/freetype.mk +index 2b0ffaedd..a2bc85ba4 100644 +--- a/builds/freetype.mk ++++ b/builds/freetype.mk +@@ -164,6 +164,7 @@ FT_CFLAGS = $(CPPFLAGS) \ + $(CFLAGS) \ + $DFT2_BUILD_LIBRARY \ + $DFT_CONFIG_MODULES_H="<ftmodule.h>" \ ++ $D_GNU_SOURCE \ + $(FTOPTION_FLAG) + + +diff --git a/configure b/configure +index 9a64f69c4..6161c0f3a 100755 +--- a/configure ++++ b/configure +@@ -13,6 +13,8 @@ + # Call the `configure' script located in `builds/unix'. + # + ++export LDFLAGS="$LDFLAGS -lm" ++ + rm -f config.mk builds/unix/unix-def.mk builds/unix/unix-cc.mk + + # respect GNUMAKE environment variable for backward compatibility +diff --git a/devel/ftoption.h b/devel/ftoption.h +index 16cf4e126..f75552db5 100644 +--- a/devel/ftoption.h ++++ b/devel/ftoption.h +@@ -601,6 +601,16 @@ FT_BEGIN_HEADER + */ + #define TT_CONFIG_OPTION_BYTECODE_INTERPRETER + ++ /*************************************************************************/ ++ /* */ ++ /* Define FT_CONFIG_OPTION_INFINALITY_PATCHSET if you want to enable */ ++ /* all additional infinality patches, which are configured via env */ ++ /* variables. */ ++ /* */ ++ /* This option requires TT_CONFIG_OPTION_SUBPIXEL_HINTING to */ ++ /* defined. */ ++ /* */ ++#define FT_CONFIG_OPTION_INFINALITY_PATCHSET + + /************************************************************************** + * +diff --git a/include/freetype/config/ftoption.h b/include/freetype/config/ftoption.h +index 12f47a82e..946a2fb93 100644 +--- a/include/freetype/config/ftoption.h ++++ b/include/freetype/config/ftoption.h +@@ -113,20 +113,21 @@ FT_BEGIN_HEADER + #define FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + + +- /************************************************************************** +- * +- * Uncomment the line below if you want to activate LCD rendering +- * technology similar to ClearType in this build of the library. This +- * technology triples the resolution in the direction color subpixels. To +- * mitigate color fringes inherent to this technology, you also need to +- * explicitly set up LCD filtering. +- * +- * Note that this feature is covered by several Microsoft patents and +- * should not be activated in any default build of the library. When this +- * macro is not defined, FreeType offers alternative LCD rendering +- * technology that produces excellent output without LCD filtering. +- */ +-/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ ++ /*************************************************************************/ ++ /* */ ++ /* Uncomment the line below if you want to activate LCD rendering */ ++ /* technology similar to ClearType in this build of the library. This */ ++ /* technology triples the resolution in the direction color subpixels. */ ++ /* To mitigate color fringes inherent to this technology, you also need */ ++ /* to explicitly set up LCD filtering. */ ++ /* */ ++ /* Note that this feature is covered by several Microsoft patents */ ++ /* and should not be activated in any default build of the library. */ ++ /* When this macro is not defined, FreeType offers alternative LCD */ ++ /* rendering technology that produces excellent output without LCD */ ++ /* filtering. */ ++ /* */ ++#define FT_CONFIG_OPTION_SUBPIXEL_RENDERING + + + /************************************************************************** +@@ -601,6 +602,17 @@ FT_BEGIN_HEADER + */ + #define TT_CONFIG_OPTION_BYTECODE_INTERPRETER + ++ /*************************************************************************/ ++ /* */ ++ /* Define FT_CONFIG_OPTION_INFINALITY_PATCHSET if you want to enable */ ++ /* all additional infinality patches, which are configured via env */ ++ /* variables. */ ++ /* */ ++ /* This option requires TT_CONFIG_OPTION_SUBPIXEL_HINTING to */ ++ /* defined. */ ++ /* */ ++#define FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ + + /************************************************************************** + * +@@ -658,8 +670,8 @@ FT_BEGIN_HEADER + * https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx + */ + /* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING 1 */ +-#define TT_CONFIG_OPTION_SUBPIXEL_HINTING 2 +-/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING ( 1 | 2 ) */ ++/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING 1 */ ++#define TT_CONFIG_OPTION_SUBPIXEL_HINTING ( 1 | 2 ) + + + /************************************************************************** +diff --git a/include/freetype/internal/ftobjs.h b/include/freetype/internal/ftobjs.h +index 0c1d3e5bf..3acde2406 100644 +--- a/include/freetype/internal/ftobjs.h ++++ b/include/freetype/internal/ftobjs.h +@@ -278,12 +278,14 @@ FT_BEGIN_HEADER + #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + + typedef void (*FT_Bitmap_LcdFilterFunc)( FT_Bitmap* bitmap, ++ FT_Render_Mode render_mode, + FT_Byte* weights ); + + + /* This is the default LCD filter, an in-place, 5-tap FIR filter. */ + FT_BASE( void ) + ft_lcd_filter_fir( FT_Bitmap* bitmap, ++ FT_Render_Mode mode, + FT_LcdFiveTapFilter weights ); + + #endif /* FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ +@@ -908,6 +910,7 @@ FT_BEGIN_HEADER + FT_DebugHook_Func debug_hooks[4]; + + #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING ++ FT_Int lcd_extra; /* number of extra pixels */ + FT_LcdFiveTapFilter lcd_weights; /* filter weights, if any */ + FT_Bitmap_LcdFilterFunc lcd_filter_func; /* filtering callback */ + #else +diff --git a/src/autofit/aflatin.c b/src/autofit/aflatin.c +index 27d402488..ac1488dcb 100644 +--- a/src/autofit/aflatin.c ++++ b/src/autofit/aflatin.c +@@ -23,7 +23,10 @@ + #include "afglobal.h" + #include "aflatin.h" + #include "aferrors.h" +- ++#include "strings.h" ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++#include "../base/ftinf.h" ++#endif + + #ifdef AF_CONFIG_OPTION_USE_WARPER + #include "afwarp.h" +@@ -39,6 +42,10 @@ + #undef FT_COMPONENT + #define FT_COMPONENT aflatin + ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++FT_Pos infinality_cur_width = 0; ++#endif ++ + + /* needed for computation of round vs. flat segments */ + #define FLAT_THRESHOLD( x ) ( x / 14 ) +@@ -1181,7 +1188,10 @@ + FT_Pos delta; + AF_LatinAxis axis; + FT_UInt nn; +- ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ FT_Bool adjust_heights = FALSE; ++ if(ftinf) adjust_heights=ftinf->autohint_increase_glyph_heights; ++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ + + if ( dim == AF_DIMENSION_HORZ ) + { +@@ -1209,7 +1219,7 @@ + { + AF_LatinAxis Axis = &metrics->axis[AF_DIMENSION_VERT]; + AF_LatinBlue blue = NULL; +- ++ int threshold = 40; + + for ( nn = 0; nn < Axis->blue_count; nn++ ) + { +@@ -1219,7 +1229,12 @@ + break; + } + } +- ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ if ( adjust_heights && ++ metrics->root.scaler.face->size->metrics.x_ppem < 15 && ++ metrics->root.scaler.face->size->metrics.x_ppem > 5 ) ++ threshold = 52; ++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ + if ( blue ) + { + FT_Pos scaled; +@@ -1375,7 +1390,13 @@ + + /* a blue zone is only active if it is less than 3/4 pixels tall */ + dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale ); ++ ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ /* Do at low ppems ( ~< 200 ), in order to prevent fringes */ ++ if ( dist <= 256 && dist >= -256 ) ++#else + if ( dist <= 48 && dist >= -48 ) ++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ + { + #if 0 + FT_Pos delta1; +@@ -1426,7 +1447,12 @@ + delta2 = -delta2; + + blue->ref.fit = FT_PIX_ROUND( blue->ref.cur ); ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ /* Round to prevent fringes */ ++ blue->shoot.fit = FT_PIX_ROUND( blue->ref.fit - delta2 ); ++#else + blue->shoot.fit = blue->ref.fit - delta2; ++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ + + #endif + +@@ -2564,7 +2590,10 @@ + dist = edge->fpos - blue->shoot.org; + if ( dist < 0 ) + dist = -dist; +- ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ /* round down to pixels */ ++ /*dist = FT_MulFix( dist, scale ) & ~63;*/ ++#endif + dist = FT_MulFix( dist, scale ); + if ( dist < best_dist ) + { +@@ -2740,8 +2769,17 @@ + FT_Pos dist = width; + FT_Int sign = 0; + FT_Int vertical = ( dim == AF_DIMENSION_VERT ); +- +- ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ FT_Int infinality_dist = 0; ++ FT_UInt autohint_snap_stem_height = 0; ++ if( ftinf ) autohint_snap_stem_height=ftinf->autohint_snap_stem_height; ++ if ( autohint_snap_stem_height > 100 ) ++ autohint_snap_stem_height = 100; ++ else if ( autohint_snap_stem_height < 0 ) ++ autohint_snap_stem_height = 0; ++ ++ if ( autohint_snap_stem_height == 0 ) ++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ + if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) || + axis->extra_light ) + return width; +@@ -2751,9 +2789,76 @@ + dist = -width; + sign = 1; + } ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ /* Calculate snap value differently than standard freetype */ ++ if ( autohint_snap_stem_height > 0 && ++ ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || ++ ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) ) ++ { ++ infinality_dist = af_latin_snap_width( axis->widths, ++ axis->width_count, dist ); ++ ++ if ( metrics->root.scaler.face->size->metrics.x_ppem > 9 && ++ axis->width_count > 0 && ++ abs( axis->widths[0].cur - infinality_dist ) < 32 && ++ axis->widths[0].cur > 52 ) ++ { ++ const char *style_name=metrics->root.scaler.face->style_name; ++ if ( style_name!=NULL && ++ ( strstr( style_name, "Regular" ) || ++ strstr( style_name, "Book" ) || ++ strstr( style_name, "Medium" ) || ++ strcmp( style_name, "Italic" ) == 0 || ++ strcmp( style_name, "Oblique" ) == 0 ) ++ ) ++ { ++ /* regular weight */ ++ if ( axis->widths[0].cur < 64 ) ++ infinality_dist = 64; ++ else if ( axis->widths[0].cur < 88 ) ++ infinality_dist = 64; ++ else if ( axis->widths[0].cur < 160 ) ++ infinality_dist = 128; ++ else if ( axis->widths[0].cur < 240 ) ++ infinality_dist = 190; ++ else infinality_dist = ( infinality_dist ) & ~63; ++ } ++ else ++ { ++ /* bold gets a different threshold */ ++ if ( axis->widths[0].cur < 64 ) ++ infinality_dist = 64 ; ++ else if ( axis->widths[0].cur < 108 ) ++ infinality_dist = 64; ++ else if ( axis->widths[0].cur < 160 ) ++ infinality_dist = 128; ++ else if ( axis->widths[0].cur < 222 ) ++ infinality_dist = 190; ++ else if ( axis->widths[0].cur < 288 ) ++ infinality_dist = 254; ++ else infinality_dist = ( infinality_dist + 16 ) & ~63; ++ } + +- if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || ++ } ++ if ( infinality_dist < 52 ) ++ { ++ if ( metrics->root.scaler.face->size->metrics.x_ppem < 9 ) ++ { ++ if ( infinality_dist < 32 ) ++ infinality_dist = 32; ++ } ++ else ++ infinality_dist = 64; ++ } ++ } ++ else if ( autohint_snap_stem_height < 100 && ++ ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || ++ ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) ) ++#else ++ ++ if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || + ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) ++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ + { + /* smooth hinting process: very lightly quantize the stem width */ + +@@ -2845,6 +2950,9 @@ + } + } + else ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ if ( autohint_snap_stem_height < 100 ) ++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ + { + /* strong hinting process: snap the stem width to integer pixels */ + +@@ -2852,7 +2960,10 @@ + + + dist = af_latin_snap_width( axis->widths, axis->width_count, dist ); +- ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ if ( autohint_snap_stem_height > 0 ) ++ goto Done_Width; ++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ + if ( vertical ) + { + /* in the case of vertical hinting, always round */ +@@ -2915,6 +3026,32 @@ + } + + Done_Width: ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ if ( axis->widths[0].cur > 42 ) ++ /* weighted average */ ++ dist = (dist * ( 100 - autohint_snap_stem_height ) ++ + infinality_dist * autohint_snap_stem_height ) / 100; ++ ++ { ++ int factor = 100; ++ if ( axis->standard_width < 100 ) ++ factor = axis->standard_width; ++ ++ if ( metrics->root.scaler.face->size->metrics.x_ppem >= 9 && dist < 52 ) ++ dist += ( (52 - dist) * factor ) / 100; ++ if ( metrics->root.scaler.face->size->metrics.x_ppem < 9 && dist < 32 ) ++ dist += ( (32 - dist) * factor ) / 100; ++ ++ if ( axis->standard_width > 100 && ++ metrics->root.scaler.face->size->metrics.x_ppem >= 11 && ++ dist < 64 ) ++ dist = 64; ++ if ( axis->standard_width > 100 && ++ metrics->root.scaler.face->size->metrics.x_ppem >= 9 && ++ dist < 52 ) ++ dist = 52; ++ } ++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ + if ( sign ) + dist = -dist; + +@@ -2933,6 +3070,8 @@ + FT_Pos dist, base_delta; + FT_Pos fitted_width; + ++/* if fitted_width causes stem_edge->pos to land basically on top of an existing ++ * stem_edge->pos, then add or remove 64. Need to figure out a way to do this */ + + dist = stem_edge->opos - base_edge->opos; + base_delta = base_edge->pos - base_edge->opos; +@@ -3540,8 +3679,11 @@ + int dim; + + AF_LatinAxis axis; +- +- ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ FT_Int emboldening_strength = 0; ++ FT_Bool use_various_tweaks = FALSE; ++ if( ftinf ) use_various_tweaks=ftinf->use_various_tweaks; ++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ + error = af_glyph_hints_reload( hints, outline ); + if ( error ) + goto Exit; +@@ -3605,7 +3747,11 @@ + } + + af_glyph_hints_save( hints, outline ); +- ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ { ++ infinality_cur_width = metrics->axis->widths[0].cur; ++ } ++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ + Exit: + return error; + } +diff --git a/src/autofit/aflatin.h b/src/autofit/aflatin.h +index 40479538c..c86ea813f 100644 +--- a/src/autofit/aflatin.h ++++ b/src/autofit/aflatin.h +@@ -64,6 +64,9 @@ FT_BEGIN_HEADER + + #define AF_LATIN_MAX_WIDTHS 16 + ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ extern FT_Pos infinality_cur_width; ++#endif + + #define AF_LATIN_BLUE_ACTIVE ( 1U << 0 ) /* zone height is <= 3/4px */ + #define AF_LATIN_BLUE_TOP ( 1U << 1 ) /* we have a top blue zone */ +diff --git a/src/autofit/afmodule.c b/src/autofit/afmodule.c +index 3e46a3655..9d35874d3 100644 +--- a/src/autofit/afmodule.c ++++ b/src/autofit/afmodule.c +@@ -21,6 +21,10 @@ + #include "afloader.h" + #include "aferrors.h" + ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++#include "../base/ftinf.h" ++#endif ++ + #ifdef FT_DEBUG_AUTOFIT + + #ifndef FT_MAKE_OPTION_SINGLE_OBJECT +@@ -451,6 +455,9 @@ + module->warping = 0; + #endif + module->no_stem_darkening = TRUE; ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ if(ftinf) module->no_stem_darkening = !ftinf->stem_darkening_autofit; ++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ + + module->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1; + module->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1; +diff --git a/src/base/Jamfile b/src/base/Jamfile +index 8e1ec4275..f6f60e677 100644 +--- a/src/base/Jamfile ++++ b/src/base/Jamfile +@@ -59,6 +59,7 @@ SubDir FT2_TOP $(FT2_SRC_DIR) base ; + ftglyph + ftgxval + ftinit ++ ftinf + ftmm + ftotval + ftpatent +diff --git a/src/base/ftbase.c b/src/base/ftbase.c +index fb8cbfcc2..6db31550f 100644 +--- a/src/base/ftbase.c ++++ b/src/base/ftbase.c +@@ -37,6 +37,9 @@ + #include "ftstream.c" + #include "fttrigon.c" + #include "ftutil.c" ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++#include "ftinf.c" ++#endif + + + /* END */ +diff --git a/src/base/ftinf.c b/src/base/ftinf.c +new file mode 100644 +index 000000000..5d6b7f682 +--- /dev/null ++++ b/src/base/ftinf.c +@@ -0,0 +1,363 @@ ++#include <stdlib.h> ++#include "ftinf.h" ++#define true 1 ++#define false 0 ++ ++#define on 1 ++#define off 0 ++#define end (-128) ++ ++#define sw2pv 18 /* STEM_WIDTH_2_PPEM */ ++#define maxp 100 /* MAX_PPEM */ ++ ++typedef signed char pv; /* ppm and values type */ ++/* the arrays start with existence flag + values */ ++typedef struct sa_rules_s { ++ const char *name; ++ pv always_use_100[1+4+1]; ++ pv brightness[1+2+1]; ++ pv contrast[1+2+1]; ++ pv edge_detection[1+4+1]; ++ pv m[1+4+1]; ++ pv bearing_correction[1+2+1]; ++ pv spacing[1+5+1]; ++ pv start[1+5+1]; ++ pv stem_scaling[1+6+1]; ++ pv stem_translating[1+2+1]; ++ pv stem_translating_only[1+10+1]; ++ pv stem_widths[1+4]; /* these end with maxp */ ++ pv synthesize_stems[1+2+1]; ++} sa_rules_t; ++ ++#pragma GCC diagnostic ignored "-Wpedantic" /* C99 struct initializer tags are needed */ ++#pragma GCC diagnostic ignored "-Wunused-function" ++ ++const ftinf_t *ftinf; ++/* final settings, updated from environment */ ++ftinf_t _env; ++ ++/* rules and hashing function */ ++#include "ftinf_rh.c" ++ ++/* rules selection */ ++void ftinf_fill_stem_values( Stem_Data *stem_values, ++ const char *family, int ppem, int use_known ){ ++ /* set the defaults */ ++ stem_values->bearing_correction = TRUE; ++ stem_values->brightness = 0.0; ++ stem_values->contrast = 0.0; ++ stem_values->edge_detection = FALSE; ++ stem_values->m = -1; ++ stem_values->stem_scaling = -1; ++ stem_values->stem_spacing = -1; ++ stem_values->stem_start = -1; ++ stem_values->stem_translating = 0; ++ stem_values->stem_translating_only = -1024; ++ stem_values->stem_width = -1; ++ stem_values->synth_stems = FALSE; ++ stem_values->use_100 = FALSE; ++ /* pick from known rules if requested and they exist for current family */ ++ if( !use_known ) ++ return; ++ else { ++ const sa_rules_t *r=ftinf_rules( family ); ++ int i; ++ if( r==NULL ) return; ++ if( r->stem_widths[0]==on ) ++ for( i=1; r->stem_widths[i]!=maxp; ++i ) ++ if( ppem < r->stem_widths[i] ){ ++ stem_values->stem_width = i-1; ++ break; ++ } ++ ++ if( r->stem_scaling[0]==on ) ++ for( i=1; r->stem_scaling[i]!=end; i+=2 ) ++ if( ppem==r->stem_scaling[i] ){ ++ stem_values->stem_scaling = r->stem_scaling[i+1]; ++ break; ++ } ++ ++ if( r->m[0]==on ) ++ for( i=1; r->m[i]!=end; i+=2 ) ++ if( ppem==r->m[i] ){ ++ stem_values->m = r->m[i+1]; ++ break; ++ } ++ ++ if( r->stem_translating_only[0]==on ) ++ for( i=1; r->stem_translating_only[i]!=end; i+=2 ) ++ if( ppem==r->stem_translating_only[i] || r->stem_translating_only[i]==0 ){ ++ stem_values->stem_translating_only = r->stem_translating_only[i+1]; ++ break; ++ } ++ ++ if( r->stem_translating[0]==on ) ++ for( i=1; r->stem_translating[i]!=end; i+=2 ) ++ if( ppem==r->stem_translating[i] || r->stem_translating[i]==0 ){ ++ stem_values->stem_translating = r->stem_translating[i+1]; ++ break; ++ } ++ ++ if( r->always_use_100[0]==on ) ++ for( i=1; r->always_use_100[i]!=end; i+=2 ) ++ if( ppem>=r->always_use_100[i] && ppem<=r->always_use_100[i+1] ){ ++ stem_values->use_100 = TRUE; ++ break; ++ } ++ ++ if( r->synthesize_stems[0]==on ) ++ for( i=1; r->synthesize_stems[i]!=end; i+=2 ) ++ if( ppem>=r->synthesize_stems[i] && ppem<=r->synthesize_stems[i+1] ){ ++ stem_values->synth_stems = TRUE; ++ break; ++ } ++ ++ if( r->edge_detection[0]==on ) ++ for( i=1; r->edge_detection[i]!=end; i+=2 ) ++ if( ppem>=r->edge_detection[i] && ppem<=r->edge_detection[i+1] ){ ++ stem_values->edge_detection = TRUE; ++ break; ++ } ++ ++ if( r->bearing_correction[0]==on ) ++ for( i=1; r->bearing_correction[i]!=end; i+=2 ) ++ if( ppem>=r->bearing_correction[i] && ppem<=r->bearing_correction[i+1] ){ ++ stem_values->bearing_correction = FALSE; ++ break; ++ } ++ ++#if(0) ++ if( r->brightness[0]==on ) ++ for( i=1; r->brightness[i]!=end; i+=2 ) ++ if( ppem==r->brightness[i]||r->brightness[i]==0 ){ ++ stem_values->brightness=r->brightness[i+1]*(1.0f/300.0f); ++ break; ++ } ++ ++ if( r->contrast[0]==on ) ++ for( i=1; r->contrast[i]!=end; i+=2 ) ++ if( ppem==r->contrast[i]||r->contrast[i]==0 ){ ++ stem_values->contrast=r->contrast[i+1]*(1.0f/300.0f); ++ break; ++ } ++ if( r->spacing[0]==on ){ ++ /* not used by original code */ ++ } ++ if( r->start[0]==on ){ ++ /* not used by original code */ ++ } ++#endif ++ } ++ return; ++} ++ ++void ftinf_get_bc( const char *family, int ppem, float *brightness, float *contrast ){ ++ const sa_rules_t *r=ftinf_rules( family ); ++ *brightness=0; ++ *contrast=0; ++ if( r ){ ++ int i; ++ if( r->brightness[0]==on ) ++ for( i=1; r->brightness[i]!=end; i+=2 ) ++ if( ppem==r->brightness[i]||r->brightness[i]==0 ){ ++ *brightness=r->brightness[i+1]*(1.0f/300.0f); ++ break; ++ } ++ ++ if( r->contrast[0]==on ) ++ for( i=1; r->contrast[i]!=end; i+=2 ) ++ if( ppem==r->contrast[i]||r->contrast[i]==0 ){ ++ *contrast=r->contrast[i+1]*(1.0f/300.0f); ++ break; ++ } ++ } ++ return; ++} ++ ++static int ++bool_val( const char *s ){ ++ if ( s != NULL ) ++ return strcasecmp(s, "true") == 0 ++ || strcasecmp(s, "1") == 0 ++ || strcasecmp(s, "on") == 0 ++ || strcasecmp(s, "yes") ==0; ++ else ++ return 0; ++} ++ ++static int ++int_val( const char *s, int min, int max ){ ++ int val; ++ sscanf ( s, "%d", &val ); ++ if ( val > max ) ++ val = max; ++ else if ( val < min ) ++ val = min; ++ return val; ++} ++ ++/* settings and hashing function */ ++#include "ftinf_sh.c" ++ ++/* ++ Get active Infinality settings ++ */ ++void ftinf_env(){ ++ const char *s; ++ ftinf=ftinf_settings( getenv( "INFINALITY_FT" ) ); ++ ++ if( ftinf==NULL ){ ++ ftinf=ftinf_settings( "ultimate3" ); ++ /* this should always succeed */ ++#if(0) ++ if( ftinf==NULL ){ ++ /* put an error here */ ++ exit(-1); ++ } ++#endif ++ } ++ _env=ftinf[0]; /* copy as defaults */ ++ ++ /* check if custom environment values are set and update with them */ ++ s=getenv( "INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS" ); ++ if( s ) _env.autohint_increase_glyph_heights=bool_val( s ); ++ s=getenv( "INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT" ); ++ if( s ) _env.autohint_snap_stem_height=int_val( s, 0, 100 ); ++ s=getenv( "INFINALITY_FT_USE_VARIOUS_TWEAKS" ); ++ if( s ) _env.use_various_tweaks=bool_val( s ); ++ s=getenv( "INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS" ); ++ if( s ) _env.use_known_settings_on_selected_fonts=bool_val(s); ++#if(0) /* not used (naming error also) */ ++ s=getenv( "INFINALITY_FT_AUTOHINT_MINIMUM_STEM_WIDTH" ); ++ if( s ) _env.autohint_minimum_stem_height=int_val( s, 0, 100 ); ++#endif ++ s=getenv( "INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE" ); ++ if( s ) sscanf( s, "%d", &_env.stem_snapping_sliding_scale ); ++ s=getenv( "INFINALITY_FT_STEM_ALIGNMENT_STRENGTH" ); ++ if( s ) sscanf( s, "%d", &_env.stem_alignment_strength ); ++ s=getenv( "INFINALITY_FT_STEM_DARKENING_AUTOFIT" ); ++ if( s ) _env.stem_darkening_autofit=bool_val( s ); ++ s=getenv( "INFINALITY_FT_STEM_DARKENING_CFF" ); ++ if( s ) _env.stem_darkening_cff=bool_val( s ); ++ s=getenv( "INFINALITY_FT_STEM_FITTING_STRENGTH" ); ++ if( s ) sscanf( s, "%d", &_env.stem_fitting_strength ); ++ s=getenv( "INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH" ); ++ if( s ) _env.chromeos_style_sharpening_strength=int_val( s, 0, 100 ); ++ s=getenv( "INFINALITY_FT_BRIGHTNESS" ); ++ if( s ) sscanf( s, "%d", &_env.brightness ); ++ s=getenv( "INFINALITY_FT_CONTRAST" ); ++ if( s ) sscanf( s, "%d", &_env.contrast ); ++ s=getenv( "INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH" ); ++ if( s ) _env.windows_style_sharpening_strength=int_val( s, 0, 100 ); ++ s=getenv( "INFINALITY_FT_GAMMA_CORRECTION" ); ++ if( s ){ ++ float *f=_env.gamma_correction; ++ sscanf ( s, "%f %f", &f[0], &f[1] ); ++ if( f[1] < 1.0f ) f[1]=1.0f; ++ } ++ s=getenv( "INFINALITY_FT_FRINGE_FILTER_STRENGTH" ); ++ if( s ) sscanf( s, "%d", &_env.fringe_filter_strength ); ++ s=getenv( "INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH" ); ++ if( s ) sscanf( s, "%d", &_env.grayscale_filter_strength ); ++ s=getenv( "INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH" ); ++ if( s ) sscanf( s, "%d", &_env.autohint_horizontal_stem_darken_strength ); ++ s=getenv( "INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH" ); ++ if( s ) sscanf( s, "%d", &_env.autohint_vertical_stem_darken_strength ); ++ s=getenv( "INFINALITY_FT_GLOBAL_EMBOLDEN_X_VALUE" ); ++ if( s ) sscanf( s, "%d", &_env.global_embolden_x_value ); ++ s=getenv( "INFINALITY_FT_GLOBAL_EMBOLDEN_Y_VALUE" ); ++ if( s ) sscanf( s, "%d", &_env.global_embolden_y_value ); ++ s=getenv( "INFINALITY_FT_BOLD_EMBOLDEN_X_VALUE" ); ++ if( s ) sscanf( s, "%d", &_env.bold_embolden_x_value ); ++ s=getenv( "INFINALITY_FT_BOLD_EMBOLDEN_Y_VALUE" ); ++ if( s ) sscanf( s, "%d", &_env.bold_embolden_y_value ); ++ s=getenv( "INFINALITY_FT_FILTER_PARAMS" ); ++ if( s ) { ++ int *f=_env.filter_params; ++ if( sscanf( s, "%d %d %d %d %d", f+1, f+2, f+3, f+4, f+5 )==5 ) ++ f[0]=on; ++ else ++ f[0]=off; /* FIXME: put a warning? */ ++ } ++ /* do the range verifications as in original code */ ++ if ( _env.stem_snapping_sliding_scale > maxp ) ++ _env.stem_snapping_sliding_scale = 0; ++ else if ( _env.stem_snapping_sliding_scale < 0 ) ++ _env.stem_snapping_sliding_scale = 0; ++ if (_env.stem_snapping_sliding_scale < 11 && ++ _env.stem_snapping_sliding_scale > 0 ) ++ _env.stem_snapping_sliding_scale = 11; ++ ++ if ( _env.stem_alignment_strength > 100 ) ++ _env.stem_alignment_strength = 100; ++ else if ( _env.stem_alignment_strength < 0 ) ++ _env.stem_alignment_strength = 0; ++ ++ if ( _env.stem_fitting_strength > 100 ) ++ _env.stem_fitting_strength = 100; ++ else if ( _env.stem_fitting_strength < 0 ) ++ _env.stem_fitting_strength = 0; ++ ++ if ( _env.chromeos_style_sharpening_strength > 100 ) ++ _env.chromeos_style_sharpening_strength = 100; ++ else if ( _env.chromeos_style_sharpening_strength < 0 ) ++ _env.chromeos_style_sharpening_strength = 0; ++ ++ if ( _env.brightness > 100 ) ++ _env.brightness = 100; ++ else if ( _env.brightness < -100 ) ++ _env.brightness = 0; ++ ++ if ( _env.contrast > 100 ) ++ _env.contrast = 100; ++ else if ( _env.contrast < -100 ) ++ _env.contrast = 0; ++ ++ if ( _env.windows_style_sharpening_strength > 100 ) ++ _env.windows_style_sharpening_strength = 100; ++ else if ( _env.windows_style_sharpening_strength < 0 ) ++ _env.windows_style_sharpening_strength = 0; ++ ++ if ( _env.fringe_filter_strength > 100 ) ++ _env.fringe_filter_strength = 100; ++ else if ( _env.fringe_filter_strength < 0 ) ++ _env.fringe_filter_strength = 0; ++ ++ if ( _env.grayscale_filter_strength > 100 ) ++ _env.grayscale_filter_strength = 100; ++ else if ( _env.grayscale_filter_strength < 0 ) ++ _env.grayscale_filter_strength = 0; ++ ++ if ( _env.autohint_horizontal_stem_darken_strength > 100 ) ++ _env.autohint_horizontal_stem_darken_strength = 100; ++ else if ( _env.autohint_horizontal_stem_darken_strength < 0 ) ++ _env.autohint_horizontal_stem_darken_strength = 0; ++ ++ if ( _env.autohint_vertical_stem_darken_strength > 100 ) ++ _env.autohint_vertical_stem_darken_strength = 100; ++ else if ( _env.autohint_horizontal_stem_darken_strength < 0 ) ++ _env.autohint_vertical_stem_darken_strength = 0; ++ ++ if ( _env.global_embolden_x_value > 128 ) ++ _env.global_embolden_x_value = 128; ++ else if ( _env.global_embolden_x_value < -128 ) ++ _env.global_embolden_x_value = -128; ++ ++ if ( _env.global_embolden_y_value > 128 ) ++ _env.global_embolden_y_value = 128; ++ else if ( _env.global_embolden_y_value < -128 ) ++ _env.global_embolden_y_value = -128; ++ ++ if ( _env.bold_embolden_x_value > 128 ) ++ _env.bold_embolden_x_value = 128; ++ else if (_env.bold_embolden_x_value < -128 ) ++ _env.bold_embolden_x_value = -128; ++ ++ if ( _env.bold_embolden_y_value > 128 ) ++ _env.bold_embolden_y_value = 128; ++ else if ( _env.bold_embolden_y_value < -128 ) ++ _env.bold_embolden_y_value = -128; ++ ++ /* point to the combined and checked settings */ ++ ftinf=&_env; ++} +diff --git a/src/base/ftinf.h b/src/base/ftinf.h +new file mode 100644 +index 000000000..fbe1bd19d +--- /dev/null ++++ b/src/base/ftinf.h +@@ -0,0 +1,66 @@ ++#ifndef _FTINF_H_ ++#define _FTINF_H_ ++/* ++ Stem snapping rules ++ (base freetype typedefs assumed already included) ++ */ ++typedef struct ++{ ++ FT_Int stem_width; ++ FT_Int stem_spacing; ++ FT_Int stem_start; ++ FT_Int stem_scaling; ++ FT_Int stem_translating_only; ++ FT_Int stem_translating; ++ float brightness; ++ float contrast; ++ FT_Bool use_100; ++ FT_Bool synth_stems; ++ FT_Bool edge_detection; ++ FT_Bool bearing_correction; ++ FT_Int m; ++} Stem_Data; ++ ++/* ++ Infinality settings ++ */ ++typedef struct ftinf_s { ++ const char *name; ++ int autohint_horizontal_stem_darken_strength; ++ int autohint_snap_stem_height; ++ int autohint_increase_glyph_heights; ++ int autohint_vertical_stem_darken_strength; ++ int bold_embolden_x_value; ++ int bold_embolden_y_value; ++ int brightness; ++ int chromeos_style_sharpening_strength; ++ int contrast; ++ int filter_params[6]; /* 1st one used as existence flag */ ++ int fringe_filter_strength; ++ float gamma_correction[2]; ++ int global_embolden_x_value; ++ int global_embolden_y_value; ++ int grayscale_filter_strength; ++ int stem_alignment_strength; ++ int stem_darkening_autofit; ++ int stem_darkening_cff; ++ int stem_fitting_strength; ++ int stem_snapping_sliding_scale; ++ int use_known_settings_on_selected_fonts; ++ int use_various_tweaks; ++ int windows_style_sharpening_strength; ++} ftinf_t; ++ ++extern FT_Pos infinality_cur_width; /* defined in aflatin.c */ ++ ++extern const ftinf_t *ftinf; /* active settings */ ++ ++extern void ftinf_fill_stem_values( Stem_Data *stem_values, ++ const char *family, int ppem, int use_known ); ++extern void ftinf_get_bc( const char *family, int ppem, ++ float *brightness, float *contrast ); ++ ++/* get values from environment (FIXME: maybe update with using user files) */ ++extern void ftinf_env(); ++ ++#endif +diff --git a/src/base/ftinf_rh.c b/src/base/ftinf_rh.c +new file mode 100644 +index 000000000..606b5671a +--- /dev/null ++++ b/src/base/ftinf_rh.c +@@ -0,0 +1,626 @@ ++/* ANSI-C code produced by gperf version 3.1 */ ++/* Command-line: gperf --output-file=ftinf_rh.c ftinf_rh.gperf */ ++/* Computed positions: -k'1,$' */ ++ ++#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ ++ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ ++ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ ++ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ ++ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ ++ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ ++ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ ++ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ ++ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ ++ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ ++ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ ++ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ ++ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ ++ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ ++ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ ++ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ ++ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ ++ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ ++ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ ++ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ ++ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ ++ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ ++ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) ++/* The character set is not based on ISO-646. */ ++#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>." ++#endif ++ ++#line 9 "ftinf_rh.gperf" ++ ++#include <ctype.h> ++static const struct sa_rules_s* _rules_get( const char*str, unsigned len ); ++/* maximum key range = 82, duplicates = 0 */ ++ ++#ifdef __GNUC__ ++__inline ++#else ++#ifdef __cplusplus ++inline ++#endif ++#endif ++static unsigned int ++_rules_hash (register const char *str, register unsigned int len) ++{ ++ static const unsigned char asso_values[] = ++ { ++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 0, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 85, 85, 5, 45, 5, ++ 35, 25, 35, 35, 50, 45, 85, 85, 0, 25, ++ 40, 5, 0, 85, 50, 20, 20, 0, 10, 10, ++ 85, 10, 85, 85, 85, 85, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, ++ 85, 85, 85, 85, 85, 85 ++ }; ++ return len + asso_values[(unsigned char)str[len - 1]] + asso_values[(unsigned char)str[0]]; ++} ++ ++#ifdef __GNUC__ ++__inline ++#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__ ++__attribute__ ((__gnu_inline__)) ++#endif ++#endif ++const struct sa_rules_s * ++_rules_get (register const char *str, register unsigned int len) ++{ ++ enum ++ { ++ TOTAL_KEYWORDS = 58, ++ MIN_WORD_LENGTH = 3, ++ MAX_WORD_LENGTH = 24, ++ MIN_HASH_VALUE = 3, ++ MAX_HASH_VALUE = 84 ++ }; ++ ++ static const struct sa_rules_s wordlist[] = ++ { ++#line 15 "ftinf_rh.gperf" ++{ .name="---", ++ .synthesize_stems={on, 13, 13, end} ++}, ++#line 253 "ftinf_rh.gperf" ++{ .name="ubuntu", ++ .always_use_100={on, 12, 13, 15, 15, end} ++}, ++#line 31 "ftinf_rh.gperf" ++{ .name="arial", ++ .always_use_100={on, 0, maxp, end}, ++ .edge_detection={on, 11, 11, 13, 13, end}, ++ .spacing={on, 10, 11, 23, 25, 30, end}, ++ .start={on, 11, 18, 23, 30, 30, end}, ++ .stem_translating={on, 11, 32, end}, ++ .stem_translating_only={on, 10, 16, 8, 32, 9, 32, 16, -24, end} ++}, ++#line 87 "ftinf_rh.gperf" ++{ .name="corbel", ++ .stem_translating_only={on, 10, 16, end}, ++ .stem_widths={on, 10, 21, maxp} ++}, ++#line 71 "ftinf_rh.gperf" ++{ .name="canwell", ++ .stem_scaling={on, 13, 0, end} ++}, ++#line 216 "ftinf_rh.gperf" ++{ .name="pragmata", ++ .always_use_100={on, 0, maxp, end} ++}, ++#line 67 "ftinf_rh.gperf" ++{ .name="cantarell", ++ .stem_translating_only={on, 11, 0, 12, 0, end}, ++ .stem_widths={on, 10, 22, maxp,} ++}, ++#line 39 "ftinf_rh.gperf" ++{ .name="arimo", ++ .always_use_100={on, 0, maxp, end}, ++ .stem_translating={on, 11, 32, end}, ++ .stem_translating_only={on, 10, 8, 8, 32, 9, 32, end} ++}, ++#line 207 "ftinf_rh.gperf" ++{ .name="optima", ++ .brightness={on, 0, -20, end}, ++ .contrast={on, 0, 25, end}, ++ .stem_scaling={on, 17, 1, end}, ++ .stem_translating_only={on, 10, 0, 11, 0, 12, 0, end} ++}, ++#line 63 "ftinf_rh.gperf" ++{ .name="candara", ++ .stem_scaling={on, 14, 1, 17, 1, end}, ++ .stem_translating_only={on, 10, 16, end} ++}, ++#line 77 "ftinf_rh.gperf" ++{ .name="comfortaa", ++ .stem_widths={on, 10, 19, 22, maxp}, ++ .stem_scaling={on, 11, 0, end} ++}, ++#line 161 "ftinf_rh.gperf" ++{ .name="liberation mono", ++ .always_use_100={on, 0, maxp, end} ++}, ++#line 18 "ftinf_rh.gperf" ++{ .name="andale mono", ++ .always_use_100={on, 0, maxp, end}, ++ .stem_scaling={on, 11, 1, end}, ++ .stem_widths={on, 10, 21, maxp,} ++}, ++#line 256 "ftinf_rh.gperf" ++{ .name="verdana", ++ .always_use_100={on, 0, 14, 16, maxp, end}, ++ .stem_scaling={on, 12, 1, 15, 1, end}, ++ .stem_translating_only={on, 8, 16, 15, 16, 14, 32, 18, 32, 19, 24, end} ++}, ++#line 74 "ftinf_rh.gperf" ++{ .name="century gothic", ++ .stem_widths={on, 10, 22, maxp,} ++}, ++#line 91 "ftinf_rh.gperf" ++{ .name="courier new", ++ .always_use_100={on, 12, 12, end}, ++ .edge_detection={on, 10, 12, end}, ++ .m={on, 13, 1, 14, 1, end} ++}, ++#line 23 "ftinf_rh.gperf" ++{ .name="arial narrow", ++ .stem_widths={on, 10, 21, maxp,} ++}, ++#line 185 "ftinf_rh.gperf" ++{ .name="luxi sans", ++ .always_use_100={on, 13, 13, end}, ++ .stem_widths={on, 10, 17, sw2pv, maxp,} ++}, ++#line 225 "ftinf_rh.gperf" ++{ .name="samba", ++ .stem_scaling={on, 11, 0, end} ++}, ++#line 233 "ftinf_rh.gperf" ++{ .name="tahoma", ++ .always_use_100={on, 11, 11, 14, maxp, end}, ++ .edge_detection={on, 11, 11, end}, ++ .spacing={on, 10, 12, 18, 18, 30, end}, ++ .start={on, 14, 17, 30, 100, 100, end}, ++ .stem_translating={on, 11, 32, end}, ++ .stem_translating_only={on, 7, 32, 8, 32, 9, 32, end}, ++}, ++#line 164 "ftinf_rh.gperf" ++{ .name="liberation sans narrow", ++ .stem_widths={on,10, 22, maxp,} ++}, ++#line 81 "ftinf_rh.gperf" ++{ .name="consolas", ++ .always_use_100={on, 0, maxp, end}, ++ .stem_translating_only={on, 8, 32, 9, 32, end}, ++ .stem_widths={on, 10, 20, maxp,}, ++ .stem_scaling={on, 11, 1, end} ++}, ++#line 203 "ftinf_rh.gperf" ++{ .name="open sans", ++ .stem_translating_only={on, 10, 16, 9, 16, end}, ++ .stem_widths={on, 10, 20, maxp,} ++}, ++#line 167 "ftinf_rh.gperf" ++{ .name="liberation sans", ++ .edge_detection={on, 11, 11, end}, ++ .stem_translating={on, 11, 32, end}, ++ .stem_translating_only={on, 10, 8, 8, 32, 9, 32, end}, ++ .stem_widths={on,10, 19, maxp,} ++}, ++#line 193 "ftinf_rh.gperf" ++{ .name="monaco", ++ .always_use_100={on, 0, maxp, end} ++}, ++#line 101 "ftinf_rh.gperf" ++{ .name="cousine", ++ .always_use_100={on, 0, maxp, end} ++}, ++#line 176 "ftinf_rh.gperf" ++{ .name="lucida grande", ++ .stem_scaling={on, 13, 1, end}, ++ .stem_translating_only={on, 13, 24, 14, 24, 8, 16, 9, 16, end}, ++ .stem_widths={on, 10, 16, sw2pv, maxp}, ++}, ++#line 173 "ftinf_rh.gperf" ++{ .name="lucida console", ++ .always_use_100={on, 0, maxp, end} ++}, ++#line 196 "ftinf_rh.gperf" ++{ .name="myriad pro", ++ .stem_scaling={on, 14, 1, 17, 1, end}, ++ .stem_translating_only={on, 10, 16, 11, 0, 9, 16, end} ++}, ++#line 26 "ftinf_rh.gperf" ++{ .name="arial unicode ms", ++ .always_use_100={on, 0, maxp, end}, ++ .stem_translating={on, 11, 32, end}, ++ .stem_translating_only={on, 10, 16, 8, 32, 9, 32, end} ++}, ++#line 213 "ftinf_rh.gperf" ++{ .name="palatino linotype", ++ .edge_detection={on, 0, 100, end} ++}, ++#line 181 "ftinf_rh.gperf" ++{ .name="lucida sans unicode", ++ .stem_translating_only={on, 13, 24, 14, 24, 8, 16, 9, 16, end}, ++ .stem_widths={on,10, 16, sw2pv, maxp,} ++}, ++#line 140 "ftinf_rh.gperf" ++{ .name="futura", ++ .stem_widths={on, 10, 14, sw2pv, maxp,} ++}, ++#line 147 "ftinf_rh.gperf" ++{ .name="georgia", ++ .stem_translating_only={on, 13, 16, 14, 16, 15, 0, end} ++}, ++#line 125 "ftinf_rh.gperf" ++{ .name="freemono", ++ .always_use_100={on, 0, maxp, end} ++}, ++#line 200 "ftinf_rh.gperf" ++{ .name="nina", ++ .stem_scaling={on, 11, 0, 12, 0, 13, 0, end} ++}, ++#line 121 "ftinf_rh.gperf" ++{ .name="essential pragmatapro", ++ .always_use_100={on, 0, maxp, end}, ++ .m={on, 13, 0, 14, 0, end} ++}, ++#line 247 "ftinf_rh.gperf" ++{ .name="trebuchet ms", ++ .always_use_100={on, 13, 13, end}, ++ .stem_scaling={on, 13, 0, 17, 0, 20, 1, end}, ++ .stem_translating_only={on, 10, 16, 11, 0, 8, 32, 9, 32, end}, ++ .stem_widths={on, 10, 17, sw2pv, maxp,} ++}, ++#line 114 "ftinf_rh.gperf" ++{ .name="droid sans mono", ++ .m={on, 12, 0, end} ++}, ++#line 104 "ftinf_rh.gperf" ++{ .name="dejavu sans mono", ++ .always_use_100={on, 0, maxp, end}, ++ .stem_translating_only={on, 7, 16, 8, 32, 9, 16, end} ++}, ++#line 57 "ftinf_rh.gperf" ++{ .name="calibri", ++ .always_use_100={on, 23, maxp, end}, ++ .stem_scaling={on, 15, 1, 17, 1, 18, 1, end}, ++ .stem_translating_only={on, 10, 16, 15, 0, end}, ++ .stem_widths={on, 1, 10, 19, maxp,} ++}, ++#line 156 "ftinf_rh.gperf" ++{ .name="inconsolata", ++ .stem_scaling={on, 12, 1, 15, 1, end}, ++ .stem_translating_only={on, 10, 24, 9, 32, end}, ++ .stem_widths={on, 10, 23, maxp,}, ++}, ++#line 96 "ftinf_rh.gperf" ++{ .name="courier", ++ .always_use_100={on, 0, maxp, end}, ++ .m={on, 13, 1, 14, 1, end}, ++ .stem_translating_only={on, 13, 16, 15, 0, end} ++}, ++#line 128 "ftinf_rh.gperf" ++{ .name="freesans", ++ .always_use_100={on, 0, maxp, end}, ++ .edge_detection={on, 11, 11, 13, 13, end}, ++ .spacing={on, 10, 12, 18, 18, 30, end}, ++ .start={on, 10, 18, 18, 25, 30, end}, ++ .stem_scaling={on, 16, 0, end}, ++ .stem_translating={on, 11, 32, end}, ++ .stem_translating_only={on, 10, 16, 9, 8, end} ++}, ++#line 150 "ftinf_rh.gperf" ++{ .name="gill sans", ++ .stem_widths={on, 10, 17, sw2pv, maxp,} ++}, ++#line 117 "ftinf_rh.gperf" ++{ .name="droid sans", ++ .always_use_100={on, 12, 12, 15, 15, end}, ++ .stem_translating_only={on, 8, 16, 9, 16, end} ++}, ++#line 108 "ftinf_rh.gperf" ++{ .name="dejavu sans", ++ .always_use_100={on, 10, 14, 16, 17, end}, ++ .m={on, 12, 0, end}, ++ .stem_scaling={on, 12, 1, end}, ++ .stem_translating_only={on, 8, 16, 15, -20, end} ++}, ++#line 219 "ftinf_rh.gperf" ++{ .name="raleway", ++ .stem_scaling={on, 15, 0, end} ++}, ++#line 153 "ftinf_rh.gperf" ++{ .name="helvetica cy", ++ .stem_widths={on, 10, 23, maxp,} ++}, ++#line 228 "ftinf_rh.gperf" ++{ .name="segoe ui", ++ .always_use_100={on, 11, 12, 14, 14, end}, ++ .stem_translating_only={on, 10, 0, 7, 32, 8, 16, 9, 24, end}, ++ .stem_widths={on, 10, 23, maxp,} ++}, ++#line 48 "ftinf_rh.gperf" ++{ .name="bitstream vera sans mono", ++ .always_use_100={on, 0, maxp, end} ++}, ++#line 241 "ftinf_rh.gperf" ++{ .name="times new roman", ++ .always_use_100={on, 14, 14, 16, 16, end}, ++ .bearing_correction={0, 100, end}, ++ .stem_scaling={on, 17, 1, end}, ++ .stem_translating_only={on, 17, 8, end} ++}, ++#line 222 "ftinf_rh.gperf" ++{ .name="rokkitt", ++ .stem_widths={on, 10, 21, maxp,} ++}, ++#line 143 "ftinf_rh.gperf" ++{ .name="garamond", ++ .brightness={on, 0, -20, end}, ++ .contrast={on, 0, 25, end} ++}, ++#line 137 "ftinf_rh.gperf" ++{ .name="freeserif", ++ .stem_scaling={on, 13, 1, 17, 1, end} ++}, ++#line 189 "ftinf_rh.gperf" ++{ .name="microsoft sans serif", ++ .always_use_100={on, 0, maxp, end}, ++ .stem_translating_only={on, 10, 16, 8, 32, 9, 32, end} ++}, ++#line 44 "ftinf_rh.gperf" ++{ .name="baskerville", ++ .brightness={on, 0, -20, end}, ++ .contrast={on, 0, 25, end} ++}, ++#line 51 "ftinf_rh.gperf" ++{ .name="bitstream vera sans", ++ .always_use_100={on, 10, 14, 16, 17, end}, ++ .m={on, 12, 0, end}, ++ .stem_scaling={on ,12, 1, end}, ++ .stem_translating_only={on, 8, 16, end} ++} ++ }; ++ ++ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) ++ { ++ register int key = _rules_hash (str, len); ++ ++ if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE) ++ { ++ register const struct sa_rules_s *resword; ++ ++ switch (key - 3) ++ { ++ case 0: ++ resword = &wordlist[0]; ++ goto compare; ++ case 3: ++ resword = &wordlist[1]; ++ goto compare; ++ case 7: ++ resword = &wordlist[2]; ++ goto compare; ++ case 8: ++ resword = &wordlist[3]; ++ goto compare; ++ case 9: ++ resword = &wordlist[4]; ++ goto compare; ++ case 10: ++ resword = &wordlist[5]; ++ goto compare; ++ case 11: ++ resword = &wordlist[6]; ++ goto compare; ++ case 12: ++ resword = &wordlist[7]; ++ goto compare; ++ case 13: ++ resword = &wordlist[8]; ++ goto compare; ++ case 14: ++ resword = &wordlist[9]; ++ goto compare; ++ case 16: ++ resword = &wordlist[10]; ++ goto compare; ++ case 17: ++ resword = &wordlist[11]; ++ goto compare; ++ case 18: ++ resword = &wordlist[12]; ++ goto compare; ++ case 19: ++ resword = &wordlist[13]; ++ goto compare; ++ case 21: ++ resword = &wordlist[14]; ++ goto compare; ++ case 23: ++ resword = &wordlist[15]; ++ goto compare; ++ case 24: ++ resword = &wordlist[16]; ++ goto compare; ++ case 26: ++ resword = &wordlist[17]; ++ goto compare; ++ case 27: ++ resword = &wordlist[18]; ++ goto compare; ++ case 28: ++ resword = &wordlist[19]; ++ goto compare; ++ case 29: ++ resword = &wordlist[20]; ++ goto compare; ++ case 30: ++ resword = &wordlist[21]; ++ goto compare; ++ case 31: ++ resword = &wordlist[22]; ++ goto compare; ++ case 32: ++ resword = &wordlist[23]; ++ goto compare; ++ case 33: ++ resword = &wordlist[24]; ++ goto compare; ++ case 34: ++ resword = &wordlist[25]; ++ goto compare; ++ case 35: ++ resword = &wordlist[26]; ++ goto compare; ++ case 36: ++ resword = &wordlist[27]; ++ goto compare; ++ case 37: ++ resword = &wordlist[28]; ++ goto compare; ++ case 38: ++ resword = &wordlist[29]; ++ goto compare; ++ case 39: ++ resword = &wordlist[30]; ++ goto compare; ++ case 41: ++ resword = &wordlist[31]; ++ goto compare; ++ case 43: ++ resword = &wordlist[32]; ++ goto compare; ++ case 44: ++ resword = &wordlist[33]; ++ goto compare; ++ case 45: ++ resword = &wordlist[34]; ++ goto compare; ++ case 46: ++ resword = &wordlist[35]; ++ goto compare; ++ case 48: ++ resword = &wordlist[36]; ++ goto compare; ++ case 49: ++ resword = &wordlist[37]; ++ goto compare; ++ case 52: ++ resword = &wordlist[38]; ++ goto compare; ++ case 53: ++ resword = &wordlist[39]; ++ goto compare; ++ case 54: ++ resword = &wordlist[40]; ++ goto compare; ++ case 58: ++ resword = &wordlist[41]; ++ goto compare; ++ case 59: ++ resword = &wordlist[42]; ++ goto compare; ++ case 60: ++ resword = &wordlist[43]; ++ goto compare; ++ case 61: ++ resword = &wordlist[44]; ++ goto compare; ++ case 62: ++ resword = &wordlist[45]; ++ goto compare; ++ case 63: ++ resword = &wordlist[46]; ++ goto compare; ++ case 64: ++ resword = &wordlist[47]; ++ goto compare; ++ case 69: ++ resword = &wordlist[48]; ++ goto compare; ++ case 70: ++ resword = &wordlist[49]; ++ goto compare; ++ case 71: ++ resword = &wordlist[50]; ++ goto compare; ++ case 72: ++ resword = &wordlist[51]; ++ goto compare; ++ case 74: ++ resword = &wordlist[52]; ++ goto compare; ++ case 75: ++ resword = &wordlist[53]; ++ goto compare; ++ case 76: ++ resword = &wordlist[54]; ++ goto compare; ++ case 77: ++ resword = &wordlist[55]; ++ goto compare; ++ case 78: ++ resword = &wordlist[56]; ++ goto compare; ++ case 81: ++ resword = &wordlist[57]; ++ goto compare; ++ } ++ return 0; ++ compare: ++ { ++ register const char *s = resword->name; ++ ++ if (*str == *s && !strcmp (str + 1, s + 1)) ++ return resword; ++ } ++ } ++ } ++ return 0; ++} ++#line 261 "ftinf_rh.gperf" ++ ++ ++static const sa_rules_t* ++ftinf_rules( const char *name ){ ++ if( name ){ ++ enum { ++ max_wlen=31 ++ }; ++ char buf[max_wlen+1]; ++ int len=strlen( name ); ++ if( len <= max_wlen ){ ++ int i; ++ for( i=0; i<len; ++i ) ++ buf[i]=tolower( name[i] ); ++ buf[len]='\0'; ++ return _rules_get( buf, len ); ++ } ++ } ++ return NULL; ++} ++/* ++ gperf --output-file=ftinf_rh.c ftinf_rh.gperf ++*/ +diff --git a/src/base/ftinf_rh.gperf b/src/base/ftinf_rh.gperf +new file mode 100644 +index 000000000..9fd8aab95 +--- /dev/null ++++ b/src/base/ftinf_rh.gperf +@@ -0,0 +1,283 @@ ++%struct-type ++%define slot-name name ++%enum ++%switch=1 ++%readonly-tables ++%omit-struct-type ++%define lookup-function-name _rules_get ++%define hash-function-name _rules_hash ++%{ ++#include <ctype.h> ++static const struct sa_rules_s* _rules_get( const char*str, unsigned len ); ++%} ++struct sa_rules_s; ++%% ++{ .name="---", ++ .synthesize_stems={on, 13, 13, end} ++}, ++{ .name="andale mono", ++ .always_use_100={on, 0, maxp, end}, ++ .stem_scaling={on, 11, 1, end}, ++ .stem_widths={on, 10, 21, maxp,} ++}, ++{ .name="arial narrow", ++ .stem_widths={on, 10, 21, maxp,} ++}, ++{ .name="arial unicode ms", ++ .always_use_100={on, 0, maxp, end}, ++ .stem_translating={on, 11, 32, end}, ++ .stem_translating_only={on, 10, 16, 8, 32, 9, 32, end} ++}, ++{ .name="arial", ++ .always_use_100={on, 0, maxp, end}, ++ .edge_detection={on, 11, 11, 13, 13, end}, ++ .spacing={on, 10, 11, 23, 25, 30, end}, ++ .start={on, 11, 18, 23, 30, 30, end}, ++ .stem_translating={on, 11, 32, end}, ++ .stem_translating_only={on, 10, 16, 8, 32, 9, 32, 16, -24, end} ++}, ++{ .name="arimo", ++ .always_use_100={on, 0, maxp, end}, ++ .stem_translating={on, 11, 32, end}, ++ .stem_translating_only={on, 10, 8, 8, 32, 9, 32, end} ++}, ++{ .name="baskerville", ++ .brightness={on, 0, -20, end}, ++ .contrast={on, 0, 25, end} ++}, ++{ .name="bitstream vera sans mono", ++ .always_use_100={on, 0, maxp, end} ++}, ++{ .name="bitstream vera sans", ++ .always_use_100={on, 10, 14, 16, 17, end}, ++ .m={on, 12, 0, end}, ++ .stem_scaling={on ,12, 1, end}, ++ .stem_translating_only={on, 8, 16, end} ++}, ++{ .name="calibri", ++ .always_use_100={on, 23, maxp, end}, ++ .stem_scaling={on, 15, 1, 17, 1, 18, 1, end}, ++ .stem_translating_only={on, 10, 16, 15, 0, end}, ++ .stem_widths={on, 1, 10, 19, maxp,} ++}, ++{ .name="candara", ++ .stem_scaling={on, 14, 1, 17, 1, end}, ++ .stem_translating_only={on, 10, 16, end} ++}, ++{ .name="cantarell", ++ .stem_translating_only={on, 11, 0, 12, 0, end}, ++ .stem_widths={on, 10, 22, maxp,} ++}, ++{ .name="canwell", ++ .stem_scaling={on, 13, 0, end} ++}, ++{ .name="century gothic", ++ .stem_widths={on, 10, 22, maxp,} ++}, ++{ .name="comfortaa", ++ .stem_widths={on, 10, 19, 22, maxp}, ++ .stem_scaling={on, 11, 0, end} ++}, ++{ .name="consolas", ++ .always_use_100={on, 0, maxp, end}, ++ .stem_translating_only={on, 8, 32, 9, 32, end}, ++ .stem_widths={on, 10, 20, maxp,}, ++ .stem_scaling={on, 11, 1, end} ++}, ++{ .name="corbel", ++ .stem_translating_only={on, 10, 16, end}, ++ .stem_widths={on, 10, 21, maxp} ++}, ++{ .name="courier new", ++ .always_use_100={on, 12, 12, end}, ++ .edge_detection={on, 10, 12, end}, ++ .m={on, 13, 1, 14, 1, end} ++}, ++{ .name="courier", ++ .always_use_100={on, 0, maxp, end}, ++ .m={on, 13, 1, 14, 1, end}, ++ .stem_translating_only={on, 13, 16, 15, 0, end} ++}, ++{ .name="cousine", ++ .always_use_100={on, 0, maxp, end} ++}, ++{ .name="dejavu sans mono", ++ .always_use_100={on, 0, maxp, end}, ++ .stem_translating_only={on, 7, 16, 8, 32, 9, 16, end} ++}, ++{ .name="dejavu sans", ++ .always_use_100={on, 10, 14, 16, 17, end}, ++ .m={on, 12, 0, end}, ++ .stem_scaling={on, 12, 1, end}, ++ .stem_translating_only={on, 8, 16, 15, -20, end} ++}, ++{ .name="droid sans mono", ++ .m={on, 12, 0, end} ++}, ++{ .name="droid sans", ++ .always_use_100={on, 12, 12, 15, 15, end}, ++ .stem_translating_only={on, 8, 16, 9, 16, end} ++}, ++{ .name="essential pragmatapro", ++ .always_use_100={on, 0, maxp, end}, ++ .m={on, 13, 0, 14, 0, end} ++}, ++{ .name="freemono", ++ .always_use_100={on, 0, maxp, end} ++}, ++{ .name="freesans", ++ .always_use_100={on, 0, maxp, end}, ++ .edge_detection={on, 11, 11, 13, 13, end}, ++ .spacing={on, 10, 12, 18, 18, 30, end}, ++ .start={on, 10, 18, 18, 25, 30, end}, ++ .stem_scaling={on, 16, 0, end}, ++ .stem_translating={on, 11, 32, end}, ++ .stem_translating_only={on, 10, 16, 9, 8, end} ++}, ++{ .name="freeserif", ++ .stem_scaling={on, 13, 1, 17, 1, end} ++}, ++{ .name="futura", ++ .stem_widths={on, 10, 14, sw2pv, maxp,} ++}, ++{ .name="garamond", ++ .brightness={on, 0, -20, end}, ++ .contrast={on, 0, 25, end} ++}, ++{ .name="georgia", ++ .stem_translating_only={on, 13, 16, 14, 16, 15, 0, end} ++}, ++{ .name="gill sans", ++ .stem_widths={on, 10, 17, sw2pv, maxp,} ++}, ++{ .name="helvetica cy", ++ .stem_widths={on, 10, 23, maxp,} ++}, ++{ .name="inconsolata", ++ .stem_scaling={on, 12, 1, 15, 1, end}, ++ .stem_translating_only={on, 10, 24, 9, 32, end}, ++ .stem_widths={on, 10, 23, maxp,}, ++}, ++{ .name="liberation mono", ++ .always_use_100={on, 0, maxp, end} ++}, ++{ .name="liberation sans narrow", ++ .stem_widths={on,10, 22, maxp,} ++}, ++{ .name="liberation sans", ++ .edge_detection={on, 11, 11, end}, ++ .stem_translating={on, 11, 32, end}, ++ .stem_translating_only={on, 10, 8, 8, 32, 9, 32, end}, ++ .stem_widths={on,10, 19, maxp,} ++}, ++{ .name="lucida console", ++ .always_use_100={on, 0, maxp, end} ++}, ++{ .name="lucida grande", ++ .stem_scaling={on, 13, 1, end}, ++ .stem_translating_only={on, 13, 24, 14, 24, 8, 16, 9, 16, end}, ++ .stem_widths={on, 10, 16, sw2pv, maxp}, ++}, ++{ .name="lucida sans unicode", ++ .stem_translating_only={on, 13, 24, 14, 24, 8, 16, 9, 16, end}, ++ .stem_widths={on,10, 16, sw2pv, maxp,} ++}, ++{ .name="luxi sans", ++ .always_use_100={on, 13, 13, end}, ++ .stem_widths={on, 10, 17, sw2pv, maxp,} ++}, ++{ .name="microsoft sans serif", ++ .always_use_100={on, 0, maxp, end}, ++ .stem_translating_only={on, 10, 16, 8, 32, 9, 32, end} ++}, ++{ .name="monaco", ++ .always_use_100={on, 0, maxp, end} ++}, ++{ .name="myriad pro", ++ .stem_scaling={on, 14, 1, 17, 1, end}, ++ .stem_translating_only={on, 10, 16, 11, 0, 9, 16, end} ++}, ++{ .name="nina", ++ .stem_scaling={on, 11, 0, 12, 0, 13, 0, end} ++}, ++{ .name="open sans", ++ .stem_translating_only={on, 10, 16, 9, 16, end}, ++ .stem_widths={on, 10, 20, maxp,} ++}, ++{ .name="optima", ++ .brightness={on, 0, -20, end}, ++ .contrast={on, 0, 25, end}, ++ .stem_scaling={on, 17, 1, end}, ++ .stem_translating_only={on, 10, 0, 11, 0, 12, 0, end} ++}, ++{ .name="palatino linotype", ++ .edge_detection={on, 0, 100, end} ++}, ++{ .name="pragmata", ++ .always_use_100={on, 0, maxp, end} ++}, ++{ .name="raleway", ++ .stem_scaling={on, 15, 0, end} ++}, ++{ .name="rokkitt", ++ .stem_widths={on, 10, 21, maxp,} ++}, ++{ .name="samba", ++ .stem_scaling={on, 11, 0, end} ++}, ++{ .name="segoe ui", ++ .always_use_100={on, 11, 12, 14, 14, end}, ++ .stem_translating_only={on, 10, 0, 7, 32, 8, 16, 9, 24, end}, ++ .stem_widths={on, 10, 23, maxp,} ++}, ++{ .name="tahoma", ++ .always_use_100={on, 11, 11, 14, maxp, end}, ++ .edge_detection={on, 11, 11, end}, ++ .spacing={on, 10, 12, 18, 18, 30, end}, ++ .start={on, 14, 17, 30, 100, 100, end}, ++ .stem_translating={on, 11, 32, end}, ++ .stem_translating_only={on, 7, 32, 8, 32, 9, 32, end}, ++}, ++{ .name="times new roman", ++ .always_use_100={on, 14, 14, 16, 16, end}, ++ .bearing_correction={0, 100, end}, ++ .stem_scaling={on, 17, 1, end}, ++ .stem_translating_only={on, 17, 8, end} ++}, ++{ .name="trebuchet ms", ++ .always_use_100={on, 13, 13, end}, ++ .stem_scaling={on, 13, 0, 17, 0, 20, 1, end}, ++ .stem_translating_only={on, 10, 16, 11, 0, 8, 32, 9, 32, end}, ++ .stem_widths={on, 10, 17, sw2pv, maxp,} ++}, ++{ .name="ubuntu", ++ .always_use_100={on, 12, 13, 15, 15, end} ++}, ++{ .name="verdana", ++ .always_use_100={on, 0, 14, 16, maxp, end}, ++ .stem_scaling={on, 12, 1, 15, 1, end}, ++ .stem_translating_only={on, 8, 16, 15, 16, 14, 32, 18, 32, 19, 24, end} ++}, ++%% ++ ++static const sa_rules_t* ++ftinf_rules( const char *name ){ ++ if( name ){ ++ enum { ++ max_wlen=31 ++ }; ++ char buf[max_wlen+1]; ++ int len=strlen( name ); ++ if( len <= max_wlen ){ ++ int i; ++ for( i=0; i<len; ++i ) ++ buf[i]=tolower( name[i] ); ++ buf[len]='\0'; ++ return _rules_get( buf, len ); ++ } ++ } ++ return NULL; ++} ++/* ++ gperf --output-file=ftinf_rh.c ftinf_rh.gperf ++*/ +diff --git a/src/base/ftinf_sh.c b/src/base/ftinf_sh.c +new file mode 100644 +index 000000000..87d2ff8bd +--- /dev/null ++++ b/src/base/ftinf_sh.c +@@ -0,0 +1,463 @@ ++/* ANSI-C code produced by gperf version 3.1 */ ++/* Command-line: gperf --output-file=ftinf_sh.c ftinf_sh.gperf */ ++/* Computed positions: -k'1,$' */ ++ ++#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ ++ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ ++ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ ++ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ ++ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ ++ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ ++ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ ++ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ ++ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ ++ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ ++ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ ++ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ ++ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ ++ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ ++ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ ++ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ ++ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ ++ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ ++ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ ++ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ ++ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ ++ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ ++ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) ++/* The character set is not based on ISO-646. */ ++#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>." ++#endif ++ ++#line 9 "ftinf_sh.gperf" ++ ++#include <ctype.h> ++static const struct ftinf_s* _settings_get( const char*str, unsigned len); ++/* maximum key range = 37, duplicates = 0 */ ++ ++#ifdef __GNUC__ ++__inline ++#else ++#ifdef __cplusplus ++inline ++#endif ++#endif ++static unsigned int ++_settings_hash (register const char *str, register unsigned int len) ++{ ++ static const unsigned char asso_values[] = ++ { ++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, ++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, ++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, ++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, ++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 13, ++ 8, 30, 25, 20, 40, 10, 40, 40, 40, 40, ++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, ++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, ++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, ++ 40, 40, 40, 40, 40, 40, 40, 5, 40, 0, ++ 0, 0, 40, 40, 10, 0, 40, 40, 15, 5, ++ 10, 0, 10, 40, 40, 0, 0, 0, 0, 0, ++ 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, ++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, ++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, ++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, ++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, ++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, ++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, ++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, ++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, ++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, ++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, ++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, ++ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, ++ 40, 40, 40, 40, 40, 40 ++ }; ++ return len + asso_values[(unsigned char)str[len - 1]] + asso_values[(unsigned char)str[0]]; ++} ++ ++#ifdef __GNUC__ ++__inline ++#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__ ++__attribute__ ((__gnu_inline__)) ++#endif ++#endif ++const struct ftinf_s * ++_settings_get (register const char *str, register unsigned int len) ++{ ++ enum ++ { ++ TOTAL_KEYWORDS = 22, ++ MIN_WORD_LENGTH = 3, ++ MAX_WORD_LENGTH = 14, ++ MIN_HASH_VALUE = 3, ++ MAX_HASH_VALUE = 39 ++ }; ++ ++ static const struct ftinf_s wordlist[] = ++ { ++#line 76 "ftinf_sh.gperf" ++{ .name="osx", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_vertical_stem_darken_strength=25, ++ .bold_embolden_x_value=16, ++ .brightness=10, ++ .contrast=20, ++ .filter_params={on, 3, 32, 38, 32, 3}, ++ .gamma_correction={1000, 80}, ++ .global_embolden_y_value=8, ++ .grayscale_filter_strength=25, ++}, ++#line 37 "ftinf_sh.gperf" ++{ .name="ipad", ++ .filter_params={on, 0, 0, 100, 0, 0}, ++ .gamma_correction={1000, 80}, ++ .grayscale_filter_strength=100 ++}, ++#line 114 "ftinf_sh.gperf" ++{ .name="shove", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_increase_glyph_heights=true, ++ .autohint_snap_stem_height=100, ++ .autohint_vertical_stem_darken_strength=25, ++ .filter_params={on, 11, 22, 38, 22, 11}, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=100, ++ .stem_fitting_strength=100, ++ .use_known_settings_on_selected_fonts=true, ++ .use_various_tweaks=true ++}, ++#line 126 "ftinf_sh.gperf" ++{ .name="ubuntu", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_vertical_stem_darken_strength=25, ++ .brightness=-10, ++ .contrast=15, ++ .filter_params={on, 11, 22, 38, 22, 11}, ++ .gamma_correction={1000, 80}, ++ .use_various_tweaks=true ++}, ++#line 27 "ftinf_sh.gperf" ++{ .name="classic", ++ .autohint_increase_glyph_heights=true, ++ .autohint_snap_stem_height=100, ++ .filter_params={on, 6, 25, 38, 25, 6}, ++ .gamma_correction={0, 100}, ++ .use_various_tweaks=true ++}, ++#line 34 "ftinf_sh.gperf" ++{ .name="disabled", ++ .gamma_correction={0, 100}, ++}, ++#line 100 "ftinf_sh.gperf" ++{ .name="sharpened", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_increase_glyph_heights=true, ++ .autohint_snap_stem_height=100, ++ .autohint_vertical_stem_darken_strength=25, ++ .filter_params={on, 11, 22, 38, 22, 11}, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=25, ++ .stem_fitting_strength=25, ++ .stem_snapping_sliding_scale=40, ++ .use_known_settings_on_selected_fonts=true, ++ .use_various_tweaks=true, ++ .windows_style_sharpening_strength=65 ++}, ++#line 42 "ftinf_sh.gperf" ++{ .name="infinality", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_increase_glyph_heights=true, ++ .autohint_snap_stem_height=100, ++ .autohint_vertical_stem_darken_strength=25, ++ .filter_params={on, 11, 22, 38, 22, 11}, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=25, ++ .stem_fitting_strength=25, ++ .stem_snapping_sliding_scale=40, ++ .use_known_settings_on_selected_fonts=true, ++ .use_various_tweaks=true, ++ .windows_style_sharpening_strength=5 ++}, ++#line 15 "ftinf_sh.gperf" ++{ .name="custom", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_snap_stem_height=100, ++ .autohint_vertical_stem_darken_strength=25, ++ .filter_params={on, 8, 24, 48, 24, 8}, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=75, ++ .stem_fitting_strength=50, ++ .stem_snapping_sliding_scale=30, ++ .use_known_settings_on_selected_fonts=true, ++ .use_various_tweaks=true ++}, ++#line 180 "ftinf_sh.gperf" ++{ .name="vanilla", ++ .filter_params={on, 6, 25, 38, 25, 6}, ++ .gamma_correction={0, 100}, ++}, ++#line 184 "ftinf_sh.gperf" ++{ .name="windows7light", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_snap_stem_height=100, ++ .autohint_vertical_stem_darken_strength=25, ++ .contrast=20, ++ .filter_params={on, 20, 25, 38, 25, 05}, ++ .fringe_filter_strength=100, ++ .gamma_correction={1000, 160}, ++ .stem_snapping_sliding_scale=30, ++ .use_known_settings_on_selected_fonts=true, ++ .use_various_tweaks=true, ++ .windows_style_sharpening_strength=100 ++}, ++#line 226 "ftinf_sh.gperf" ++{ .name="windowsxplight", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_snap_stem_height=100, ++ .autohint_vertical_stem_darken_strength=25, ++ .brightness=20, ++ .contrast=30, ++ .filter_params={on, 6, 25, 44, 25, 6}, ++ .fringe_filter_strength=100, ++ .gamma_correction={1000, 120}, ++ .stem_alignment_strength=15, ++ .stem_fitting_strength=15, ++ .stem_snapping_sliding_scale=30, ++ .use_known_settings_on_selected_fonts=true, ++ .use_various_tweaks=true, ++ .windows_style_sharpening_strength=65 ++}, ++#line 64 "ftinf_sh.gperf" ++{ .name="nudge", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_increase_glyph_heights=true, ++ .autohint_snap_stem_height=100, ++ .autohint_vertical_stem_darken_strength=25, ++ .filter_params={on, 11, 22, 38, 22, 11}, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=25, ++ .stem_fitting_strength=15, ++ .stem_snapping_sliding_scale=30, ++ .use_various_tweaks=true, ++}, ++#line 144 "ftinf_sh.gperf" ++{ .name="ultimate2", ++ .filter_params={on, 6, 22, 36, 22, 6}, ++ .fringe_filter_strength=25, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=15, ++ .stem_fitting_strength=15, ++ .use_various_tweaks=true, ++ .windows_style_sharpening_strength=25 ++}, ++#line 197 "ftinf_sh.gperf" ++{ .name="windows7", ++ .filter_params={on, 20, 25, 42, 25, 06}, ++ .fringe_filter_strength=100, ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_vertical_stem_darken_strength=25, ++ .windows_style_sharpening_strength=65, ++ .gamma_correction={1000, 120}, ++ .brightness=10, ++ .contrast=20, ++ .use_various_tweaks=true, ++ .autohint_snap_stem_height=100, ++ .use_known_settings_on_selected_fonts=true, ++}, ++#line 210 "ftinf_sh.gperf" ++{ .name="windowsxp", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_snap_stem_height=100, ++ .autohint_vertical_stem_darken_strength=25, ++ .brightness=10, ++ .contrast=20, ++ .filter_params={on, 6, 25, 44, 25, 6}, ++ .fringe_filter_strength=100, ++ .gamma_correction={1000, 120}, ++ .stem_alignment_strength=15, ++ .stem_fitting_strength=15, ++ .stem_snapping_sliding_scale=30, ++ .use_known_settings_on_selected_fonts=true, ++ .use_various_tweaks=true, ++ .windows_style_sharpening_strength=65 ++}, ++#line 56 "ftinf_sh.gperf" ++{ .name="linux", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_snap_stem_height=100, ++ .autohint_vertical_stem_darken_strength=25, ++ .filter_params={on, 6, 25, 44, 25, 6}, ++ .gamma_correction={0, 100}, ++ .use_various_tweaks=true ++}, ++#line 135 "ftinf_sh.gperf" ++{ .name="ultimate1", ++ .filter_params={on, 4, 22, 38, 22, 4}, ++ .fringe_filter_strength=25, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=15, ++ .stem_fitting_strength=15, ++ .use_various_tweaks=true, ++ .windows_style_sharpening_strength=25 ++}, ++#line 87 "ftinf_sh.gperf" ++{ .name="push", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_increase_glyph_heights=true, ++ .autohint_snap_stem_height=100, ++ .autohint_vertical_stem_darken_strength=25, ++ .filter_params={on, 11, 22, 38, 22, 11}, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=75, ++ .stem_fitting_strength=50, ++ .stem_snapping_sliding_scale=30, ++ .use_known_settings_on_selected_fonts=true, ++ .use_various_tweaks=true ++}, ++#line 171 "ftinf_sh.gperf" ++{ .name="ultimate5", ++ .filter_params={on, 12, 28, 42, 28, 12}, ++ .fringe_filter_strength=25, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=15, ++ .stem_fitting_strength=15, ++ .use_various_tweaks=true, ++ .windows_style_sharpening_strength=25 ++}, ++#line 162 "ftinf_sh.gperf" ++{ .name="ultimate4", ++ .filter_params={on, 10, 25, 37, 25, 10}, ++ .fringe_filter_strength=25, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=15, ++ .stem_fitting_strength=15, ++ .use_various_tweaks=true, ++ .windows_style_sharpening_strength=25 ++}, ++#line 153 "ftinf_sh.gperf" ++{ .name="ultimate3", ++ .filter_params={on, 8, 24, 36, 24, 8}, ++ .fringe_filter_strength=25, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=15, ++ .stem_fitting_strength=15, ++ .use_various_tweaks=true, ++ .windows_style_sharpening_strength=25 ++} ++ }; ++ ++ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) ++ { ++ register int key = _settings_hash (str, len); ++ ++ if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE) ++ { ++ register const struct ftinf_s *resword; ++ ++ switch (key - 3) ++ { ++ case 0: ++ resword = &wordlist[0]; ++ goto compare; ++ case 1: ++ resword = &wordlist[1]; ++ goto compare; ++ case 2: ++ resword = &wordlist[2]; ++ goto compare; ++ case 3: ++ resword = &wordlist[3]; ++ goto compare; ++ case 4: ++ resword = &wordlist[4]; ++ goto compare; ++ case 5: ++ resword = &wordlist[5]; ++ goto compare; ++ case 6: ++ resword = &wordlist[6]; ++ goto compare; ++ case 7: ++ resword = &wordlist[7]; ++ goto compare; ++ case 8: ++ resword = &wordlist[8]; ++ goto compare; ++ case 9: ++ resword = &wordlist[9]; ++ goto compare; ++ case 10: ++ resword = &wordlist[10]; ++ goto compare; ++ case 11: ++ resword = &wordlist[11]; ++ goto compare; ++ case 12: ++ resword = &wordlist[12]; ++ goto compare; ++ case 14: ++ resword = &wordlist[13]; ++ goto compare; ++ case 15: ++ resword = &wordlist[14]; ++ goto compare; ++ case 16: ++ resword = &wordlist[15]; ++ goto compare; ++ case 17: ++ resword = &wordlist[16]; ++ goto compare; ++ case 19: ++ resword = &wordlist[17]; ++ goto compare; ++ case 21: ++ resword = &wordlist[18]; ++ goto compare; ++ case 26: ++ resword = &wordlist[19]; ++ goto compare; ++ case 31: ++ resword = &wordlist[20]; ++ goto compare; ++ case 36: ++ resword = &wordlist[21]; ++ goto compare; ++ } ++ return 0; ++ compare: ++ { ++ register const char *s = resword->name; ++ ++ if (*str == *s && !strcmp (str + 1, s + 1)) ++ return resword; ++ } ++ } ++ } ++ return 0; ++} ++#line 242 "ftinf_sh.gperf" ++ ++ ++static const ftinf_t* ++ftinf_settings( const char *name ){ ++ if( name ){ ++ enum { ++ max_wlen=31 ++ }; ++ char buf[max_wlen+1]; ++ int len=strlen( name ); ++ if( len <= max_wlen ){ ++ int i; ++ for( i=0; i<len; ++i ) ++ buf[i]=tolower( name[i] ); ++ buf[len]='\0'; ++ return _settings_get( buf, len ); ++ } ++ } ++ return NULL; ++} ++/* ++ gperf --output-file=ftinf_sh.c ftinf_sh.gperf ++*/ +diff --git a/src/base/ftinf_sh.gperf b/src/base/ftinf_sh.gperf +new file mode 100644 +index 000000000..5f6e0ae62 +--- /dev/null ++++ b/src/base/ftinf_sh.gperf +@@ -0,0 +1,264 @@ ++%struct-type ++%define slot-name name ++%enum ++%switch=1 ++%readonly-tables ++%omit-struct-type ++%define lookup-function-name _settings_get ++%define hash-function-name _settings_hash ++%{ ++#include <ctype.h> ++static const struct ftinf_s* _settings_get( const char*str, unsigned len); ++%} ++struct ftinf_s; ++%% ++{ .name="custom", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_snap_stem_height=100, ++ .autohint_vertical_stem_darken_strength=25, ++ .filter_params={on, 8, 24, 48, 24, 8}, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=75, ++ .stem_fitting_strength=50, ++ .stem_snapping_sliding_scale=30, ++ .use_known_settings_on_selected_fonts=true, ++ .use_various_tweaks=true ++}, ++{ .name="classic", ++ .autohint_increase_glyph_heights=true, ++ .autohint_snap_stem_height=100, ++ .filter_params={on, 6, 25, 38, 25, 6}, ++ .gamma_correction={0, 100}, ++ .use_various_tweaks=true ++}, ++{ .name="disabled", ++ .gamma_correction={0, 100}, ++}, ++{ .name="ipad", ++ .filter_params={on, 0, 0, 100, 0, 0}, ++ .gamma_correction={1000, 80}, ++ .grayscale_filter_strength=100 ++}, ++{ .name="infinality", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_increase_glyph_heights=true, ++ .autohint_snap_stem_height=100, ++ .autohint_vertical_stem_darken_strength=25, ++ .filter_params={on, 11, 22, 38, 22, 11}, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=25, ++ .stem_fitting_strength=25, ++ .stem_snapping_sliding_scale=40, ++ .use_known_settings_on_selected_fonts=true, ++ .use_various_tweaks=true, ++ .windows_style_sharpening_strength=5 ++}, ++{ .name="linux", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_snap_stem_height=100, ++ .autohint_vertical_stem_darken_strength=25, ++ .filter_params={on, 6, 25, 44, 25, 6}, ++ .gamma_correction={0, 100}, ++ .use_various_tweaks=true ++}, ++{ .name="nudge", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_increase_glyph_heights=true, ++ .autohint_snap_stem_height=100, ++ .autohint_vertical_stem_darken_strength=25, ++ .filter_params={on, 11, 22, 38, 22, 11}, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=25, ++ .stem_fitting_strength=15, ++ .stem_snapping_sliding_scale=30, ++ .use_various_tweaks=true, ++}, ++{ .name="osx", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_vertical_stem_darken_strength=25, ++ .bold_embolden_x_value=16, ++ .brightness=10, ++ .contrast=20, ++ .filter_params={on, 3, 32, 38, 32, 3}, ++ .gamma_correction={1000, 80}, ++ .global_embolden_y_value=8, ++ .grayscale_filter_strength=25, ++}, ++{ .name="push", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_increase_glyph_heights=true, ++ .autohint_snap_stem_height=100, ++ .autohint_vertical_stem_darken_strength=25, ++ .filter_params={on, 11, 22, 38, 22, 11}, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=75, ++ .stem_fitting_strength=50, ++ .stem_snapping_sliding_scale=30, ++ .use_known_settings_on_selected_fonts=true, ++ .use_various_tweaks=true ++}, ++{ .name="sharpened", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_increase_glyph_heights=true, ++ .autohint_snap_stem_height=100, ++ .autohint_vertical_stem_darken_strength=25, ++ .filter_params={on, 11, 22, 38, 22, 11}, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=25, ++ .stem_fitting_strength=25, ++ .stem_snapping_sliding_scale=40, ++ .use_known_settings_on_selected_fonts=true, ++ .use_various_tweaks=true, ++ .windows_style_sharpening_strength=65 ++}, ++{ .name="shove", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_increase_glyph_heights=true, ++ .autohint_snap_stem_height=100, ++ .autohint_vertical_stem_darken_strength=25, ++ .filter_params={on, 11, 22, 38, 22, 11}, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=100, ++ .stem_fitting_strength=100, ++ .use_known_settings_on_selected_fonts=true, ++ .use_various_tweaks=true ++}, ++{ .name="ubuntu", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_vertical_stem_darken_strength=25, ++ .brightness=-10, ++ .contrast=15, ++ .filter_params={on, 11, 22, 38, 22, 11}, ++ .gamma_correction={1000, 80}, ++ .use_various_tweaks=true ++}, ++{ .name="ultimate1", ++ .filter_params={on, 4, 22, 38, 22, 4}, ++ .fringe_filter_strength=25, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=15, ++ .stem_fitting_strength=15, ++ .use_various_tweaks=true, ++ .windows_style_sharpening_strength=25 ++}, ++{ .name="ultimate2", ++ .filter_params={on, 6, 22, 36, 22, 6}, ++ .fringe_filter_strength=25, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=15, ++ .stem_fitting_strength=15, ++ .use_various_tweaks=true, ++ .windows_style_sharpening_strength=25 ++}, ++{ .name="ultimate3", ++ .filter_params={on, 8, 24, 36, 24, 8}, ++ .fringe_filter_strength=25, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=15, ++ .stem_fitting_strength=15, ++ .use_various_tweaks=true, ++ .windows_style_sharpening_strength=25 ++}, ++{ .name="ultimate4", ++ .filter_params={on, 10, 25, 37, 25, 10}, ++ .fringe_filter_strength=25, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=15, ++ .stem_fitting_strength=15, ++ .use_various_tweaks=true, ++ .windows_style_sharpening_strength=25 ++}, ++{ .name="ultimate5", ++ .filter_params={on, 12, 28, 42, 28, 12}, ++ .fringe_filter_strength=25, ++ .gamma_correction={0, 100}, ++ .stem_alignment_strength=15, ++ .stem_fitting_strength=15, ++ .use_various_tweaks=true, ++ .windows_style_sharpening_strength=25 ++}, ++{ .name="vanilla", ++ .filter_params={on, 6, 25, 38, 25, 6}, ++ .gamma_correction={0, 100}, ++}, ++{ .name="windows7light", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_snap_stem_height=100, ++ .autohint_vertical_stem_darken_strength=25, ++ .contrast=20, ++ .filter_params={on, 20, 25, 38, 25, 05}, ++ .fringe_filter_strength=100, ++ .gamma_correction={1000, 160}, ++ .stem_snapping_sliding_scale=30, ++ .use_known_settings_on_selected_fonts=true, ++ .use_various_tweaks=true, ++ .windows_style_sharpening_strength=100 ++}, ++{ .name="windows7", ++ .filter_params={on, 20, 25, 42, 25, 06}, ++ .fringe_filter_strength=100, ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_vertical_stem_darken_strength=25, ++ .windows_style_sharpening_strength=65, ++ .gamma_correction={1000, 120}, ++ .brightness=10, ++ .contrast=20, ++ .use_various_tweaks=true, ++ .autohint_snap_stem_height=100, ++ .use_known_settings_on_selected_fonts=true, ++}, ++{ .name="windowsxp", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_snap_stem_height=100, ++ .autohint_vertical_stem_darken_strength=25, ++ .brightness=10, ++ .contrast=20, ++ .filter_params={on, 6, 25, 44, 25, 6}, ++ .fringe_filter_strength=100, ++ .gamma_correction={1000, 120}, ++ .stem_alignment_strength=15, ++ .stem_fitting_strength=15, ++ .stem_snapping_sliding_scale=30, ++ .use_known_settings_on_selected_fonts=true, ++ .use_various_tweaks=true, ++ .windows_style_sharpening_strength=65 ++}, ++{ .name="windowsxplight", ++ .autohint_horizontal_stem_darken_strength=10, ++ .autohint_snap_stem_height=100, ++ .autohint_vertical_stem_darken_strength=25, ++ .brightness=20, ++ .contrast=30, ++ .filter_params={on, 6, 25, 44, 25, 6}, ++ .fringe_filter_strength=100, ++ .gamma_correction={1000, 120}, ++ .stem_alignment_strength=15, ++ .stem_fitting_strength=15, ++ .stem_snapping_sliding_scale=30, ++ .use_known_settings_on_selected_fonts=true, ++ .use_various_tweaks=true, ++ .windows_style_sharpening_strength=65 ++}, ++%% ++ ++static const ftinf_t* ++ftinf_settings( const char *name ){ ++ if( name ){ ++ enum { ++ max_wlen=31 ++ }; ++ char buf[max_wlen+1]; ++ int len=strlen( name ); ++ if( len <= max_wlen ){ ++ int i; ++ for( i=0; i<len; ++i ) ++ buf[i]=tolower( name[i] ); ++ buf[len]='\0'; ++ return _settings_get( buf, len ); ++ } ++ } ++ return NULL; ++} ++/* ++ gperf --output-file=ftinf_sh.c ftinf_sh.gperf ++*/ +diff --git a/src/base/ftinit.c b/src/base/ftinit.c +index c73cd78b8..7f07928c0 100644 +--- a/src/base/ftinit.c ++++ b/src/base/ftinit.c +@@ -43,6 +43,10 @@ + #include FT_INTERNAL_DEBUG_H + #include FT_MODULE_H + ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++#include "ftinf.h" ++#endif ++ + + /************************************************************************** + * +@@ -220,10 +224,14 @@ + error = FT_New_Library( memory, alibrary ); + if ( error ) + FT_Done_Memory( memory ); +- else ++ else { + FT_Add_Default_Modules( *alibrary ); +- +- FT_Set_Default_Properties( *alibrary ); ++ FT_Set_Default_Properties( *alibrary ); ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ /* get Infinality settings */ ++ ftinf_env(); ++#endif ++ } + + return error; + } +diff --git a/src/base/ftlcdfil.c b/src/base/ftlcdfil.c +index d9f4af429..e03fbc081 100644 +--- a/src/base/ftlcdfil.c ++++ b/src/base/ftlcdfil.c +@@ -22,7 +22,10 @@ + #include FT_LCD_FILTER_H + #include FT_IMAGE_H + #include FT_INTERNAL_OBJECTS_H +- ++#include <math.h> ++#include <string.h> ++#include <strings.h> ++#include "ftinf.h" + + #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING + +@@ -77,13 +80,13 @@ + /* FIR filter used by the default and light filters */ + FT_BASE_DEF( void ) + ft_lcd_filter_fir( FT_Bitmap* bitmap, ++ FT_Render_Mode mode, + FT_LcdFiveTapFilter weights ) + { + FT_UInt width = (FT_UInt)bitmap->width; + FT_UInt height = (FT_UInt)bitmap->rows; + FT_Int pitch = bitmap->pitch; + FT_Byte* origin = bitmap->buffer; +- FT_Byte mode = bitmap->pixel_mode; + + + /* take care of bitmap flow */ +@@ -91,7 +94,7 @@ + origin += pitch * (FT_Int)( height - 1 ); + + /* horizontal in-place FIR filter */ +- if ( mode == FT_PIXEL_MODE_LCD && width >= 2 ) ++ if ( mode == FT_RENDER_MODE_LCD && width >= 2 ) + { + FT_Byte* line = origin; + +@@ -134,7 +137,7 @@ + } + + /* vertical in-place FIR filter */ +- else if ( mode == FT_PIXEL_MODE_LCD_V && height >= 2 ) ++ else if ( mode == FT_RENDER_MODE_LCD_V && height >= 2 ) + { + FT_Byte* column = origin; + +@@ -183,13 +186,13 @@ + /* intra-pixel filter used by the legacy filter */ + static void + _ft_lcd_filter_legacy( FT_Bitmap* bitmap, ++ FT_Render_Mode mode, + FT_Byte* weights ) + { + FT_UInt width = (FT_UInt)bitmap->width; + FT_UInt height = (FT_UInt)bitmap->rows; + FT_Int pitch = bitmap->pitch; + FT_Byte* origin = bitmap->buffer; +- FT_Byte mode = bitmap->pixel_mode; + + static const unsigned int filters[3][3] = + { +@@ -206,7 +209,7 @@ + origin += pitch * (FT_Int)( height - 1 ); + + /* horizontal in-place intra-pixel filter */ +- if ( mode == FT_PIXEL_MODE_LCD && width >= 3 ) ++ if ( mode == FT_RENDER_MODE_LCD && width >= 3 ) + { + FT_Byte* line = origin; + +@@ -243,7 +246,7 @@ + } + } + } +- else if ( mode == FT_PIXEL_MODE_LCD_V && height >= 3 ) ++ else if ( mode == FT_RENDER_MODE_LCD_V && height >= 3 ) + { + FT_Byte* column = origin; + +@@ -299,6 +302,7 @@ + + ft_memcpy( library->lcd_weights, weights, FT_LCD_FILTER_FIVE_TAPS ); + library->lcd_filter_func = ft_lcd_filter_fir; ++ library->lcd_extra = 2; + + return FT_Err_Ok; + } +@@ -310,11 +314,37 @@ + FT_Library_SetLcdFilter( FT_Library library, + FT_LcdFilter filter ) + { +- static const FT_LcdFiveTapFilter default_weights = +- { 0x08, 0x4d, 0x56, 0x4d, 0x08 }; + static const FT_LcdFiveTapFilter light_weights = + { 0x00, 0x55, 0x56, 0x55, 0x00 }; + ++#ifndef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ static const FT_LcdFiveTapFilter default_weights = ++ { 0x08, 0x4d, 0x56, 0x4d, 0x08 }; ++#else ++ FT_LcdFiveTapFilter default_weights; ++ if( ftinf && ftinf->filter_params[0] ) ++ { ++ const int *f=ftinf->filter_params; ++ /* Assume we were given integers [0-100] get them to [0-255] */ ++ int val; /* 2611=2.55*1024 */ ++ val=(f[1]*2611+512)>>10; if( val > 255 ) val=255; ++ default_weights[0] = (FT_Byte) val; ++ val=(f[2]*2611+512)>>10; if( val > 255 ) val=255; ++ default_weights[1] = (FT_Byte) val; ++ val=(f[3]*2611+512)>>10; if( val > 255 ) val=255; ++ default_weights[2] = (FT_Byte) val; ++ val=(f[4]*2611+512)>>10; if( val > 255 ) val=255; ++ default_weights[3] = (FT_Byte) val; ++ val=(f[5]*2611+512)>>10; if( val > 255 ) val=255; ++ default_weights[4] = (FT_Byte) val; ++ } else { ++ default_weights[0]=0x08; ++ default_weights[1]=0x4d; ++ default_weights[2]=0x56; ++ default_weights[3]=0x4d; ++ default_weights[4]=0x08; ++ } ++#endif + + if ( !library ) + return FT_THROW( Invalid_Library_Handle ); +@@ -323,6 +353,7 @@ + { + case FT_LCD_FILTER_NONE: + library->lcd_filter_func = NULL; ++ library->lcd_extra = 0; + break; + + case FT_LCD_FILTER_DEFAULT: +@@ -330,6 +361,7 @@ + default_weights, + FT_LCD_FILTER_FIVE_TAPS ); + library->lcd_filter_func = ft_lcd_filter_fir; ++ library->lcd_extra = 2; + break; + + case FT_LCD_FILTER_LIGHT: +@@ -337,6 +369,7 @@ + light_weights, + FT_LCD_FILTER_FIVE_TAPS ); + library->lcd_filter_func = ft_lcd_filter_fir; ++ library->lcd_extra = 2; + break; + + #ifdef USE_LEGACY +@@ -344,6 +377,7 @@ + case FT_LCD_FILTER_LEGACY: + case FT_LCD_FILTER_LEGACY1: + library->lcd_filter_func = _ft_lcd_filter_legacy; ++ library->lcd_extra = 0; + break; + + #endif +diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c +index e301f8f11..7654c9458 100644 +--- a/src/base/ftobjs.c ++++ b/src/base/ftobjs.c +@@ -46,7 +46,9 @@ + #ifdef FT_CONFIG_OPTION_MAC_FONTS + #include "ftbase.h" + #endif +- ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++#include "ftinf.h" ++#endif + + #ifdef FT_DEBUG_LEVEL_TRACE + +@@ -96,6 +98,11 @@ + + #define GRID_FIT_METRICS + ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++#include <strings.h> ++#include <stdlib.h> ++#include "../autofit/aflatin.h" ++#endif + + /* forward declaration */ + static FT_Error +@@ -739,6 +746,25 @@ + ft_lookup_glyph_renderer( FT_GlyphSlot slot ); + + ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ static void ++ ft_glyphslot_enlarge_metrics( FT_GlyphSlot slot, ++ FT_Render_Mode mode ) ++ { ++ FT_Glyph_Metrics* metrics = &slot->metrics; ++ FT_Pos enlarge_cbox = 0; ++ ++ ++ /* enlarge for grayscale rendering */ ++ if ( mode == FT_RENDER_MODE_NORMAL ) ++ enlarge_cbox = 64; ++ ++ metrics->horiBearingX -= enlarge_cbox; ++ metrics->width += 2 * enlarge_cbox; ++ } ++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ ++ ++ + #ifdef GRID_FIT_METRICS + static void + ft_glyphslot_grid_fit_metrics( FT_GlyphSlot slot, +@@ -805,8 +831,18 @@ + FT_Bool autohint = FALSE; + FT_Module hinter; + TT_Face ttface = (TT_Face)face; ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET + ++ FT_Bool use_various_tweaks = FALSE; ++ if( ftinf ) use_various_tweaks=ftinf->use_various_tweaks; + ++ /* Force autohint if no tt instructions */ ++ /* NOTE: NEEDS TO BE RUN LATER IN CODE???? */ ++ /*if ( use_various_tweaks && ++ ttface->num_locations && ++ ttface->max_profile.maxSizeOfInstructions == 0 ) ++ load_flags |= FT_LOAD_FORCE_AUTOHINT;*/ ++#endif + if ( !face || !face->size || !face->glyph ) + return FT_THROW( Invalid_Face_Handle ); + +@@ -908,6 +944,18 @@ + { + FT_AutoHinter_Interface hinting; + ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ if ( use_various_tweaks ) ++ { ++ /* Force slight hinting over full hinting always */ ++ load_flags &= ~FT_LOAD_TARGET_LCD; ++ load_flags &= ~FT_LOAD_TARGET_LCD_V; ++ load_flags &= ~FT_LOAD_TARGET_MONO; ++ load_flags &= ~FT_LOAD_TARGET_NORMAL; ++ load_flags |= FT_LOAD_TARGET_LIGHT; ++ /*printf("%d ", load_flags);*/ ++ } ++#endif + + /* try to load embedded bitmaps first if available */ + /* */ +@@ -953,6 +1001,18 @@ + if ( error ) + goto Exit; + ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ infinality_cur_width = 0; ++ ++ { ++ /* fix for sdl_ttf */ ++ FT_Render_Mode mode = FT_LOAD_TARGET_MODE( load_flags ); ++ ++ if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) ++ ft_glyphslot_enlarge_metrics( slot, mode ); ++ } ++#endif ++ + if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) + { + /* check that the loaded outline is correct */ +@@ -5292,6 +5352,11 @@ + /* That's ok now */ + *alibrary = library; + ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ /* get Infinality settings */ ++ ftinf_env(); ++#endif ++ + return FT_Err_Ok; + } + +diff --git a/src/base/ftoutln.c b/src/base/ftoutln.c +index 0e2ba3475..8c6888a39 100644 +--- a/src/base/ftoutln.c ++++ b/src/base/ftoutln.c +@@ -22,7 +22,9 @@ + #include FT_INTERNAL_CALC_H + #include FT_INTERNAL_DEBUG_H + #include FT_TRIGONOMETRY_H +- ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++#include "ftinf.h" ++#endif + + /************************************************************************** + * +@@ -906,10 +908,16 @@ + FT_Pos xstrength, + FT_Pos ystrength ) + { +- FT_Vector* points; +- FT_Int c, first, last; +- FT_Orientation orientation; +- ++ FT_Vector* points; ++ FT_Int c, first, last; ++ FT_Int orientation; ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ FT_Bool use_various_tweaks = FALSE; ++ if( ftinf ) use_various_tweaks=ftinf->use_various_tweaks; ++ ++ if ( use_various_tweaks ) ++ ystrength = FT_PIX_FLOOR ( ystrength ); ++#endif + + if ( !outline ) + return FT_THROW( Invalid_Outline ); +diff --git a/src/base/ftsynth.c b/src/base/ftsynth.c +index f87ed65e7..620d57f07 100644 +--- a/src/base/ftsynth.c ++++ b/src/base/ftsynth.c +@@ -22,7 +22,9 @@ + #include FT_INTERNAL_OBJECTS_H + #include FT_OUTLINE_H + #include FT_BITMAP_H +- ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++#include "ftinf.h" ++#endif + + /************************************************************************** + * +@@ -93,7 +95,10 @@ + FT_Face face; + FT_Error error; + FT_Pos xstr, ystr; +- ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ FT_Bool use_various_tweaks = FALSE; ++ if( ftinf ) use_various_tweaks=ftinf->use_various_tweaks; ++#endif + + if ( !slot ) + return; +@@ -111,8 +116,16 @@ + ystr = xstr; + + if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) ++ { ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ if ( use_various_tweaks ) ++ (void)FT_Outline_EmboldenXY( &slot->outline, ++ xstr, ++ FT_PIX_FLOOR( ystr ) ); ++ else ++#endif + FT_Outline_EmboldenXY( &slot->outline, xstr, ystr ); +- ++ } + else /* slot->format == FT_GLYPH_FORMAT_BITMAP */ + { + /* round to full pixels */ +@@ -150,6 +163,9 @@ + + slot->metrics.width += xstr; + slot->metrics.height += ystr; ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ if ( !use_various_tweaks ) ++#endif + slot->metrics.horiAdvance += xstr; + slot->metrics.vertAdvance += ystr; + slot->metrics.horiBearingY += ystr; +diff --git a/src/base/rules.mk b/src/base/rules.mk +index 4b24c6dce..b8771b9ca 100644 +--- a/src/base/rules.mk ++++ b/src/base/rules.mk +@@ -44,6 +44,7 @@ BASE_SRC := $(BASE_DIR)/ftadvanc.c \ + $(BASE_DIR)/ftfntfmt.c \ + $(BASE_DIR)/ftgloadr.c \ + $(BASE_DIR)/fthash.c \ ++ $(BASE_DIR)/ftinf.c \ + $(BASE_DIR)/ftlcdfil.c \ + $(BASE_DIR)/ftobjs.c \ + $(BASE_DIR)/ftoutln.c \ +diff --git a/src/cff/cffobjs.c b/src/cff/cffobjs.c +index f76245f30..4b573d695 100644 +--- a/src/cff/cffobjs.c ++++ b/src/cff/cffobjs.c +@@ -43,6 +43,9 @@ + #include FT_INTERNAL_POSTSCRIPT_AUX_H + #include FT_SERVICE_CFF_TABLE_LOAD_H + ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++#include "../base/ftinf.h" ++#endif + + /************************************************************************** + * +@@ -1170,6 +1173,9 @@ + #endif + + driver->no_stem_darkening = TRUE; ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ if(ftinf) driver->no_stem_darkening = !ftinf->stem_darkening_cff; ++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ + + driver->darken_params[0] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1; + driver->darken_params[1] = CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1; +diff --git a/src/smooth/ftsmooth.c b/src/smooth/ftsmooth.c +index cd034d2b4..e82c15c25 100644 +--- a/src/smooth/ftsmooth.c ++++ b/src/smooth/ftsmooth.c +@@ -1,19 +1,19 @@ +-/**************************************************************************** +- * +- * ftsmooth.c +- * +- * Anti-aliasing renderer interface (body). +- * +- * Copyright (C) 2000-2019 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. +- * +- */ ++/***************************************************************************/ ++/* */ ++/* ftsmooth.c */ ++/* */ ++/* Anti-aliasing renderer interface (body). */ ++/* */ ++/* Copyright 2000-2017 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 <ft2build.h> +@@ -25,88 +25,2293 @@ + + #include "ftsmerrs.h" + ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++#include <math.h> ++#include FT_BITMAP_H ++#include <string.h> ++#include <strings.h> ++#include FT_OUTLINE_H ++#include "../base/ftinf.h" ++ ++#define verbose FALSE ++#define STVALUES if (verbose) \ ++ printf ( "scale:%f translate:%ld ", *scale_value, *translate_value ); ++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ + + /* initialize renderer -- init its raster */ + static FT_Error + ft_smooth_init( FT_Renderer render ) + { ++ render->clazz->raster_class->raster_reset( render->raster, NULL, 0 ); ++ ++ return 0; ++ } ++ ++ ++ /* sets render-specific mode */ ++ static FT_Error ++ ft_smooth_set_mode( FT_Renderer render, ++ FT_ULong mode_tag, ++ FT_Pointer data ) ++ { ++ /* we simply pass it to the raster */ ++ return render->clazz->raster_class->raster_set_mode( render->raster, ++ mode_tag, ++ data ); ++ } ++ ++ /* transform a given glyph image */ ++ static FT_Error ++ ft_smooth_transform( FT_Renderer render, ++ FT_GlyphSlot slot, ++ const FT_Matrix* matrix, ++ const FT_Vector* delta ) ++ { ++ FT_Error error = FT_Err_Ok; ++ ++ ++ if ( slot->format != render->glyph_format ) ++ { ++ error = FT_THROW( Invalid_Argument ); ++ goto Exit; ++ } ++ ++ if ( matrix ) ++ FT_Outline_Transform( &slot->outline, matrix ); ++ ++ if ( delta ) ++ FT_Outline_Translate( &slot->outline, delta->x, delta->y ); ++ ++ Exit: ++ return error; ++ } ++ ++ ++ /* return the glyph's control box */ ++ static void ++ ft_smooth_get_cbox( FT_Renderer render, ++ FT_GlyphSlot slot, ++ FT_BBox* cbox ) ++ { ++ FT_ZERO( cbox ); ++ ++ if ( slot->format == render->glyph_format ) ++ FT_Outline_Get_CBox( &slot->outline, cbox ); ++ } ++ ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ static FT_Fixed FT_FixedFromFloat(float f) ++ { ++ short value = f; ++ unsigned short fract = (f - value) * 0xFFFF; ++ ++ ++ return (FT_Fixed)((long)value << 16 | (unsigned long)fract ); ++ } ++ ++ ++ /* ChromeOS sharpening algorithm */ ++ /* soften the sub-pixel anti-aliasing and sharpen */ ++ static void ++ _ft_lcd_chromeos_sharpen( FT_Bitmap* bitmap, ++ FT_Render_Mode mode, ++ FT_Byte cutoff, ++ double gamma_value ) ++ { ++ static FT_Bool initialized_gamma = FALSE; ++ static unsigned short gamma_ramp[256]; ++ FT_UInt width = (FT_UInt)bitmap->width; ++ FT_UInt height = (FT_UInt)bitmap->rows; ++ int ii; ++ ++ if ( !initialized_gamma ) ++ { ++ initialized_gamma = TRUE; ++ /* linear to voltage */ ++ for ( ii = 0; ii < 256; ii++ ) ++ { ++ gamma_ramp[ii] = (unsigned char) ++ ( pow( (double)ii / 255.0, gamma_value ) * 255.0f ); ++ if ( gamma_ramp[ii] < cutoff ) ++ gamma_ramp[ii] = 0; ++ } ++ } ++ ++ /* horizontal in-place sub-pixel sharpening filter */ ++ if ( mode == FT_RENDER_MODE_LCD ) ++ { ++ FT_Byte* line = bitmap->buffer; ++ ++ ++ for ( ; height > 0; height--, line += bitmap->pitch ) ++ { ++ FT_UInt xx; ++ ++ ++ for ( xx = 0; xx < width; xx++ ) ++ line[xx] = gamma_ramp[line[xx]]; ++ } ++ } ++ } ++ ++ /* simple linear scale to handle various sliding values */ ++ float ++ sliding_scale ( int min_value, ++ int max_value, ++ float min_amount, ++ float max_amount, ++ int cur_value ) ++ { ++ ++ float m = ( min_amount - max_amount ) / (float)( min_value - max_value ); ++ float result = ( ( (float)cur_value * m) + ( max_amount - max_value * m ) ) ; ++ ++ if ( min_amount < max_amount ) ++ { ++ if ( result < min_amount ) ++ return min_amount; ++ if ( result > max_amount ) ++ return max_amount; ++ } ++ else ++ { ++ if ( result < max_amount ) ++ return max_amount; ++ if ( result > min_amount ) ++ return min_amount; ++ } ++ ++ return result; ++ } ++ ++ ++ /* brightness and contrast adjustment on the bitmap */ ++ static FT_Bool ++ _ft_bitmap_bc ( FT_Bitmap* bitmap, ++ float brightness, ++ float contrast ) ++ { ++ ++ FT_UInt width = (FT_UInt)bitmap->width; ++ FT_UInt height = (FT_UInt)bitmap->rows; ++ FT_Byte* line = bitmap->buffer; ++ FT_UInt xx; ++ ++ ++ if ( brightness == 0 && contrast == 0 ) ++ return FALSE; ++ ++ for ( height = (FT_UInt)bitmap->rows; ++ height > 0; ++ height--, line += bitmap->pitch ) ++ { ++ for ( xx = 0; xx < width - 1; xx += 1 ) ++ { ++ if ( line[xx] > 0) ++ { ++ float value = (float)( 255 - line[xx] ) / 256.0; ++ FT_Int result = 0; ++ ++ if ( brightness < 0.0 ) ++ value = value * ( 1.0 + brightness ); ++ else ++ value = value + ( ( 1.0 - value ) * brightness ); ++ ++ value = ( value - 0.5 ) * ++ ( tan ( ( contrast + 1.0 ) * 3.141592/4.0 ) ) + 0.5; ++ ++ result = (FT_Int)( 255.0 - value * 256.0 ); ++ ++ if ( result < 0 ) ++ result = 0; ++ if ( result > 255 ) ++ result = 255; ++ ++ line[xx] = result; ++ } ++ } ++ } ++ return TRUE; ++ } ++ ++ ++ /* Filter to mimic Windows-style sharpening */ ++ /* Determined via 100% experimentation. */ ++ static void ++ _ft_lcd_windows_sharpen( FT_Bitmap* bitmap, ++ FT_Render_Mode mode, ++ FT_UInt strength, ++ FT_Library library ) ++ { ++ ++ FT_UInt width = (FT_UInt)bitmap->width; ++ FT_UInt height = (FT_UInt)bitmap->rows; ++ FT_Byte* new_line; ++ FT_Byte* line = bitmap->buffer; ++ FT_Bitmap new_bitmap; ++ ++ ++ FT_Bitmap_Init( &new_bitmap ); ++ FT_Bitmap_Copy( library, bitmap, &new_bitmap ); ++ new_line = (&new_bitmap)->buffer; ++ ++ if (strength > 0) ++ for (height = (FT_UInt)bitmap->rows; ++ height > 0; ++ height--, line += bitmap->pitch, new_line += bitmap->pitch ) ++ { ++ FT_UInt xx, threshold = 128; ++ FT_Byte* prevline = line - bitmap->pitch; ++ FT_Byte* nextline = line + bitmap->pitch; ++ FT_Byte* new_prevline = new_line - bitmap->pitch; ++ FT_Byte* new_nextline = new_line + bitmap->pitch; ++ ++ for ( xx = 1; xx < width - 1; xx += 1 ) ++ { ++ /* subpixel grid sp11 sp21 sp31 */ ++ /* where sp22 is sp12 sp22 sp32 */ ++ /* current subpixel. sp13 sp23 sp33 */ ++ ++ FT_Int prevtotal, nexttotal, lefttotal, righttotal, sidesdiff, ++ prevdiff, nextdiff, sp11, sp21, sp31, sp12, sp22, sp32, ++ sp13, sp23, sp33; ++ ++ sp12 = line [xx-1]; ++ sp22 = line [xx]; ++ sp32 = line [xx+1]; ++ ++ if ( height == bitmap->rows ) ++ { ++ prevtotal = sp11 = sp21 = sp31 = 0; ++ prevdiff = sp22; ++ lefttotal = sp12 + sp13; ++ righttotal = sp32 + sp33; ++ } ++ else ++ { ++ prevtotal = prevline[xx-1] + prevline[xx] + prevline[xx+1]; ++ sp11 = prevline [xx-1]; ++ sp21 = prevline [xx]; ++ sp31 = prevline [xx+1]; ++ prevdiff = sp22 - sp21; ++ lefttotal = sp11 + sp12 + sp13; ++ righttotal = sp31 + sp32 + sp33; ++ } ++ ++ if ( height == 1 ) ++ { ++ nexttotal = sp13 = sp23 = sp33 = 0; ++ nextdiff = sp22; ++ lefttotal = sp11 + sp12; ++ righttotal = sp31 + sp32; ++ } ++ else ++ { ++ nexttotal = nextline[xx-1] + nextline[xx] + nextline[xx+1]; ++ sp13 = nextline [xx-1]; ++ sp23 = nextline [xx]; ++ sp33 = nextline [xx+1]; ++ nextdiff = sp23 - sp22; ++ lefttotal = sp11 + sp12 + sp13; ++ righttotal = sp31 + sp32 + sp33; ++ } ++ ++ sidesdiff = lefttotal - righttotal; ++ ++ if ( sidesdiff < 0 ) ++ sidesdiff *= -1; ++ ++ if ( prevdiff < 0 ) ++ prevdiff *= -1; ++ ++ if ( nextdiff < 0 ) ++ nextdiff *= -1; ++ ++ /* if the current pixel is less than threshold, and greater than 0 */ ++ if ( sp22 <= threshold && sp22 > 0 ) ++ { ++ /* A pixel is horizontally isolated if: */ ++ /* 1: All upper adjecent pixels are >= threshold */ ++ if ( prevtotal >= nexttotal && ++ abs( sp11 - sp12 ) > 5 && ++ abs( sp21 - sp22 ) > 5 && ++ abs( sp31 - sp32 ) > 5 && /* not a vert stem end */ ++ sp11 >= threshold && ++ sp21 >= threshold && ++ sp31 >= threshold && ++ abs( sp23 - sp22 ) > 15 ) /* not on a vert stem */ ++ { ++ /* darken upper adjacent subpixel; lighten current */ ++ if ( height != (FT_UInt)bitmap->rows ) ++ new_prevline[xx] += ( ( 255 - new_prevline[xx] ) ++ * strength ) / 100 ; ++ ++ new_line[xx] -= ( new_line[xx] * strength ) / 100; ++ ++ if ( height != 1 && height != (FT_UInt)bitmap->rows ) ++ if ( new_nextline[xx] > 155 + ( 100 - strength ) ) ++ new_prevline[xx] = 255; ++ ++ } ++ else if ( nexttotal > prevtotal && ++ abs( sp13 - sp12 ) > 5 && ++ abs( sp23 - sp22 ) > 5 && ++ abs( sp33 - sp32 ) > 5 && ++ /* 2: All lower adjecent pixels are >= threshold */ ++ sp13 >= threshold && ++ sp23 >= threshold && ++ sp33 >= threshold && ++ abs( sp22 - sp21 ) > 15 ) ++ { ++ /* darken lower adjacent subpixel; lighten current */ ++ if ( height != 1 ) ++ new_nextline[xx] += ( 255 - new_nextline[xx] ) * strength / 100; ++ ++ new_line[xx] -= ( new_line[xx] * strength ) / 100; ++ ++ if ( height != 1 ) ++ if ( new_nextline[xx] > 155 + ( 100 - strength ) ) ++ new_nextline[xx] = 255; ++ ++ } ++ } ++ else if ( sp22 > threshold && sp22 < 255 ) ++ { ++ if ( sp11 <= threshold && ++ abs( sp13 - sp12 ) > 5 && ++ abs( sp23 - sp22 ) > 5 && ++ abs( sp33 - sp32 ) > 5 && ++ sp21 <= threshold && ++ sp31 <= threshold && ++ prevtotal <= nexttotal && ++ abs( sp22 - sp21 ) > 15 ) ++ { ++ /* bring this subpixel 1/3 of the way to 255 at 100% strength */ ++ new_line[xx] += ( strength * ( 255 - new_line[xx] ) ) / 100; ++ ++ if ( height != (FT_UInt)bitmap->rows ) ++ new_prevline[xx] -= ( new_prevline[xx] * strength ) / 300; ++ } ++ else if ( sp13 <= threshold && ++ abs( sp11 - sp12 ) > 5 && ++ abs( sp21 - sp22 ) > 5 && ++ abs( sp31 - sp32 ) > 5 && ++ sp23 <= threshold && ++ sp33 <= threshold && ++ nexttotal < prevtotal && ++ abs( sp23 - sp22 ) > 15 ) ++ { ++ new_line[xx] += ( strength * ( 255 - new_line[xx] ) ) / 100; ++ ++ if ( height != 1 ) ++ new_nextline[xx] -= ( new_nextline[xx] * strength ) / 300; ++ } ++ } ++ } ++ } ++ FT_Bitmap_Copy( library, &new_bitmap, bitmap); ++ FT_Bitmap_Done( library, &new_bitmap ); ++ } ++ ++ ++ static void ++ _ft_lcd_darken_x ( FT_Bitmap* bitmap, ++ FT_Render_Mode mode, ++ FT_UInt strength, ++ FT_Library library ) ++ { ++ ++ FT_UInt width = (FT_UInt)bitmap->width; ++ FT_UInt height = (FT_UInt)bitmap->rows; ++ FT_Byte* new_line; ++ FT_Byte* line = bitmap->buffer; ++ FT_Bitmap new_bitmap; ++ int factor1, factor2; ++ int bias = 0; ++ ++ FT_Bitmap_Init( &new_bitmap ); ++ ++ FT_Bitmap_Copy( library, bitmap, &new_bitmap ); ++ new_line = (&new_bitmap)->buffer; ++ ++ if ( strength > 0 ) ++ for ( height = (FT_UInt)bitmap->rows; ++ height > 0; ++ height--, line += bitmap->pitch, new_line += bitmap->pitch ) ++ { ++ FT_UInt xx; ++ FT_Byte* prevline = line - bitmap->pitch; ++ FT_Byte* nextline = line + bitmap->pitch; ++ ++ for ( xx = 1; xx < width - 1; xx += 1 ) ++ { ++ /* subpixel grid sp11 sp21 sp31 */ ++ /* where sp22 is sp12 sp22 sp32 */ ++ /* current subpixel. sp13 sp23 sp33 */ ++ ++ FT_Int sp21, sp12, sp22, sp32, sp23; ++ ++ sp12 = line [xx-1]; ++ sp22 = line [xx]; ++ sp32 = line [xx+1]; ++ ++ if ( height == bitmap->rows ) ++ sp21 = 0; ++ else ++ sp21 = prevline [xx]; ++ ++ if ( height == 1 ) ++ sp23 = 0; ++ else ++ sp23 = nextline [xx]; ++ ++ /* darken subpixel if neighbor above and below are much less than */ ++ /* safer but less effective */ ++ factor1 = 5; ++ factor2 = 5; ++ ++ /* make matches in the middle of glyph slightly darker */ ++ /*if (height > 1 && height < (FT_UInt)bitmap->rows) bias = 1;*/ ++ ++ if ( sp22 > factor1 * sp21 && ++ sp22 > factor1 * sp23 && ++ sp22 > factor2 && ++ sp12 > 16 && ++ sp32 > 16 ) ++ if ( new_line[xx] < ( strength * 255 ) / 100 ) ++ new_line[xx] = (strength * 255 ) / 100 ++ + bias * ( 255 - ( strength * 255 ) / 100 ) / 3; ++ ++ } ++ } ++ FT_Bitmap_Copy( library, &new_bitmap, bitmap ); ++ FT_Bitmap_Done( library, &new_bitmap ); ++ } ++ ++ ++ static void ++ _ft_lcd_darken_y ( FT_Bitmap* bitmap, ++ FT_Render_Mode mode, ++ FT_UInt strength, ++ FT_Library library ) ++ { ++ ++ FT_UInt width = (FT_UInt)bitmap->width; ++ FT_UInt height = (FT_UInt)bitmap->rows; ++ FT_Byte* new_line; ++ FT_Byte* line = bitmap->buffer; ++ FT_Bitmap new_bitmap; ++ ++ ++ FT_Bitmap_Init( &new_bitmap ); ++ FT_Bitmap_Copy( library, bitmap, &new_bitmap ); ++ new_line = (&new_bitmap)->buffer; ++ ++ if ( strength > 0 ) ++ for ( height = (FT_UInt)bitmap->rows; ++ height > 0; ++ height--, line += bitmap->pitch, new_line += bitmap->pitch ) ++ { ++ FT_UInt xx; ++ ++ ++ for ( xx = 1; xx < width - 1; xx += 1 ) ++ { ++ if ( line[xx] > line[xx-1] && line[xx] > line[xx+1] ) ++ { ++ if (new_line[xx] > 0) ++ new_line[xx] += ( strength * ( 255 - new_line[xx] ) ) / 100; ++ new_line[xx-1] += ( strength * ( 255 - line[xx-1] ) ) / 100; ++ new_line[xx+1] += ( strength * ( 255 - line[xx+1] ) ) / 100; ++ } ++ } ++ } ++ FT_Bitmap_Copy( library, &new_bitmap, bitmap ); ++ FT_Bitmap_Done( library, &new_bitmap ); ++ } ++ ++ ++ static void ++ _ft_bitmap_cap ( FT_Bitmap* bitmap, ++ FT_UInt strength, ++ FT_Library library ) ++ { ++ ++ FT_UInt width = (FT_UInt)bitmap->width; ++ FT_UInt height = (FT_UInt)bitmap->rows; ++ FT_Byte* new_line; ++ FT_Byte* line = bitmap->buffer; ++ FT_UInt cur_value = 0; ++ FT_Bitmap new_bitmap; ++ ++ ++ FT_Bitmap_Init( &new_bitmap ); ++ FT_Bitmap_Copy( library, bitmap, &new_bitmap ); ++ new_line = (&new_bitmap)->buffer; ++ ++ if ( strength > 0 ) ++ for ( height = (FT_UInt)bitmap->rows; ++ height > 0; ++ height--, line += bitmap->pitch, new_line += bitmap->pitch ) ++ { ++ FT_UInt xx; ++ ++ ++ for ( xx = 1; xx < width - 1; xx += 1 ) ++ { ++ cur_value = ( new_line[xx-1] + new_line[xx] + new_line[xx+1] ) / 3; ++ if ( cur_value > ( strength * 255 ) / 100 ) ++ { ++ FT_UInt new_factor = ( strength * 255 ) / 100; ++ new_line[xx] = ( new_line[xx] * new_factor ) / cur_value; ++ new_line[xx+1] = ( new_line[xx+1] * new_factor ) / cur_value; ++ new_line[xx-1] = ( new_line[xx-1] * new_factor ) / cur_value; ++ } ++ } ++ } ++ FT_Bitmap_Copy( library, &new_bitmap, bitmap ); ++ FT_Bitmap_Done( library, &new_bitmap ); ++ } ++ ++ static int ++ pseudo_gamma ( int val, float value ) ++ { ++ return 256 * ( 1.0f - powf( ( 1.0f - val * (1.0f/256.0f) ), 1.0f / value ) ); ++ } ++ ++#if(0) ++ static void ++ _ft_bitmap_embolden ( FT_Bitmap* bitmap, ++ FT_UInt strength, ++ FT_Library library ) ++ { ++ ++ FT_UInt width = (FT_UInt)bitmap->width; ++ FT_UInt height = (FT_UInt)bitmap->rows; ++ FT_Byte* new_line; ++ FT_Byte* line = bitmap->buffer; ++ FT_Bitmap new_bitmap; ++ FT_UInt xx; ++ ++ ++ FT_Bitmap_Init(&new_bitmap); ++ FT_Bitmap_Copy(library, bitmap, &new_bitmap); ++ new_line = (&new_bitmap)->buffer; ++ ++ if ( strength > 0 ) ++ for ( height = (FT_UInt)bitmap->rows; ++ height > 0; ++ height--, line += bitmap->pitch, new_line += bitmap->pitch ) ++ { ++ for ( xx = 1; xx < width - 1; xx += 1 ) ++ { ++ FT_Int new_value = 0; ++ ++ ++ new_value = ( strength * line [xx-1] ) / 100 ++ + pseudo_gamma( line [xx], .75 ) ++ + (strength * line [xx+1] ) / 100; ++ if ( new_value > 255 ) ++ new_value = 255; ++ ++ new_line[xx] = new_value; ++ } ++ } ++ FT_Bitmap_Copy( library, &new_bitmap, bitmap ); ++ FT_Bitmap_Done( library, &new_bitmap ); ++ } ++ ++ ++ ++ static void ++ _ft_bitmap_gamma ( FT_Bitmap* bitmap, ++ float strength ) ++ { ++ ++ FT_UInt width = (FT_UInt)bitmap->width; ++ FT_UInt height = (FT_UInt)bitmap->rows; ++ FT_Byte* line = bitmap->buffer; ++ FT_UInt xx; ++ ++ ++ if ( strength > 0 ) ++ for ( height = (FT_UInt)bitmap->rows; ++ height > 0; ++ height--, line += bitmap->pitch ) ++ { ++ ++ for ( xx = 1; xx < width - 1; xx += 1 ) ++ { ++ if ( abs( line[xx-1] - line[xx] ) < 20 || ++ abs( line[xx+1] - line[xx] ) < 20 ) ++ line [xx] = pseudo_gamma( line [xx], strength ) ; ++ } ++ } ++ } ++#endif ++ ++ /* Fringe filter */ ++ static void ++ _ft_lcd_fringe_filter ( FT_Bitmap* bitmap, ++ FT_Render_Mode mode, ++ FT_UInt strength, ++ FT_Library library ) ++ { ++ ++ FT_UInt width = (FT_UInt)bitmap->width; ++ FT_UInt height = (FT_UInt)bitmap->rows; ++ FT_Byte* new_line; ++ FT_Byte* line = bitmap->buffer; ++ FT_Bitmap new_bitmap; ++ ++ ++ FT_Bitmap_Init(&new_bitmap); ++ ++ line = bitmap->buffer; ++ FT_Bitmap_Copy( library, bitmap, &new_bitmap ); ++ new_line = (&new_bitmap)->buffer; ++ ++ for ( height = (FT_UInt)bitmap->rows; ++ height > 0; ++ height--, line += bitmap->pitch, new_line += bitmap->pitch ) ++ { ++ /* Threshold set to 1/2 pixel intensity */ ++ FT_UInt xx, threshold = 128; ++ ++ /* Hack to make this work when bitmap is at first or last line */ ++ FT_Int fudge = bitmap->pitch * (height == (FT_UInt)bitmap->rows); ++ ++ FT_Byte* prevline = line - bitmap->pitch + fudge; ++ FT_Byte* nextline = line + bitmap->pitch; ++ ++ ++ for ( xx = 1; xx < width - 1; xx += 1 ) ++ { ++ /* subpixel grid sp11 sp21 sp31 */ ++ /* where sp22 is sp12 sp22 sp32 */ ++ /* current subpixel. sp13 sp23 sp33 */ ++ ++ FT_Int prevtotal, nexttotal, lefttotal, righttotal, sidesdiff, ++ leftdiff, rightdiff, prevdiff, nextdiff, sp11, sp21, sp31, ++ sp12, sp22, sp32, sp13, sp23, sp33; ++ ++ sp12 = line [xx-1]; ++ sp22 = line [xx]; ++ sp32 = line [xx+1]; ++ ++ /* if at max height fake out some values */ ++ if ( height == (FT_UInt)bitmap->rows ) ++ { ++ prevtotal = sp11 = sp21 = sp31 = 0; ++ prevdiff = sp22; ++ lefttotal = sp12 + sp13; ++ righttotal = sp32 + sp33; ++ } ++ else ++ { ++ prevtotal = prevline[xx-1] + prevline[xx] + prevline[xx+1]; ++ sp11 = prevline [xx-1]; ++ sp21 = prevline [xx]; ++ sp31 = prevline [xx+1]; ++ prevdiff = sp22 - sp21; ++ lefttotal = sp11 + sp12 + sp13; ++ righttotal = sp31 + sp32 + sp33; ++ } ++ ++ /* if at min height fake out some values */ ++ if ( height == 1 ) ++ { ++ nexttotal = sp13 = sp23 = sp33 = 0; ++ nextdiff = sp22; ++ lefttotal = sp11 + sp12; ++ righttotal = sp31 + sp32; ++ } ++ else ++ { ++ nexttotal = nextline[xx-1] + nextline[xx] + nextline[xx+1]; ++ sp13 = nextline [xx-1]; ++ sp23 = nextline [xx]; ++ sp33 = nextline [xx+1]; ++ nextdiff = sp23 - sp22; ++ lefttotal = sp11 + sp12 + sp13; ++ righttotal = sp31 + sp32 + sp33; ++ } ++ ++ sidesdiff = lefttotal - righttotal; ++ leftdiff = sp22 - sp12; ++ rightdiff = sp32 - sp22; ++ ++ if ( sidesdiff < 0 ) ++ sidesdiff *= -1; ++ ++ if ( prevdiff < 0 ) ++ prevdiff *= -1; ++ ++ if ( nextdiff < 0 ) ++ nextdiff *= -1; ++ ++ if ( leftdiff < 0 ) ++ leftdiff *= -1; ++ ++ if ( rightdiff < 0 ) ++ rightdiff *= -1; ++ ++ /* if the current subpixel is less than threshold, and varies only ++ slightly to left or right, lighten it */ ++ if ( sp22 <= threshold && sp22 > 0 && ++ ( leftdiff < 10 || rightdiff < 10 ) ) ++ { ++ /* A pixel is horizontally isolated if: */ ++ /* 1: All upper adjecent subpixels are >= threshold and all lower ++ adjacent ones are essentially white */ ++ if ( prevtotal >= nexttotal && ++ sp11 >= threshold && ++ sp21 >= threshold && ++ sp31 >= threshold && ++ sp13 < 2 && ++ sp23 < 2 && ++ sp33 < 2 ) ++ ++ { ++ new_line[xx] -= ( new_line[xx] * strength ) / 100; ++ ++ if ( leftdiff < 10 ) ++ /* OPPORTUNITY FOR IMPROVEMENT - keep going left until 255? */ ++ new_line[xx-1] -= ( new_line[xx-1] * strength ) / 200; ++ ++ if ( rightdiff < 10 ) ++ /* OPPORTUNITY FOR IMPROVEMENT */ ++ new_line[xx+1] -= ( new_line[xx+1] * strength ) / 200; ++ } ++ else if ( nexttotal > prevtotal && ++ /* 2: the inverse of above */ ++ sp13 >= threshold && ++ sp23 >= threshold && ++ sp33 >= threshold && ++ sp11 < 2 && ++ sp21 < 2 && ++ sp31 < 2 ) ++ { ++ new_line[xx] -= ( new_line[xx] * strength ) / 100; ++ ++ if ( leftdiff < 10 ) ++ /* OPPORTUNITY FOR IMPROVEMENT - keep going left until 255? */ ++ new_line[xx-1] -= ( new_line[xx-1] * strength ) / 200; ++ ++ if ( rightdiff < 10 ) ++ /* OPPORTUNITY FOR IMPROVEMENT */ ++ new_line[xx+1] -= ( new_line[xx+1] * strength ) / 200; ++ } ++ } ++ /* otherwise if the current subpixel is more than threshold, and varies ++ slightly to left or right, darken it */ ++ else if ( sp22 > threshold && ++ sp22 < 255 && ++ ( leftdiff < 10 || ++ rightdiff < 10 ) ) ++ { ++ if ( sp11 <= 2 && ++ sp21 <= 2 && ++ sp31 <= 2 && ++ sp13 >= threshold && ++ sp23 >= threshold && ++ sp33 >= threshold && ++ prevtotal < nexttotal ) ++ new_line[xx] += ( ( 255 - new_line[xx] ) * strength ) / 100; ++ ++ else if ( sp13 <= 2 && ++ sp23 <= 2 && ++ sp33 <= 2 && ++ nexttotal < prevtotal && ++ sp11 >= threshold && ++ sp21 >= threshold && ++ sp31 >= threshold ) ++ new_line[xx] += ( ( 255 - new_line[xx] ) * strength ) / 100; ++ ++ } ++ } ++ } ++ FT_Bitmap_Copy( library, &new_bitmap, bitmap ); ++ FT_Bitmap_Done( library, &new_bitmap ); ++ } ++ ++ ++ /* Grayscale filter */ ++ static void ++ _ft_lcd_grayscale_filter ( FT_Bitmap* bitmap, ++ FT_Render_Mode mode, ++ FT_UInt strength, ++ FT_Library library ) ++ { ++ ++ FT_UInt width = (FT_UInt)bitmap->width; ++ FT_UInt height = (FT_UInt)bitmap->rows; ++ FT_Byte* line = bitmap->buffer; ++ ++ ++ for ( height = (FT_UInt)bitmap->rows; ++ height > 0; ++ height--, line += bitmap->pitch ) ++ { ++ FT_UInt xx; ++ ++ ++ for ( xx = 0; xx < width - 1; xx += 3 ) ++ { ++ FT_UInt total = line [xx] + line [xx + 1] + line [xx + 2]; ++ line[xx] = ( ( 100 - strength ) * line[xx] ++ + strength * ( total / 3 ) ) / 100; ++ line[xx+1] = ( ( 100 - strength ) * line[xx+1] ++ + strength * ( total / 3 ) ) / 100; ++ line[xx+2] = ( ( 100 - strength ) * line[xx+2] ++ + strength * ( total / 3 ) ) / 100; ++ } ++ } ++ } ++ ++/* ++ These need to be in sync with params inside ftinf.c ++ (not ideal but perhaps better than making these public) ++ */ ++#define STEM_WIDTH_2_PPEM 18 ++#define MAX_PPEM 100 ++ ++ typedef struct Stem_Segment_ ++ { ++ FT_Long x1; ++ FT_Long x2; ++ FT_Int y; ++ } Stem_Segment; ++ ++ typedef struct Stem_Center_ ++ { ++ FT_Long x; ++ FT_Long y; ++ FT_Long w; ++ FT_Long x1; ++ FT_Long x2; ++ } Stem_Center; ++ ++ typedef struct Stem_ ++ { ++ FT_Long center; ++ FT_Long count; ++ FT_Long rcount; /* used to count within a range in possible stems */ ++ FT_Long width; ++ FT_Long height; ++ FT_Short zone; /* 1 2 or 3 */ ++ FT_Bool generated; ++ } Stem; ++ ++ static void ++ swap_stem ( Stem* s1, Stem* s2 ) ++ { ++ Stem s; ++ s.center = s1->center; ++ s.count = s1->count; ++ s.rcount = s1->rcount; ++ s.width = s1->width; ++ s.zone = s1->zone; ++ s.generated = s1->generated; ++ ++ s1->center = s2->center; ++ s1->count = s2->count; ++ s1->rcount = s2->rcount; ++ s1->width = s2->width; ++ s1->zone = s2->zone; ++ s1->generated = s2->generated; ++ ++ s2->center = s.center; ++ s2->count = s.count; ++ s2->rcount = s.rcount; ++ s2->width = s.width; ++ s2->zone = s.zone; ++ s2->generated = s.generated; ++ } ++ ++ /* Stem alignment for bitmaps; A hack with very nice results */ ++ /* Ideally this could be implemented on the outline, prior to ++ * rasterization. Possible future enhancement is to use the ++ * warper code to achieve this */ ++ static void ++ _lcd_stem_align ( FT_Bitmap* bitmap, ++ FT_Render_Mode mode, ++ FT_GlyphSlot slot, ++ FT_Long* translate_value, ++ float* scale_value, ++ FT_UInt alignment_strength, ++ FT_UInt fitting_strength, ++ float* embolden_value ++ ) ++ { ++ FT_UInt width = (FT_UInt)bitmap->width; ++ FT_UInt height = (FT_UInt)bitmap->rows; ++ ++ Stem_Segment* segments; ++ Stem_Segment* leftmost_segment; ++ Stem_Segment* rightmost_segment; ++ Stem_Segment* leftmost_segment_not_extrema; ++ Stem_Segment* rightmost_segment_not_extrema; ++ Stem* stems; ++ Stem* possible_stems; ++ Stem* leftmost_stem; ++ Stem* rightmost_stem; ++ Stem_Data* known_stem_values; ++ Stem_Center* centers; ++ FT_Long leftmost_point = width * 256; ++ FT_Long rightmost_point = 0; ++ FT_Long leftmost_point_not_extrema = width * 256; ++ FT_Long rightmost_point_not_extrema = 0; ++ FT_Long num_segments = 0; ++ FT_Long num_centers = 0; ++ FT_Long *stem_centers; ++ FT_UInt h; ++ FT_ULong valid_stems = 0, valid_possible_stems = 0; ++ FT_Long center, stem_matches, stem_matches_ledge; ++ FT_Long stem_matches_redge, next_center, last_matching_center; ++ FT_Long last_matching_ledge, last_matching_redge, this_center; ++ FT_Int max_strength; ++ FT_Byte* line = bitmap->buffer; ++ FT_UInt current_value = 0; ++ FT_UInt xx; ++ FT_Long linearHoriAdvance = slot->linearHoriAdvance >> 10; ++ ++ FT_Int m_horiBearingX = slot->metrics.horiBearingX; ++ FT_Int m_horiAdvance = slot->metrics.horiAdvance; ++ FT_Int m_width = slot->metrics.width; ++ FT_Pos one_pixel = 768; ++ FT_Pos one_third_pixel = 256; ++ FT_Int columns_per_pixel = 3; ++ /*FT_Int extra_columns = 6;*/ ++ ++ /* on / off flags for testing different features */ ++ FT_Bool strategy_translate_using_closest_stem = TRUE; ++ FT_Bool strategy_scale_to_closest_centers = FALSE; ++ FT_Bool strategy_scale_to_closest_centers_up_only = FALSE; ++ FT_Bool strategy_always_use_distance_ceiling = FALSE; ++ FT_Bool strategy_auto_change_center_offset = TRUE; ++ FT_Bool strategy_use_m_control = FALSE; ++ FT_Bool strategy_correct_out_of_bounds_outlines = FALSE; ++ FT_Bool strategy_also_use_edge_detection_for_stems = FALSE; ++ FT_Bool strategy_use_strengths = TRUE; ++ FT_Bool strategy_synthesize_stems = FALSE; ++ FT_Bool strategy_bearing_correction = TRUE; ++ FT_Bool strategy_use_d_correction = TRUE; ++ FT_Bool strategy_fit_to_width = FALSE; ++ /*FT_Bool strategy_center_glyph = FALSE;*/ ++ ++ const FT_Int MIN_PPEM = 7; ++ /*const FT_Int MAX_PPEM = 100;*/ ++ const FT_Int MAX_STEMS = 3; ++ FT_Int ppem = 0; ++ ++ Stem_Data stem_data; ++ ++ /* reset to default */ ++ *scale_value = 1.0; ++ ++ /* Simply return in odd cases where these don't seem to be set */ ++ /* Flash and some pdf viewers will crash otherwise */ ++ if ( !slot->face || ++ !slot->face->size || ++ !slot->face->size->metrics.x_ppem ) ++ return; ++ ++ if ( slot->face->size->metrics.x_ppem > MAX_PPEM ) ++ return; ++ ++ if ( slot->face->size->metrics.x_ppem < MIN_PPEM ) ++ return; ++ ++ if ( !FT_IS_SCALABLE( slot->face ) ) ++ return; ++ ++ ppem = slot->face->size->metrics.x_ppem; ++ ++ if ( ppem < 9 ) ++ return; ++ if ( ppem > 20 ) ++ strategy_use_m_control = TRUE; ++ ++ /* only perform alignment on styles we know, that aren't bold or italic */ ++ /* perhaps detection could be added on those that are not set? */ ++ /* Require certain ppems for narrow and light fonts */ ++ if( slot->face->style_name ) ++ { ++ if ( strcasestr( slot->face->style_name, "Italic" ) || ++ strcasestr( slot->face->style_name, "Oblique" ) || ++ strcasestr( slot->face->style_name, "Script" ) || ++ strcasestr( slot->face->style_name, "Handwriting" ) || ++ strcasestr( slot->face->style_name, "Bold" ) || ++ strcasestr( slot->face->style_name, "Black" ) || ++ ( ( strcasestr( slot->face->style_name, "Extra Thin" ) || ++ strcasestr( slot->face->style_name, "Extra Light" ) ) && ++ ppem < 10 ) || ++ ( strcasestr( slot->face->style_name, "Thin" ) ++ && ppem < 10 ) || ++ ( strcasestr( slot->face->style_name, "Light" ) ++ && ppem < 10 ) || ++ ( strcasestr( slot->face->style_name, "Narrow" ) ++ && ppem < 15 ) || ++ ( strcasestr( slot->face->style_name, "Condensed" ) ++ && ppem < 20 ) ) ++ return; ++ } ++ ++ if( slot->face->family_name ) ++ { ++ if ( strcasestr( slot->face->family_name, "Italic" ) || ++ strcasestr( slot->face->family_name, "Oblique" ) || ++ strcasestr( slot->face->family_name, "Script" ) || ++ strcasestr( slot->face->family_name, "Handwriting" ) || ++ strcasestr( slot->face->family_name, "Bold" ) || ++ strcasestr( slot->face->family_name, "Black" ) || ++ ( ( strcasestr( slot->face->family_name, "Extra Thin" ) || ++ strcasestr( slot->face->family_name, "Extra Light" ) ) && ++ ppem < 10 ) || ++ ( strcasestr( slot->face->family_name, "Thin" ) ++ && ppem < 10 ) || ++ ( strcasestr( slot->face->family_name, "Light" ) ++ && ppem < 10 ) || ++ ( strcasestr( slot->face->family_name, "Narrow" ) ++ && ppem < 15 ) || ++ ( strcasestr( slot->face->family_name, "Condensed" ) ++ && ppem < 20 ) ) ++ return; ++ } ++ else if ( slot->face->style_flags ) ++ { ++ if ( slot->face->style_flags & FT_STYLE_FLAG_ITALIC || ++ slot->face->style_flags & FT_STYLE_FLAG_BOLD || ++ FT_IS_TRICKY( slot->face ) ) ++ return; ++ } ++ else return; ++ ++ if ( mode != FT_RENDER_MODE_LCD ) ++ { ++ columns_per_pixel = 1; ++ one_pixel = 256; ++ one_third_pixel = 85; ++ /*extra_columns = 0;*/ ++ /* until this can be figured out just return */ ++ /* There are issues with missing glyphs */ ++ return; ++ } ++ ++ known_stem_values=&stem_data; ++ if ( ftinf && ftinf->use_known_settings_on_selected_fonts ) ++ { ++ ftinf_fill_stem_values( known_stem_values, slot->face->family_name, ppem, TRUE ); ++ /* translate value may be set for < 10 */ ++ if (known_stem_values->stem_translating_only > -1024 ) ++ { ++ *translate_value = known_stem_values->stem_translating_only; ++ return; ++ } ++ if( known_stem_values->bearing_correction == FALSE ) ++ strategy_bearing_correction = FALSE; ++ } else ++ ftinf_fill_stem_values( known_stem_values, slot->face->family_name, ppem, FALSE ); ++ ++ if ( known_stem_values->use_100 || ++ known_stem_values->m >= 0 ) ++ { ++ alignment_strength = fitting_strength = 100; ++ strategy_use_m_control = TRUE; ++ } ++ ++ if ( known_stem_values->edge_detection ) ++ strategy_also_use_edge_detection_for_stems = TRUE; ++ ++ /* Allocate */ ++ segments = NULL; ++ leftmost_segment = (Stem_Segment*) malloc( 4*sizeof ( Stem_Segment ) ); ++ leftmost_segment_not_extrema = leftmost_segment+1; ++ rightmost_segment = leftmost_segment+2; ++ rightmost_segment_not_extrema = leftmost_segment+3; ++ ++ stems = (Stem*) malloc ( (2*MAX_STEMS+2) * sizeof ( Stem ) ); ++ possible_stems = stems+MAX_STEMS; ++ leftmost_stem = possible_stems+MAX_STEMS; ++ rightmost_stem = leftmost_stem + 1; ++ centers = NULL; ++ ++ if ( verbose ) ++ printf("\n"); ++ ++ /* Initialize */ ++ stem_centers=(FT_Long*)calloc( width * 256, sizeof(stem_centers[0]) ); ++ ++ rightmost_segment->x1 = 0; ++ rightmost_segment->x2 = 0; ++ rightmost_segment->y = 0; ++ leftmost_segment->x1 = 99999999; ++ leftmost_segment->x2 = 0; ++ leftmost_segment->y = 0; ++ ++ rightmost_segment_not_extrema->x1 = 0; ++ rightmost_segment_not_extrema->x2 = 0; ++ rightmost_segment_not_extrema->y = 0; ++ leftmost_segment_not_extrema->x1 = 99999999; ++ leftmost_segment_not_extrema->x2 = 0; ++ leftmost_segment_not_extrema->y = 0; ++ ++ /* Locate stem centers for later processing */ ++ for ( h = (FT_UInt)bitmap->rows; h > 0; h--, line += bitmap->pitch ) ++ { ++ current_value = 0; ++ /* Calculate various sums and stem widths of glyph */ ++ for ( xx = 0; xx < width; xx += 1 ) ++ { ++ /* Reallocate (in blocks of 64) */ ++ if( num_segments % 64 == 0 ) ++ segments = (Stem_Segment*) realloc ++ ( segments, ( num_segments + 64 ) * sizeof ( Stem_Segment ) ); ++ ++ /* if line is white, and now has color, it's the start of a stem */ ++ if ( current_value == 0 && line[xx] > 0 ) ++ { ++ /* start of stem */ ++ segments[num_segments].x1 = 256 * xx + ( 255 - line[xx] ); ++ segments[num_segments].y = h; ++ } ++ ++ /* otherwise, if it's currently black and the new value is 0, ++ it's the end of a stem */ ++ else if ( ( current_value > 0 && line[xx] == 0 ) || ++ ( current_value > 0 && xx == width - 1 ) ) ++ { ++ FT_Long stem_center_x; ++ segments[num_segments].x2 = 256 * ( xx - 1 ) + line[xx-1]; ++ ++ if ( xx == width - 1 ) ++ segments[num_segments].x2 += line[xx]; ++ ++ /*stem center is average of start and end of stem */ ++ stem_center_x = ( segments[num_segments].x2 ++ + segments[num_segments].x1 ) / 2; ++ ++ /* Reallocate (in blocks of 32) */ ++ if( num_centers % 32 == 0 ) ++ centers = (Stem_Center*) realloc ++ ( centers, ( num_centers + 32 ) * sizeof ( Stem_Center ) ); ++ centers[num_centers].x = stem_center_x; ++ centers[num_centers].y = h; ++ centers[num_centers].x1 = segments[num_segments].x1; ++ centers[num_centers].x2 = segments[num_segments].x2; ++ ++ num_centers++; ++ ++ stem_centers[stem_center_x] += 1; ++ ++ /* Find left and rightmost points for later calculations */ ++ /* OR - Favor ones that aren't on the top or bottom if */ ++ /* possible to prevent v and w from getting caught later */ ++ if ( segments[num_segments].x1 < leftmost_segment->x1 || ++ ( segments[num_segments].y > 1 && ++ segments[num_segments].y < height && ++ segments[num_segments].x1 == leftmost_segment->x1 ) ) ++ { ++ leftmost_segment->x1 = segments[num_segments].x1; ++ leftmost_segment->x2 = segments[num_segments].x2; ++ leftmost_segment->y = h; ++ } ++ if ( segments[num_segments].x2 > rightmost_segment->x2 || ++ ( segments[num_segments].y > 1 && ++ segments[num_segments].y < height && ++ segments[num_segments].x1 == rightmost_segment->x1 ) ) ++ { ++ rightmost_segment->x1 = segments[num_segments].x1; ++ rightmost_segment->x2 = segments[num_segments].x2; ++ rightmost_segment->y = h; ++ } ++ ++ if ( segments[num_segments].x1 ++ < leftmost_segment_not_extrema->x1 || ++ ( segments[num_segments].y > 1 && ++ segments[num_segments].y < height && ++ segments[num_segments].x1 ++ == leftmost_segment_not_extrema->x1 && ++ h < (FT_UInt)bitmap->rows && h > 0 ) ) ++ { ++ leftmost_segment_not_extrema->x1 = segments[num_segments].x1; ++ leftmost_segment_not_extrema->x2 = segments[num_segments].x2; ++ leftmost_segment_not_extrema->y = h; ++ } ++ if ( segments[num_segments].x2 ++ > rightmost_segment_not_extrema->x2 || ++ ( segments[num_segments].y > 1 && ++ segments[num_segments].y < height && ++ segments[num_segments].x1 ++ == rightmost_segment_not_extrema->x1 && ++ h < (FT_UInt)bitmap->rows && h > 0 ) ) ++ { ++ rightmost_segment_not_extrema->x1 = segments[num_segments].x1; ++ rightmost_segment_not_extrema->x2 = segments[num_segments].x2; ++ rightmost_segment_not_extrema->y = h; ++ } ++ ++ if ( segments[num_segments].x1 < leftmost_point ) ++ leftmost_point = segments[num_segments].x1; ++ ++ if ( segments[num_segments].x2 > rightmost_point ) ++ rightmost_point = segments[num_segments].x2; ++ ++ if ( segments[num_segments].x1 < leftmost_point_not_extrema && ++ h < (FT_UInt)bitmap->rows && h > 0 ) ++ leftmost_point_not_extrema = segments[num_segments].x1; ++ ++ if ( segments[num_segments].x2 > rightmost_point_not_extrema && ++ h < (FT_UInt)bitmap->rows && h > 0 ) ++ rightmost_point_not_extrema = segments[num_segments].x2; ++ ++ num_segments++; ++ } ++ /* else - other conditions - need some error checking here */ ++ current_value = line[xx]; ++ } ++ } ++ ++ /* initialize */ ++ for ( xx = 0; xx < MAX_STEMS; xx +=1 ) ++ { ++ stems[xx].center = 0; ++ stems[xx].count = 0; ++ stems[xx].width = 0; ++ stems[xx].height = 0; ++ possible_stems[xx].center = 0; ++ possible_stems[xx].count = 0; ++ possible_stems[xx].width = 0; ++ possible_stems[xx].height = 0; ++ } ++ ++ valid_stems = 0; ++ valid_possible_stems = 0; ++ ++ /* Determine which centers belong to stems */ ++ center = 0; ++ ++ while ( center < num_centers ) ++ { ++ /* slope at within which to consider a point part of a stem */ ++ /*const FT_UInt slope = 1; ++ const FT_UInt topslope = (256 * 3) / 10; */ ++ ++ /* 10 to 20 with 4 matches seems good, */ ++ /* but 1 or 2 with 3 stems needs to somehow get included */ ++ FT_Int deviation1 = 5; ++ FT_Int deviation2=-1, requirement1 = 4, stem_match_requirement = 3; ++ FT_Int center_difference_in_height; ++ FT_Int center_difference_in_width, valid_center_average; ++ FT_Int smallest_width_ledge, smallest_width_redge; ++ FT_Int x1_difference_in_width, x2_difference_in_width; ++ FT_Bool no_gap_found = FALSE; ++ FT_Bool no_gap_found_ledge = FALSE; ++ FT_Bool no_gap_found_redge = FALSE; ++ FT_Bool stem_detected = FALSE; ++ FT_Int set_width_to, set_center_to; ++ ++ /* seems to not do damage */ ++ /* May not be effective */ ++ requirement1 = height / 4; ++ if ( requirement1 < 5 ) ++ requirement1 = 5; ++ deviation1 = 20; ++ deviation2 = 20; ++ ++ if ( columns_per_pixel == 1 ) ++ deviation1 = deviation2 = 10; ++ ++ if ( (FT_Int)bitmap->rows <= 6 ) ++ deviation1 = 25; ++ ++ if ( (FT_Int)bitmap->rows <= 6 ) ++ deviation2 = 25; ++ ++ if ( columns_per_pixel == 1 && ++ (FT_Int)bitmap->rows <= 6 ) ++ deviation1 = deviation2 = 12; ++ ++ valid_center_average = 0; ++ ++ no_gap_found = no_gap_found_ledge = no_gap_found_redge = FALSE; ++ stem_detected = FALSE; ++ ++ if ( ppem < 11 ) ++ requirement1 = 4; ++ ++ if ( ppem > 18 ) ++ { ++ stem_match_requirement = height / 4; ++ if ( stem_match_requirement < 3 ) ++ stem_match_requirement = 3; ++ } ++ ++ smallest_width_ledge = smallest_width_redge = width * 256; ++ stem_matches = 0; ++ stem_matches_ledge = 0; ++ stem_matches_redge = 0; ++ last_matching_center = -1; ++ last_matching_ledge = -1; ++ last_matching_redge = -1; ++ ++ /* set currently looked at center to center value */ ++ this_center = center; ++ next_center = 0; ++ ++ /* For each center, compare with all other centers to see if others */ ++ /* match the properties of this one */ ++ while ( next_center < num_centers ) ++ { ++ ++ /* calculate differences */ ++ center_difference_in_width = abs ( centers[this_center].x ++ - centers[next_center].x ); ++ center_difference_in_height = abs ( centers[this_center].y ++ - centers[next_center].y ); ++ x1_difference_in_width = abs ( centers[this_center].x1 ++ - centers[next_center].x1 ); ++ x2_difference_in_width = abs ( centers[this_center].x2 ++ - centers[next_center].x2 ); ++ ++ ++ /* property - stem center points that align */ ++ /* if the center is within range, the center is less than */ ++ /* 1/2 the height away, and at least one edge is also within range */ ++ if ( center_difference_in_width ++ < center_difference_in_height * deviation1 && ++ center_difference_in_height ++ <= (FT_Int)bitmap->rows / 2 && ++ /* prevents w from getting caught ---- but also kills m */ ++ ( x1_difference_in_width ++ < center_difference_in_height * deviation2 || ++ x2_difference_in_width ++ < center_difference_in_height * deviation2 ) ) ++ { ++ stem_matches += 1; ++ valid_center_average += centers[next_center].x; ++ ++ /* try to find where the matching centers are far apart */ ++ if ( last_matching_center >= 0 && ++ abs( centers[last_matching_center].y ++ - centers[next_center].y ) >= (FT_Int)bitmap->rows / 2 ) ++ ++ /* try to find where matching centers are next to each other */ ++ if ( last_matching_center >= 0 && ++ abs( centers[last_matching_center].y ++ - centers[next_center].y ) == 1 ) ++ no_gap_found = TRUE; ++ ++ last_matching_center = next_center; ++ } ++ ++ if ( strategy_also_use_edge_detection_for_stems ) ++ { ++ /* property - stem left edge points that align */ ++ /* if the center is within range, */ ++ /* the center is less than 1/2 the height away */ ++ if ( x1_difference_in_width ++ < center_difference_in_height * deviation1 && ++ center_difference_in_height <= (FT_Int)bitmap->rows / 2 ) ++ { ++ stem_matches_ledge += 1; ++ /* may not need for edges */ ++ /*valid_center_average += centers[next_center].x; */ ++ ++ if ( centers[next_center].x2 - centers[next_center].x1 ++ < smallest_width_ledge ) ++ smallest_width_ledge = centers[next_center].x2 ++ - centers[next_center].x1; ++ ++ /* try to find where the matching centers are far apart */ ++ if ( last_matching_ledge >= 0 && ++ abs( centers[last_matching_ledge].y ++ - centers[next_center].y) ++ >= (FT_Int)bitmap->rows / 2 ) ++ ++ /* try to find where matching centers are next to each other */ ++ if ( last_matching_ledge >= 0 && ++ abs( centers[last_matching_ledge].y ++ - centers[next_center].y ) == 1 ) ++ no_gap_found_ledge = TRUE; ++ last_matching_ledge = next_center; ++ } ++ } ++ ++ if ( strategy_also_use_edge_detection_for_stems ) ++ { ++ /* property - stem right edge points that align */ ++ /* if the center is within range, the center is less than 1/2 */ ++ /* the height away */ ++ if ( x2_difference_in_width ++ < center_difference_in_height * deviation1 && ++ center_difference_in_height ++ <= (FT_Int)bitmap->rows / 2 ) ++ { ++ stem_matches_redge += 1; ++ /* may not need for edges */ ++ /*valid_center_average += centers[next_center].x; */ ++ ++ if ( centers[next_center].x2 - centers[next_center].x1 ++ < smallest_width_redge ) ++ smallest_width_redge = centers[next_center].x2 ++ - centers[next_center].x1; ++ ++ /* try to find where the matching centers are far apart */ ++ if ( last_matching_redge >= 0 && ++ abs( centers[last_matching_redge].y ++ - centers[next_center].y ) >= (FT_Int)bitmap->rows / 2 ) ++ ++ /* try to find where matching centers are next to each other */ ++ if ( last_matching_redge >= 0 && ++ abs( centers[last_matching_redge].y ++ - centers[next_center].y ) == 1 ) ++ no_gap_found_redge = TRUE; ++ ++ last_matching_redge = next_center; ++ } ++ } ++ ++ next_center++; ++ } ++ ++ if ( stem_matches > 0 ) ++ valid_center_average /= stem_matches; ++ ++ if ( ( stem_matches >= stem_match_requirement || ++ ( ( (FT_Int)bitmap->rows <= 6 || ppem < 11 ) && ++ stem_matches >= 2 && ++ abs ( valid_center_average ++ - centers[center].x) < deviation1 /2 ) || ++ /* try to catch tightly aligned stuff where the matching centers */ ++ /* are next to each other only */ ++ ( stem_matches == 2 && ++ abs( valid_center_average ++ - centers[center].x) <= deviation1 /2 && ++ no_gap_found && ++ ppem < 18 ) ) && ++ /* catches things like times 16 u but gets a lot of w's too */ ++ /* stem width is less than 1/3 of the bitmap width, */ ++ /* or bitmap_width is small */ ++ ( centers[center].x2 - centers[center].x1 ++ < (m_horiAdvance * 12) / 2 || ++ m_horiAdvance * 12 <= columns_per_pixel * one_pixel ) ) ++ { ++ stem_detected = TRUE; ++ set_width_to = centers[center].x2 - centers[center].x1; ++ set_center_to = centers[center].x; ++ } ++ ++ /* see if edges found anything */ ++ if ( strategy_also_use_edge_detection_for_stems && !stem_detected ) ++ { ++ /* Require no gap for edges */ ++ /* stem width less than 1/3 bitmap width, or bitmap_width is small */ ++ /* The stem occurs on the left side of glyph only */ ++ if ( ( stem_matches_ledge >= stem_match_requirement && ++ no_gap_found_ledge ) && ++ ( centers[center].x2 - centers[center].x1 ++ < ( m_horiAdvance * 12 ) / 2 || ++ m_horiAdvance * 12 <= columns_per_pixel * one_pixel ) && ++ centers[center].x < ( m_horiAdvance * 12 ) / 2 ) ++ { ++ stem_detected = TRUE; ++ set_width_to = smallest_width_ledge; ++ set_center_to = centers[center].x1 + set_width_to / 2; ++ stem_matches = stem_matches_ledge; ++ } ++ /* Require no gap for edges */ ++ /* stem width is less than 1/3 bitmap width, or bitmap_width is small */ ++ /* The stem occurs on the right side of glyph only */ ++ else if ( ( stem_matches_redge >= stem_match_requirement && ++ no_gap_found_redge ) && ++ ( centers[center].x2 - centers[center].x1 ++ < ( m_horiAdvance * 12 ) / 2 || ++ m_horiAdvance * 12 <= columns_per_pixel * one_pixel ) && ++ centers[center].x > (m_horiAdvance * 12) / 2 ) ++ { ++ stem_detected = TRUE; ++ set_width_to = smallest_width_redge; ++ set_center_to = centers[center].x2 - set_width_to / 2; ++ stem_matches = stem_matches_redge; ++ } ++ } ++ ++ ++ /*store and/or replace highest occurrences with 3 or more centers */ ++ /* because this matched, it will become the top dog regardless */ ++ if ( stem_detected && (stem_matches > possible_stems[0].height) ) ++ { ++ /* if this is the first stem just go ahead */ ++ if ( valid_possible_stems == 0 ) ++ { ++ valid_possible_stems = 1; ++ possible_stems[0].center = set_center_to; ++ possible_stems[0].count = stem_matches; ++ possible_stems[0].width = set_width_to; ++ possible_stems[0].height = stem_matches; ++ } ++ ++ /* otherwise, if there is already a stem */ ++ else if ( valid_possible_stems == 1 ) ++ { ++ /* if stem is within range of existing one, replace existing one */ ++ ++ /* if the stem isn't within the range of this one swap it with */ ++ /* next one first */ ++ if ( abs ( set_center_to - possible_stems[0].center ) ++ >= one_pixel * 2 ) ++ { ++ swap_stem ( &possible_stems[0], &possible_stems[1] ); ++ valid_possible_stems = 2; ++ } ++ possible_stems[0].center = set_center_to; ++ possible_stems[0].count = stem_matches; ++ possible_stems[0].width = set_width_to; ++ possible_stems[0].height = stem_matches; ++ } ++ ++ /* otherwise if there are already 2 stems */ ++ else if ( valid_possible_stems >= 2 ) ++ { ++ /* if the stem is within the range of existing one, replace */ ++ /* existing one */ ++ if ( abs ( set_center_to - possible_stems[0].center ) ++ <= one_pixel * 2 ) ++ { ++ possible_stems[0].center = set_center_to; ++ possible_stems[0].count = stem_matches; ++ possible_stems[0].width = set_width_to; ++ possible_stems[0].height = stem_matches; ++ } ++ /* if the stem isn't within the range of this one */ ++ else ++ { ++ /* see if within range of next one and swap if so and proceed */ ++ /* overwriting it */ ++ if ( abs ( set_center_to - possible_stems[1].center ) ++ <= one_pixel * 2 ) ++ swap_stem ( &possible_stems[0], &possible_stems[1] ); ++ ++ /* otherwise see if in range of third one */ ++ else if ( abs ( set_center_to - possible_stems[2].center ) ++ <= one_pixel * 2 ) ++ swap_stem ( &possible_stems[0], &possible_stems[2] ); ++ ++ /* otherwise this is the new top dog, so demote everything */ ++ else ++ { ++ swap_stem ( &possible_stems[1], &possible_stems[2] ); ++ swap_stem ( &possible_stems[0], &possible_stems[1] ); ++ valid_possible_stems += 1; ++ } ++ possible_stems[0].center = set_center_to; ++ possible_stems[0].count = stem_matches; ++ possible_stems[0].width = set_width_to; ++ possible_stems[0].height = stem_matches; ++ } ++ } ++ } ++ ++ else if ( stem_matches > possible_stems[1].height && ++ set_center_to != 0 ) ++ { ++ ++ /* make sure it doesn't match the first stem */ ++ if ( abs ( set_center_to - possible_stems[0].center ) >= one_pixel * 2 ) ++ { ++ ++ /* if this is the second stem */ ++ if ( valid_possible_stems == 1 ) ++ valid_possible_stems = 2; ++ ++ /* otherwise if there is already a stem here */ ++ else if ( valid_possible_stems >= 2 ) ++ { ++ /* if it doesn't match the second stem, proceed to swap out */ ++ /* with the third. if it does, replace it */ ++ if ( abs ( set_center_to - possible_stems[1].center ) ++ >= one_pixel * 2 ) ++ { ++ swap_stem ( &possible_stems[1], &possible_stems[2] ); ++ valid_possible_stems +=1; ++ } ++ } ++ possible_stems[1].center = set_center_to; ++ possible_stems[1].count = stem_matches; ++ possible_stems[1].width = set_width_to; ++ possible_stems[1].height = stem_matches; ++ } ++ } ++ ++ else if ( stem_matches > possible_stems[2].height && ++ set_center_to != 0 ) ++ { ++ /* if it doesn't match the first or second one */ ++ if ( abs( set_center_to - possible_stems[0].center) >= one_pixel * 2 && ++ abs( set_center_to - possible_stems[1].center) >= one_pixel * 2 ) ++ { ++ if ( valid_possible_stems == 2 ) ++ valid_possible_stems += 1; ++ ++ possible_stems[2].center = set_center_to; ++ possible_stems[2].count = stem_matches; ++ possible_stems[2].width = set_width_to; ++ possible_stems[1].height = stem_matches; ++ } ++ } ++ ++ if ( valid_possible_stems > 3 ) ++ valid_possible_stems = 3; ++ ++ center++; ++ } ++ ++ /* promote to stem */ ++ if ( valid_possible_stems > 0 ) ++ { ++ stems[0].center = possible_stems[0].center; ++ stems[0].count = possible_stems[0].count; ++ stems[0].width = possible_stems[0].width; ++ stems[0].height = possible_stems[0].height; ++ stems[0].generated = FALSE; ++ valid_stems++; ++ } ++ ++ if ( valid_stems == 1 && ++ valid_possible_stems > 1 ) ++ { ++ stems[1].center = possible_stems[1].center; ++ stems[1].count = possible_stems[1].count; ++ stems[1].width = possible_stems[1].width; ++ stems[1].height = possible_stems[1].height; ++ stems[1].generated = FALSE; ++ valid_stems++; ++ } ++ ++ if ( valid_stems == 2 && ++ valid_possible_stems > 2 && ++ possible_stems[2].center != 0 ) ++ { ++ stems[2].center = possible_stems[2].center; ++ stems[2].count = possible_stems[2].count; ++ stems[2].width = possible_stems[2].width; ++ stems[2].height = possible_stems[2].height; ++ stems[2].generated = FALSE; ++ valid_stems++; ++ } ++ ++ /* sort stems in x direction */ ++ if ( valid_stems == 3 ) ++ { ++ if ( stems[0].center > stems[1].center ) ++ swap_stem ( &stems[0], &stems[1] ); ++ ++ if ( stems[0].center > stems[2].center ) ++ swap_stem ( &stems[1], &stems[2] ); ++ ++ if ( stems[1].center > stems[2].center ) ++ swap_stem ( &stems[1], &stems[2] ); ++ ++ if ( stems[0].center > stems[1].center ) ++ swap_stem ( &stems[0], &stems[1] ); ++ ++ /* only look at first and last stem for now */ ++ swap_stem ( &stems[1], &stems[2] ); ++ } ++ ++ /* synthesize stems - Works, but needs work */ ++ if ( ( strategy_synthesize_stems || ++ known_stem_values->synth_stems ) && ++ valid_stems == 0 && ++ ppem > 10 ) ++ { ++ /* if the leftmost segment's leftmost point is the same as the glyph's */ ++ /* leftmost point, and it is of reasonable width, and is not on the */ ++ /* top or bottom of the bitmap */ ++ if ( leftmost_segment_not_extrema->x1 ++ == leftmost_point_not_extrema && ++ abs ( leftmost_segment_not_extrema->x2 ++ - leftmost_segment_not_extrema->x1 ) ++ < ( rightmost_point_not_extrema ++ - leftmost_point_not_extrema ) / 3 && ++ leftmost_segment_not_extrema->y < height && ++ leftmost_segment_not_extrema->y > 1 ) ++ { ++ stems[valid_stems].center = ( leftmost_segment_not_extrema->x2 ++ + leftmost_segment_not_extrema->x1 ) / 2; ++ stems[valid_stems].width = leftmost_segment_not_extrema->x2 ++ - leftmost_segment_not_extrema->x1; ++ stems[valid_stems].generated = TRUE; ++ valid_stems += 1; ++ } ++ ++ ++ if ( rightmost_segment_not_extrema->x2 ++ == rightmost_point_not_extrema && ++ abs ( rightmost_segment_not_extrema->x2 ++ - rightmost_segment_not_extrema->x1 ) ++ < ( rightmost_point_not_extrema ++ - leftmost_point_not_extrema ) / 3 && ++ rightmost_segment_not_extrema->y < height && ++ rightmost_segment_not_extrema->y > 1 ) ++ { ++ stems[valid_stems].center = ( rightmost_segment_not_extrema->x2 ++ + rightmost_segment_not_extrema->x1 ) / 2; ++ stems[valid_stems].width = rightmost_segment_not_extrema->x2 ++ - rightmost_segment_not_extrema->x1; ++ stems[valid_stems].generated = TRUE; ++ valid_stems += 1; ++ } ++ ++ } ++ ++ /* sort stems in x direction */ ++ if ( valid_stems > 1 && stems[0].center > stems[1].center ) ++ swap_stem ( &stems[0], &stems[1] ); ++ ++ if ( valid_stems == 0 && known_stem_values->stem_translating != 0 ) ++ { ++ *translate_value += known_stem_values->stem_translating; ++ ++ if ( strategy_use_strengths ) ++ { ++ /* consider 1/2 pixel the max when strength is at 100%, ++ unless translate is already greater than that */ ++ FT_Int strength_cutoff = 32; ++ ++ ++ if ( abs ( *translate_value ) > strength_cutoff) ++ strength_cutoff = *translate_value; ++ ++ max_strength = ( strength_cutoff * alignment_strength ) / 100; ++ ++ if ( *translate_value < -max_strength ) ++ *translate_value = -max_strength; ++ else if ( *translate_value > max_strength ) ++ *translate_value = max_strength; ++ } ++ } ++ else ++ /* Start snapping */ ++ { ++ FT_Int center_offset; ++ FT_Int modulus; ++ FT_Int delta, delta2; ++ FT_Long stem_distance = 1, new_distance = 1; ++ FT_Int distance_floor, distance_ceiling; ++ FT_Int translate_value2 = 0; ++ FT_Int main_stem = 0; ++ FT_Int lbearing = m_horiBearingX * 12; ++ FT_Int bitmap_stem_location = stems[0].center; ++ FT_Int advance_stem_location = bitmap_stem_location ++ + lbearing - one_pixel; ++ FT_Int advance_width = m_horiAdvance * 12; ++ FT_Int original_advance_width = 12 * ( slot->linearHoriAdvance >> 10 ); ++ FT_Int glyph_width = rightmost_point - leftmost_point; ++ FT_Int stem_width = stems[0].width; ++ FT_Int advance_leftmost_location = leftmost_point ++ + lbearing - one_pixel; ++ FT_Int advance_rightmost_location = rightmost_point ++ + lbearing - one_pixel; ++ ++#define proposed_transformed_point(point) \ ++ point * (float)(new_distance) / (float)(stem_distance) \ ++ + *translate_value * 12 - ( stems[main_stem].center * (float)(new_distance) \ ++ / (float)(stem_distance) - stems[main_stem].center) ++ ++#define proposed_translated_point(point) point + *translate_value * 12 ++ ++ center_offset = one_pixel / 2; /* half pixel */ ++ modulus = one_pixel; /* whole pixel */ ++ ++ /* Determine center_offset via known values */ ++ if ( known_stem_values->stem_width >= 0 ) ++ { ++ if ( known_stem_values->stem_width % 2 == 0 ) ++ center_offset = 0; ++ else ++ center_offset = one_pixel / 2; ++ } ++ /* otherwise do intelligent guessing, if set */ ++ else if ( strategy_auto_change_center_offset && ++ ppem >= STEM_WIDTH_2_PPEM && ++ stems[0].width < one_pixel * 1.45 ) ++ center_offset = one_pixel / 2; ++ else if ( strategy_auto_change_center_offset && ++ ppem >= STEM_WIDTH_2_PPEM && ++ stems[0].width >= one_pixel * 1.45 && ++ stems[0].width < one_pixel * 2.6 ) ++ center_offset = 0; ++ else if ( strategy_auto_change_center_offset && ++ ppem >= STEM_WIDTH_2_PPEM && ++ stems[0].width >= one_pixel * 2.6 && ++ stems[0].width < one_pixel * 3.6 ) ++ center_offset = one_pixel / 2; ++ else if ( strategy_auto_change_center_offset && ++ ppem >= STEM_WIDTH_2_PPEM ) ++ center_offset = ++ ( one_pixel ++ * ( ( ( (int)( stems[0].width + one_pixel / 2 ) ) ++ / one_pixel ) % 2 ) ) / 2; ++ ++ /* Snap to closest translate and scale values by default */ ++ if ( valid_stems >= 1 ) ++ { ++ /* closest snapping point for stem 0 */ ++ delta = ( stems[0].center + center_offset ) % modulus; ++ ++ if ( delta < modulus / 2 ) ++ /* snap left */ ++ *translate_value = -delta / ( columns_per_pixel * 4 ); ++ else ++ /* snap right */ ++ *translate_value = ( modulus - delta ) / ( columns_per_pixel * 4 ); ++ } ++ ++ if ( strategy_use_d_correction ) ++ { ++ /* if the only stem is in the last 1/3 of glyph width, the advance */ ++ /* is 6 pixels, the ppem 11, and doing so doesn't violate bitmap , */ ++ /* boundaries force it to snap right */ ++ if ( valid_stems == 1 && ++ advance_stem_location > (advance_width * 2) / 3 && ++ advance_width == 6 * one_pixel && ++ rightmost_point + modulus - delta ++ <= ( width - (columns_per_pixel * 2) / 3) * 256 && ++ ppem == 11 ) ++ *translate_value = ( modulus - delta ) / ( columns_per_pixel * 4 ); ++ } + +-#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING ++ if ( strategy_use_strengths ) ++ { ++ /* consider 1/2 pixel the max when strength is at 100%, ++ unless translate is already greater than that */ ++ FT_Int strength_cutoff = 32; ++ if ( abs ( *translate_value ) > strength_cutoff ) ++ strength_cutoff = *translate_value; ++ ++ max_strength = ( strength_cutoff * alignment_strength ) / 100; ++ ++ if ( *translate_value < -max_strength ) ++ *translate_value = -max_strength; ++ else if ( *translate_value > max_strength ) ++ *translate_value = max_strength; ++ } + +- FT_Vector* sub = render->root.library->lcd_geometry; ++ /* If 2 stems is detected, scale distance ++ between in order to land on pixels */ ++ if ( valid_stems >= 2 ) ++ { ++ stem_distance = abs ( stems[1].center - stems[0].center ); ++ ++ delta = stem_distance % modulus; ++ new_distance = stem_distance - delta; ++ ++ distance_floor = stem_distance - delta; ++ distance_ceiling = stem_distance + ( modulus - delta ); ++ ++ if ( delta < modulus / 2 ) ++ new_distance = distance_floor; ++ else ++ new_distance = distance_ceiling; ++ ++ if ( columns_per_pixel == 3 && ++ valid_stems == 3 && ++ strategy_use_m_control && ++ ( width - 2 * columns_per_pixel ) > 6 * columns_per_pixel && ++ ppem > 8 && ++ ( advance_stem_location - advance_leftmost_location ) ++ < stems[main_stem].width * 2 ) ++ { ++ /* Possibly use 2 only when compatible widths is on? */ ++ FT_Int mod_factor = 2; ++ ++ if ( verbose ) ++ printf ( "USING M CONTROL "); ++ ++ distance_floor = stem_distance ++ - stem_distance % ( modulus * mod_factor ) ; ++ distance_ceiling = distance_floor + modulus * mod_factor; ++ ++ new_distance = distance_ceiling; ++ ++ /* force certain ideal situations */ ++ /* these 2 are mostly safe to do */ ++ if ( distance_ceiling ++ + one_pixel * columns_per_pixel == advance_width && ++ stem_width < one_pixel * 1.25 ) ++ new_distance = distance_ceiling; ++ /* NEED TO FIGURE OUT A WAY TO DETERMINE WHETHER ++ THAT NUDGE IS UP OR DOWN */ ++ else if ( stem_distance + one_pixel * 2.6 >= advance_width && ++ stem_width < one_pixel * 1.25 ) ++ new_distance = distance_ceiling; ++ ++ if ( proposed_transformed_point ( leftmost_point ) ++ < one_third_pixel * 2 || ++ proposed_transformed_point ( rightmost_point ) ++ > ( width -2 ) * one_third_pixel ) ++ new_distance = distance_floor; ++ ++ /* NEED TO IGNORE SERIF Ms HERE */ ++ /* perhaps check bitmap boundaries instead??? */ ++ if ( strategy_bearing_correction && new_distance == distance_ceiling ) ++ { ++ /* Correct if bearings are made substantially worse ++ (more than 1/3 a pixel beyond advance) */ ++ if ( proposed_transformed_point( advance_rightmost_location ) ++ > advance_width + one_third_pixel && ++ proposed_transformed_point( advance_rightmost_location ) ++ > advance_rightmost_location && ++ -proposed_transformed_point( advance_leftmost_location ) ++ < advance_rightmost_location - advance_width ) ++ new_distance = distance_floor; ++ } ++ ++ if ( known_stem_values->m >= 0 ) ++ { ++ if ( known_stem_values->m == 0 ) ++ new_distance = distance_floor; ++ else ++ new_distance = distance_ceiling; ++ } ++ ++ if ( ( rightmost_point - leftmost_point) - ++ ( ( rightmost_point * *scale_value) ++ - ( leftmost_point * *scale_value ) ) >= one_pixel * 1.5 ) ++ { ++ *scale_value = 1.0; ++ *translate_value = 0; ++ goto Exit; ++ } + ++ } ++ else if ( columns_per_pixel == 1 && ++ valid_stems == 3 && ++ strategy_use_m_control && valid_stems == 3 && ++ width >= 6 * columns_per_pixel && ++ ppem > 8 && ++ ( advance_stem_location - advance_leftmost_location ) ++ < stems[main_stem].width * 2 ) ++ { ++ /* Possibly use 2 only when compatible widths is on? */ ++ FT_Int mod_factor = 2; ++ ++ if ( verbose ) ++ printf ("USING M CONTROL "); ++ distance_floor = stem_distance - stem_distance ++ % ( modulus * mod_factor) ; ++ distance_ceiling = distance_floor + modulus * mod_factor; ++ ++ new_distance = distance_ceiling; ++ ++ /* force certain ideal situations */ ++ /* these 2 are mostly safe to do */ ++ if ( distance_ceiling ++ + one_pixel * columns_per_pixel == advance_width && ++ stem_width < one_pixel * 1.25 ) ++ new_distance = distance_ceiling; ++ /* NEED TO FIGURE OUT A WAY TO DETERMINE WHETHER ++ THAT NUDGE IS UP OR DOWN */ ++ else if ( stem_distance + one_pixel * 2.6 >= advance_width && ++ stem_width < one_pixel * 1.25 ) ++ new_distance = distance_ceiling; ++ ++ if ( proposed_transformed_point( leftmost_point ) < 0 || ++ proposed_transformed_point( rightmost_point ) ++ > width * one_pixel - 2 * one_third_pixel ) ++ new_distance = distance_floor; ++ ++ /* NEED TO IGNORE SERIF Ms HERE */ ++ /* perhaps check bitmap boundaries instead??? */ ++ if ( strategy_bearing_correction && new_distance == distance_ceiling ) ++ { ++ /* Correct if bearings are made substantially worse ++ (more than 1/3 a pixel beyond advance) */ ++ if ( proposed_transformed_point( advance_rightmost_location ) ++ > advance_width + one_third_pixel && ++ proposed_transformed_point( advance_rightmost_location ) ++ > advance_rightmost_location && ++ -proposed_transformed_point( advance_leftmost_location ) ++ < advance_rightmost_location - advance_width ) ++ new_distance = distance_floor; ++ } ++ ++ if ( known_stem_values->m >= 0 ) ++ { ++ if ( known_stem_values->m == 0 ) ++ new_distance = distance_floor; ++ else ++ new_distance = distance_ceiling; ++ } ++ ++ ++ if ( ( rightmost_point - leftmost_point ) ++ - ( ( rightmost_point * *scale_value ) ++ - ( leftmost_point * *scale_value ) ) >= one_pixel * 1.5 ) ++ { ++ *scale_value = 1.0; ++ *translate_value = 0; ++ goto Exit; ++ } + +- /* set up default subpixel geometry for striped RGB panels. */ +- sub[0].x = -21; +- sub[0].y = 0; +- sub[1].x = 0; +- sub[1].y = 0; +- sub[2].x = 21; +- sub[2].y = 0; ++ } ++ else ++ { ++ if ( strategy_fit_to_width ) ++ new_distance = advance_width - 3 * one_pixel; ++ else if ( known_stem_values->stem_scaling >= 0 ) ++ { ++ if ( known_stem_values->stem_scaling > 0 ) ++ new_distance = distance_ceiling; ++ else ++ new_distance = distance_floor; ++ ++ /* enforce advance width boundaries */ ++ /* TOO RESTRICTIVE ON SERIF FONTS */ ++ if ( proposed_transformed_point( advance_rightmost_location ) ++ >= advance_width || ++ proposed_transformed_point( advance_leftmost_location ) ++ <= 0 ) ++ new_distance = distance_floor; ++ ++ /* enforce literal bitmap boundaries if no translate room */ ++ if ( ( proposed_transformed_point(rightmost_point) >= width * 256 ++ || proposed_transformed_point(leftmost_point ) <= one_pixel ) ++ && new_distance + one_pixel * 3 > advance_width ) ++ new_distance = distance_floor; ++ ++ } ++ else if ( strategy_translate_using_closest_stem ) ++ { ++ /* closest snapping point for stem 1 */ ++ delta2 = ( stems[1].center + center_offset ) % modulus; ++ ++ if ( delta2 < modulus / 2 ) ++ /* snap left */ ++ translate_value2 = -delta2 / ( columns_per_pixel * 4 ); ++ else ++ /* snap right */ ++ translate_value2 = ( modulus - delta2 ) ++ / ( columns_per_pixel * 4 ); ++ ++ if ( abs ( translate_value2 ) < abs ( *translate_value ) ) ++ { ++ *translate_value = translate_value2; ++ main_stem = 1; ++ } ++ ++ } ++ else if ( strategy_scale_to_closest_centers ) ++ { ++ /* closest snapping point for stem 0 */ ++ delta = ( stems[0].center + center_offset ) % modulus; ++ delta2 = ( stems[1].center + center_offset ) % modulus; ++ ++ if ( delta < modulus / 2 ) ++ /* stretch left */ ++ new_distance = delta + stem_distance; ++ else ++ /* stretch right */ ++ new_distance = delta - modulus + stem_distance; ++ ++ if ( delta2 < modulus / 2 ) ++ new_distance -= delta2; /* stretch left */ ++ else ++ new_distance += modulus - delta2; /* stretch right */ ++ ++ } ++ else if ( strategy_scale_to_closest_centers_up_only ) ++ { ++ FT_Int net_change = 0; ++ ++ /* closest snapping point for stem 0 */ ++ delta = ( stems[0].center + center_offset ) % modulus; ++ delta2 = ( stems[1].center + center_offset ) % modulus; ++ ++ if ( delta < modulus / 2 ) ++ net_change = delta; /* stretch left */ ++ else ++ net_change = -( modulus - delta ); /* stretch right */ ++ ++ if ( delta2 < modulus / 2 ) ++ net_change -= delta2; /* stretch left */ ++ else ++ net_change += modulus - delta2; /* stretch right */ ++ ++ if ( net_change > 0 && ++ proposed_transformed_point( advance_rightmost_location ) ++ < advance_width && ++ proposed_transformed_point( advance_leftmost_location ) > 0 ) ++ new_distance = distance_ceiling; ++ } ++ ++ else if ( strategy_always_use_distance_ceiling ) ++ { ++ if ( proposed_transformed_point( advance_rightmost_location ) ++ < advance_width && ++ proposed_transformed_point( advance_leftmost_location ) > 0 ) ++ new_distance = distance_ceiling; ++ } ++ } + +-#elif 0 /* or else, once ClearType patents expire */ ++ if ( strategy_use_strengths ) ++ { ++ FT_Int strength_cutoff = center_offset; + +- FT_Library_SetLcdFilter( render->root.library, FT_LCD_FILTER_DEFAULT ); + +-#endif ++ delta2 = new_distance - stem_distance; + +- render->clazz->raster_class->raster_reset( render->raster, NULL, 0 ); ++ if ( abs ( delta2 ) > strength_cutoff ) ++ strength_cutoff = delta2; + +- return 0; +- } ++ max_strength = ( strength_cutoff * fitting_strength ) / 100; + ++ if ( delta2 < -max_strength ) ++ new_distance = stem_distance - max_strength; ++ else if ( delta2 > max_strength ) ++ new_distance = stem_distance + max_strength; ++ } + +- /* sets render-specific mode */ +- static FT_Error +- ft_smooth_set_mode( FT_Renderer render, +- FT_ULong mode_tag, +- FT_Pointer data ) +- { +- /* we simply pass it to the raster */ +- return render->clazz->raster_class->raster_set_mode( render->raster, +- mode_tag, +- data ); +- } ++ *scale_value = (float)( new_distance ) / (float)( stem_distance ); ++ *translate_value = *translate_value ++ - ( (float)( stems[main_stem].center * (float)new_distance ) ++ / (float)stem_distance - stems[main_stem].center ) / 12; + +- /* transform a given glyph image */ +- static FT_Error +- ft_smooth_transform( FT_Renderer render, +- FT_GlyphSlot slot, +- const FT_Matrix* matrix, +- const FT_Vector* delta ) +- { +- FT_Error error = FT_Err_Ok; ++ if ( valid_stems == 2 ) ++ *embolden_value = ( 64.0 / *scale_value - 64.0 ); + ++ if ( valid_stems == 3 ) ++ *embolden_value = ( 64.0 / *scale_value - 64.0 ) / 1.5; ++ } + +- if ( slot->format != render->glyph_format ) +- { +- error = FT_THROW( Invalid_Argument ); ++ if ( verbose ) ++ printf ( "%lu stems:", valid_stems ); ++ ++ if ( valid_stems == 1 && verbose ) ++ printf ( "1 stem: bitmapwidth:%d glyphwidth:%f glyph_width:%f center:%f bearing:%f advance:%f lhadvance:%f stemwidth:%f %d %d", ++ (width - 6) / columns_per_pixel, ++ (float)m_width / 64.0, ++ (float)glyph_width / (float)one_pixel, ++ (float)( (float)advance_stem_location ) / (float)one_pixel, ++ (float)m_horiBearingX / 64.0, ++ (float)m_horiAdvance / 64.0, ++ (float)linearHoriAdvance / 64.0, ++ (float)stems[0].width / (float)one_pixel, ++ advance_width, original_advance_width ); ++ else if ( valid_stems >= 2 && verbose ) ++ printf ( "%lu stems: bitmapwidth:%d center1:%f center2:%f difference:%f bearing:%f advance:%f advstemloc:%f ", ++ valid_stems, ++ (width - 6) / columns_per_pixel, ++ ( (float)advance_stem_location ) / (float)one_pixel, ++ ( (float)advance_stem_location ++ + (float)abs ( stems[1].center ++ - stems[0].center) ) / (float)one_pixel, ++ ( (float)abs ( stems[1].center ++ - stems[0].center ) ) / (float)one_pixel, ++ (float)m_horiBearingX / 64.0, ++ (float)m_horiAdvance / 64.0, ++ (float)advance_stem_location / (float)one_pixel ); ++ ++ if ( strategy_bearing_correction ) ++ { ++ /* Correct if negative bearings are made substantially worse */ ++ /* (more than 1/3 a pixel) */ ++ if ( proposed_transformed_point( advance_rightmost_location ) ++ > advance_width && ++ proposed_transformed_point( advance_rightmost_location ) ++ > advance_rightmost_location && ++ -proposed_transformed_point( advance_leftmost_location ) ++ < advance_rightmost_location - advance_width && ++ *translate_value ++ > one_third_pixel / ( columns_per_pixel * 4 ) ) ++ { ++ *translate_value -=64 ; ++ if ( verbose ) ++ printf ( "TRANSLATING -64 " ); ++ } ++ } + goto Exit; + } + +- if ( matrix ) +- FT_Outline_Transform( &slot->outline, matrix ); ++ Exit: + +- if ( delta ) +- FT_Outline_Translate( &slot->outline, delta->x, delta->y ); ++#define transformed_point( point ) point * *scale_value + *translate_value * 12 + +- Exit: +- return error; ++ if ( strategy_correct_out_of_bounds_outlines ) ++ { ++ /* Correct if outside bitmap */ ++ if ( transformed_point( rightmost_point ) ++ >= width * 256 - 2 * one_third_pixel && ++ transformed_point( leftmost_point ) ++ > one_pixel + 2 * one_third_pixel ) ++ *translate_value -=64 ; ++ else if ( transformed_point( leftmost_point ) ++ <= one_pixel / 2 && ++ transformed_point( rightmost_point ) ++ <= width * 256 - ( one_pixel + one_pixel / 2 ) ) ++ *translate_value += 64; ++ } ++ ++ STVALUES ++ free ( centers ); ++ free ( segments ); ++ free ( stem_centers ); ++ free ( stems ); ++ free ( leftmost_segment ); + } + + +- /* return the glyph's control box */ ++ /* Gamma correction */ + static void +- ft_smooth_get_cbox( FT_Renderer render, +- FT_GlyphSlot slot, +- FT_BBox* cbox ) ++ _ft_lcd_gamma_correction_correction ( FT_Bitmap* bitmap, ++ FT_Render_Mode mode, ++ FT_GlyphSlot slot, ++ float gamma_correction_lt, ++ float gamma_correction_value ) + { +- FT_ZERO( cbox ); ++ if ( gamma_correction_value != 1.0 ) ++ { ++ FT_UInt width = (FT_UInt)bitmap->width; ++ FT_UInt height = (FT_UInt)bitmap->rows; ++ FT_Byte* line = bitmap->buffer; ++ float ppem = (float)slot->face->size->metrics.x_ppem; + +- if ( slot->format == render->glyph_format ) +- FT_Outline_Get_CBox( &slot->outline, cbox ); ++ ++ if ( !slot->face || !slot->face->size ) return; ++ ++ if ( ppem >= 5 ) ++ for ( height = (FT_UInt)bitmap->rows; ++ height > 0; ++ height--, line += bitmap->pitch ) ++ { ++ FT_UInt xx; ++ ++ ++ for ( xx = 0; xx < width; xx += 1 ) ++ { ++ /*normal*/ ++ /*line[xx] = pseudo_gamma ( line[xx], gamma_correction_value );*/ ++ ++ /* sloped */ ++ /*line[xx] = pseudo_gamma ( line[xx], gamma_correction_value - 5 ++ * (1-gamma_correction_value)/(gamma_correction_lt -5) ++ + ((1-gamma_correction_value)/(gamma_correction_lt -5)) * ppem );*/ ++ ++ /* 1/3-sloped */ ++ line[xx] = pseudo_gamma ( line[xx], gamma_correction_value - 5 ++ * ( ( 1 - gamma_correction_value ) ++ / ( 3 * ( gamma_correction_lt -5 ) ) ) ++ + ( ( 1 - gamma_correction_value ) ++ / ( 3 * ( gamma_correction_lt -5) ) ) * ppem ); ++ } ++ } ++ } + } + ++#endif + + /* convert a slot's glyph image into a bitmap */ + static FT_Error +@@ -116,17 +2321,218 @@ + const FT_Vector* origin, + FT_Render_Mode required_mode ) + { +- FT_Error error = FT_Err_Ok; +- FT_Outline* outline = &slot->outline; ++ FT_Error error; ++ FT_Outline* outline = NULL; ++ FT_Outline* outline_orig = NULL; ++ FT_BBox cbox; ++ FT_Pos width, height, pitch, ppem; ++#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING ++ FT_Pos height_org, width_org; ++#endif + FT_Bitmap* bitmap = &slot->bitmap; + FT_Memory memory = render->root.memory; +- FT_Pos x_shift = 0; +- FT_Pos y_shift = 0; + FT_Int hmul = ( mode == FT_RENDER_MODE_LCD ); + FT_Int vmul = ( mode == FT_RENDER_MODE_LCD_V ); ++ FT_Pos x_shift = 0; ++ FT_Pos y_shift = 0; ++ FT_Pos x_left, y_top; + + FT_Raster_Params params; + ++ FT_Bool have_translated_origin = FALSE; ++ FT_Bool have_outline_shifted = FALSE; ++ FT_Bool have_buffer = FALSE; ++ ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ FT_Matrix scaleMat; ++ FT_Long translate_value = 0; ++ float scale_value = 1.0; ++ FT_Int align_called = 0; ++ ++ ++ int chromeos_style_sharpening_strength = 0; ++ int alignment_strength = 0; ++ int fitting_strength = 0; ++ int fringe_filter_strength = 0; ++ int grayscale_filter_strength = 0; ++ ++ int autohint_horizontal_stem_darken_strength = 0; ++ int autohint_vertical_stem_darken_strength = 0; ++ ++ int windows_style_sharpening_strength = 0; ++ float gamma_correction_value = 1; ++ float gamma_correction_lt = 0; ++ ++ FT_Int brightness_value = 0.0; ++ FT_Int contrast_value = 0.0; ++ ++ FT_Int snapping_sliding_scale_value = 0; ++ ++ FT_Int global_embolden_x_value = 0; ++ FT_Int global_embolden_y_value = 0; ++ ++ FT_Int bold_embolden_x_value = 0; ++ FT_Int bold_embolden_y_value = 0; ++ ++ FT_Byte chromeos_cutoff; ++ double chromeos_gamma_value; ++ ++ float embolden_value = 0.0; ++ FT_Bool autohinted = FALSE; ++ FT_Bool use_various_tweaks = FALSE; ++ FT_Pos cur_width = infinality_cur_width; ++ ++ const FT_Int MIN_PPEM = 1; ++ /*const FT_Int MAX_PPEM = 100; */ ++ ++ FT_Bool use_known_settings_on_selected_fonts; ++ ++ if ( slot->face && ++ slot->face->size && ++ slot->face->size->metrics.x_ppem ) ++ ppem = slot->face->size->metrics.x_ppem; ++ else ++ ppem = 0; ++ ++ if ( cur_width ) ++ { ++ autohinted = TRUE; ++ } ++ if( ftinf ){ ++ const float *f=ftinf->gamma_correction; ++ ++ use_known_settings_on_selected_fonts=ftinf->use_known_settings_on_selected_fonts; ++ use_various_tweaks=ftinf->use_various_tweaks; ++ snapping_sliding_scale_value=ftinf->stem_snapping_sliding_scale; ++ ++ alignment_strength=ftinf->stem_alignment_strength; ++ if ( snapping_sliding_scale_value != 0 ) ++ alignment_strength = sliding_scale(10, snapping_sliding_scale_value, alignment_strength, 100, ppem); ++ ++ fitting_strength=ftinf->stem_fitting_strength; ++ if ( snapping_sliding_scale_value != 0 ) ++ fitting_strength = sliding_scale(10, snapping_sliding_scale_value, fitting_strength, 100, ppem); ++ ++ chromeos_style_sharpening_strength=ftinf->chromeos_style_sharpening_strength; ++ ++ if ( ppem > 10 ) ++ chromeos_style_sharpening_strength = ++ ( chromeos_style_sharpening_strength * ppem ) / 10; ++ ++ if ( chromeos_style_sharpening_strength > 100 ) ++ chromeos_style_sharpening_strength = 100; ++ ++ brightness_value=ftinf->brightness; ++ contrast_value=ftinf->contrast; ++ ++ windows_style_sharpening_strength=ftinf->windows_style_sharpening_strength; ++ ++ /* Decrease effect slightly to have a more linear increase in sharpness */ ++ windows_style_sharpening_strength = ++ ( ( windows_style_sharpening_strength ++ * windows_style_sharpening_strength ) / 100 ++ + windows_style_sharpening_strength ) / 2; ++ ++ gamma_correction_lt = f[0]; ++ gamma_correction_value = f[1] / 100.0f; ++ ++ fringe_filter_strength=ftinf->fringe_filter_strength; ++ grayscale_filter_strength=ftinf->grayscale_filter_strength; ++ ++ autohint_horizontal_stem_darken_strength=ftinf->autohint_horizontal_stem_darken_strength; ++ autohint_vertical_stem_darken_strength=ftinf->autohint_vertical_stem_darken_strength; ++ ++ global_embolden_x_value=ftinf->global_embolden_x_value; ++ global_embolden_y_value=ftinf->global_embolden_y_value; ++ ++ bold_embolden_x_value=ftinf->bold_embolden_x_value; ++ bold_embolden_y_value=ftinf->bold_embolden_y_value; ++ } else { ++ use_known_settings_on_selected_fonts=FALSE; ++ } ++ ++ /* set gamma value to 1 if out of range */ ++ if ( slot->face && ++ slot->face->size && ++ slot->face->size->metrics.x_ppem ) ++ { ++ if ( slot->face->size->metrics.x_ppem >= gamma_correction_lt ) ++ gamma_correction_value = 1; ++ } ++ else ++ gamma_correction_value = 1; ++ ++ if( use_various_tweaks && ++ slot->face && ++ slot->face->style_name ) ++ { ++ /* needs to also check for artifical italics */ ++ if ( strcasestr(slot->face->style_name, "Italic" ) || ++ strcasestr(slot->face->style_name, "Oblique" ) ) ++ { ++ windows_style_sharpening_strength = 0; ++ chromeos_style_sharpening_strength = 0; ++ } ++ } ++ ++ /*if (fitting_strength == 100) scale_value = 1.1;*/ ++ ++#endif ++ ++#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING ++ ++ FT_Int lcd_extra = 0; ++ FT_LcdFiveTapFilter lcd_weights = { 0 }; ++ FT_Bool have_custom_weight = FALSE; ++ FT_Bitmap_LcdFilterFunc lcd_filter_func = NULL; ++ ++ ++ if ( slot->face ) ++ { ++ FT_Char i; ++ ++ ++ for ( i = 0; i < FT_LCD_FILTER_FIVE_TAPS; i++ ) ++ if ( slot->face->internal->lcd_weights[i] != 0 ) ++ { ++ have_custom_weight = TRUE; ++ break; ++ } ++ } ++ ++ /* ++ * The LCD filter can be set library-wide and per-face. Face overrides ++ * library. If the face filter weights are all zero (the default), it ++ * means that the library default should be used. ++ */ ++ if ( have_custom_weight ) ++ { ++ /* ++ * A per-font filter is set. It always uses the default 5-tap ++ * in-place FIR filter that needs 2 extra pixels. ++ */ ++ ft_memcpy( lcd_weights, ++ slot->face->internal->lcd_weights, ++ FT_LCD_FILTER_FIVE_TAPS ); ++ lcd_filter_func = ft_lcd_filter_fir; ++ lcd_extra = 2; ++ } ++ else ++ { ++ /* ++ * The face's lcd_weights is {0, 0, 0, 0, 0}, meaning `use library ++ * default'. If the library is set to use no LCD filtering ++ * (lcd_filter_func == NULL), `lcd_filter_func' here is also set to ++ * NULL and the tests further below pass over the filtering process. ++ */ ++ ft_memcpy( lcd_weights, ++ slot->library->lcd_weights, ++ FT_LCD_FILTER_FIVE_TAPS ); ++ lcd_filter_func = slot->library->lcd_filter_func; ++ lcd_extra = slot->library->lcd_extra; ++ } ++ ++#endif /*FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + + /* check glyph image format */ + if ( slot->format != render->glyph_format ) +@@ -142,6 +2548,128 @@ + goto Exit; + } + ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++RERENDER: ++ if ( align_called == 1 ) ++ { ++ scaleMat.xx = FT_FixedFromFloat(scale_value); ++ scaleMat.xy = 0; ++ scaleMat.yx = 0; ++ scaleMat.yy = ( 1 << 16 ); ++ ++ FT_Outline_Copy(outline_orig, outline); ++ ++ if ( scale_value != 1.0 ) ++ FT_Outline_Transform( outline, &scaleMat ); ++ ++ FT_Outline_Translate( outline, translate_value, 0 ); ++ ++ FT_Outline_EmboldenXY( outline, embolden_value, 0 ); ++ } ++ else ++ { ++#endif ++ outline = &slot->outline; ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ /* Need to get this PRIOR to embolden, otherwise bad things happen */ ++ FT_Outline_Get_CBox( outline, &cbox ); ++ ++ /* Various hacks that need to be turned into a new rule set */ ++ /*if ( !autohinted ++ && use_known_settings_on_selected_fonts ++ && mode == FT_RENDER_MODE_LCD ++ && slot->face->family_name ++ && slot->face->style_name ++ && ( strcasestr(slot->face->family_name, "Courier New" ) ++ && ( strcasestr(slot->face->style_name, "Regular" ) ++ || strcasestr(slot->face->style_name, "Italic" ) ) ) ) ++ FT_Outline_Embolden( outline, 24 );*/ ++ ++ if ( slot->face ) ++ { ++ if ( !autohinted && ++ use_known_settings_on_selected_fonts && ++ mode == FT_RENDER_MODE_LCD && ++ slot->face->family_name && ++ slot->face->style_name && ++ strcasestr( slot->face->family_name, "Times New Roman" ) && ++ strcasestr( slot->face->style_name, "Italic" ) ) ++ FT_Outline_EmboldenXY( outline, 12, 0 ); ++ ++ if ( use_known_settings_on_selected_fonts && ++ autohinted && ++ mode == FT_RENDER_MODE_LCD && ++ slot->face->family_name && ++ slot->face->style_name && ++ strcasestr(slot->face->family_name, "FreeSerif" ) && ++ strcasestr(slot->face->style_name, "Italic" ) ) ++ FT_Outline_EmboldenXY( outline, 8, 0 ); ++ ++ if ( global_embolden_x_value != 0 || global_embolden_y_value != 0 ) ++ FT_Outline_EmboldenXY( outline, ++ global_embolden_x_value, ++ global_embolden_y_value ); ++ ++ if ( ( bold_embolden_x_value != 0 || bold_embolden_y_value != 0 ) && ++ ( slot->face->style_name && ++ ( strcasestr(slot->face->style_name, "Bold" ) || ++ strcasestr(slot->face->style_name, "Black" ) || ++ ( slot->face->style_flags && ++ slot->face->style_flags & FT_STYLE_FLAG_BOLD ) ) ) ) ++ FT_Outline_EmboldenXY( outline, ++ bold_embolden_x_value, ++ bold_embolden_y_value ); ++ } ++ ++ FT_Outline_Copy( outline, outline_orig ); ++ } ++ ++ /* translate the outline to the new origin if needed */ ++ if ( align_called == 0 ) ++ { ++ FT_Pos enlarge_cbox = 0; ++ ++ /* enlarge for grayscale rendering */ ++ if ( mode == FT_RENDER_MODE_NORMAL ) ++ enlarge_cbox = 64; ++ ++ if ( origin ) ++ { ++ FT_Outline_Translate( outline, origin->x, origin->y ); ++ have_translated_origin = TRUE; ++ } ++ ++ /* compute the control box, and grid fit it */ ++ /*FT_Outline_Get_CBox( outline, &cbox );*/ ++ ++ cbox.xMin = FT_PIX_FLOOR( cbox.xMin - enlarge_cbox ); ++ cbox.yMin = FT_PIX_FLOOR( cbox.yMin ); ++ cbox.xMax = FT_PIX_CEIL( cbox.xMax + enlarge_cbox ); ++ cbox.yMax = FT_PIX_CEIL( cbox.yMax ); ++#else ++ if ( origin ) ++ { ++ FT_Outline_Translate( outline, origin->x, origin->y ); ++ have_translated_origin = TRUE; ++ } ++ ++ /* compute the control box, and grid fit it */ ++ FT_Outline_Get_CBox( outline, &cbox ); ++ ++ cbox.xMin = FT_PIX_FLOOR( cbox.xMin ); ++ cbox.yMin = FT_PIX_FLOOR( cbox.yMin ); ++ cbox.xMax = FT_PIX_CEIL( cbox.xMax ); ++ cbox.yMax = FT_PIX_CEIL( cbox.yMax ); ++#endif ++ ++ width = (FT_ULong)( cbox.xMax - cbox.xMin ) >> 6; ++ height = (FT_ULong)( cbox.yMax - cbox.yMin ) >> 6; ++ ++#ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING ++ width_org = width; ++ height_org = height; ++#endif ++ + /* release old bitmap buffer */ + if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) + { +@@ -149,34 +2677,85 @@ + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + +- if ( ft_glyphslot_preset_bitmap( slot, mode, origin ) ) ++ /* allocate new one */ ++ pitch = width; ++ if ( hmul ) + { +- error = FT_THROW( Raster_Overflow ); +- goto Exit; ++ width = width * 3; ++ pitch = FT_PAD_CEIL( width, 4 ); + } + +- /* allocate new one */ +- if ( FT_ALLOC_MULT( bitmap->buffer, bitmap->rows, bitmap->pitch ) ) +- goto Exit; ++ if ( vmul ) ++ height *= 3; + +- slot->internal->flags |= FT_GLYPH_OWN_BITMAP; ++ x_shift = cbox.xMin; ++ y_shift = cbox.yMin; ++ x_left = cbox.xMin >> 6; ++ y_top = cbox.yMax >> 6; + +- x_shift = 64 * -slot->bitmap_left; +- y_shift = 64 * -slot->bitmap_top; +- if ( bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V ) +- y_shift += 64 * (FT_Int)bitmap->rows / 3; +- else +- y_shift += 64 * (FT_Int)bitmap->rows; ++#ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING ++ if ( lcd_filter_func ) ++ { ++ if ( hmul ) ++ { ++ x_shift -= 64 * ( lcd_extra >> 1 ); ++ x_left -= lcd_extra >> 1; ++ width += 3 * lcd_extra; ++ pitch = FT_PAD_CEIL( width, 4 ); ++ } + +- if ( origin ) ++ if ( vmul ) ++ { ++ y_shift -= 64 * ( lcd_extra >> 1 ); ++ y_top += lcd_extra >> 1; ++ height += 3 * lcd_extra; ++ } ++ } ++#endif ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ } ++#endif ++ ++ ++ /* Required check is (pitch * height < FT_ULONG_MAX), */ ++ /* but we care realistic cases only. Always pitch <= width. */ ++ if ( width > 0x7FFF || height > 0x7FFF ) + { +- x_shift += origin->x; +- y_shift += origin->y; ++ FT_ERROR(( "ft_smooth_render_generic: glyph too large: %u x %u\n", ++ width, height )); ++ error = FT_THROW( Raster_Overflow ); ++ goto Exit; + } + ++ bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; ++ bitmap->num_grays = 256; ++ bitmap->width = (unsigned int)width; ++ bitmap->rows = (unsigned int)height; ++ bitmap->pitch = pitch; ++ + /* translate outline to render it into the bitmap */ +- if ( x_shift || y_shift ) +- FT_Outline_Translate( outline, x_shift, y_shift ); ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ if ( align_called == 0 ) ++ { ++#endif ++ FT_Outline_Translate( outline, -x_shift, -y_shift ); ++ have_outline_shifted = TRUE; ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ } ++#endif ++ /* release old bitmap buffer */ ++ if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) ++ { ++ FT_FREE( bitmap->buffer ); ++ slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; ++ } ++ ++ if ( FT_ALLOC( bitmap->buffer, (FT_ULong)( pitch * height ) ) ) ++ goto Exit; ++ else ++ have_buffer = TRUE; ++ ++ slot->internal->flags |= FT_GLYPH_OWN_BITMAP; + + /* set up parameters */ + params.target = bitmap; +@@ -223,159 +2802,240 @@ + if ( error ) + goto Exit; + +- /* finally apply filtering */ +- if ( hmul || vmul ) ++#ifdef FT_CONFIG_OPTION_INFINALITY_PATCHSET ++ if ( ppem <= MAX_PPEM && ppem >= MIN_PPEM ) + { +- FT_Byte* lcd_weights; +- FT_Bitmap_LcdFilterFunc lcd_filter_func; +- +- +- /* Per-face LCD filtering takes priority if set up. */ +- if ( slot->face && slot->face->internal->lcd_filter_func ) ++ if ( align_called == 0 && cur_width / ppem < 10 && ++ ( alignment_strength > 0 || fitting_strength > 0 ) ) ++ _lcd_stem_align ( bitmap, ++ mode, ++ slot, ++ &translate_value, ++ &scale_value, ++ alignment_strength, ++ fitting_strength, ++ &embolden_value ); ++ ++ if ( align_called == 0 && ++ ( translate_value != 0 || scale_value != 1.0 ) ) + { +- lcd_weights = slot->face->internal->lcd_weights; +- lcd_filter_func = slot->face->internal->lcd_filter_func; ++ align_called = 1; ++ goto RERENDER; + } +- else ++ ++ if ( mode == FT_RENDER_MODE_LCD ) + { +- lcd_weights = slot->library->lcd_weights; +- lcd_filter_func = slot->library->lcd_filter_func; +- } + +- if ( lcd_filter_func ) +- lcd_filter_func( bitmap, lcd_weights ); +- } ++ if ( fringe_filter_strength > 0 /*&& autohinted*/ ) ++ _ft_lcd_fringe_filter( bitmap, ++ mode, ++ fringe_filter_strength, ++ slot->library ); ++ ++ /*if ( autohinted) ++ _ft_lcd_stem_end_filter( bitmap, mode, 100, slot->library );*/ ++ ++ if ( gamma_correction_lt > 0 && gamma_correction_value != 1.0 ) ++ _ft_lcd_gamma_correction_correction( bitmap, ++ mode, ++ slot, ++ gamma_correction_lt, ++ gamma_correction_value ); ++ ++ chromeos_cutoff = (FT_Byte)( 0.5 * 255.0 ) ++ * ( chromeos_style_sharpening_strength / 100.0 ); ++ chromeos_gamma_value = 1; ++ ++ if ( chromeos_style_sharpening_strength > 0 ) ++ _ft_lcd_chromeos_sharpen( bitmap, ++ mode, ++ chromeos_cutoff, ++ chromeos_gamma_value ); ++ ++ if ( ppem > 8 ) ++ if ( windows_style_sharpening_strength > 0 ) ++ _ft_lcd_windows_sharpen( bitmap, ++ mode, ++ windows_style_sharpening_strength, ++ slot->library ); ++ ++ if ( autohinted && ++ ( cur_width * 100 ) / 64 ++ > autohint_horizontal_stem_darken_strength && ++ autohint_horizontal_stem_darken_strength != 0 ) ++ autohint_horizontal_stem_darken_strength = ( cur_width * 100 ) / 64; ++ ++ if ( autohint_horizontal_stem_darken_strength > 100) ++ autohint_horizontal_stem_darken_strength = 100; ++ ++ /* only do on autohinted fonts */ ++ /* Necessary to do on some non-thin fonts, which is why it is outside */ ++ /* of the below conditional */ ++ if ( autohint_horizontal_stem_darken_strength > 0 && autohinted ) ++ _ft_lcd_darken_x ( bitmap, ++ mode, ++ autohint_horizontal_stem_darken_strength, ++ slot->library ); ++ ++ /* Enhance thin fonts */ ++ if ( autohinted ) ++ { ++ /* if forcibly set use that, otherwise make a good estimate */ ++ float contrast, brightness; ++ ftinf_get_bc( slot->face->family_name, ppem, &brightness, &contrast); ++ if ( slot->face && !_ft_bitmap_bc ( bitmap, brightness, contrast ) ) ++ { ++ FT_Bool is_fixed_name = FALSE; ++ ++ if ( slot->face->family_name && ++ strcasestr(slot->face->family_name, "Mono" ) ) ++ is_fixed_name = TRUE; ++ ++ /* Darken vertical stems */ ++ _ft_lcd_darken_y ( bitmap, ++ mode, ++ autohint_vertical_stem_darken_strength, ++ slot->library ); ++ ++ /* Adjust brightness / contrast automatically based on stem width */ ++ if ( cur_width != 0 && cur_width < 30 ) ++ cur_width = 30; ++ ++ if ( cur_width >= 30 && cur_width <= 60 ) ++ { ++ float ppem_factor = sliding_scale ( 5, 11, 0.0, 1.0, ppem ); ++ float brightness_factor = sliding_scale ( 30, 52, -.3, 0.0, ++ cur_width ); ++ float contrast_factor = sliding_scale ( 30, 52, .45, 0.0, ++ cur_width ); ++ _ft_bitmap_bc ( bitmap, ++ ppem_factor * brightness_factor, ++ ppem_factor * contrast_factor ); ++ ++ /* Only cap variable width thin-stemmed fonts */ ++ if ( !FT_IS_FIXED_WIDTH( slot->face ) && !is_fixed_name ) ++ _ft_bitmap_cap ( bitmap, ++ ( cur_width * 150 ) / 64, ++ slot->library ); ++ } ++ } ++ } + +-#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + +- if ( hmul ) /* lcd */ +- { +- FT_Byte* line; +- FT_Byte* temp = NULL; +- FT_UInt i, j; ++ if ( lcd_filter_func ) ++ lcd_filter_func( bitmap, mode, lcd_weights ); + +- unsigned int height = bitmap->rows; +- unsigned int width = bitmap->width; +- int pitch = bitmap->pitch; ++ if ( grayscale_filter_strength > 0 ) ++ _ft_lcd_grayscale_filter( bitmap, ++ mode, ++ grayscale_filter_strength, ++ slot->library ); + +- FT_Vector* sub = slot->library->lcd_geometry; ++ } + ++ /* Global values */ ++ if ( brightness_value != 0 || contrast_value != 0 ) ++ _ft_bitmap_bc ( bitmap, ++ (float)brightness_value / 300.0, ++ (float)contrast_value / 300.0); + +- /* Render 3 separate monochrome bitmaps, shifting the outline. */ +- width /= 3; ++ FT_Outline_Done( slot->library, outline_orig ); ++ } ++ else if ( mode == FT_RENDER_MODE_LCD && ++ lcd_filter_func ) ++ lcd_filter_func( bitmap, mode, lcd_weights ); ++#else ++ if ( lcd_filter_func ) ++ lcd_filter_func( bitmap, mode, lcd_weights ); ++#endif /* FT_CONFIG_OPTION_INFINALITY_PATCHSET */ + +- FT_Outline_Translate( outline, +- -sub[0].x, +- -sub[0].y ); +- error = render->raster_render( render->raster, ¶ms ); +- if ( error ) +- goto Exit; ++#else /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + +- bitmap->buffer += width; +- FT_Outline_Translate( outline, +- sub[0].x - sub[1].x, +- sub[0].y - sub[1].y ); +- error = render->raster_render( render->raster, ¶ms ); +- bitmap->buffer -= width; +- if ( error ) +- goto Exit; ++ /* render outline into bitmap */ ++ error = render->raster_render( render->raster, ¶ms ); ++ if ( error ) ++ goto Exit; + +- bitmap->buffer += 2 * width; +- FT_Outline_Translate( outline, +- sub[1].x - sub[2].x, +- sub[1].y - sub[2].y ); +- error = render->raster_render( render->raster, ¶ms ); +- bitmap->buffer -= 2 * width; +- if ( error ) +- goto Exit; ++ /* expand it horizontally */ ++ if ( hmul ) ++ { ++ FT_Byte* line = bitmap->buffer; ++ FT_UInt hh; + +- x_shift -= sub[2].x; +- y_shift -= sub[2].y; + +- /* XXX: Rearrange the bytes according to FT_PIXEL_MODE_LCD. */ +- /* XXX: It is more efficient to render every third byte above. */ ++ for ( hh = height_org; hh > 0; hh--, line += pitch ) ++ { ++ FT_UInt xx; ++ FT_Byte* end = line + width; + +- if ( FT_ALLOC( temp, (FT_ULong)pitch ) ) +- goto Exit; + +- for ( i = 0; i < height; i++ ) +- { +- line = bitmap->buffer + i * (FT_ULong)pitch; +- for ( j = 0; j < width; j++ ) ++ for ( xx = width_org; xx > 0; xx-- ) + { +- temp[3 * j ] = line[j]; +- temp[3 * j + 1] = line[j + width]; +- temp[3 * j + 2] = line[j + width + width]; ++ FT_UInt pixel = line[xx-1]; ++ ++ ++ end[-3] = (FT_Byte)pixel; ++ end[-2] = (FT_Byte)pixel; ++ end[-1] = (FT_Byte)pixel; ++ end -= 3; + } +- FT_MEM_COPY( line, temp, pitch ); + } +- +- FT_FREE( temp ); + } +- else if ( vmul ) /* lcd_v */ ++ ++ /* expand it vertically */ ++ if ( vmul ) + { +- int pitch = bitmap->pitch; ++ FT_Byte* read = bitmap->buffer + ( height - height_org ) * pitch; ++ FT_Byte* write = bitmap->buffer; ++ FT_UInt hh; + +- FT_Vector* sub = slot->library->lcd_geometry; + ++ for ( hh = height_org; hh > 0; hh-- ) ++ { ++ ft_memcpy( write, read, pitch ); ++ write += pitch; + +- /* Render 3 separate monochrome bitmaps, shifting the outline. */ +- /* Notice that the subpixel geometry vectors are rotated. */ +- /* Triple the pitch to render on each third row. */ +- bitmap->pitch *= 3; +- bitmap->rows /= 3; ++ ft_memcpy( write, read, pitch ); ++ write += pitch; + +- FT_Outline_Translate( outline, +- -sub[0].y, +- sub[0].x ); +- error = render->raster_render( render->raster, ¶ms ); +- if ( error ) +- goto Exit; ++ ft_memcpy( write, read, pitch ); ++ write += pitch; ++ read += pitch; ++ } ++ } + +- bitmap->buffer += pitch; +- FT_Outline_Translate( outline, +- sub[0].y - sub[1].y, +- sub[1].x - sub[0].x ); +- error = render->raster_render( render->raster, ¶ms ); +- bitmap->buffer -= pitch; +- if ( error ) +- goto Exit; ++#endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + +- bitmap->buffer += 2 * pitch; +- FT_Outline_Translate( outline, +- sub[1].y - sub[2].y, +- sub[2].x - sub[1].x ); +- error = render->raster_render( render->raster, ¶ms ); +- bitmap->buffer -= 2 * pitch; +- if ( error ) +- goto Exit; ++ /* ++ * XXX: on 16bit system, we return an error for huge bitmap ++ * to prevent an overflow. ++ */ ++ if ( x_left > FT_INT_MAX || y_top > FT_INT_MAX ) ++ { ++ error = FT_THROW( Invalid_Pixel_Size ); ++ goto Exit; ++ } + +- x_shift -= sub[2].y; +- y_shift += sub[2].x; ++ slot->format = FT_GLYPH_FORMAT_BITMAP; ++ slot->bitmap_left = (FT_Int)x_left; ++ slot->bitmap_top = (FT_Int)y_top; + +- bitmap->pitch /= 3; +- bitmap->rows *= 3; +- } +- else /* grayscale */ +- error = render->raster_render( render->raster, ¶ms ); ++ /* everything is fine; don't deallocate buffer */ ++ have_buffer = FALSE; + +-#endif /* !FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ ++ error = FT_Err_Ok; + + Exit: +- if ( !error ) +- { +- /* everything is fine; the glyph is now officially a bitmap */ +- slot->format = FT_GLYPH_FORMAT_BITMAP; +- } +- else if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) ++ if ( have_outline_shifted ) ++ FT_Outline_Translate( outline, x_shift, y_shift ); ++ if ( have_translated_origin ) ++ FT_Outline_Translate( outline, -origin->x, -origin->y ); ++ if ( have_buffer ) + { + FT_FREE( bitmap->buffer ); + slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP; + } + +- if ( x_shift || y_shift ) +- FT_Outline_Translate( outline, -x_shift, -y_shift ); +- + return error; + } + +@@ -402,8 +3062,14 @@ + FT_Render_Mode mode, + const FT_Vector* origin ) + { +- return ft_smooth_render_generic( render, slot, mode, origin, +- FT_RENDER_MODE_LCD ); ++ FT_Error error; ++ ++ error = ft_smooth_render_generic( render, slot, mode, origin, ++ FT_RENDER_MODE_LCD ); ++ if ( !error ) ++ slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD; ++ ++ return error; + } + + +@@ -414,8 +3080,14 @@ + FT_Render_Mode mode, + const FT_Vector* origin ) + { +- return ft_smooth_render_generic( render, slot, mode, origin, +- FT_RENDER_MODE_LCD_V ); ++ FT_Error error; ++ ++ error = ft_smooth_render_generic( render, slot, mode, origin, ++ FT_RENDER_MODE_LCD_V ); ++ if ( !error ) ++ slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD_V; ++ ++ return error; + } + + +@@ -442,7 +3114,7 @@ + (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, /* get_glyph_cbox */ + (FT_Renderer_SetModeFunc) ft_smooth_set_mode, /* set_mode */ + +- (FT_Raster_Funcs*)&ft_grays_raster /* raster_class */ ++ (FT_Raster_Funcs*)&ft_grays_raster /* raster_class */ + ) + + +@@ -469,7 +3141,7 @@ + (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, /* get_glyph_cbox */ + (FT_Renderer_SetModeFunc) ft_smooth_set_mode, /* set_mode */ + +- (FT_Raster_Funcs*)&ft_grays_raster /* raster_class */ ++ (FT_Raster_Funcs*)&ft_grays_raster /* raster_class */ + ) + + +@@ -496,7 +3168,7 @@ + (FT_Renderer_GetCBoxFunc) ft_smooth_get_cbox, /* get_glyph_cbox */ + (FT_Renderer_SetModeFunc) ft_smooth_set_mode, /* set_mode */ + +- (FT_Raster_Funcs*)&ft_grays_raster /* raster_class */ ++ (FT_Raster_Funcs*)&ft_grays_raster /* raster_class */ + ) + + +diff --git a/src/truetype/ttinterp.c b/src/truetype/ttinterp.c +index 70434e172..1d84e6618 100644 +--- a/src/truetype/ttinterp.c ++++ b/src/truetype/ttinterp.c +@@ -5901,6 +5901,7 @@ + + if ( exc->ignore_x_mode && + exc->GS.freeVector.x != 0 && ++ exc->GS.freeVector.y == 0 && + !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) ) + control_value_cutin = 0; + } |