freetype-entire-infinality-patchset (excludes the TT subpixel patches) ------------------------------------------------------------------- This patch contains all the patches I used to distribute separately. It made more sense to lump these all together into a single file now that there are runtime options. It's also easier for me to maintain. ;) I recommend that if you are using this patch that you use /etc/fonts/local.conf that I provide at: http://www.infinality.net/files/local.conf You will also need: http://www.infinality.net/files/infinality-settings The second one will need to be included in your profile with something like: . ~/path/to/the/file/infinality-settings It should be adjusted to your personal tastes as an end-user. DISCLAIMERS: This patch will almost certainly result in a performance hit when freetype is rendering the glyphs. The good news is that fontconfig caches the glyphs so it's only the first time they are displayed that there could be a performance issue. I expect that if you compile freetype with this patch along with my TT subpixel hinting patch, you will have a complete build that works the way I expect it to. However, I have not tested all compile configurations for errors. I intend to at some point. This patch may make your system crash, have memory leaks, not compile, or render fonts in a way that you don't like. Either way, when you use this patch, you should recognize that it is ALPHA / BETA quality. That said, I intend to run these patches on my personal system, so they had better be pretty stable! Changelog 2010-11-14 - All patches can now be enabled at runtime with ENVIRONMENT_VARIABLES. See the file infinality-settings (and below) for how to enable these. Effects that used to work now **REQUIRE** these in order to be turned on at runtime. This lets end users have full control over what they want without requiring different compiles. - Added option to auto-embolden thin/light fonts. - Further refinement of the stem calculations for enhanced autohint. - Adjustable FIR filter at runtime. - Stem alignment ability to align glyph bitmaps to pixel boundaries. - Adjustable gamma correction prior to the FIR filter for LCD rendering. This can be used to make small ppem text more readable, or for whatever else you want to use it for. - A height tweak on the enhanced autohint that makes Arial, Segoe, Times and others render more similarly to Windows. - Separated out the option to maintain the original width of glyphs when doing fake emboldening. ################################################################## # The environment variables below should be copied to a file in # /etc/profile.d/ for system-wide effects and/or included in # ~/.bashrc or ~/.bash_profile for per-user effects: # # . ~/path/to/the/file/infinality-settings # # Of course, the per-user settings will override the system-wide # settings. ################################################################## # INFINALITY_FT_FILTER_PARAMS # # This is a modified version of the patch here: # http://levelsofdetail.kendeeter.com/2008/12/dynamic_fir_filter_patch.html # # Allows you to adjust the FIR filter at runtime instead of at # compile time. The idea is to have values add up to one, and be # symmetrical around the middle value. Here are some samples # of various filter parameters: # # Strong Extra Smooth "0.15 0.2 0.3 0.2 0.15" (extra smooth, natural weight) # Extra Smooth "0.20 0.20 0.30 0.20 0.20" (extra smooth, extra weight) # Smooth "0.15 0.20 0.32 0.20 0.15" (smooth, natural weight) # Stronger Gibson "0.11 0.22 0.38 0.22 0.11" (smooth, extra weight) # Gibson "0.11 0.22 0.33 0.22 0.11" (smooth, natural weight) # Freetype Light "0.00 0.33 0.34 0.33 0.00" (sharp, natural weight) # Freetype Default "0.06 0.25 0.44 0.25 0.06" (sharp, extra weight) *default # Extra Sharp "0.00 0.35 0.35 0.35 0.00" (extra sharp, extra weight) # # Default: [Freetype's default] # Recommended: "0.11 0.22 0.38 0.22 0.11" # # Example 1: export INFINALITY_FT_FILTER_PARAMS="0.11 0.22 0.38 0.22 0.11" # export INFINALITY_FT_FILTER_PARAMS="0.11 0.22 0.38 0.22 0.11" ################################################################## # INFINALITY_FT_STEM_ALIGNMENT_TYPE # # This performs analysis on each glyph and determines the best # subpixel orientation for the glyph. The glyph is not scaled in # any way, just moved left or right by a subpixel amount. This # results in subtley cleaner looking fonts, at the expense of # proper distances between glyphs. This is only active for sizes # 10 px or greater and does not apply to bold or italic fonts. # # Possible values: # full - Allows a glyph to be moved to the LEFT or RIGHT by 1 subpixel # Best alignment, Worst positioning # medium,medium1 - Only allows a glyph to be moved to the LEFT by 1 subpixel # Good alignment, Good positioning # medium2 - Only allows a glyph to be moved to the RIGHT by 1 subpixel # Good alignment, Good positioning # slight,slight1 - A stricter version of medium # Minor alignment, Best positioning # slight2 - A stricter version of medium2 # Minor alignment, Best positioning # infinality - medium1 when stem < 5 subpixels, full when >= 5 subpixels # none - Don't do any alignment # # Default: none # Recommended: medium export INFINALITY_FT_STEM_ALIGNMENT_TYPE=medium ################################################################## # INFINALITY_FT_AUTOFIT_STEM_SNAP_LIGHT # # Cause the height of horizontal stems to snap to integer pixels # when using light auto-hinting. (This happens automatically # when using full auto-hinting) # # This produces an effect similar to the way Windows renders fonts # without requiring the font to contain bytecode instructions. # # Possible values: # true - enable stem snapping # false - do not enable stem snapping # # Default: false # Recommended: true export INFINALITY_FT_AUTOFIT_STEM_SNAP_LIGHT=true ################################################################## # INFINALITY_FT_AUTOFIT_EMBOLDEN_LIGHT # # Embolden particularly light or thin fonts, like DejaVu Sans Light, # Inconsolata, Freemono, Courier New, etc. up until stem width is # 1 pixel wide. This makes these fonts easier to read at lower # ppems. Only applies when the autohinter is being used. # # Possible values: # true - enable emboldening of light fonts # false - do not enable emboldening of light fonts # # Default: false # Recommended: true export INFINALITY_FT_AUTOFIT_EMBOLDEN_LIGHT=true ################################################################## # INFINALITY_FT_PSEUDO_GAMMA # # This does a weighted gamma correction at the LCD filter phase # prior to the LCD filter. # # The first value indicates a px value, the second indicates a # "gamma" value. All sizes < the px value will be corrected # on a weighted scale based on the second value. # # Values .1 < 1.0 will darken the glyph # Values > 1.0 will lighten the glyph # # Example 1: Darken glyphs that are less than 10 px. With some fonts # even 5 or 6px is readable! # export INFINALITY_FT_PSEUDO_GAMMA="10 .6" # # Example 2: Lighten all glyphs (below 100px) # export INFINALITY_FT_PSEUDO_GAMMA="100 1.5" # # Default: [No gamma correction] # Recommended: "9 .7" export INFINALITY_FT_PSEUDO_GAMMA="9 .7" ################################################################## # INFINALITY_FT_AUTOFIT_ADJUST_HEIGHTS # # This will slightly stretch some glyphs vertically between 9px # and 14px (inclusive). Some people may find this more # aesthetically pleasing. This only applies to fonts that are # using autohint. # # Possible values: # true - enable height adjustment # false - do not enable height adjustment # # Default: false export INFINALITY_FT_AUTOFIT_ADJUST_HEIGHTS=true ################################################################## # INFINALITY_FT_ENHANCED_EMBOLDEN # # When doing artificial emboldening, only embolden in the X # direction, skipping the Y direction. Most people will find this # more aesthetically pleasing than the default behavior. # # Possible values: # true - enable enhanced emboldening # false - no not enable enhanced emboldening # # Default: false # Recommended: true export INFINALITY_FT_ENHANCED_EMBOLDEN=true ################################################################## # INFINALITY_FT_EMBOLDEN_MAINTAIN_WIDTH # # When doing artificial emboldening, don't change the glyph width. # # Possible values: # true - maintain width # false - do not maintain width # # Default: false # Recommended: true export INFINALITY_FT_EMBOLDEN_MAINTAIN_WIDTH=true ################################################################## # INFINALITY_FT_AUTO_AUTOHINT # # Automatically use autohint when rendering a font that contains # no truetype instructions, regardless of what the calling # program asks for. The truetype hinter will not do a good job # on these. # # Possible values: # true - automatically use autohint # false - do not automatically use autohint # # Default: false # Recommended: true export INFINALITY_FT_AUTO_AUTOHINT=true INFINALITY_FT_AUTOFIT_STEM_SNAP_LIGHT details --------------------------------------------- This patch is intended to make freetype's autohinter round down widths of horizontal stems to whole pixel values. This dramatically reduces the graininess of the rendering at small sizes, at the expense of being true to the glyph. Put simply, it makes freetype's autohinter render fonts similarly to well-hinted TrueType fonts, even on fonts that contain no instructions. So, as far as I can tell, this makes it 100% patent-free. The most dramatic results are on sans-serif fonts like Lucida Grande, Arial, Helvetica Neue, Inconsolata, Droid Sans, Trebuchet MS, etc. It is recommended to use this with antialiasing on, and fonts set to slight hinting: rgb true true true hintslight lcddefault diff -Nur freetype-2.4.3.orig/configure freetype-2.4.3.new/configure --- freetype-2.4.3.orig/configure 2010-10-03 13:05:26.000000000 -0500 +++ freetype-2.4.3.new/configure 2010-11-14 18:17:36.593491866 -0600 @@ -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 if test "x$GNUMAKE" = x; then diff -Nur freetype-2.4.3.orig/include/freetype/internal/ftobjs.h freetype-2.4.3.new/include/freetype/internal/ftobjs.h --- freetype-2.4.3.orig/include/freetype/internal/ftobjs.h 2010-07-18 11:07:31.000000000 -0500 +++ freetype-2.4.3.new/include/freetype/internal/ftobjs.h 2010-11-07 11:18:19.681501081 -0600 @@ -762,6 +770,10 @@ FT_Library library ); + typedef void (*FT_Bitmap_LcdStemAlignFunc)( FT_Bitmap* bitmap, + FT_Render_Mode render_mode, + FT_GlyphSlot slot ); + /*************************************************************************/ /* */ /* */ @@ -862,6 +874,7 @@ FT_Int lcd_extra; /* number of extra pixels */ FT_Byte lcd_weights[7]; /* filter weights, if any */ FT_Bitmap_LcdFilterFunc lcd_filter_func; /* filtering callback */ + FT_Bitmap_LcdStemAlignFunc lcd_stem_align_func; #endif #ifdef FT_CONFIG_OPTION_PIC diff -Nur freetype-2.4.3.orig/src/autofit/aflatin.c freetype-2.4.3.new/src/autofit/aflatin.c --- freetype-2.4.3.orig/src/autofit/aflatin.c 2010-09-11 01:23:02.000000000 -0500 +++ freetype-2.4.3.new/src/autofit/aflatin.c 2010-11-14 18:55:57.678647844 -0600 @@ -21,6 +21,7 @@ #include "aflatin.h" #include "aferrors.h" +#include "strings.h" #ifdef AF_USE_WARPER @@ -495,6 +496,29 @@ AF_LatinAxis axis; FT_UInt nn; + int checked_adjust_heights_env = 0; + FT_Bool adjust_heights = FALSE; + + if ( checked_adjust_heights_env == 0 ) + { + char *adjust_heights_env = getenv( "INFINALITY_FT_AUTOFIT_ADJUST_HEIGHTS" ); + if ( adjust_heights_env != NULL ) + { + if ( strcasecmp(adjust_heights_env, "default" ) != 0 ) + { + if ( strcasecmp(adjust_heights_env, "true") == 0) + adjust_heights = TRUE; + else if ( strcasecmp(adjust_heights_env, "1") == 0) + adjust_heights = TRUE; + else if ( strcasecmp(adjust_heights_env, "on") == 0) + adjust_heights = TRUE; + else if ( strcasecmp(adjust_heights_env, "yes") == 0) + adjust_heights = TRUE; + } + } + checked_adjust_heights_env = 1; + } + if ( dim == AF_DIMENSION_HORZ ) { @@ -522,21 +546,46 @@ { AF_LatinAxis Axis = &metrics->axis[AF_DIMENSION_VERT]; AF_LatinBlue blue = NULL; - + int threshold = 40; for ( nn = 0; nn < Axis->blue_count; nn++ ) { - if ( Axis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT ) + if ( Axis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT + || ( adjust_heights && Axis->blues[nn].flags & AF_LATIN_BLUE_TOP ) + ) { blue = &Axis->blues[nn]; break; } } + if ( adjust_heights + && metrics->root.scaler.face->size->metrics.x_ppem < 15 + && metrics->root.scaler.face->size->metrics.x_ppem > 8 ) + threshold = 52; + + /* NEED TO FIND A WAY TO ADJUST CAPS AND LOWER SEPARATELY */ + /* The below does not work */ + /* if (Axis->blues[nn].flags & AF_LATIN_BLUE_SMALL_TOP ) + { + if (metrics->root.scaler.face->size->metrics.x_ppem < 15) + threshold = 22; + else threshold = 40; + break; + } + if ( Axis->blues[nn].flags & AF_LATIN_BLUE_CAPITAL_TOP ) + { + if (metrics->root.scaler.face->size->metrics.x_ppem < 15) + threshold = 40; + else threshold = 40; + break; + } + */ + if ( blue ) { FT_Pos scaled = FT_MulFix( blue->shoot.org, scaler->y_scale ); - FT_Pos fitted = ( scaled + 40 ) & ~63; + FT_Pos fitted = ( scaled + threshold ) & ~63; if ( scaled != fitted ) @@ -1340,7 +1389,8 @@ if ( dist < 0 ) dist = -dist; - dist = FT_MulFix( dist, scale ); + /* round down to pixels */ + dist = FT_MulFix( dist, scale ) & ~63; if ( dist < best_dist ) { best_dist = dist; @@ -1500,9 +1550,33 @@ FT_Int vertical = ( dim == AF_DIMENSION_VERT ); - if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) || - axis->extra_light ) - return width; + int checked_stem_snap_env = 0; + FT_Bool stem_snap_light = FALSE; + + if ( checked_stem_snap_env == 0 ) + { + char *stem_snap_env = getenv( "INFINALITY_FT_AUTOFIT_STEM_SNAP_LIGHT" ); + if ( stem_snap_env != NULL ) + { + if ( strcasecmp(stem_snap_env, "default" ) != 0 ) + { + if ( strcasecmp(stem_snap_env, "true") == 0) + stem_snap_light = TRUE; + else if ( strcasecmp(stem_snap_env, "1") == 0) + stem_snap_light = TRUE; + else if ( strcasecmp(stem_snap_env, "on") == 0) + stem_snap_light = TRUE; + else if ( strcasecmp(stem_snap_env, "yes") == 0) + stem_snap_light = TRUE; + } + } + checked_stem_snap_env = 1; + } + + if ( !stem_snap_light ) + if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) || + axis->extra_light ) + return width; if ( dist < 0 ) { @@ -1510,8 +1584,67 @@ sign = 1; } - if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || - ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) + if ( stem_snap_light + && ( + ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) + || ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) ) + { + 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 - dist ) < 32 + && axis->widths[0].cur > 52 ) + { + if ( strstr(metrics->root.scaler.face->style_name, "Regular") + || strstr(metrics->root.scaler.face->style_name, "Book") + || strstr(metrics->root.scaler.face->style_name, "Medium") + || strcmp(metrics->root.scaler.face->style_name, "Italic") == 0 + || strcmp(metrics->root.scaler.face->style_name, "Oblique") == 0 ) + { + /* regular weight */ + if ( axis->widths[0].cur < 64 ) dist = 64 ; + else if (axis->widths[0].cur < 88) dist = 64; + else if (axis->widths[0].cur < 160) dist = 128; + else if (axis->widths[0].cur < 240) dist = 190; + else dist = ( dist ) & ~63; + } + else + { + /* bold gets a different threshold */ + if ( axis->widths[0].cur < 64 ) dist = 64 ; + else if (axis->widths[0].cur < 108) dist = 64; + else if (axis->widths[0].cur < 160) dist = 128; + else if (axis->widths[0].cur < 222) dist = 190; + else if (axis->widths[0].cur < 288) dist = 254; + else dist = ( dist + 16 ) & ~63; + } + + /* fix any unusually low values */ + if (dist < ( axis->widths[0].cur & ~63 ) ) + dist = (axis->widths[0].cur & ~63); + + /* fix any unusually high values */ + if (dist > ( ( axis->widths[0].cur + 64 ) & ~63 ) ) + dist = ( ( axis->widths[0].cur + 64 ) & ~63 ); + + if (dist < 64 ) dist = 64 ; + + } + if (dist < 52) + { + if (metrics->root.scaler.face->size->metrics.x_ppem < 9 ) + { + /*dist = 64 - (64 - dist) / 2 ;*/ + if (dist < 31) dist = 31; + } + else + dist = 52; + } + + } + else if ( !stem_snap_light && (( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) || + ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ) ) { /* smooth hinting process: very lightly quantize the stem width */ @@ -1569,7 +1702,7 @@ dist = ( dist + 32 ) & ~63; } } - else + else if (!stem_snap_light) { /* strong hinting process: snap the stem width to integer pixels */ FT_Pos org_dist = dist; @@ -1577,6 +1710,8 @@ dist = af_latin_snap_width( axis->widths, axis->width_count, dist ); + if ( stem_snap_light ) goto Done_Width; + if ( vertical ) { /* in the case of vertical hinting, always round */ @@ -2100,7 +2235,30 @@ { FT_Error error; int dim; + int e_strength = 0; + + int checked_embolden_light_env = 0; + FT_Bool embolden_light = FALSE; + if ( checked_embolden_light_env == 0 ) + { + char *embolden_light_env = getenv( "INFINALITY_FT_AUTOFIT_EMBOLDEN_LIGHT" ); + if ( embolden_light_env != NULL ) + { + if ( strcasecmp(embolden_light_env, "default" ) != 0 ) + { + if ( strcasecmp(embolden_light_env, "true") == 0) + embolden_light = TRUE; + else if ( strcasecmp(embolden_light_env, "1") == 0) + embolden_light = TRUE; + else if ( strcasecmp(embolden_light_env, "on") == 0) + embolden_light = TRUE; + else if ( strcasecmp(embolden_light_env, "yes") == 0) + embolden_light = TRUE; + } + } + checked_embolden_light_env = 1; + } error = af_glyph_hints_reload( hints, outline ); if ( error ) @@ -2146,8 +2304,15 @@ } #endif - if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) || - ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) ) + if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) ) + { + af_latin_hint_edges( hints, (AF_Dimension)dim ); + af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim ); + af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim ); + af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim ); + } + + if ( ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) ) { af_latin_hint_edges( hints, (AF_Dimension)dim ); af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim ); @@ -2157,6 +2322,34 @@ } af_glyph_hints_save( hints, outline ); + /* if the font is particularly thin, embolden it, up to 1 px */ + if ( embolden_light + && metrics->axis->widths[0].cur <= 80 + && !( dim == AF_DIMENSION_VERT ) + && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) + { + if ( metrics->axis->widths[0].cur + / metrics->root.scaler.face->size->metrics.x_ppem < 5 ) + { + /* weakest at width 80, stronger at lower widths */ + e_strength = 40 * ( 80 - metrics->axis->widths[0].cur)/80 ; + /* Don't do low ppems as much */ + if ( metrics->root.scaler.face->size->metrics.x_ppem < 9 ) + e_strength -= + ( 9 - metrics->root.scaler.face->size->metrics.x_ppem ) * 10; + } + + /* Embolden small fonts on a sliding scale. Better readability. */ + if ( e_strength > 0 + && ( strstr(metrics->root.scaler.face->style_name, "Regular") + || strstr(metrics->root.scaler.face->style_name, "Book") + || strstr(metrics->root.scaler.face->style_name, "Light") + || strstr(metrics->root.scaler.face->style_name, "Medium") + || strcmp(metrics->root.scaler.face->style_name, "Italic") == 0 + || strcmp(metrics->root.scaler.face->style_name, "Oblique") == 0 ) ) + FT_Outline_Embolden(outline,e_strength); + } + Exit: return error; } diff -Nur freetype-2.4.3.orig/src/autofit/afloader.c freetype-2.4.3.new/src/autofit/afloader.c --- freetype-2.4.3.orig/src/autofit/afloader.c 2009-07-03 08:28:24.000000000 -0500 +++ freetype-2.4.3.new/src/autofit/afloader.c 2010-10-22 22:22:04.073099288 -0500 @@ -180,8 +180,8 @@ AF_Edge edge2 = edge1 + axis->num_edges - 1; /* rightmost edge */ - - if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) ) +/* dont hint metrics - temporary until different hinting can be done */ + if ( FALSE && axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) ) { old_rsb = loader->pp2.x - edge2->opos; old_lsb = edge1->opos; @@ -214,7 +214,8 @@ slot->lsb_delta = loader->pp1.x - pp1x_uh; slot->rsb_delta = loader->pp2.x - pp2x_uh; } - else +/* dont hint metrics - temporary until different hinting can be done */ + else if (FALSE) { FT_Pos pp1x = loader->pp1.x; FT_Pos pp2x = loader->pp2.x; diff -Nur freetype-2.4.3.orig/src/base/ftlcdfil.c freetype-2.4.3.new/src/base/ftlcdfil.c --- freetype-2.4.3.orig/src/base/ftlcdfil.c 2010-04-01 03:18:57.000000000 -0500 +++ freetype-2.4.3.new/src/base/ftlcdfil.c 2010-11-14 18:33:58.300770778 -0600 @@ -21,9 +21,659 @@ #include FT_IMAGE_H #include FT_INTERNAL_OBJECTS_H +#include +#include +#include #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING +/* +int sinc( int val ) { + if (val == 0.0) + return(1.0); + return 256.0 * (sin(3.14*(double) (val/256.0))/(3.14*(double) (val/256.0))); +} + +int sigmoidal( int val ) { + int val2; + val2 = 256.0 /(1.0+exp(-(10.0*(val/256.0-.5)))); + return window(val2); +} + +int window ( int val ) +{ + if (val < 0 ) return 0; + if (val > 255) return 255; + else return val; +} +*/ +int gamma2 ( int val, float value ) { + return 256 * (1.0 - pow((1.0 - (float)val/ 256.0) , 1.0/value)); +} +/* +int gamma3 ( int val, float value ) { + 1- (x-1)^10 +} +*/ +/* +int gamma ( int val ) { + return 256 * (1.0 - pow((1.0 - (float)val/ 256.0) , 1.5)); +} + +int brick (int val) { + if (val > 50) return val; + else return 0; +} + +int brick2 (int val) { + if (val > 100) return val; + if (val > 50) return 100; + else return 0; +} + +int none (int val) { + return val; +} + +float pixmoid (int val1, int val2, int val3, int testval) +{ + int avg; + int result; + + avg = (val1 + val2 + val3)/3; + + if ( avg < 128 ) + { + if (testval > 128) result = avg; + else result = testval; + } + else + { + if (testval < 128) result = avg; + else result = testval; + } + + return none(result); +} + +float pixmoid2 (int val1, int val2, int val3, int testval) +{ + int avg; + int result; + + avg = (val1 + val2 + val3)/3; + + if ( avg > 160 ) return 255; + else if ( avg < 100 ) return 0; + else return testval; + + return none(result); + +} +*/ +/* +bool Resample(FT_Byte* line, int newWidth, int newHeight) +{ + + unsigned char* newData = new unsigned char [newWidth * newHeight * 3]; + + double scaleWidth = (double)newWidth / (double)_width; + double scaleHeight = (double)newHeight / (double)_height; + + for(int cy = 0; cy < newHeight; cy++) + { + for(int cx = 0; cx < newWidth; cx++) + { + int pixel = (cy * (newWidth *3)) + (cx*3); + int nearestMatch = (((int)(cy / scaleHeight) + * (_width *3)) + ((int)(cx / scaleWidth) *3) ); + + newData[pixel ] = _data[nearestMatch ]; + newData[pixel + 1] = _data[nearestMatch + 1]; + newData[pixel + 2] = _data[nearestMatch + 2]; + } + } + + delete[] _data; + _data = newData; + _width = newWidth; + _height = newHeight; + + return true; +}*/ + + + /* Stem alignment for bitmaps; A hack with very nice results */ + /* Ideally this could be implemented on the outline, prior to + * rasterization */ + static void + _lcd_stem_align ( FT_Bitmap* bitmap, + FT_Render_Mode mode, + FT_GlyphSlot slot ) + { + /*FT_Byte* weights = library->lcd_weights;*/ + FT_UInt width = (FT_UInt)bitmap->width; + FT_UInt height = (FT_UInt)bitmap->rows; + + FT_UInt h; + + FT_UInt alignment_type = 0; + FT_UInt checked_alignment_type = 0; + float pseudo_gamma_value = 1; + float pseudo_gamma_lt = 0; + FT_UInt checked_pseudo_gamma_value = 0; + + if ( checked_alignment_type == 0) + { + char *alignment_type_env = getenv( "INFINALITY_FT_STEM_ALIGNMENT_TYPE" ); + if ( alignment_type_env != NULL ) + { + /*sscanf ( alignment_type_env, "%d", &alignment_type );*/ + if (strcasecmp(alignment_type_env, "full") == 0) alignment_type = 1; + else if (strcasecmp(alignment_type_env, "medium") == 0) alignment_type = 2; + else if (strcasecmp(alignment_type_env, "medium1") == 0) alignment_type = 2; + else if (strcasecmp(alignment_type_env, "slight") == 0) alignment_type = 3; + else if (strcasecmp(alignment_type_env, "slight1") == 0) alignment_type = 3; + else if (strcasecmp(alignment_type_env, "medium2") == 0) alignment_type = 4; + else if (strcasecmp(alignment_type_env, "slight2") == 0) alignment_type = 5; + else if (strcasecmp(alignment_type_env, "infinality") == 0) alignment_type = 6; + else if (strcasecmp(alignment_type_env, "infinality1") == 0) alignment_type = 6; + else alignment_type = 0; + + if ( /*strstr(slot.metrics->root.scaler.face->style_name, "Regular") + || strstr(slot.metrics->root.scaler.face->style_name, "Book") + || strstr(slot.metrics->root.scaler.face->style_name, "Medium") + ||*/ strcasestr(slot->face->style_name, "Italic") + || strcasestr(slot->face->style_name, "Oblique") ) + alignment_type = 0; + if ( strcasestr(slot->face->style_name, "Bold") ) + alignment_type = 0; + } + checked_alignment_type = 1; + } + + if ( checked_pseudo_gamma_value == 0 ) + { + char *pseudo_gamma_value_env = getenv( "INFINALITY_FT_PSEUDO_GAMMA" ); + if ( pseudo_gamma_value_env != NULL ) + { + float f1, f2; + + if ( strcasecmp(pseudo_gamma_value_env, "default" ) != 0) + { + sscanf ( pseudo_gamma_value_env, "%f %f", &f1, &f2 ); + pseudo_gamma_lt = f1; + pseudo_gamma_value = f2; + } + if ( pseudo_gamma_value < .1 ) pseudo_gamma_value = 1; + if ( pseudo_gamma_lt < 0 ) pseudo_gamma_lt = 1; + } + checked_pseudo_gamma_value = 1; + } + + /*printf("%s,%s ", slot->face->family_name, slot->face->style_name);*/ + /*printf("%d ", slot->face->size->metrics.x_ppem);*/ + + /* set gamma value to 1 if out of range */ + if ( slot->face->size->metrics.x_ppem >= pseudo_gamma_lt ) + { + pseudo_gamma_value = 1; + } + + /* don't do alignment for < 10 */ + if ( slot->face->size->metrics.x_ppem < 10 ) + { + alignment_type = 0; + } + + if ( mode == FT_RENDER_MODE_LCD ) + { + if (width >= 4 && alignment_type != 0 ) + { + FT_Byte* line = bitmap->buffer; + FT_Byte* lineabove = bitmap->buffer; + FT_Byte* linebelow = bitmap->buffer; + + FT_UInt vsums[width], vtotals[width], offsetruns[width / 2][width/2]; + FT_UInt offsetrank[width/2], offsetchosen, stemwidths[width], stemwidthsmax; + FT_UInt stemwidth, vstems = 0; + + FT_UInt shift = 0; + FT_UInt xx; + + FT_ULong rtotal = 0, vweight = 0, wtotal = 0; + FT_UInt lreached = 0, rreached = 0, rr = 0, ll = 0, testwidth; + FT_UInt lwidth = 0, loffset = 0, offset = 0, htotal = 0, windowstart; + FT_UInt windowelement; + + line = bitmap->buffer; + rreached = 0; lreached = width, ll = width; + + lwidth = 0; + loffset = 0; + + + /* initialize variables - can this be done inline??? */ + for ( testwidth = 3; testwidth < 4; testwidth += 1 ) + { + for ( offset = 0; offset < 3; offset +=1 ) + { + offsetruns[offset][testwidth] = 0; + offsetrank[offset] = 0; + } + } + for ( xx = 0; xx < width; xx += 1 ) + { + stemwidths[xx] = 0; + } + + + for ( h = (FT_UInt)bitmap->rows; h > 0; h--, line += bitmap->pitch ) + { + + if (rr > rreached) rreached = rr; + if (ll < lreached) lreached = ll; + + rr = width; + ll = 0; + rtotal = 0; + htotal = 0; + + /*stemwidthsmax = 0;*/ + stemwidth = 0; + + + /* Calculate various sums and stem widths of glyph */ + for ( xx = 0; xx < width; xx += 1 ) + { + if (line[xx] >= 128) + { + stemwidth += 1; + /*if (stemwidth > stemwidthsmax) stemwidthsmax = stemwidth;*/ /* necessary ? */ + } + else + { + if (xx > 0 && line[xx - 1] >= 128) stemwidths[stemwidth] += 1; + stemwidth = 0; + } + + if (h == (FT_UInt)bitmap->rows) vsums[xx] = 0; + if ( h == (FT_UInt)bitmap->rows ) vtotals[xx] = 0; + + if (line[xx] == 0) vsums[xx] -= 255; + else vsums[xx] += line[xx]; + if (vsums[xx] < 0) vsums[xx] = 0; + + if (ll == 0 && line[xx] != 0) ll = (xx); + + if (line[xx] != 0) rr = (xx); + + if (xx < width / 2) vweight -= line[xx]; + else vweight += line[xx]; + + htotal += line [xx]; + vtotals[xx] += line[xx]; + } + + if ( h < (FT_UInt)bitmap->rows ) lineabove = line - bitmap->pitch; + if ( h > 1 ) linebelow = line + bitmap->pitch; + + + /* Determine the offset at which the most weight of the glyph exists */ + /* This is currently hard-coded at 3, but the code is here to adjust */ + for ( testwidth = 3; testwidth < 4; testwidth += 1 ) + { + /* test the widths at each of these offsets */ + for ( offset = 0; offset < 3; offset +=1 ) + { + /* test window of size testwidth, starting at offset */ + rtotal = 0; + for ( windowstart = offset; windowstart < width; + windowstart += testwidth ) + { + /* calculate total for this window */ + wtotal = 0; + for ( windowelement = windowstart; + windowelement < windowstart + testwidth; windowelement += 1 ) + if ( windowelement < width) + { + wtotal += line[windowelement]; + + /* Assign extra value to this subpixel under certain conditions */ + if ( line[windowelement] == 255 ) + { + /* favor if full pixels above and below */ + if ( h < (FT_UInt)bitmap->rows + && lineabove[windowelement] == 255 ) + wtotal += 10; + if ( h > 1 && linebelow[windowelement] == 255 ) + wtotal += 10; + + /* favor if full pixels next to them */ + if ( windowelement > 0 && line[windowelement-1] == 255 ) + { + wtotal += 10; + if ( windowelement > 1 && line[windowelement-2] == 255 ) + { + wtotal += 10; + if ( windowelement > 2 && line[windowelement-3] == 255 ) + wtotal += 10; + } + } + if ( windowelement < width - 1 && line[windowelement+1] == 255 ) + { + wtotal += 10; + if ( windowelement < width - 2 && line[windowelement+2] == 255 ) + { + wtotal += 10; + if ( windowelement < width - 3 && line[windowelement+3] == 255 ) + wtotal += 10; + } + } + } + } + /* divide window total by number of subpixel samples */ + /* add to total for this run */ + rtotal += (wtotal * wtotal) / testwidth; + } + /* dont count horizontal stems */ + /*if (rtotal < ( 255 * testwidth ) * (255 * testwidth) * (width / testwidth) / (testwidth * 2) )*/ + if ( rtotal < ( 255 * 255 * width / 2 ) ) + offsetruns[offset][testwidth] += rtotal; + } + + /* determine the best offset for this width and increment its counter */ + offsetchosen = 0; + for ( offset = 0; offset < 2; offset +=1 ) + { + if ( offsetruns[offset][testwidth] < offsetruns[offset + 1][testwidth] ){ + offsetrank[offset + 1] += 1; + offsetchosen = offset; + } + } + if (offsetchosen == 0) offsetrank[0] += 1; + } + } + + /* Use the best offset */ + loffset = 0; + for ( offset = 0; offset < 2; offset +=1 ) + { + if ( offsetrank[offset] < offsetrank[offset + 1] ){ + loffset = offset + 1; + } + } + + /* Use the best width */ + lwidth = 0; + stemwidthsmax = 0; + + for ( xx = 0; xx < width - 1; xx +=1 ) + { + if ( stemwidthsmax < stemwidths[xx + 1] ){ + lwidth = xx + 1; + stemwidthsmax = stemwidths[xx + 1]; + } + } + + /* currently unused */ + rreached = width - rreached; + + /* Set the number of vertical stem components */ + for ( xx = 0; xx < width; xx += 1 ) + { + if ( height > 0 && vsums[xx] / height > 110 ) + vstems++; + } + + + /******************** CALCULATE GLYPH ALIGNMENT *********************/ + /*printf(" %d,%d,%d,%d,%d,%d,%d\n", width, height, lreached, + rreached, lwidth,vstems,alignment_type );*/ + + shift = 0; + + /* infinality1 alignment - combination of below */ + if ( alignment_type == 6 ) + { + if ( lwidth < 5 ) alignment_type = 2; + else alignment_type = 1; + } + + /* strong alignment - shift glyph left or right one subpixel */ + if ( alignment_type == 1 /*&& vstems > 0*/ ) + { + if ( lwidth < 5) + { + /* lower widths should use this */ + if (loffset % 3 == 0) shift = -1; + if (loffset % 3 == 1) shift = 1; + if (loffset % 3 == 2) shift = 0; + } + else if ( lwidth < 6 ) + { + /* medium widths should use this */ + if (loffset % 3 == 0) shift = 1; + if (loffset % 3 == 1) shift = 0; + if (loffset % 3 == 2) shift = -1; + } + else if ( lwidth < 20 ) + { + /* higher widths should use this */ + if (loffset % 3 == 0) shift = 1; + if (loffset % 3 == 1) shift = -1; + if (loffset % 3 == 2) shift = 0; + } + } + + /* medium alignment - shift glyph ONLY LEFT one subpixel + * - a compromise to prevent spacing issues */ + else if ( alignment_type == 2 /*&& vstems > 0*/ ){ + + if ( lwidth < 5 ) + { + /* medium alignment - use next highest value instead */ + if ( loffset == 1 && offsetrank[0] > offsetrank[2] ) loffset = 0; + + if ( loffset % 3 == 0 ) shift = -1; + /*if (loffset % 3 == 1 ) shift = 1;*/ + if ( loffset % 3 == 2 ) shift = 0; + } + else if (lwidth < 6 ) + { + /* medium alignment - use next highest value instead */ + if ( loffset == 0 && offsetrank[2] > offsetrank[1] ) loffset = 2; + /*if (loffset % 3 == 0 ) shift = 1;*/ + if ( loffset % 3 == 1 ) shift = 0; + if ( loffset % 3 == 2 ) shift = -1; + } + else if ( lwidth < 20 ) + { + /* medium alignment - use next highest value instead */ + if ( loffset == 0 && offsetrank[1] > offsetrank[2] ) loffset = 1; + /*if (loffset % 3 == 0 ) shift = 1;*/ + if ( loffset % 3 == 1 ) shift = -1; + if ( loffset % 3 == 2 ) shift = 0; + } + } + + /* medium alignment 2 - shift glyph ONLY RIGHT one subpixel + * - a compromise to prevent spacing issues */ + else if ( alignment_type == 4 ){ + if ( lwidth < 5 ) + { + /* medium alignment - use next highest value instead */ + if ( loffset == 0 && offsetrank[1] > offsetrank[2] ) loffset = 1; + + /*if ( loffset % 3 == 0 ) shift = -1;*/ + if ( loffset % 3 == 1 ) shift = 1; + if ( loffset % 3 == 2 ) shift = 0; + } + else if ( lwidth < 6 ) + { + /* medium alignment - use next highest value instead */ + if ( loffset == 2 && offsetrank[0] > offsetrank[1] ) loffset = 0; + if ( loffset % 3 == 0 ) shift = 1; + if ( loffset % 3 == 1 ) shift = 0; + /*if ( loffset % 3 == 2 ) shift = -1;*/ + } + else if ( lwidth < 20 ) + { + /* medium alignment - use next highest value instead */ + if ( loffset == 1 && offsetrank[0] > offsetrank[2] ) loffset = 0; + if ( loffset % 3 == 0 ) shift = 1; + /*if (loffset % 3 == 1 ) shift = -1;*/ + if ( loffset % 3 == 2 ) shift = 0; + } + } + + /* light alignment - shift glyph ONLY LEFT one subpixel + * - a compromise to prevent spacing issues */ + else if ( alignment_type == 3 ){ + if ( lwidth < 5 ) + { + if ( loffset % 3 == 0 ) shift = -1; + /*if ( loffset % 3 == 1 ) shift = 1;*/ + if ( loffset % 3 == 2 ) shift = 0; + } + else if ( lwidth < 6 ) + { + /*if ( loffset % 3 == 0 ) shift = 1;*/ + if ( loffset % 3 == 1 ) shift = 0; + if ( loffset % 3 == 2 ) shift = -1; + } + else if ( lwidth < 20 ) + { + /*if ( loffset % 3 == 0 ) shift = 1;*/ + if ( loffset % 3 == 1 ) shift = -1; + if ( loffset % 3 == 2 ) shift = 0; + } + } + + /* light alignment 2 - shift glyph ONLY RIGHT one subpixel + * - a compromise to prevent spacing issues */ + else if ( alignment_type == 5 ){ + if ( lwidth < 5 ) + { + /*if ( loffset % 3 == 0 ) shift = -1;*/ + if ( loffset % 3 == 1 ) shift = 1; + if ( loffset % 3 == 2 ) shift = 0; + } + else if ( lwidth < 6 ) + { + if ( loffset % 3 == 0 ) shift = 1; + if ( loffset % 3 == 1 ) shift = 0; + /*if ( loffset % 3 == 2 ) shift = -1;*/ + } + else if ( lwidth < 20 ) + { + if ( loffset % 3 == 0 ) shift = 1; + /*if ( loffset % 3 == 1 ) shift = -1;*/ + if ( loffset % 3 == 2 ) shift = 0; + } + } + + /******************** ALIGN GLYPHS *********************/ + if (shift == -1) + { + 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 += 1 ) + { + line[xx] = line[xx+1]; + } + line[width - 1] = 1; + } + } + + else if (shift == -2) + { + line = bitmap->buffer; + for ( height = (FT_UInt)bitmap->rows; height > 0; height--, + line += bitmap->pitch ) + { + FT_UInt xx; + + for ( xx = 0; xx < width - 2; xx += 1 ) + { + line[xx] = line[xx+2]; + } + line[width - 2] = 1; + line[width - 1] = 1; + } + } + else if (shift == 1) + { + line = bitmap->buffer; + for ( height = (FT_UInt)bitmap->rows; height > 0; height--, + line += bitmap->pitch ) + { + FT_UInt xx; + + for ( xx = width - 1; xx > 0; xx -= 1 ) + { + line[xx] = line[xx-1]; + } + line[0] = 1; + } + } + else if (shift == 2) + { + line = bitmap->buffer; + for ( height = (FT_UInt)bitmap->rows; height > 0; height--, + line += bitmap->pitch ) + { + FT_UInt xx; + + for ( xx = width; xx > 1; xx -= 1 ) + { + line[xx] = line[xx-2]; + } + line[0] = 1; + line[1] = 1; + } + } + } + + if ( pseudo_gamma_value != 1 ) + { + FT_Byte* line = bitmap->buffer; + float ppem = (float)slot->face->size->metrics.x_ppem; + + 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] = gamma2 ( line[xx], pseudo_gamma_value );*/ + + /* sloped */ + /*line[xx] = gamma2 ( line[xx], pseudo_gamma_value - 5 + * (1-pseudo_gamma_value)/(pseudo_gamma_lt -5) + + ((1-pseudo_gamma_value)/(pseudo_gamma_lt -5)) * ppem );*/ + + /* 1/3-sloped */ + line[xx] = gamma2 ( line[xx], pseudo_gamma_value - 5 + * ((1-pseudo_gamma_value)/(3*(pseudo_gamma_lt -5))) + * + ((1-pseudo_gamma_value)/(3*(pseudo_gamma_lt -5))) * ppem ); + } + } + } + } + } + + + + + + /* define USE_LEGACY to implement the legacy filter */ #define USE_LEGACY @@ -287,9 +1017,31 @@ { 0x00, 0x55, 0x56, 0x55, 0x00 }; /* the values here sum up to a value larger than 256, */ /* providing a cheap gamma correction */ - static const FT_Byte default_filter[5] = + static FT_Byte default_filter[5] = { 0x10, 0x40, 0x70, 0x40, 0x10 }; + int checked_filter_params_env = 0; + + if ( checked_filter_params_env == 0 ) + { + char *filter_params = getenv( "INFINALITY_FT_FILTER_PARAMS" ); + if ( filter_params != NULL ) + { + float f1, f2, f3, f4, f5; + + if ( strcasecmp(filter_params, "default" ) != 0) + { + sscanf ( filter_params, "%f %f %f %f %f", &f1, &f2, &f3, &f4, &f5 ); + + default_filter[0] = (FT_Byte) (f1 * 255.0f + 0.5f); + default_filter[1] = (FT_Byte) (f2 * 255.0f + 0.5f); + default_filter[2] = (FT_Byte) (f3 * 255.0f + 0.5f); + default_filter[3] = (FT_Byte) (f4 * 255.0f + 0.5f); + default_filter[4] = (FT_Byte) (f5 * 255.0f + 0.5f); + } + } + checked_filter_params_env = 1; + } if ( !library ) return FT_Err_Invalid_Argument; @@ -304,17 +1056,20 @@ case FT_LCD_FILTER_DEFAULT: #if defined( FT_FORCE_LEGACY_LCD_FILTER ) + library->lcd_stem_align_func = _lcd_stem_align; library->lcd_filter_func = _ft_lcd_filter_legacy; library->lcd_extra = 0; #elif defined( FT_FORCE_LIGHT_LCD_FILTER ) + library->lcd_stem_align_func = _lcd_stem_align; ft_memcpy( library->lcd_weights, light_filter, 5 ); library->lcd_filter_func = _ft_lcd_filter_fir; library->lcd_extra = 2; #else + library->lcd_stem_align_func = _lcd_stem_align; ft_memcpy( library->lcd_weights, default_filter, 5 ); library->lcd_filter_func = _ft_lcd_filter_fir; library->lcd_extra = 2; @@ -325,6 +1080,7 @@ case FT_LCD_FILTER_LIGHT: ft_memcpy( library->lcd_weights, light_filter, 5 ); + library->lcd_stem_align_func = _lcd_stem_align; library->lcd_filter_func = _ft_lcd_filter_fir; library->lcd_extra = 2; break; @@ -332,6 +1088,7 @@ #ifdef USE_LEGACY case FT_LCD_FILTER_LEGACY: + library->lcd_stem_align_func = _lcd_stem_align; library->lcd_filter_func = _ft_lcd_filter_legacy; library->lcd_extra = 0; break; diff -Nur freetype-2.4.3.orig/src/base/ftobjs.c freetype-2.4.3.new/src/base/ftobjs.c --- freetype-2.4.3.orig/src/base/ftobjs.c 2010-08-06 13:02:15.000000000 -0500 +++ freetype-2.4.3.new/src/base/ftobjs.c 2010-11-14 15:43:02.906303324 -0600 @@ -562,6 +562,45 @@ FT_Bool autohint = FALSE; FT_Module hinter; + TT_Face face2=(TT_Face)face; + int checked_auto_autohint_env; + FT_Bool auto_autohint = FALSE; + + if ( !checked_auto_autohint_env ) + { + char *auto_autohint_env = getenv( "INFINALITY_FT_AUTO_AUTOHINT" ); + if ( auto_autohint_env != NULL ) + { + if ( strcasecmp(auto_autohint_env, "default" ) != 0 ) + { + if ( strcasecmp(auto_autohint_env, "true") == 0) auto_autohint = TRUE; + else if ( strcasecmp(auto_autohint_env, "1") == 0) auto_autohint = TRUE; + else if ( strcasecmp(auto_autohint_env, "on") == 0) auto_autohint = TRUE; + else if ( strcasecmp(auto_autohint_env, "yes") == 0) auto_autohint = TRUE; + } + } + checked_auto_autohint_env = 1; + } +/*printf("%d,%d ", load_flags, FT_LOAD_TARGET_NORMAL); +10000001000101000 +0#define FT_LOAD_DEFAULT 0x0 +0#define FT_LOAD_NO_SCALE 0x1 +0#define FT_LOAD_NO_HINTING 0x2 +1#define FT_LOAD_RENDER 0x4 +0#define FT_LOAD_NO_BITMAP 0x8 +1#define FT_LOAD_VERTICAL_LAYOUT 0x10 +0#define FT_LOAD_FORCE_AUTOHINT 0x20 +0#define FT_LOAD_CROP_BITMAP 0x40 +0#define FT_LOAD_PEDANTIC 0x80 +1#define FT_LOAD_ADVANCE_ONLY 0x100 +0#define FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH 0x200 +0#define FT_LOAD_NO_RECURSE 0x400 +0#define FT_LOAD_IGNORE_TRANSFORM 0x800 +0#define FT_LOAD_MONOCHROME 0x1000 +0#define FT_LOAD_LINEAR_DESIGN 0x2000 +0#define FT_LOAD_SBITS_ONLY 0x4000 +1#define FT_LOAD_NO_AUTOHINT 0x8000U +*/ if ( !face || !face->size || !face->glyph ) return FT_Err_Invalid_Face_Handle; @@ -627,8 +666,11 @@ if ( mode == FT_RENDER_MODE_LIGHT || - face->internal->ignore_unpatented_hinter ) + face->internal->ignore_unpatented_hinter || + ( auto_autohint && face2->max_profile.maxSizeOfInstructions == 0 ) ) + { autohint = TRUE; + } } } diff -Nur freetype-2.4.3.orig/src/base/ftoutln.c freetype-2.4.3.new/src/base/ftoutln.c --- freetype-2.4.3.orig/src/base/ftoutln.c 2010-06-27 08:03:58.000000000 -0500 +++ freetype-2.4.3.new/src/base/ftoutln.c 2010-11-14 09:06:38.779916717 -0600 @@ -888,6 +888,28 @@ FT_Int c, n, first; FT_Int orientation; + int checked_enhanced_embolden_env = 0; + FT_Bool enhanced_embolden = FALSE; + + if ( checked_enhanced_embolden_env == 0 ) + { + char *enhanced_embolden_env = getenv( "INFINALITY_FT_ENHANCED_EMBOLDEN" ); + if ( enhanced_embolden_env != NULL ) + { + if ( strcasecmp(enhanced_embolden_env, "default" ) != 0 ) + { + if ( strcasecmp(enhanced_embolden_env, "true") == 0) + enhanced_embolden = TRUE; + else if ( strcasecmp(enhanced_embolden_env, "1") == 0) + enhanced_embolden = TRUE; + else if ( strcasecmp(enhanced_embolden_env, "on") == 0) + enhanced_embolden = TRUE; + else if ( strcasecmp(enhanced_embolden_env, "yes") == 0) + enhanced_embolden = TRUE; + } + } + checked_enhanced_embolden_env = 1; + } if ( !outline ) return FT_Err_Invalid_Argument; @@ -957,7 +979,8 @@ } outline->points[n].x = v_cur.x + strength + in.x; - outline->points[n].y = v_cur.y + strength + in.y; + if ( !enhanced_embolden ) + outline->points[n].y = v_cur.y + strength + in.y; v_prev = v_cur; v_cur = v_next; diff -Nur freetype-2.4.3.orig/src/base/ftsynth.c freetype-2.4.3.new/src/base/ftsynth.c --- freetype-2.4.3.orig/src/base/ftsynth.c 2010-09-11 01:28:32.000000000 -0500 +++ freetype-2.4.3.new/src/base/ftsynth.c 2010-11-14 09:19:16.860168106 -0600 @@ -88,9 +88,28 @@ FT_Error error; FT_Pos xstr, ystr; + int checked_enhanced_embolden_env = 0; + FT_Bool enhanced_embolden = FALSE; + + if ( checked_enhanced_embolden_env == 0 ) + { + char *enhanced_embolden_env = getenv( "INFINALITY_FT_EMBOLDEN_MAINTAIN_WIDTH" ); + if ( enhanced_embolden_env != NULL ) + { + if ( strcasecmp(enhanced_embolden_env, "default" ) != 0 ) + { + if ( strcasecmp(enhanced_embolden_env, "true") == 0) enhanced_embolden = TRUE; + else if ( strcasecmp(enhanced_embolden_env, "1") == 0) enhanced_embolden = TRUE; + else if ( strcasecmp(enhanced_embolden_env, "on") == 0) enhanced_embolden = TRUE; + else if ( strcasecmp(enhanced_embolden_env, "yes") == 0) enhanced_embolden = TRUE; + } + } + checked_enhanced_embolden_env = 1; + } + if ( slot->format != FT_GLYPH_FORMAT_OUTLINE && - slot->format != FT_GLYPH_FORMAT_BITMAP ) + slot->format != FT_GLYPH_FORMAT_BITMAP ) return; /* some reasonable strength */ @@ -108,7 +127,7 @@ xstr = xstr * 2; ystr = xstr; } - else /* slot->format == FT_GLYPH_FORMAT_BITMAP */ + else if ( slot->format == FT_GLYPH_FORMAT_BITMAP ) { /* round to full pixels */ xstr &= ~63; @@ -146,7 +165,8 @@ slot->metrics.width += xstr; slot->metrics.height += ystr; slot->metrics.horiBearingY += ystr; - slot->metrics.horiAdvance += xstr; + /* Don't add any horiAdvance - Personal preference */ + if ( !enhanced_embolden ) slot->metrics.horiAdvance += xstr; slot->metrics.vertBearingX -= xstr / 2; slot->metrics.vertBearingY += ystr; slot->metrics.vertAdvance += ystr; diff -Nur freetype-2.4.3.orig/src/smooth/ftsmooth.c freetype-2.4.3.new/src/smooth/ftsmooth.c --- freetype-2.4.3.orig/src/smooth/ftsmooth.c 2010-08-09 19:47:47.000000000 -0500 +++ freetype-2.4.3.new/src/smooth/ftsmooth.c 2010-11-07 11:17:08.693652341 -0600 @@ -283,6 +283,9 @@ vec->y /= 3; } + if ( slot->library->lcd_stem_align_func ) + slot->library->lcd_stem_align_func ( bitmap, mode, slot ); + if ( slot->library->lcd_filter_func ) slot->library->lcd_filter_func( bitmap, mode, slot->library );