diff options
Diffstat (limited to 'testing/freetype-infinality/freetype-add-subpixel-hinting-infinality-20101114-1.patch')
-rw-r--r-- | testing/freetype-infinality/freetype-add-subpixel-hinting-infinality-20101114-1.patch | 2776 |
1 files changed, 2776 insertions, 0 deletions
diff --git a/testing/freetype-infinality/freetype-add-subpixel-hinting-infinality-20101114-1.patch b/testing/freetype-infinality/freetype-add-subpixel-hinting-infinality-20101114-1.patch new file mode 100644 index 0000000000..05e9c4414c --- /dev/null +++ b/testing/freetype-infinality/freetype-add-subpixel-hinting-infinality-20101114-1.patch @@ -0,0 +1,2776 @@ +Infinality Freetype Truetype Subpixel Hinting Patch +------------------------------------------------------------------- +Should patch cleanly to freetype-2.4.3 + + +Changes for 2010-11-14: + * Rule tweaks on various fonts. Fixed the Cyrillic y issue and e issue + with Trebuchet, and the ^ issue with Arial. Other issues + (firefox and @font-face) are still present to a degree. + + * A couple new rules to deal with various issues. (work in progress) + + * Additional commenting. + + * Some cleanup of obsolete code. + + * Added some debugging code for potential future enhancements. Please + ignore the mess. + + +Changes for 2010-10-22: + * I'm refocusing on just getting the subpixel looking nice, so I've stripped + back the rendering modes to just 2. The standard SUBPIXEL_HINTING and + the ADDITIONAL_TWEAKS. The rules structure is still in place. I recommend + using ADDITIONAL_TWEAKS mode. + + * Fixed an issue with monochrome rendering that made fonts look really bad. + There is still an issue with them, but they are at least tolerable to + look at now. + + * Added some testing code for detecting inline delta functions. Not sure + if this is useful yet. + + * Added more rules to deal with certain artifacts on various fonts, like the + issue with < > and ^. Created some "exception" rules for certain rules. + + * Reverted back to older rounding functions. The new experimental ones I + was trying were causing artifacts on some fonts. + + * Some code cleanup. + + +Changes for 2010-10-08: + * Fix PDF crashes. + +Changes for 2010-10-04: + * Update to freetype-2.4.3 + + +Changes for 2010-10-03: + * There are lots of changes for this one, some big, some small, and some + that still are not implemented. Not sure if I can remember them all + but I will try! THIS IS A POINT RELEASE THAT IS NOT + INTENDED TO WORK 100%. Some fonts and compile options may be broken + and the code may be inefficient and/or not syntactiacally correct. + That said, I do plan on using this on my system right away. + + * There are now "rendering modes" for the subpixel hinting, with the idea + that this will enventually be able to be controlled by fontconfig. The 4 + modes of enhanced hinting defined so far are: + 1) NATIVE HINTING - this is what freetype TT interpreter does by default. + 2) FIXED NATIVE HINTING - A slighly tweaked version of the above that + does "better" native rendering when displaying on LCD, for those + that still seem to like incorrect, thin fonts, which were only ever + there due to technical limitations. + 3) SUBPIXEL OPTIMIZED HINTING - this is straight up subpixel hinting with + very few tweaks. Just enough to get it working. + 4) COMPATIBILITY MODE HINTING - this is the sweet spot I'm working on + that will hopefully supplant #3 because it will work so well with all + fonts. The idea here is to tweak all available fonts so that each + renders well. + All of these modes either turn on or off switches in the interpreter + to make the fonts render properly for each mode. Right now these are only + compile-time options. + + * Subpixel-related code has been broken out into its own files, so as to not + clutter up the existing code. + + * The rasterizer now pays attention to the additional bits of MS rasterizer + v. 37, meaning that it can now indicate to fonts that it can handle + subpixel rendering. + + * The rounding functions have been adapted to accept a grid resolution + variable, which lets them work on pixel and subpixel boundaries + automatically. Y still needs to be implemented. + + * Additional conditions have been added to the switches, to further refine + how they are applied to different fonts. + + * What all this means qualitatively is that legacy fonts now render much + better. There are still some that need a bit of love, like Courier New. + + - Courier New has some fixes, and some breakage (Ghost pixels above bold + fonts, too thin on regular font) + - Times New Roman has some fixes and breakage (serifs, particularly) + - Tahoma and Trebuchet MS have been cleaned up + - Arial now snaps to grid better, but that causes breakage on a few glyphs + - Verdana 13 is now set to grid fit, but some glyhs are broken (mwxyz) + - Geneva and Geneva CY no longer look like turds + - Lucida Sans Unicode now looks arguably better than Lucida Grande + + + +Changes for 2010-09-16: + + * The changes from 2010-09-14 regarding subpixel when LIGHT hinting enabled + have been reverted due to problems. The old behavior is back. + + * Disable grayscale when subpixel is enabled. This results in better + behavior of some TT instructions within some fonts, like Times New Roman. + + * Some modification of the tweaks, in light of above. + + +Changes for 2010-09-14: + + /************************** NO LONGER IN PLACE *****************************/ + * Subpixel hinting is now used when the LIGHT hinting method and the TT + hinting is called. If FULL hinting is requested it will do the usual + behavior of the TT hinter. + + This allows for all previously existing behavior, plus the new subpixel + hinting behavior, all in the same compile, and it makes sense in that + the slight hinting of the autohinter is essentially doing the same thing + as this, which is not forcing X-direction hints. + + Previously, even if TT was selected, but LIGHT hinting was used, the + autohinter would still be forced. Other than this, autohint is not affected. + /***************************************************************************/ + + * Added a couple more conditionals around things to test whether subpixel + hinting is enabled. There were a few missing that ended up causing some + goofy hinting if subpixel was not enabled, but compiled in. + + + + + + + + + +diff -Nur freetype-2.4.3.orig/include/freetype/config/ftoption.h freetype-2.4.3.new/include/freetype/config/ftoption.h +--- freetype-2.4.3.orig/include/freetype/config/ftoption.h 2010-07-04 23:38:55.000000000 -0500 ++++ freetype-2.4.3.new/include/freetype/config/ftoption.h 2010-10-23 21:47:20.476211579 -0500 +@@ -501,6 +501,48 @@ + + /*************************************************************************/ + /* */ ++ /* Define TT_CONFIG_OPTION_SUBPIXEL_HINTING if you want to compile */ ++ /* EXPERIMENTAL subpixel hinting support into the TrueType driver. */ ++ /* This will replace the native TrueType hinting mechanism when */ ++ /* anything but FT_RENDER_MODE_MONO is requested. */ ++ /* */ ++ /* Enabling this causes the TrueType driver to ignore instructions */ ++ /* under certain conditions. This is done in accordance with the */ ++ /* guide here, with some minor differences: */ ++ /* */ ++ /* http://www.microsoft.com/typography/cleartype/truetypecleartype.aspx */ ++ /* */ ++ /* By undefining this, you will only compile the code necessary to */ ++ /* hint TrueType glyphs with native TT hinting. */ ++ /* */ ++ /* This option requires TT_CONFIG_OPTION_BYTECODE_INTERPRETER to be */ ++ /* defined. */ ++ /* */ ++/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING */ ++ ++ ++ /*************************************************************************/ ++ /* */ ++ /* Define TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS if you */ ++ /* want to enable additional subpixel hinting tweaks of individual fonts,*/ ++ /* glyphs, styles and sizes. The idea here is that some glyphs and */ ++ /* fonts still do not render in a desirable way with */ ++ /* TT_CONFIG_OPTION_SUBPIXEL_HINTING. */ ++ /* */ ++ /* This is disabled by default, as some people may not care, or may not */ ++ /* want the additional overhead involved in doing this. */ ++ /* */ ++ /* By undefining this, you will only compile the code necessary to */ ++ /* do subpixel hinting as defined above. */ ++ /* */ ++ /* This option requires TT_CONFIG_OPTION_SUBPIXEL_HINTING to be */ ++ /* defined. */ ++ /* */ ++/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS */ ++ ++ ++ /*************************************************************************/ ++ /* */ + /* If you define TT_CONFIG_OPTION_UNPATENTED_HINTING, a special version */ + /* of the TrueType bytecode interpreter is used that doesn't implement */ + /* any of the patented opcodes and algorithms. The patents related to */ +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 +@@ -81,6 +81,14 @@ + #define FT_PIX_ROUND( x ) FT_PIX_FLOOR( (x) + 32 ) + #define FT_PIX_CEIL( x ) FT_PIX_FLOOR( (x) + 63 ) + ++ /* ++ * These are used in ttinterp.c for subpixel hinting with an ++ * adjustable grids-per-pixel value. ++ */ ++#define FT_PIX_FLOOR_GRID( x, n ) ( (x) & ~(64 / n - 1) ) ++#define FT_PIX_ROUND_GRID( x, n ) FT_PIX_FLOOR_GRID( (x) + 32 / n, n) ++#define FT_PIX_CEIL_GRID( x, n ) FT_PIX_FLOOR_GRID( (x) + 63 / n, n) ++ + + /* + * Return the highest power of 2 that is <= value; this correspond to +diff -Nur freetype-2.4.3.orig/src/truetype/rules.mk freetype-2.4.3.new/src/truetype/rules.mk +--- freetype-2.4.3.orig/src/truetype/rules.mk 2009-03-14 08:45:26.000000000 -0500 ++++ freetype-2.4.3.new/src/truetype/rules.mk 2010-10-22 19:25:46.060977607 -0500 +@@ -30,7 +30,8 @@ + $(TT_DIR)/ttgload.c \ + $(TT_DIR)/ttinterp.c \ + $(TT_DIR)/ttgxvar.c \ +- $(TT_DIR)/ttdriver.c ++ $(TT_DIR)/ttdriver.c \ ++ $(TT_DIR)/ttsubpixel.c + + # TrueType driver headers + # +diff -Nur freetype-2.4.3.orig/src/truetype/truetype.c freetype-2.4.3.new/src/truetype/truetype.c +--- freetype-2.4.3.orig/src/truetype/truetype.c 2009-07-03 08:28:24.000000000 -0500 ++++ freetype-2.4.3.new/src/truetype/truetype.c 2010-10-22 19:25:46.061853066 -0500 +@@ -27,6 +27,7 @@ + + #ifdef TT_USE_BYTECODE_INTERPRETER + #include "ttinterp.c" ++#include "ttsubpixel.c" + #endif + + #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +diff -Nur freetype-2.4.3.orig/src/truetype/ttgload.c freetype-2.4.3.new/src/truetype/ttgload.c +--- freetype-2.4.3.orig/src/truetype/ttgload.c 2010-09-14 02:00:35.000000000 -0500 ++++ freetype-2.4.3.new/src/truetype/ttgload.c 2010-11-14 09:07:50.835981062 -0600 +@@ -33,7 +33,7 @@ + #endif + + #include "tterrors.h" +- ++#include "ttsubpixel.h" + + /*************************************************************************/ + /* */ +@@ -166,6 +166,12 @@ + loader->top_bearing = top_bearing; + loader->vadvance = advance_height; + ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ if ( loader->exec ) loader->exec->sph_tweak_flags = 0x00000; ++ /* this may not be the right place for this, but it works */ ++ if ( loader->exec && loader->exec->enhanced ) sph_set_tweaks( loader, glyph_index ); ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ ++ + if ( !loader->linear_def ) + { + loader->linear_def = 1; +@@ -1683,13 +1689,23 @@ + IS_HINTED( loader->load_flags ) ) + { + FT_Byte* widthp; ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ FT_Bool enhanced; + ++ enhanced = ++ FT_BOOL( FT_LOAD_TARGET_MODE( loader->load_flags ) ++ != FT_RENDER_MODE_MONO ); + ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + widthp = tt_face_get_device_metrics( face, + size->root.metrics.x_ppem, + glyph_index ); + ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ if ( ( !enhanced || BITMAP_WIDTHS ) && widthp ) ++#else + if ( widthp ) ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + glyph->metrics.horiAdvance = *widthp << 6; + } + +@@ -1883,8 +1899,13 @@ + { + TT_ExecContext exec; + FT_Bool grayscale; +- +- ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ FT_Bool subpixel_hinting; ++ FT_Bool grayscale_hinting; ++ /*FT_Bool compatible_widths; ++ FT_Bool symmetrical_smoothing; ++ FT_Bool bgr;*/ ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + if ( !size->cvt_ready ) + { + FT_Error error = tt_size_ready_bytecode( size ); +@@ -1898,20 +1919,75 @@ + if ( !exec ) + return TT_Err_Could_Not_Find_Context; + ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ subpixel_hinting = ++ FT_BOOL( (FT_LOAD_TARGET_MODE( load_flags ) != FT_RENDER_MODE_MONO) ++ && SET_SUBPIXEL ); ++ ++ if ( subpixel_hinting ) grayscale = grayscale_hinting = FALSE; ++ else if ( SET_GRAYSCALE ) ++ { ++ grayscale = grayscale_hinting = TRUE; ++ subpixel_hinting = FALSE; ++ } ++ ++ exec->enhanced = ( subpixel_hinting ++ || grayscale_hinting ); ++ ++ exec->rasterizer_version = SET_RASTERIZER_VERSION; ++ ++ exec->compatible_widths = SET_COMPATIBLE_WIDTHS; ++ /*FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) ++ != TT_LOAD_COMPATIBLE_WIDTHS );*/ ++ ++ exec->symmetrical_smoothing = FALSE; ++ /*FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) ++ != TT_LOAD_SYMMETRICAL_SMOOTHING );*/ ++ ++ exec->bgr = FALSE; ++ /*FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) ++ != TT_LOAD_BGR );*/ ++#else + grayscale = + FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != FT_RENDER_MODE_MONO ); ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + + TT_Load_Context( exec, face, size ); + +- /* a change from mono to grayscale rendering (and vice versa) */ ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ ++ /* a change from mono to subpixel rendering (and vice versa) */ + /* requires a re-execution of the CVT program */ +- if ( grayscale != exec->grayscale ) ++ if ( subpixel_hinting != exec->subpixel_hinting ) ++ { ++ FT_UInt i; ++ ++ exec->subpixel_hinting = subpixel_hinting; ++ ++ for ( i = 0; i < size->cvt_size; i++ ) ++ size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale ); ++ tt_size_run_prep( size ); ++ } ++ ++ /* a change from mono to grayscale rendering (and vice versa) */ ++ /* requires a re-execution of the CVT program */ ++ if ( grayscale != exec->grayscale_hinting ) + { + FT_UInt i; + ++ exec->grayscale_hinting = grayscale_hinting; + +- FT_TRACE4(( "tt_loader_init: grayscale change," +- " re-executing `prep' table\n" )); ++ for ( i = 0; i < size->cvt_size; i++ ) ++ size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale ); ++ tt_size_run_prep( size ); ++ } ++#else ++ ++ /* a change from mono to grayscale rendering (and vice versa) */ ++ /* requires a re-execution of the CVT program */ ++ if ( grayscale != exec->grayscale ) ++ { ++ FT_UInt i; + + exec->grayscale = grayscale; + +@@ -1919,6 +1995,7 @@ + size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale ); + tt_size_run_prep( size ); + } ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + + /* see whether the cvt program has disabled hinting */ + if ( exec->GS.instruct_control & 1 ) +@@ -2050,6 +2127,7 @@ + if ( face->postscript.isFixedPitch && + ( load_flags & FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ) == 0 ) + glyph->linearHoriAdvance = face->horizontal.advance_Width_Max; ++ + } + + return TT_Err_Ok; +@@ -2125,6 +2203,9 @@ + } + else + glyph->outline.flags |= FT_OUTLINE_IGNORE_DROPOUTS; ++ ++ ++ + } + + #endif /* TT_USE_BYTECODE_INTERPRETER */ +diff -Nur freetype-2.4.3.orig/src/truetype/ttinterp.c freetype-2.4.3.new/src/truetype/ttinterp.c +--- freetype-2.4.3.orig/src/truetype/ttinterp.c 2010-10-01 01:08:19.000000000 -0500 ++++ freetype-2.4.3.new/src/truetype/ttinterp.c 2010-11-14 09:25:21.736322597 -0600 +@@ -27,10 +27,12 @@ + + #include "tterrors.h" + ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++#include "ttsubpixel.h" ++#endif + + #ifdef TT_USE_BYTECODE_INTERPRETER + +- + #define TT_MULFIX FT_MulFix + #define TT_MULDIV FT_MulDiv + #define TT_MULDIV_NO_ROUND FT_MulDiv_No_Round +@@ -150,11 +152,11 @@ + #define NORMalize( x, y, v ) \ + Normalize( EXEC_ARG_ x, y, v ) + +-#define SET_SuperRound( scale, flags ) \ +- SetSuperRound( EXEC_ARG_ scale, flags ) ++#define SET_SuperRound( scale, flags, res ) \ ++ SetSuperRound( EXEC_ARG_ scale, flags, res ) + +-#define ROUND_None( d, c ) \ +- Round_None( EXEC_ARG_ d, c ) ++#define ROUND_None( d, c, e ) \ ++ Round_None( EXEC_ARG_ d, c, e ) + + #define INS_Goto_CodeRange( range, ip ) \ + Ins_Goto_CodeRange( EXEC_ARG_ range, ip ) +@@ -165,8 +167,8 @@ + #define CUR_Func_move_orig( z, p, d ) \ + CUR.func_move_orig( EXEC_ARG_ z, p, d ) + +-#define CUR_Func_round( d, c ) \ +- CUR.func_round( EXEC_ARG_ d, c ) ++#define CUR_Func_round( d, c, e ) \ ++ CUR.func_round( EXEC_ARG_ d, c, e ) + + #define CUR_Func_read_cvt( index ) \ + CUR.func_read_cvt( EXEC_ARG_ index ) +@@ -246,6 +248,12 @@ + #define GUESS_VECTOR( V ) + #endif + ++ ++ /*FT_Int CUR.num_delta_funcs;*/ ++ /*FT_ULong inline_delta_funcs[5];*/ ++ /*FT_Long CUR.infunc;*/ ++ ++ + /*************************************************************************/ + /* */ + /* CODERANGE FUNCTIONS */ +@@ -1838,24 +1846,33 @@ + FT_ASSERT( !CUR.face->unpatented_hinting ); + #endif + +- v = CUR.GS.freeVector.x; +- +- if ( v != 0 ) ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ if ( !CUR.enhanced || CUR.sph_tweak_flags & SPH_TWEAK_ALLOW_DMOVE_FREEV ) + { +- zone->cur[point].x += TT_MULDIV( distance, ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ ++ ++ v = CUR.GS.freeVector.x; ++ ++ if ( v != 0 ) ++ { ++ zone->cur[point].x += TT_MULDIV( distance, + v * 0x10000L, + CUR.F_dot_P ); + +- zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; ++ zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; ++ } ++ ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + } ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + + v = CUR.GS.freeVector.y; + + if ( v != 0 ) + { + zone->cur[point].y += TT_MULDIV( distance, +- v * 0x10000L, +- CUR.F_dot_P ); ++ v * 0x10000L, ++ CUR.F_dot_P ); + + zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y; + } +@@ -1895,18 +1912,17 @@ + + if ( v != 0 ) + zone->org[point].x += TT_MULDIV( distance, +- v * 0x10000L, +- CUR.F_dot_P ); ++ v * 0x10000L, ++ CUR.F_dot_P ); + + v = CUR.GS.freeVector.y; + + if ( v != 0 ) + zone->org[point].y += TT_MULDIV( distance, +- v * 0x10000L, +- CUR.F_dot_P ); ++ v * 0x10000L, ++ CUR.F_dot_P ); + } + +- + /*************************************************************************/ + /* */ + /* Special versions of Direct_Move() */ +@@ -1923,9 +1939,16 @@ + FT_F26Dot6 distance ) + { + FT_UNUSED_EXEC; +- +- zone->cur[point].x += distance; +- zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ if ( !CUR.enhanced ++ || ( CUR.sph_tweak_flags & SPH_TWEAK_ALLOW_DMOVEX_FREEV ) ) ++ { ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ ++ zone->cur[point].x += distance; ++ zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ } ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + } + + +@@ -1940,7 +1963,6 @@ + zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y; + } + +- + /*************************************************************************/ + /* */ + /* Special versions of Direct_Move_Orig() */ +@@ -1959,6 +1981,7 @@ + FT_UNUSED_EXEC; + + zone->org[point].x += distance; ++ + } + + +@@ -1969,7 +1992,7 @@ + { + FT_UNUSED_EXEC; + +- zone->org[point].y += distance; ++ zone->org[point].y += distance; + } + + +@@ -1997,7 +2020,8 @@ + /* */ + static FT_F26Dot6 + Round_None( EXEC_OP_ FT_F26Dot6 distance, +- FT_F26Dot6 compensation ) ++ FT_F26Dot6 compensation, ++ FT_Int resolution ) + { + FT_F26Dot6 val; + +@@ -2016,6 +2040,7 @@ + if ( val > 0 ) + val = 0; + } ++ + return val; + } + +@@ -2038,7 +2063,8 @@ + /* */ + static FT_F26Dot6 + Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance, +- FT_F26Dot6 compensation ) ++ FT_F26Dot6 compensation, ++ FT_Int resolution ) + { + FT_F26Dot6 val; + +@@ -2047,15 +2073,15 @@ + + if ( distance >= 0 ) + { +- val = distance + compensation + 32; ++ val = distance + compensation + 32 / resolution; + if ( distance && val > 0 ) +- val &= ~63; ++ val &= ~(64 / resolution - 1); + else + val = 0; + } + else + { +- val = -FT_PIX_ROUND( compensation - distance ); ++ val = -FT_PIX_ROUND_GRID( compensation - distance, resolution ); + if ( val > 0 ) + val = 0; + } +@@ -2082,22 +2108,22 @@ + /* */ + static FT_F26Dot6 + Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance, +- FT_F26Dot6 compensation ) ++ FT_F26Dot6 compensation, ++ FT_Int resolution ) + { + FT_F26Dot6 val; + + FT_UNUSED_EXEC; + +- + if ( distance >= 0 ) + { +- val = FT_PIX_FLOOR( distance + compensation ) + 32; ++ val = FT_PIX_FLOOR_GRID( distance + compensation, resolution ) + 32 / resolution; + if ( distance && val < 0 ) + val = 0; + } + else + { +- val = -( FT_PIX_FLOOR( compensation - distance ) + 32 ); ++ val = -( FT_PIX_FLOOR_GRID( compensation - distance, resolution ) + 32 / resolution ); + if ( val > 0 ) + val = 0; + } +@@ -2124,7 +2150,8 @@ + /* */ + static FT_F26Dot6 + Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance, +- FT_F26Dot6 compensation ) ++ FT_F26Dot6 compensation, ++ FT_Int resolution ) + { + FT_F26Dot6 val; + +@@ -2135,13 +2162,13 @@ + { + val = distance + compensation; + if ( distance && val > 0 ) +- val &= ~63; ++ val &= ~(64 / resolution - 1 ); + else + val = 0; + } + else + { +- val = -( ( compensation - distance ) & -64 ); ++ val = -( ( compensation - distance ) & -(64 / resolution) ); + if ( val > 0 ) + val = 0; + } +@@ -2168,7 +2195,8 @@ + /* */ + static FT_F26Dot6 + Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance, +- FT_F26Dot6 compensation ) ++ FT_F26Dot6 compensation, ++ FT_Int resolution ) + { + FT_F26Dot6 val; + +@@ -2177,15 +2205,15 @@ + + if ( distance >= 0 ) + { +- val = distance + compensation + 63; ++ val = distance + compensation + (64 / resolution - 1); + if ( distance && val > 0 ) +- val &= ~63; ++ val &= ~(64 / resolution - 1); + else + val = 0; + } + else + { +- val = - FT_PIX_CEIL( compensation - distance ); ++ val = - FT_PIX_CEIL_GRID( compensation - distance, resolution ); + if ( val > 0 ) + val = 0; + } +@@ -2212,24 +2240,26 @@ + /* */ + static FT_F26Dot6 + Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance, +- FT_F26Dot6 compensation ) ++ FT_F26Dot6 compensation, ++ FT_Int resolution ) + { + FT_F26Dot6 val; + + FT_UNUSED_EXEC; + + +- if ( distance >= 0 ) ++ if ( distance >= 0 ) + { +- val = distance + compensation + 16; ++ val = distance + compensation + 16 / resolution ; + if ( distance && val > 0 ) +- val &= ~31; ++ val &= ~(32 / resolution - 1); + else + val = 0; + } + else + { +- val = -FT_PAD_ROUND( compensation - distance, 32 ); ++ ++ val = -FT_PAD_ROUND( compensation - distance, 32 / resolution ); + if ( val > 0 ) + val = 0; + } +@@ -2262,7 +2292,8 @@ + /* */ + static FT_F26Dot6 + Round_Super( EXEC_OP_ FT_F26Dot6 distance, +- FT_F26Dot6 compensation ) ++ FT_F26Dot6 compensation, ++ FT_Int resolution ) + { + FT_F26Dot6 val; + +@@ -2310,7 +2341,8 @@ + /* */ + static FT_F26Dot6 + Round_Super_45( EXEC_OP_ FT_F26Dot6 distance, +- FT_F26Dot6 compensation ) ++ FT_F26Dot6 compensation, ++ FT_Int resolution ) + { + FT_F26Dot6 val; + +@@ -2401,7 +2433,8 @@ + /* */ + static void + SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod, +- FT_Long selector ) ++ FT_Long selector, ++ FT_Int resolution ) + { + switch ( (FT_Int)( selector & 0xC0 ) ) + { +@@ -3061,13 +3094,13 @@ + + + #define DO_SROUND \ +- SET_SuperRound( 0x4000, args[0] ); \ ++ SET_SuperRound( 0x4000, args[0], 1 ); \ + CUR.GS.round_state = TT_Round_Super; \ + CUR.func_round = (TT_Round_Func)Round_Super; + + + #define DO_S45ROUND \ +- SET_SuperRound( 0x2D41, args[0] ); \ ++ SET_SuperRound( 0x2D41, args[0], 1 ); \ + CUR.GS.round_state = TT_Round_Super_45; \ + CUR.func_round = (TT_Round_Func)Round_Super_45; + +@@ -3228,11 +3261,11 @@ + + + #define DO_ODD \ +- args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 ); ++ args[0] = ( ( CUR_Func_round( args[0], 0, 1 ) & 127 ) == 64 ); + + + #define DO_EVEN \ +- args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 ); ++ args[0] = ( ( CUR_Func_round( args[0], 0, 1 ) & 127 ) == 0 ); + + + #define DO_AND \ +@@ -3281,7 +3314,31 @@ + #define DO_CEILING \ + args[0] = FT_PIX_CEIL( args[0] ); + +- ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++#define DO_RS \ ++ { \ ++ FT_ULong I = (FT_ULong)args[0]; \ ++ \ ++ \ ++ if ( BOUNDSL( I, CUR.storeSize ) ) \ ++ { \ ++ if ( CUR.pedantic_hinting ) \ ++ { \ ++ ARRAY_BOUND_ERROR; \ ++ } \ ++ else \ ++ args[0] = 0; \ ++ } \ ++ else \ ++ /* Subpixel Hinting - Avoid Typeman Dstroke and Istroke \ ++ * and Vacuform Rounds */ \ ++ if ( CUR.enhanced \ ++ && ( I == 24 || I == 22 || I == 8 ) \ ++ && !( CUR.sph_tweak_flags & SPH_TWEAK_DO_RS ) ) \ ++ args[0] = 0; \ ++ else args[0] = CUR.storage[I]; \ ++ } ++#else + #define DO_RS \ + { \ + FT_ULong I = (FT_ULong)args[0]; \ +@@ -3299,6 +3356,7 @@ + else \ + args[0] = CUR.storage[I]; \ + } ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + + + #define DO_WS \ +@@ -3378,12 +3436,12 @@ + #define DO_ROUND \ + args[0] = CUR_Func_round( \ + args[0], \ +- CUR.tt_metrics.compensations[CUR.opcode - 0x68] ); ++ CUR.tt_metrics.compensations[CUR.opcode - 0x68], 1 ); + + + #define DO_NROUND \ + args[0] = ROUND_None( args[0], \ +- CUR.tt_metrics.compensations[CUR.opcode - 0x6C] ); ++ CUR.tt_metrics.compensations[CUR.opcode - 0x6C], 1 ); + + + #define DO_MAX \ +@@ -4554,7 +4612,21 @@ + FT_ULong n; + TT_DefRecord* rec; + TT_DefRecord* limit; +- ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ int opcode_pattern[4][12]= { ++ /* VacuFormRound function */ ++ {0x45,0x23,0x46,0x60,0x20}, ++ /* inline delta function 1 */ ++ {0x4B,0x53,0x23,0x4B,0x51,0x5A,0x58,0x38,0x1B,0x21,0x21,0x59}, ++ /* inline delta function 2 */ ++ {0x4B,0x54,0x58,0x38,0x1B,0x5A,0x21,0x21,0x59}, ++ /* diagonal stroke function */ ++ {0x20,0x20,0x40,0x60,0x47,0x40,0x23,0x42}, ++ }; ++ int opcode_patterns = 4; ++ int i; ++ int opcode_pointer[4] = {0,0,0,0} ; ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + + /* some font programs are broken enough to redefine functions! */ + /* We will then parse the current table. */ +@@ -4592,6 +4664,7 @@ + rec->opc = (FT_UInt16)n; + rec->start = CUR.IP + 1; + rec->active = TRUE; ++ rec->inline = FALSE; + + if ( n > CUR.maxFunc ) + CUR.maxFunc = (FT_UInt16)n; +@@ -4601,20 +4674,63 @@ + + while ( SKIP_Code() == SUCCESS ) + { ++ /*printf ("%d ", CUR.opcode);*/ ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ for ( i = 0; i < opcode_patterns; i++ ){ ++ if ( CUR.opcode == opcode_pattern[i][opcode_pointer[i]] ) ++ { ++ /*printf ("function %d, opcode ptrn: %d op# %d: %d FOUND -------------\n ", n, i, opcode_pointer[i], CUR.opcode);*/ ++ opcode_pointer[i] += 1; ++ ++ if (i == 0 && opcode_pointer[0] == 5){ ++ /*inline_delta_funcs[CUR.num_delta_funcs] = n; ++ CUR.num_delta_funcs++;*/ ++ /*printf ("Vacuform Round FUNCTION %d detected \n ", n);*/ ++ if (CUR.enhanced) /*rec->active = FALSE;*/ ++ opcode_pointer[i] = 0; ++ } ++ if (i == 1 && opcode_pointer[1] == 12){ ++ /*rec->active = FALSE;*/ ++ /*CUR.inline_delta_funcs[CUR.num_delta_funcs] = n; ++ CUR.num_delta_funcs++;*/ ++ rec->inline = TRUE; ++ /*printf ("inline delta FUNCTION1 %d detected \n ", n, CUR.num_delta_funcs);*/ ++ opcode_pointer[i] = 0; ++ } ++ if (i == 2 && opcode_pointer[1] == 9){ ++ /* CUR.inline_delta_funcs[CUR.num_delta_funcs] = n; ++ CUR.num_delta_funcs++;*/ ++ rec->inline = TRUE; ++ /*printf ("inline delta2 FUNCTION2 %d detected \n ", n, CUR.num_delta_funcs);*/ ++ opcode_pointer[i] = 0; ++ } ++ if (i == 4 && opcode_pointer[1] == 8){ ++ /* CUR.inline_delta_funcs[CUR.num_delta_funcs] = n; ++ CUR.num_delta_funcs++;*/ ++ /*rec->inline = TRUE;*/ ++ /*printf ("diagonal stroke function %d detected \n ", n, CUR.num_delta_funcs);*/ ++ opcode_pointer[i] = 0; ++ } ++ } ++ else { ++ opcode_pointer[i]=0; ++ } ++ } ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ ++ + switch ( CUR.opcode ) + { +- case 0x89: /* IDEF */ +- case 0x2C: /* FDEF */ +- CUR.error = TT_Err_Nested_DEFS; +- return; ++ case 0x89: /* IDEF */ ++ case 0x2C: /* FDEF */ ++ CUR.error = TT_Err_Nested_DEFS; ++ return; + +- case 0x2D: /* ENDF */ +- return; ++ case 0x2D: /* ENDF */ ++ return; + } + } + } + +- + /*************************************************************************/ + /* */ + /* ENDF[]: END Function definition */ +@@ -4643,6 +4759,13 @@ + + CUR.step_ins = FALSE; + ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ /* CUR.enhanced may be turned off prior to function calls. This ++ * ensures it is turned back on. ++ */ ++ CUR.enhanced = ( CUR.subpixel_hinting || CUR.grayscale_hinting ); ++#endif /*TT_CONFIG_OPTION_SUBPIXEL_HINTING*/ ++ + if ( pRec->Cur_Count > 0 ) + { + CUR.callTop++; +@@ -4675,8 +4798,9 @@ + FT_ULong F; + TT_CallRec* pCrec; + TT_DefRecord* def; +- +- ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ FT_Bool oldF; ++#endif /*TT_CONFIG_OPTION_SUBPIXEL_HINTING*/ + /* first of all, check the index */ + + F = args[0]; +@@ -4713,6 +4837,17 @@ + if ( !def->active ) + goto Fail; + ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ /* This is test code used to detect inline delta functions */ ++ oldF = def->inline; ++ if (CUR.enhanced) ++ { ++ if ( def->inline ) { CUR.infunc = TRUE; } ++ } ++ ++ /* if ( F == 35 || F == 34 ){ CUR.enhanced = 0; printf ("ENTERING %d ", F); }*/ ++#endif /*TT_CONFIG_OPTION_SUBPIXEL_HINTING*/ ++ + /* check the call stack */ + if ( CUR.callTop >= CUR.callSize ) + { +@@ -4733,6 +4868,12 @@ + def->start ); + + CUR.step_ins = FALSE; ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ { ++ CUR.infunc = oldF; /*printf ("Leaving %d ", F);*/ ++ } ++ /*if ( F == 35 || F == 34 ){ CUR.enhanced = 1; printf ("Leaving %d ", F); }*/ ++#endif /*TT_CONFIG_OPTION_SUBPIXEL_HINTING*/ + return; + + Fail: +@@ -4752,7 +4893,9 @@ + FT_ULong F; + TT_CallRec* pCrec; + TT_DefRecord* def; +- ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ FT_Bool oldF; ++#endif /*TT_CONFIG_OPTION_SUBPIXEL_HINTING*/ + + /* first of all, check the index */ + F = args[1]; +@@ -4788,7 +4931,16 @@ + /* check that the function is active */ + if ( !def->active ) + goto Fail; +- ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ oldF=def->inline; ++ if (CUR.enhanced) ++ { ++ if ( def->inline ) ++ { ++ CUR.infunc = TRUE; ++ } ++ } ++#endif /*TT_CONFIG_OPTION_SUBPIXEL_HINTING*/ + /* check stack */ + if ( CUR.callTop >= CUR.callSize ) + { +@@ -4811,6 +4963,11 @@ + + CUR.step_ins = FALSE; + } ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ { ++ CUR.infunc = oldF; ++ } ++#endif /*TT_CONFIG_OPTION_SUBPIXEL_HINTING*/ + return; + + Fail: +@@ -5154,6 +5311,10 @@ + } + } + ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ /* Disable Type 2 Vacuform Rounds - e.g. Arial Narrow */ ++ if ( CUR.enhanced && FT_ABS(D) == 64) D += 1; ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + args[0] = D; + } + +@@ -5634,13 +5795,21 @@ + } + #endif + +- if ( CUR.GS.freeVector.x != 0 ) ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ if ( !CUR.enhanced ++ || ( CUR.enhanced ++ && ( CUR.sph_tweak_flags & SPH_TWEAK_ALLOW_MOVEZP2_FREEV ) )) + { +- CUR.zp2.cur[point].x += dx; +- if ( touch ) +- CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X; ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ ++ if ( CUR.GS.freeVector.x != 0 ) ++ { ++ CUR.zp2.cur[point].x += dx; ++ if ( touch ) ++ CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X; ++ } ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + } +- ++#endif + if ( CUR.GS.freeVector.y != 0 ) + { + CUR.zp2.cur[point].y += dy; +@@ -5649,7 +5818,6 @@ + } + } + +- + /*************************************************************************/ + /* */ + /* SHP[a]: SHift Point by the last point */ +@@ -5819,7 +5987,7 @@ + { + FT_F26Dot6 dx, dy; + FT_UShort point; +- ++ FT_Int B1, B2; + + if ( CUR.top < CUR.GS.loop + 1 ) + { +@@ -5863,11 +6031,64 @@ + } + } + else +- MOVE_Zp2_Point( point, dx, dy, TRUE ); ++ { ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ /* The conditionals here still to not do a perfect job and need work. ++ * ++ * If not using enhanced rendering, allow ZP2 move. ++ * ++ * If using enhanced rendering, allow ZP2 point move if: ++ * - The glyph is composite ++ * - The glyph is specifically set to allow SHPIX moves ++ * - The move is in the Y direction on a previously touched point ++ * ++ * It seems that what qualifies as a previously touched point varies ++ * somewhat from font to font. Some render better when either X or Y ++ * must be touched ( SPH_TWEAK_SHPIX_CLASS_A ) and some render better ++ * when both must be touched. ++ */ ++ ++ if ( CUR.enhanced ) ++ { ++ B1 = CUR.zp2.cur[point].y; ++ if ( CUR.is_composite ++ || ( CUR.sph_tweak_flags & SPH_TWEAK_DO_SHPIX ) ++ || ( /*CUR.infunc && !(CUR.sph_tweak_flags ++ & SPH_TWEAK_SKIP_NONPIXEL_INLINE_MOVES) &&*/ /*CUR.infunc &&*/ ++ CUR.GS.freeVector.y != 0 ++ && CUR.iup_called == 0 ++ && CUR.iupy_called == 0 ++ && ( ++ ( (CUR.sph_tweak_flags & SPH_TWEAK_SHPIX_CLASS_A ) ++ && (( CUR.pts.tags[point] & FT_CURVE_TAG_TOUCH_X ) != 0 ++ || ( CUR.pts.tags[point] & FT_CURVE_TAG_TOUCH_Y ) != 0 )) ++ || ( !(CUR.sph_tweak_flags & SPH_TWEAK_SHPIX_CLASS_A ) ++ && (( CUR.pts.tags[point] & FT_CURVE_TAG_TOUCH_X ) != 0 ++ && ( CUR.pts.tags[point] & FT_CURVE_TAG_TOUCH_Y ) != 0 )) ++ ) ++ /*|| !CUR.infunc*/ ) ) ++ MOVE_Zp2_Point( point, dx, dy, TRUE ); ++ ++ B2 = CUR.zp2.cur[point].y; ++ ++ /* Reverse moves that move the point off a pixel boundary */ ++ if ((CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_INLINE_MOVES) ++ && B1 % 64 == 0 ++ && B2 % 64 != 0 ) ++ { ++ /*printf ("Reversing ZP2 move ");*/ ++ MOVE_Zp2_Point( point, -dx, -dy, TRUE ); ++ } ++ } ++ else ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ ++ MOVE_Zp2_Point( point, dx, dy, TRUE ); ++ ++ } + + CUR.GS.loop--; + } +- ++ /*printf("SHPIX:%d ", CUR.infunc);*/ + CUR.GS.loop = 1; + CUR.new_top = CUR.args; + } +@@ -5884,7 +6105,17 @@ + { + FT_UShort point; + FT_F26Dot6 distance; ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ FT_Int resolution = 1; + ++ if ( CUR.enhanced ) ++ { ++ if ( CUR.GS.freeVector.x != 0 ) ++ resolution = Grids_Per_Pixel_X; ++ else if ( CUR.GS.freeVector.y != 0 ) ++ resolution = Grids_Per_Pixel_Y; ++ } ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + + point = (FT_UShort)args[0]; + +@@ -5908,6 +6139,15 @@ + distance = CUR_Func_project( CUR.zp1.cur + point, + CUR.zp0.cur + CUR.GS.rp0 ); + ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ /* Subpixel Hinting - make MSIRP respect CVT cutin */ ++ /* Fixes "k" issue with Arial */ ++ if ( CUR.enhanced && CUR.GS.freeVector.x != 0 ++ && FT_ABS( distance - args[1]) ++ >= CUR.GS.control_value_cutin / resolution ) ++ distance = args[1]; ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ ++ + CUR_Func_move( &CUR.zp1, point, args[1] - distance ); + + CUR.GS.rp1 = CUR.GS.rp0; +@@ -5930,7 +6170,19 @@ + FT_UShort point; + FT_F26Dot6 cur_dist, + distance; ++ FT_Int resolution = 1; + ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ if ( CUR.enhanced ) ++ { ++ if ( CUR.GS.freeVector.x != 0 ++ && !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND_MDAP )) ++ resolution = Grids_Per_Pixel_X; ++ else if ( CUR.GS.freeVector.y != 0 ++ && !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND_MDAP )) ++ resolution = Grids_Per_Pixel_Y; ++ } ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + + point = (FT_UShort)args[0]; + +@@ -5946,8 +6198,8 @@ + if ( ( CUR.opcode & 1 ) != 0 ) + { + cur_dist = CUR_fast_project( &CUR.zp0.cur[point] ); +- distance = CUR_Func_round( cur_dist, +- CUR.tt_metrics.compensations[0] ) - cur_dist; ++ distance = CUR_Func_round( cur_dist, ++ CUR.tt_metrics.compensations[0], resolution ) - cur_dist; + } + else + distance = 0; +@@ -5972,7 +6224,19 @@ + FT_UShort point; + FT_F26Dot6 distance, + org_dist; ++ FT_Int resolution = 1; + ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ if ( CUR.enhanced ) ++ { ++ if ( CUR.GS.freeVector.x != 0 ++ && !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND_MIAP )) ++ resolution = Grids_Per_Pixel_X; ++ else if ( CUR.GS.freeVector.y != 0 ++ && !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND_MIAP )) ++ resolution = Grids_Per_Pixel_Y; ++ } ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + + cvtEntry = (FT_ULong)args[1]; + point = (FT_UShort)args[0]; +@@ -6020,10 +6284,13 @@ + + if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cutin flag */ + { +- if ( FT_ABS( distance - org_dist ) > CUR.GS.control_value_cutin ) +- distance = org_dist; +- +- distance = CUR_Func_round( distance, CUR.tt_metrics.compensations[0] ); ++ { ++ if ( FT_ABS( distance - org_dist ) ++ > CUR.GS.control_value_cutin / resolution ) ++ distance = org_dist; ++ distance = CUR_Func_round( distance, ++ CUR.tt_metrics.compensations[0], resolution ); ++ } + } + + CUR_Func_move( &CUR.zp0, point, distance - org_dist ); +@@ -6044,6 +6311,24 @@ + { + FT_UShort point; + FT_F26Dot6 org_dist, distance; ++ FT_Int minimum_distance_factor = 64; ++ FT_Int resolution = 1; ++ ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ if ( CUR.enhanced ) ++ { ++ if ( CUR.GS.freeVector.x != 0 ++ && !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND_MDRP )) ++ { ++ resolution = Grids_Per_Pixel_X; ++ minimum_distance_factor = 64 - resolution / 3; ++ } ++ else if ( CUR.GS.freeVector.y != 0 ++ && !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND_MDRP )) ++ resolution = Grids_Per_Pixel_Y; ++ ++ } ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + + + point = (FT_UShort)args[0]; +@@ -6107,13 +6392,15 @@ + /* round flag */ + + if ( ( CUR.opcode & 4 ) != 0 ) ++ { + distance = CUR_Func_round( + org_dist, +- CUR.tt_metrics.compensations[CUR.opcode & 3] ); ++ CUR.tt_metrics.compensations[CUR.opcode & 3], resolution ); ++ } + else + distance = ROUND_None( + org_dist, +- CUR.tt_metrics.compensations[CUR.opcode & 3] ); ++ CUR.tt_metrics.compensations[CUR.opcode & 3], resolution ); + + /* minimum distance flag */ + +@@ -6121,13 +6408,17 @@ + { + if ( org_dist >= 0 ) + { +- if ( distance < CUR.GS.minimum_distance ) +- distance = CUR.GS.minimum_distance; ++ if ( distance < FT_MulDiv(minimum_distance_factor, ++ CUR.GS.minimum_distance, 64) ) ++ distance = FT_MulDiv(minimum_distance_factor, ++ CUR.GS.minimum_distance, 64); + } + else + { +- if ( distance > -CUR.GS.minimum_distance ) +- distance = -CUR.GS.minimum_distance; ++ if ( distance > -FT_MulDiv( minimum_distance_factor, ++ CUR.GS.minimum_distance, 64 ) ) ++ distance = -FT_MulDiv( minimum_distance_factor, ++ CUR.GS.minimum_distance, 64 ); + } + } + +@@ -6163,10 +6454,30 @@ + cur_dist, + org_dist; + ++ FT_Int minimum_distance_factor = 64; ++ FT_Int B1, B2, resolution = 1; + + point = (FT_UShort)args[0]; + cvtEntry = (FT_ULong)( args[1] + 1 ); + ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ if ( CUR.enhanced ) ++ { ++ if ( CUR.GS.freeVector.x != 0 ++ && !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND_MIRP )) ++ { ++ resolution = Grids_Per_Pixel_X; ++ /* High value emboldens glyphs at lower ppems ( < 14 ) */ ++ /* Courier looks better with 52 */ ++ /* MS Cleartype Rasterizer supposedly uses 32 */ ++ minimum_distance_factor = 64 - resolution / 3; ++ } ++ else if ( CUR.GS.freeVector.y != 0 ++ && !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND_MIRP )) ++ resolution = Grids_Per_Pixel_Y; ++ } ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ ++ + /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */ + + if ( BOUNDS( point, CUR.zp1.n_points ) || +@@ -6230,36 +6541,55 @@ + /* refer to the same zone. */ + + if ( CUR.GS.gep0 == CUR.GS.gep1 ) +- if ( FT_ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin ) ++ if ( FT_ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin / resolution ) + cvt_dist = org_dist; + + distance = CUR_Func_round( + cvt_dist, +- CUR.tt_metrics.compensations[CUR.opcode & 3] ); ++ CUR.tt_metrics.compensations[CUR.opcode & 3], resolution ); + } + else + distance = ROUND_None( + cvt_dist, +- CUR.tt_metrics.compensations[CUR.opcode & 3] ); ++ CUR.tt_metrics.compensations[CUR.opcode & 3], resolution ); + + /* minimum distance test */ +- + if ( ( CUR.opcode & 8 ) != 0 ) + { + if ( org_dist >= 0 ) + { +- if ( distance < CUR.GS.minimum_distance ) +- distance = CUR.GS.minimum_distance; ++ if ( distance < FT_MulDiv( minimum_distance_factor, ++ CUR.GS.minimum_distance, 64 ) ) ++ distance = FT_MulDiv( minimum_distance_factor, ++ CUR.GS.minimum_distance, 64 ); + } + else + { +- if ( distance > -CUR.GS.minimum_distance ) +- distance = -CUR.GS.minimum_distance; ++ if ( distance > -FT_MulDiv( minimum_distance_factor, ++ CUR.GS.minimum_distance, 64 ) ) ++ distance = -FT_MulDiv( minimum_distance_factor, ++ CUR.GS.minimum_distance, 64 ); + } + } + ++ B1 = CUR.zp1.cur[point].y; ++ + CUR_Func_move( &CUR.zp1, point, distance - cur_dist ); + ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ if ( CUR.enhanced && CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_INLINE_MOVES) ++ { ++ B2 = CUR.zp1.cur[point].y; ++ ++ if ( ( CUR.GS.freeVector.x != 0 && B1 % 64 == 0 && B2 % 64 != 0 ) ++ || ( CUR.GS.freeVector.y != 0 && B2 % 64 != 0 ) ) ++ { ++ /* reverse the MIRP move. Ideally this could be implemented better */ ++ CUR_Func_move( &CUR.zp1, point, -(distance - cur_dist) ); ++ } ++ } ++#endif /*TT_CONFIG_OPTION_SUBPIXEL_HINTING*/ ++ + CUR.GS.rp1 = CUR.GS.rp0; + + if ( ( CUR.opcode & 16 ) != 0 ) +@@ -6751,6 +7081,14 @@ + contour = 0; + point = 0; + ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ if ( CUR.enhanced ) ++ { ++ CUR.iup_called = 1; ++ if ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_IUP ) return; ++ } ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ ++ + do + { + end_point = CUR.pts.contours[contour] - CUR.pts.first_point; +@@ -6820,7 +7158,19 @@ + FT_UShort A; + FT_ULong C; + FT_Long B; +- ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ FT_Byte orig_round_state; ++ FT_Int resolution = 1; ++ FT_UShort B1, B2; ++ ++ if (CUR.enhanced ) ++ { ++ if ( CUR.GS.freeVector.x != 0 ) ++ resolution = Grids_Per_Pixel_X; ++ else if ( CUR.GS.freeVector.y != 0 ) ++ resolution = Grids_Per_Pixel_Y; ++ } ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + + #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING + /* Delta hinting is covered by US Patent 5159668. */ +@@ -6889,8 +7239,81 @@ + if ( B >= 0 ) + B++; + B = B * 64 / ( 1L << CUR.GS.delta_shift ); ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS ++ /* Undocumented hack that will round the point prior to or instead ++ * of the delta move. Fixes glitches in various fonts due to bad ++ * y-hinting routines. ++ */ ++ if ( CUR.enhanced && CUR.GS.freeVector.y != 0 ) ++ { ++ orig_round_state= CUR.GS.round_state; ++ ++ if ( CUR.sph_tweak_flags & SPH_TWEAK_DELTAP_RDTG ) ++ { ++ COMPUTE_Round( TT_Round_Down_To_Grid ); ++ B = CUR_Func_round( B, CUR.tt_metrics.compensations[0], 1 ); ++ } ++ ++ else if ( CUR.sph_tweak_flags & SPH_TWEAK_DELTAP_RUTG ) ++ { ++ COMPUTE_Round( TT_Round_Up_To_Grid ); ++ B = CUR_Func_round( B, CUR.tt_metrics.compensations[0], 1 ); ++ } ++ ++ else if ( CUR.sph_tweak_flags & SPH_TWEAK_DELTAP_RTG ) ++ { ++ COMPUTE_Round( TT_Round_To_Grid ); ++ B = CUR_Func_round( B, CUR.tt_metrics.compensations[0], 1 ); ++ } ++ ++ COMPUTE_Round( orig_round_state ); ++ } ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS */ ++ ++ /* Allow delta move if: ++ * - Not using enhanced rendering ++ * - Glyph is specifically set to allow it ++ * - Glyph is composite ++ */ ++ if ( !CUR.enhanced ++ || CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_DO_DELTAP ++ || CUR.is_composite ) ++ CUR_Func_move( &CUR.zp0, A, B ); + ++ else if ( !( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) ) ++ { ++ /* Save the y value of the point now. Compare after move */ ++ B1 = CUR.zp0.cur[A].y; ++ ++ /* Allow delta move if using enhanced rendering, IUP has not ++ * been called, and point is touched on X or Y. ++ * ++ * Working code, but needs more features. ++ */ ++ if ( CUR.enhanced && CUR.GS.freeVector.y != 0 ++ && CUR.iup_called == 0 && CUR.iupy_called == 0 ++ && ( ( CUR.pts.tags[A] & FT_CURVE_TAG_TOUCH_X ) != 0 ++ || ( CUR.pts.tags[A] & FT_CURVE_TAG_TOUCH_Y ) != 0 ) ) ++ /* Should resolution always be 1 for this move ??? */ ++ CUR_Func_move( &CUR.zp0, A, B ); ++ ++ B2 = CUR.zp0.cur[A].y; ++ ++ /* Reverse this move if it results in a move off a pixel ++ * boundary. ++ */ ++ if ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_INLINE_MOVES ) ++ && B1 % 64 == 0 ++ && B2 % 64 != 0 ) ++ { ++ CUR_Func_move( &CUR.zp0, A, -B ); ++ } ++ ++ } ++#else + CUR_Func_move( &CUR.zp0, A, B ); ++#endif /* *TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + } + } + else +@@ -7015,22 +7438,100 @@ + + K = 0; + +- /* We return MS rasterizer version 1.7 for the font scaler. */ +- if ( ( args[0] & 1 ) != 0 ) +- K = 35; +- +- /* Has the glyph been rotated? */ ++ /********************************/ ++ /* RASTERIZER VERSION */ ++ /* Selector Bit: 0 */ ++ /* Return Bit(s): 0-7 */ ++ /* */ ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ if ( ( args[0] & 1 ) != 0 ++ && CUR.enhanced ++ && !( CUR.sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 ) ){ ++ K = CUR.rasterizer_version; /*printf (" SETTING AS 37 \n" );*/ } ++ else ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ ++ if ( ( args[0] & 1 ) != 0 ){ ++ K = 35; /*printf (" SETTING AS 35 \n" );*/ ++ } ++ /********************************/ ++ /* GLYPH ROTATED */ ++ /* Selector Bit: 1 */ ++ /* Return Bit(s): 8 */ ++ /* */ + if ( ( args[0] & 2 ) != 0 && CUR.tt_metrics.rotated ) +- K |= 0x80; ++ K |= 1 << 8; + +- /* Has the glyph been stretched? */ ++ /********************************/ ++ /* GLYPH STRETCHED */ ++ /* Selector Bit: 2 */ ++ /* Return Bit(s): 9 */ ++ /* */ + if ( ( args[0] & 4 ) != 0 && CUR.tt_metrics.stretched ) +- K |= 1 << 8; ++ /*K |= 1 << 8; Original value appears to be incorrect?? */ ++ K |= 1 << 9; + +- /* Are we hinting for grayscale? */ ++ /********************************/ ++ /* HINTING FOR GRAYSCALE */ ++ /* Selector Bit: 5 */ ++ /* Return Bit(s): 12 */ ++ /* */ + if ( ( args[0] & 32 ) != 0 && CUR.grayscale ) + K |= 1 << 12; + ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ if ( CUR.enhanced && !( CUR.sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 ) ) ++ { ++ /********************************/ ++ /* HINTING FOR GRAYSCALE */ ++ /* Selector Bit: 5 */ ++ /* Return Bit(s): 12 */ ++ /* */ ++ if ( ( args[0] & 32 ) != 0 && CUR.grayscale_hinting ) ++ K |= 1 << 12; ++ ++ /********************************/ ++ /* HINTING FOR SUBPIXEL */ ++ /* Selector Bit: 6 */ ++ /* Return Bit(s): 13 */ ++ /* */ ++ if ( ( args[0] & 64 ) != 0 && CUR.subpixel_hinting ) ++ { ++ K |= 1 << 13; ++ ++ /* The below are irrelevant if subpixel_hinting is not set */ ++ ++ /********************************/ ++ /* COMPATIBLE WIDTHS ENABLED */ ++ /* Selector Bit: 7 */ ++ /* Return Bit(s): 14 */ ++ /* */ ++ /* Functionality still needs to be added */ ++ if ( ( args[0] & 128 ) != 0 && CUR.compatible_widths ) ++ { ++ K |= 1 << 14; ++ } ++ ++ /********************************/ ++ /* SYMMETRICAL SMOOTHING */ ++ /* Selector Bit: 8 */ ++ /* Return Bit(s): 15 */ ++ /* */ ++ /* Functionality still needs to be added */ ++ if ( ( args[0] & 256 ) != 0 && CUR.symmetrical_smoothing ) ++ K |= 1 << 15; ++ ++ /********************************/ ++ /* HINTING FOR BGR? */ ++ /* Selector Bit: 9 */ ++ /* Return Bit(s): 16 */ ++ /* */ ++ /* Functionality still needs to be added */ ++ if ( ( args[0] & 512 ) != 0 && CUR.bgr ) ++ K |= 1 << 16; ++ } ++ } ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ ++ + args[0] = K; + } + +@@ -7405,6 +7906,14 @@ + cur = *exc; + #endif + ++ ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ /* Ensure some variables are set for this run */ ++ CUR.iup_called = FALSE; ++ CUR.iupy_called = FALSE; ++ CUR.infunc = FALSE; ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ ++ + /* set CVT functions */ + CUR.tt_metrics.ratio = 0; + if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem ) +@@ -7683,8 +8192,16 @@ + + + case 0x30: /* IUP */ ++ Ins_IUP( EXEC_ARG_ args ); ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ CUR.iup_called = TRUE; ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ ++ break; + case 0x31: /* IUP */ + Ins_IUP( EXEC_ARG_ args ); ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ CUR.iupy_called = TRUE; ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING*/ + break; + + case 0x32: /* SHP */ +diff -Nur freetype-2.4.3.orig/src/truetype/ttinterp.h freetype-2.4.3.new/src/truetype/ttinterp.h +--- freetype-2.4.3.orig/src/truetype/ttinterp.h 2010-08-05 16:56:05.000000000 -0500 ++++ freetype-2.4.3.new/src/truetype/ttinterp.h 2010-10-23 14:00:05.553373908 -0500 +@@ -68,7 +68,8 @@ + /* Rounding function */ + typedef FT_F26Dot6 + (*TT_Round_Func)( EXEC_OP_ FT_F26Dot6 distance, +- FT_F26Dot6 compensation ); ++ FT_F26Dot6 compensation, ++ FT_Int resolution ); + + /* Point displacement along the freedom vector routine */ + typedef void +@@ -106,6 +107,24 @@ + } TT_CallRec, *TT_CallStack; + + ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ /*************************************************************************/ ++ /* */ ++ /* This structure defines a rule used to tweak subpixel hinting for */ ++ /* various fonts. "", 0, "", NULL value indicates to match any value. */ ++ /* */ ++ ++ typedef struct SPH_TweakRule_ ++ { ++ const char family[32]; ++ const int ppem; ++ const char style[32]; ++ const char glyph; ++ } SPH_TweakRule; ++ ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ ++ ++ + /*************************************************************************/ + /* */ + /* The main structure for the interpreter which collects all necessary */ +@@ -215,7 +234,32 @@ + TT_Set_CVT_Func func_write_cvt; /* write a cvt entry (in pixels) */ + TT_Set_CVT_Func func_move_cvt; /* incr a cvt entry (in pixels) */ + +- FT_Bool grayscale; /* are we hinting for grayscale? */ ++ FT_Bool grayscale; /* are we hinting for grayscale? */ ++ ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ TT_Round_Func func_round_sphn; /* subpixel rounding fuction */ ++ ++ FT_Bool grayscale_hinting; /* are we hinting for subpixel? */ ++ FT_Bool subpixel_hinting; /* are we hinting for subpixel? */ ++ FT_Bool enhanced; /* are we using enhanced rendering? */ ++ /* ( grayscale_hinting || subpixel_hinting ) */ ++ FT_Bool native_hinting; /* do native hinting when true */ ++ /* the following 3 are unimplemented but here for future reference */ ++ ++ FT_Bool compatible_widths; /* are we using compatible widths?*/ ++ FT_Bool symmetrical_smoothing; /* symmetrical_smoothing? */ ++ FT_Bool bgr; /* are we using bgr, not rgb? */ ++ FT_Int rasterizer_version;/* return ms rasterizer version */ ++ ++ FT_Bool iup_called; /* IUP[x] been called for glyph? */ ++ FT_Bool iupy_called; /* IUP[y] been called for glyph? */ ++ FT_Bool infunc; /* inside an inline delta func? */ ++ ++ FT_ULong sph_tweak_flags; /* flags to control hint tweaks */ ++ ++ FT_Int num_delta_funcs; ++ FT_ULong inline_delta_funcs[5]; ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + + } TT_ExecContextRec; + +diff -Nur freetype-2.4.3.orig/src/truetype/ttobjs.h freetype-2.4.3.new/src/truetype/ttobjs.h +--- freetype-2.4.3.orig/src/truetype/ttobjs.h 2009-07-03 08:28:24.000000000 -0500 ++++ freetype-2.4.3.new/src/truetype/ttobjs.h 2010-10-22 19:25:46.075900111 -0500 +@@ -177,6 +177,7 @@ + FT_Long start; /* where does it start? */ + FT_UInt opc; /* function #, or instruction code */ + FT_Bool active; /* is it active? */ ++ FT_Bool inline; /* function that defines inline delta */ + + } TT_DefRecord, *TT_DefArray; + +diff -Nur freetype-2.4.3.orig/src/truetype/ttsubpixel.c freetype-2.4.3.new/src/truetype/ttsubpixel.c +--- freetype-2.4.3.orig/src/truetype/ttsubpixel.c 1969-12-31 18:00:00.000000000 -0600 ++++ freetype-2.4.3.new/src/truetype/ttsubpixel.c 2010-11-14 09:25:59.206993605 -0600 +@@ -0,0 +1,171 @@ ++/***************************************************************************/ ++/* */ ++/* ttsubpixel.c */ ++/* */ ++/* TrueType Subpixel Hinting. */ ++/* */ ++/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */ ++/* 2010 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> ++#include FT_INTERNAL_DEBUG_H ++#include FT_INTERNAL_CALC_H ++#include FT_INTERNAL_STREAM_H ++#include FT_INTERNAL_SFNT_H ++#include FT_TRUETYPE_TAGS_H ++#include FT_OUTLINE_H ++ ++#include "ttsubpixel.h" ++ ++ ++ /*************************************************************************/ ++ /* */ ++ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ ++ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ ++ /* messages during execution. */ ++ /* */ ++#undef FT_COMPONENT ++#define FT_COMPONENT trace_ttgload ++ ++ ++ ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS ++ static FT_Bool ++ sph_test_tweak ( TT_Face face, ++ FT_String* family, ++ int ppem, ++ FT_String* style, ++ FT_UInt glyph_index, ++ SPH_TweakRule* rule, ++ int num_rules ) ++ { ++ FT_UInt i; ++ ++ /* rule checks may be able to be optimized further */ ++ for ( i = 0; i < num_rules; i++ ) ++ { ++ if ( family && ( strcmp( rule[i].family, "" ) == 0 ++ || strcmp ( rule[i].family, family ) == 0 ) ) ++ if ( rule[i].ppem == 0 ++ || (rule[i].ppem == ppem) ) ++ if ( ( style && strcmp ( rule[i].style, "" ) == 0 ) ++ || strcmp ( rule[i].style, style ) == 0 ) ++ if ( rule[i].glyph == 0 ++ || FT_Get_Char_Index( (FT_Face)face, rule[i].glyph ) ++ == glyph_index ) ++ { ++ /* printf ("%s,%d,%s,%c ", family, ppem, style, rule[i].glyph); */ ++ return TRUE; ++ } ++ } ++ return FALSE; ++ } ++ ++ static void ++ sph_set_tweaks( TT_Loader loader, ++ FT_UInt glyph_index ) ++ { ++ TT_Face face = (TT_Face)loader->face; ++ FT_String* family = face->root.family_name; ++ int ppem = loader->size->metrics.x_ppem; ++ FT_String* style = face->root.style_name; ++ ++ /* loader->exec->sph_tweak_flags = 0x0000; */ ++ ++ /*printf ("%s,%d,%s,%c ", family, ppem, style, glyph_index); */ ++ ++ if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ NORMAL_ROUND_MIRP_Rules, NORMAL_ROUND_MIRP_RULES_SIZE ) ) ++ loader->exec->sph_tweak_flags |= SPH_TWEAK_NORMAL_ROUND_MIRP; ++ if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ NORMAL_ROUND_MDRP_Rules, NORMAL_ROUND_MDRP_RULES_SIZE ) ) ++ loader->exec->sph_tweak_flags |= SPH_TWEAK_NORMAL_ROUND_MDRP; ++ if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ NORMAL_ROUND_MDAP_Rules, NORMAL_ROUND_MDAP_RULES_SIZE ) ) ++ loader->exec->sph_tweak_flags |= SPH_TWEAK_NORMAL_ROUND_MDAP; ++ if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ NORMAL_ROUND_MIAP_Rules, NORMAL_ROUND_MIAP_RULES_SIZE ) ) ++ loader->exec->sph_tweak_flags |= SPH_TWEAK_NORMAL_ROUND_MIAP; ++ ++ if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ SKIP_IUP_Rules, SKIP_IUP_RULES_SIZE ) ) ++ loader->exec->sph_tweak_flags |= SPH_TWEAK_SKIP_IUP; ++ ++ if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ ALWAYS_SKIP_DELTAP_Rules, ALWAYS_SKIP_DELTAP_RULES_SIZE ) ) ++ loader->exec->sph_tweak_flags |= SPH_TWEAK_ALWAYS_SKIP_DELTAP; ++ if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ ALWAYS_DO_DELTAP_Rules, ALWAYS_DO_DELTAP_RULES_SIZE ) ) ++ loader->exec->sph_tweak_flags |= SPH_TWEAK_ALWAYS_DO_DELTAP; ++ else if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ DELTAP_RTG_Rules, DELTAP_RTG_RULES_SIZE ) ) ++ loader->exec->sph_tweak_flags |= SPH_TWEAK_DELTAP_RTG; ++ else if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ DELTAP_RUTG_Rules, DELTAP_RUTG_RULES_SIZE ) ) ++ loader->exec->sph_tweak_flags |= SPH_TWEAK_DELTAP_RUTG; ++ else if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ DELTAP_RDTG_Rules, DELTAP_RDTG_RULES_SIZE ) ) ++ loader->exec->sph_tweak_flags |= SPH_TWEAK_DELTAP_RDTG; ++ ++ if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ ALLOW_DMOVEX_FREEV_Rules, ALLOW_DMOVEX_FREEV_RULES_SIZE ) ) ++ loader->exec->sph_tweak_flags |= SPH_TWEAK_ALLOW_DMOVEX_FREEV; ++ ++ if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ ALLOW_DMOVE_FREEV_Rules, ALLOW_DMOVE_FREEV_RULES_SIZE ) ) ++ loader->exec->sph_tweak_flags |= SPH_TWEAK_ALLOW_DMOVE_FREEV; ++ ++ ++ if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ ALLOW_DMOVEX_FREEV_Rules_Exceptions, ALLOW_DMOVEX_FREEV_RULES_EXCEPTIONS_SIZE ) ) ++ loader->exec->sph_tweak_flags &= ~SPH_TWEAK_ALLOW_DMOVEX_FREEV; ++ ++ if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ ALLOW_DMOVE_FREEV_Rules_Exceptions, ALLOW_DMOVE_FREEV_RULES_EXCEPTIONS_SIZE ) ) ++ loader->exec->sph_tweak_flags &= ~SPH_TWEAK_ALLOW_DMOVE_FREEV; ++ ++ if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ RASTERIZER_35_Rules, RASTERIZER_35_RULES_SIZE ) ) ++ loader->exec->sph_tweak_flags |= SPH_TWEAK_RASTERIZER_35; ++ ++ if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ ALLOW_MOVEZP2_FREEV_Rules, ALLOW_MOVEZP2_FREEV_RULES_SIZE ) ) ++ loader->exec->sph_tweak_flags |= SPH_TWEAK_ALLOW_MOVEZP2_FREEV; ++ ++ if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ ALLOW_MOVEZP2_FREEV_Rules_Exceptions, ALLOW_MOVEZP2_FREEV_RULES_EXCEPTIONS_SIZE ) ) ++ loader->exec->sph_tweak_flags &= ~SPH_TWEAK_ALLOW_MOVEZP2_FREEV; ++ ++ if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ DO_RS_Rules, DO_RS_RULES_SIZE ) ) ++ loader->exec->sph_tweak_flags |= SPH_TWEAK_DO_RS; ++ ++ if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ DO_SHPIX_Rules, DO_SHPIX_RULES_SIZE ) ) ++ loader->exec->sph_tweak_flags |= SPH_TWEAK_DO_SHPIX; ++ ++ if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ SKIP_NONPIXEL_INLINE_MOVES_Rules, SKIP_NONPIXEL_INLINE_MOVES_RULES_SIZE ) ) ++ loader->exec->sph_tweak_flags |= SPH_TWEAK_SKIP_NONPIXEL_INLINE_MOVES; ++ ++ if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ SHPIX_CLASS_A_Rules, SHPIX_CLASS_A_RULES_SIZE ) ) ++ loader->exec->sph_tweak_flags |= SPH_TWEAK_SHPIX_CLASS_A; ++ ++ if ( sph_test_tweak( face, family, ppem, style, glyph_index, ++ SHPIX_CLASS_A_Rules_Exceptions, SHPIX_CLASS_A_RULES_EXCEPTIONS_SIZE ) ) ++ loader->exec->sph_tweak_flags &= ~SPH_TWEAK_SHPIX_CLASS_A; ++ ++ } ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS */ ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ +diff -Nur freetype-2.4.3.orig/src/truetype/ttsubpixel.h freetype-2.4.3.new/src/truetype/ttsubpixel.h +--- freetype-2.4.3.orig/src/truetype/ttsubpixel.h 1969-12-31 18:00:00.000000000 -0600 ++++ freetype-2.4.3.new/src/truetype/ttsubpixel.h 2010-11-14 19:16:58.095874324 -0600 +@@ -0,0 +1,819 @@ ++/***************************************************************************/ ++/* */ ++/* ttsubpixel.h */ ++/* */ ++/* TrueType Subpixel Hinting. */ ++/* */ ++/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */ ++/* 2010 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. */ ++/* */ ++/***************************************************************************/ ++ ++#ifndef __TTSUBPIXEL_H__ ++#define __TTSUBPIXEL_H__ ++ ++#include <ft2build.h> ++#include "ttobjs.h" ++ ++#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING ++ /*************************************************************************/ ++ /* */ ++ /* Tweak flags that are set for each glyph */ ++ /* */ ++ /* */ ++#define SPH_TWEAK_NORMAL_ROUND_MIRP 0x00001 ++#define SPH_TWEAK_NORMAL_ROUND_MDRP 0x00002 ++#define SPH_TWEAK_DELTAP_RDTG 0x00004 ++#define SPH_TWEAK_DELTAP_RTG 0x00008 ++#define SPH_TWEAK_DELTAP_RUTG 0x00010 ++#define SPH_TWEAK_ALLOW_DMOVEX_FREEV 0x00020 ++#define SPH_TWEAK_ALLOW_DMOVE_FREEV 0x00040 ++#define SPH_TWEAK_ALLOW_MOVEZP2_FREEV 0x00080 ++#define SPH_TWEAK_ALWAYS_SKIP_DELTAP 0x00100 ++#define SPH_TWEAK_SKIP_IUP 0x00200 ++#define SPH_TWEAK_NORMAL_ROUND_MIAP 0x00400 ++#define SPH_TWEAK_NORMAL_ROUND_MDAP 0x00800 ++#define SPH_TWEAK_DO_RS 0x01000 ++#define SPH_TWEAK_DO_SHPIX 0x02000 ++#define SPH_TWEAK_ALWAYS_DO_DELTAP 0x04000 ++#define SPH_TWEAK_SKIP_NONPIXEL_INLINE_MOVES 0x08000 ++#define SPH_TWEAK_SHPIX_CLASS_A 0x10000 ++#define SPH_TWEAK_RASTERIZER_35 0x20000 ++ ++ ++ static FT_Bool ++ sph_test_tweak ( TT_Face face, ++ FT_String* family, ++ int ppem, ++ FT_String* style, ++ FT_UInt glyph_index, ++ SPH_TweakRule* rule, ++ int num_rules ); ++ static void ++ sph_set_tweaks( TT_Loader loader, ++ FT_UInt glyph_index ); ++ ++ ++ /*************************************************************************/ ++ /* */ ++ /* These are groups of rules that affect how the TT Interpreter does */ ++ /* hinting. */ ++ /* */ ++ /* "" string or 0 int/char indicates to apply to all. */ ++ /* "-" used as dummy placeholders, but any non-matching string works */ ++ /* */ ++ /* Remaining rules are tweaks for various fonts / glyphs */ ++ /* Some of this could arguably be implemented in fontconfig, however: */ ++ /* */ ++ /* - Fontconfig can't set things on a glyph-by-glyph basis. */ ++ /* - The tweaks that happen here are very low-level, from an average */ ++ /* user's point of view and are best implemented in the hinter */ ++ /* */ ++ /* Ideally, some of these should be generalized across affected fonts, */ ++ /* and enabled by default in the code. The rule structure is designed so */ ++ /* that entirely new rules can easily be added when a new compatibility */ ++ /* feature is discovered. */ ++ /* */ ++ ++ /*************************************************************************/ ++ /* */ ++ /* TT_CONFIG_OPTION_SUBPIXEL_HINTING Rules */ ++ /* */ ++ /* Simply, this attempts to duplicate the fuctionality described here */ ++ /* and nothing more: */ ++ /* */ ++ /* http://www.microsoft.com/typography/cleartype/truetypecleartype.aspx */ ++ /* */ ++ /* This mode is enabled when */ ++ /* TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS */ ++ /* is undefined */ ++ /* */ ++ ++ ++#ifndef TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS ++ ++#if FALSE /* THIS RULESET NOT CURRENTLY BEING USED */ ++ ++#define BITMAP_WIDTHS FALSE ++#define SET_SUBPIXEL FALSE ++#define SET_GRAYSCALE TRUE ++#define SET_MONOCHROME FALSE ++#define SET_COMPATIBLE_WIDTHS TRUE ++#define SET_RASTERIZER_VERSION 35 ++#define Grids_Per_Pixel_X 1 ++#define Grids_Per_Pixel_Y 1 ++ ++ ++/********** MOVE RULES *************/ ++ ++/* Allow a Direct_Move_X along freedom vector when matched */ ++#define ALLOW_DMOVEX_FREEV_RULES_SIZE 1 ++SPH_TweakRule ALLOW_DMOVEX_FREEV_Rules ++[ALLOW_DMOVEX_FREEV_RULES_SIZE] = { ++ { "", 0, "", 0 }, ++}; ++ ++/* Allow a Direct_Move along freedom vector when matched */ ++#define ALLOW_DMOVE_FREEV_RULES_SIZE 1 ++SPH_TweakRule ALLOW_DMOVE_FREEV_Rules ++[ALLOW_DMOVE_FREEV_RULES_SIZE] = { ++ { "", 0, "", 0 }, ++}; ++ ++/* Allow a ZP2 Move along freedom vector when matched */ ++#define ALLOW_MOVEZP2_FREEV_RULES_SIZE 1 ++SPH_TweakRule ALLOW_MOVEZP2_FREEV_Rules ++[ALLOW_MOVEZP2_FREEV_RULES_SIZE] = { ++ { "", 0, "", 0 }, ++}; ++ ++/* Don't skip RS calls */ ++#define DO_RS_RULES_SIZE 1 ++SPH_TweakRule DO_RS_Rules ++[DO_RS_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Force requested SHPIX operations when matched */ ++#define DO_SHPIX_RULES_SIZE 1 ++SPH_TweakRule DO_SHPIX_Rules ++[DO_SHPIX_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++#define SKIP_NONPIXEL_INLINE_MOVES_RULES_SIZE 1 ++SPH_TweakRule SKIP_NONPIXEL_INLINE_MOVES_Rules ++[SKIP_NONPIXEL_INLINE_MOVES_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++#define NORMAL_ROUND_MIRP_RULES_SIZE 1 ++SPH_TweakRule NORMAL_ROUND_MIRP_Rules ++[NORMAL_ROUND_MIRP_RULES_SIZE] = { ++ { "", 0, "", 0 }, ++}; ++ ++#define NORMAL_ROUND_MIAP_RULES_SIZE 1 ++SPH_TweakRule NORMAL_ROUND_MIAP_Rules ++[NORMAL_ROUND_MIAP_RULES_SIZE] = { ++ { "", 0, "", 0 }, ++}; ++ ++#define NORMAL_ROUND_MDRP_RULES_SIZE 1 ++SPH_TweakRule NORMAL_ROUND_MDRP_Rules ++[NORMAL_ROUND_MDRP_RULES_SIZE] = { ++ { "", 0, "", 0 }, ++}; ++ ++#define NORMAL_ROUND_MDAP_RULES_SIZE 1 ++SPH_TweakRule NORMAL_ROUND_MDAP_Rules ++[NORMAL_ROUND_MDAP_RULES_SIZE] = { ++ { "", 0, "", 0 }, ++}; ++ ++/* Indicates that SHPIX needs to match a touched point on x OR y */ ++#define SHPIX_CLASS_A_RULES_SIZE 1 ++SPH_TweakRule SHPIX_CLASS_A_Rules ++[SHPIX_CLASS_A_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Mystery rules that make SHPIX work on certain fonts/glyphs. */ ++/* Indicates that SHPIX needs to match a touched point on x AND y */ ++/* This is dirty and needs to be generalized and incorporated. */ ++#define SHPIX_CLASS_A_RULES_EXCEPTIONS_SIZE 1 ++SPH_TweakRule SHPIX_CLASS_A_Rules_Exceptions ++[SHPIX_CLASS_A_RULES_EXCEPTIONS_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++#define ALLOW_DMOVEX_FREEV_RULES_EXCEPTIONS_SIZE 1 ++SPH_TweakRule ALLOW_DMOVEX_FREEV_Rules_Exceptions ++[ALLOW_DMOVEX_FREEV_RULES_EXCEPTIONS_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++#define ALLOW_DMOVE_FREEV_RULES_EXCEPTIONS_SIZE 1 ++SPH_TweakRule ALLOW_DMOVE_FREEV_Rules_Exceptions ++[ALLOW_DMOVE_FREEV_RULES_EXCEPTIONS_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++#define ALLOW_MOVEZP2_FREEV_RULES_EXCEPTIONS_SIZE 1 ++SPH_TweakRule ALLOW_MOVEZP2_FREEV_Rules_Exceptions ++[ALLOW_MOVEZP2_FREEV_RULES_EXCEPTIONS_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Skip IUP instructions when matched */ ++#define SKIP_IUP_RULES_SIZE 1 ++SPH_TweakRule SKIP_IUP_Rules ++[SKIP_IUP_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Skip DELTAP instructions when matched */ ++#define ALWAYS_SKIP_DELTAP_RULES_SIZE 1 ++SPH_TweakRule ALWAYS_SKIP_DELTAP_Rules ++[ALWAYS_SKIP_DELTAP_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Always do DELTAP instructions when matched */ ++#define ALWAYS_DO_DELTAP_RULES_SIZE 1 ++SPH_TweakRule ALWAYS_DO_DELTAP_Rules ++[ALWAYS_DO_DELTAP_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Do an extra RTG instruction in DELTAP when matched */ ++#define DELTAP_RTG_RULES_SIZE 1 ++SPH_TweakRule DELTAP_RTG_Rules ++[DELTAP_RTG_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Do an extra RUTG instruction in DELTAP when matched */ ++#define DELTAP_RUTG_RULES_SIZE 1 ++SPH_TweakRule DELTAP_RUTG_Rules ++[DELTAP_RUTG_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Do an extra RDTG instruction in DELTAP when matched */ ++#define DELTAP_RDTG_RULES_SIZE 1 ++SPH_TweakRule DELTAP_RDTG_Rules ++[DELTAP_RDTG_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Return MS rasterizer 35 when matched */ ++#define RASTERIZER_35_RULES_SIZE 1 ++SPH_TweakRule RASTERIZER_35_Rules ++[RASTERIZER_35_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++#endif ++ ++ ++#define BITMAP_WIDTHS FALSE ++#define SET_SUBPIXEL TRUE ++#define SET_GRAYSCALE FALSE ++#define SET_MONOCHROME FALSE ++#define SET_COMPATIBLE_WIDTHS FALSE ++#define SET_RASTERIZER_VERSION 37 ++#define Grids_Per_Pixel_X 64 ++#define Grids_Per_Pixel_Y 1 ++ ++ ++/********** MOVE RULES *************/ ++ ++/* Allow a Direct_Move_X along freedom vector when matched */ ++#define ALLOW_DMOVEX_FREEV_RULES_SIZE 1 ++SPH_TweakRule ALLOW_DMOVEX_FREEV_Rules ++[ALLOW_DMOVEX_FREEV_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Allow a Direct_Move along freedom vector when matched */ ++#define ALLOW_DMOVE_FREEV_RULES_SIZE 1 ++SPH_TweakRule ALLOW_DMOVE_FREEV_Rules ++[ALLOW_DMOVE_FREEV_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Allow a ZP2 Move along freedom vector when matched */ ++#define ALLOW_MOVEZP2_FREEV_RULES_SIZE 1 ++SPH_TweakRule ALLOW_MOVEZP2_FREEV_Rules ++[ALLOW_MOVEZP2_FREEV_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Don't skip RS calls */ ++#define DO_RS_RULES_SIZE 1 ++SPH_TweakRule DO_RS_Rules ++[DO_RS_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Force requested SHPIX operations when matched */ ++#define DO_SHPIX_RULES_SIZE 1 ++SPH_TweakRule DO_SHPIX_Rules ++[DO_SHPIX_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++#define SKIP_NONPIXEL_INLINE_MOVES_RULES_SIZE 1 ++SPH_TweakRule SKIP_NONPIXEL_INLINE_MOVES_Rules ++[SKIP_NONPIXEL_INLINE_MOVES_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++#define NORMAL_ROUND_MIRP_RULES_SIZE 1 ++SPH_TweakRule NORMAL_ROUND_MIRP_Rules ++[NORMAL_ROUND_MIRP_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++#define NORMAL_ROUND_MIAP_RULES_SIZE 1 ++SPH_TweakRule NORMAL_ROUND_MIAP_Rules ++[NORMAL_ROUND_MIAP_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++#define NORMAL_ROUND_MDRP_RULES_SIZE 1 ++SPH_TweakRule NORMAL_ROUND_MDRP_Rules ++[NORMAL_ROUND_MDRP_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++#define NORMAL_ROUND_MDAP_RULES_SIZE 1 ++SPH_TweakRule NORMAL_ROUND_MDAP_Rules ++[NORMAL_ROUND_MDAP_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Indicates that SHPIX needs to match a touched point on x OR y */ ++#define SHPIX_CLASS_A_RULES_SIZE 1 ++SPH_TweakRule SHPIX_CLASS_A_Rules ++[SHPIX_CLASS_A_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Mystery rules that make SHPIX work on certain fonts/glyphs. */ ++/* Indicates that SHPIX needs to match a touched point on x AND y */ ++/* This is dirty and needs to be generalized and incorporated. */ ++#define SHPIX_CLASS_A_RULES_EXCEPTIONS_SIZE 1 ++SPH_TweakRule SHPIX_CLASS_A_Rules_Exceptions ++[SHPIX_CLASS_A_RULES_EXCEPTIONS_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++#define ALLOW_DMOVEX_FREEV_RULES_EXCEPTIONS_SIZE 1 ++SPH_TweakRule ALLOW_DMOVEX_FREEV_Rules_Exceptions ++[ALLOW_DMOVEX_FREEV_RULES_EXCEPTIONS_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++#define ALLOW_DMOVE_FREEV_RULES_EXCEPTIONS_SIZE 1 ++SPH_TweakRule ALLOW_DMOVE_FREEV_Rules_Exceptions ++[ALLOW_DMOVE_FREEV_RULES_EXCEPTIONS_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++#define ALLOW_MOVEZP2_FREEV_RULES_EXCEPTIONS_SIZE 1 ++SPH_TweakRule ALLOW_MOVEZP2_FREEV_Rules_Exceptions ++[ALLOW_MOVEZP2_FREEV_RULES_EXCEPTIONS_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Skip IUP instructions when matched */ ++#define SKIP_IUP_RULES_SIZE 1 ++SPH_TweakRule SKIP_IUP_Rules ++[SKIP_IUP_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Skip DELTAP instructions when matched */ ++#define ALWAYS_SKIP_DELTAP_RULES_SIZE 1 ++SPH_TweakRule ALWAYS_SKIP_DELTAP_Rules ++[ALWAYS_SKIP_DELTAP_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Always do DELTAP instructions when matched */ ++#define ALWAYS_DO_DELTAP_RULES_SIZE 1 ++SPH_TweakRule ALWAYS_DO_DELTAP_Rules ++[ALWAYS_DO_DELTAP_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Do an extra RTG instruction in DELTAP when matched */ ++#define DELTAP_RTG_RULES_SIZE 1 ++SPH_TweakRule DELTAP_RTG_Rules ++[DELTAP_RTG_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Do an extra RUTG instruction in DELTAP when matched */ ++#define DELTAP_RUTG_RULES_SIZE 1 ++SPH_TweakRule DELTAP_RUTG_Rules ++[DELTAP_RUTG_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Do an extra RDTG instruction in DELTAP when matched */ ++#define DELTAP_RDTG_RULES_SIZE 1 ++SPH_TweakRule DELTAP_RDTG_Rules ++[DELTAP_RDTG_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++/* Return MS rasterizer 35 when matched */ ++#define RASTERIZER_35_RULES_SIZE 1 ++SPH_TweakRule RASTERIZER_35_Rules ++[RASTERIZER_35_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++ ++ /*************************************************************************/ ++ /* */ ++ /* TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS Rules */ ++ /* */ ++ /* This set of rules is an attempt at enhancing the basic subpixel rules */ ++ /* defined above, to fix visual problems with individual fonts and */ ++ /* glyphs. */ ++ /* */ ++ /* This mode is enabled when */ ++ /* TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS */ ++ /* is defined */ ++ /* */ ++ /* ****************** WORK IN PROGRESS ******************* */ ++ /* */ ++ ++#else ++ ++#define BITMAP_WIDTHS FALSE ++#define SET_SUBPIXEL TRUE ++#define SET_GRAYSCALE FALSE ++#define SET_MONOCHROME FALSE ++#define SET_COMPATIBLE_WIDTHS FALSE ++#define SET_RASTERIZER_VERSION 37 ++#define Grids_Per_Pixel_X 64 ++#define Grids_Per_Pixel_Y 1 ++ ++ ++/* Don't avoid RS Rules (as the basic subpixel hinting does) */ ++#define DO_RS_RULES_SIZE 1 ++SPH_TweakRule DO_RS_Rules[DO_RS_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++}; ++ ++ ++/******************* DELTA RULES *********************/ ++ ++/* Do requested SHPIX operations when matched. This requires ZP2 moves */ ++/* to be enabled in order to get SHPIX moves in the X direction */ ++/* Do all "Optimized for Cleartype" fonts need to be here??. */ ++/* the below doesn't work because the bit is not set in MS cleartype fonts */ ++/* CUR.face->header.Flags & 0x10000 */ ++ ++#define DO_SHPIX_RULES_SIZE 7 ++SPH_TweakRule DO_SHPIX_Rules[DO_SHPIX_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++ { "-Verdana", 0, "Regular", 0 }, ++ { "-Verdana", 12, "Regular", 0 }, ++ { "Verdana", 13, "Regular", 0 }, ++ /* aligns to pixels nicely, but messes up some glyphs */ ++ { "-Times New Roman", 0, "Regular", 0 }, ++ { "+++Segoe UI", 0, "Regular", 0 }, ++ { "-Segoe UI", 0, "Semibold", 0 }, ++}; ++ ++/* Indicates that SHPIX needs to match a touched point on x OR y */ ++#define SHPIX_CLASS_A_RULES_SIZE 1 ++SPH_TweakRule SHPIX_CLASS_A_Rules[SHPIX_CLASS_A_RULES_SIZE] = { ++ { "", 0, "", 0 }, ++}; ++ ++/* Mystery rules that make SHPIX work on certain fonts/glyphs. */ ++/* Indicates that SHPIX needs to match a touched point on x AND y */ ++/* This is dirty and needs to be generalized and incorporated. */ ++#define SHPIX_CLASS_A_RULES_EXCEPTIONS_SIZE 2 ++SPH_TweakRule SHPIX_CLASS_A_Rules_Exceptions ++[SHPIX_CLASS_A_RULES_EXCEPTIONS_SIZE] = { ++ { "---", 0, "", 0 }, ++ { "Arial", 11, "Regular", 's' }, ++}; ++ ++/* Skip moves that don't align to a pixel in various functions. */ ++/* Fixes Tahoma, trebuchet oddities and some issues with $ */ ++#define SKIP_NONPIXEL_INLINE_MOVES_RULES_SIZE 4 ++SPH_TweakRule SKIP_NONPIXEL_INLINE_MOVES_Rules ++[SKIP_NONPIXEL_INLINE_MOVES_RULES_SIZE] = { ++ { "", 0, "Regular", 0 }, ++ /* keeps the weight in the center of the N */ ++ { "", 0, "Regular", 'N' }, ++ { "Tahoma", 0, "Regular", 0 }, ++ { "==Trebuchet MS", 0, "Regular", 0 }, ++}; ++ ++ ++/********** MOVE RULES *************/ ++ ++/* Allow a Direct_Move_X along X freedom vector when matched */ ++#define ALLOW_DMOVEX_FREEV_RULES_SIZE 20 ++SPH_TweakRule ALLOW_DMOVEX_FREEV_Rules[ALLOW_DMOVEX_FREEV_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++ { "-", 0, "Regular", 0 }, ++ { "-", 0, "Italic", 0 }, ++ { "-", 0, "Regular", 0 }, ++ { "-Verdana", 12, "Regular", 0 }, ++ { "-Geneva", 0, "", 0 }, ++ { "-Courier New", 0, "Regular", 0 }, ++ { "-Courier New", 0, "", 0 }, ++ { "-Arial", 0, "Bold", 0 }, ++ { "Verdana", 13, "Regular", 0 }, ++ { "-Times New Roman", 0, "Regular", 0 }, ++ { "Arial", 13, "Regular", 0 }, ++ { "Arial", 14, "Regular", 0 }, ++ { "-Tahoma", 0, "Regular", 0 }, ++ { "+++Trebuchet MS", 0, "Regular", 0 }, ++ { "-Trebuchet MS", 0, "Bold", 0 }, ++ { "-Segoe UI", 0, "Semibold", 0 }, ++ { "-Segoe UI", 12, "Regular", 'H' }, ++ { "Arial Narrow", 0, "Regular", 0 }, ++ { "+++Andale Mono", 17, "Regular", 0 }, ++}; ++ ++/* Allow a Direct_Move along X freedom vector when matched */ ++#define ALLOW_DMOVE_FREEV_RULES_SIZE 21 ++SPH_TweakRule ALLOW_DMOVE_FREEV_Rules ++[ALLOW_DMOVE_FREEV_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++ { "-", 0, "Regular", 0 }, ++ { "-", 0, "Italic", 0 }, ++ { "-Verdana", 12, "Regular", 0 }, ++ { "Verdana", 13, "Regular", 0 }, ++ { "-Courier New", 0, "Bold", 0 }, ++ { "-Times New Roman", 0, "Regular", 0 }, ++ { "Arial", 13, "Regular", 0 }, ++ { "Arial", 14, "Regular", 0 }, ++ { "-Arial", 0, "Bold", 0 }, ++ { "-Tahoma", 0, "Regular", 0 }, ++ { "+++Trebuchet MS", 0, "Regular", 0 }, ++ { "-Trebuchet MS", 0, "Bold", 0 }, ++ { "-Geneva", 0, "", 0 }, ++ { "-------", 0, "Regular", 0 }, ++ { "-Segoe UI", 0, "Semibold", 0 }, ++ { "+++Segoe UI", 12, "Regular", 'H' }, ++ { "-----", 0, "Regular", 0 }, ++ { "Arial Narrow", 0, "Regular", 0 }, ++ { "+++Andale Mono", 17, "Regular", 0 }, ++ { "-Courier New", 0, "", 0 }, ++}; ++ ++ ++#define ALLOW_DMOVEX_FREEV_RULES_EXCEPTIONS_SIZE 9 ++SPH_TweakRule ALLOW_DMOVEX_FREEV_Rules_Exceptions ++ [ALLOW_DMOVEX_FREEV_RULES_EXCEPTIONS_SIZE] = { ++ { "-", 0, "", 0 }, ++ { "-Times New Roman", 0, "Regular", 'a' }, ++ { "-Times New Roman", 0, "Regular", 'q' }, ++ { "-Times New Roman", 0, "Regular", 'P' }, ++ { "-Times New Roman", 0, "Regular", 'R' }, ++ { "-Times New Roman", 0, "Regular", 'B' }, ++ { "Arial", 0, "Regular", '4' }, ++ { "Arial", 0, "Regular", 's' }, ++ { "Arial", 0, "Regular", '^' }, ++}; ++ ++#define ALLOW_DMOVE_FREEV_RULES_EXCEPTIONS_SIZE 9 ++SPH_TweakRule ALLOW_DMOVE_FREEV_Rules_Exceptions ++[ALLOW_DMOVE_FREEV_RULES_EXCEPTIONS_SIZE] = { ++ { "-", 0, "", 0 }, ++ { "-Times New Roman", 0, "Regular", 'a' }, ++ { "-Times New Roman", 0, "Regular", 'q' }, ++ { "-Times New Roman", 0, "Regular", 'P' }, ++ { "-Times New Roman", 0, "Regular", 'R' }, ++ { "-Times New Roman", 0, "Regular", 'B' }, ++ { "Arial", 0, "Regular", '4' }, ++ { "Arial", 0, "Regular", 's' }, ++ { "Arial", 0, "Regular", '^' }, ++}; ++ ++ ++/* Allow a ZP2 Move along freedom vector when matched */ ++/* This is called from SHP, SHPIX, SHC, SHZ */ ++#define ALLOW_MOVEZP2_FREEV_RULES_SIZE 14 ++SPH_TweakRule ALLOW_MOVEZP2_FREEV_Rules[ALLOW_MOVEZP2_FREEV_RULES_SIZE] = { ++ { "-", 0, "Regular", 0 }, ++ { "-Verdana", 12, "Regular", 0 }, ++ { "Verdana", 13, "Regular", 0 }, ++ { "-Times New Roman", 0, "Regular", 0 }, ++ { "-Courier New", 0, "Bold", 0 }, ++ { "-Tahoma", 0, "Regular", 0 }, ++ { "-Courier New", 0, "", 0 }, ++ { "Arial", 13, "Regular", 0 }, ++ { "Arial", 14, "Regular", 0 }, ++ { "-Arial", 0, "Bold", 0 }, ++ { "+++Trebuchet MS", 0, "Regular", 0 }, ++ { "-Trebuchet MS", 0, "Bold", 0 }, ++ { "-Verdana", 13, "Regular", 0 }, ++ /* this needs a bit of work though */ ++ { "-Microsoft Sans Serif", 0, "Regular", 0 }, ++}; ++ ++/* Return MS rasterizer 35 when matched */ ++#define RASTERIZER_35_RULES_SIZE 1 ++SPH_TweakRule RASTERIZER_35_Rules ++[RASTERIZER_35_RULES_SIZE] = { ++ { "Times New Roman", 0, "Regular", 'i' }, ++}; ++ ++/************** DIRTY, DIRTY HACKS!!!!!!!! ***************/ ++ ++#define ALLOW_MOVEZP2_FREEV_RULES_EXCEPTIONS_SIZE 11 ++SPH_TweakRule ALLOW_MOVEZP2_FREEV_Rules_Exceptions ++[ALLOW_MOVEZP2_FREEV_RULES_EXCEPTIONS_SIZE] = { ++ { "-", 0, "", 0 }, ++ { "Times New Roman", 0, "Regular", 'a' }, ++ { "Times New Roman", 0, "Regular", 'q' }, ++ { "Verdana", 13, "Regular", 'N' }, ++ { "Verdana", 13, "Regular", 'f' }, ++ { "Verdana", 13, "Regular", 'v' }, ++ { "-------", 13, "Regular", 'k' }, ++ { "Verdana", 13, "Regular", 'w' }, ++ { "Verdana", 13, "Regular", 'x' }, ++ { "Verdana", 13, "Regular", 'y' }, ++ { "Verdana", 13, "Regular", 'z' }, ++}; ++ ++/*********** ROUNDING ***************/ ++/* These only have an effect on fonts that are allowed to move X (above) */ ++/* It appears all MS cleartype fonts may be OK using normal rounds */ ++#define NORMAL_ROUND_MIRP_RULES_SIZE 16 ++SPH_TweakRule NORMAL_ROUND_MIRP_Rules[NORMAL_ROUND_MIRP_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++ { "-Tahoma", 9, "Regular", 0 }, ++ { "-Courier New", 0, "Regular", 'W' }, ++ { "-Courier New", 0, "Regular", 'K' }, ++ { "-Courier New", 0, "Regular", 'k' }, ++ { "-Courier New", 0, "Regular", 'V' }, ++ { "-Courier New", 0, "Regular", 'O' }, ++ { "-Courier New", 0, "Regular", 'X' }, ++ { "-Courier New", 0, "Regular", 'Y' }, ++ { "-Courier New", 0, "Regular", 'A' }, ++ { "-Courier New", 0, "Regular", 'v' }, ++ { "-Courier New", 0, "Regular", 'z' }, ++ { "-Courier New", 0, "Regular", 'x' }, ++ { "-Courier New", 0, "Regular", 'y' }, ++ { "Calibri", 0, "Italic", 0 }, ++ { "Calibri", 0, "Bold Italic", 0 }, ++}; ++ ++#define NORMAL_ROUND_MIAP_RULES_SIZE 16 ++SPH_TweakRule NORMAL_ROUND_MIAP_Rules[NORMAL_ROUND_MIAP_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++ { "-Tahoma", 9, "Regular", 0 }, ++ { "-Courier New", 0, "Regular", 'W' }, ++ { "-Courier New", 0, "Regular", 'K' }, ++ { "-Courier New", 0, "Regular", 'k' }, ++ { "-Courier New", 0, "Regular", 'V' }, ++ { "-Courier New", 0, "Regular", 'O' }, ++ { "-Courier New", 0, "Regular", 'X' }, ++ { "-Courier New", 0, "Regular", 'Y' }, ++ { "-Courier New", 0, "Regular", 'A' }, ++ { "-Courier New", 0, "Regular", 'v' }, ++ { "-Courier New", 0, "Regular", 'z' }, ++ { "-Courier New", 0, "Regular", 'x' }, ++ { "-Courier New", 0, "Regular", 'y' }, ++ { "Calibri", 0, "Italic", 0 }, ++ { "Calibri", 0, "Bold Italic", 0 }, ++}; ++ ++#define NORMAL_ROUND_MDRP_RULES_SIZE 16 ++SPH_TweakRule NORMAL_ROUND_MDRP_Rules[NORMAL_ROUND_MDRP_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++ { "-Tahoma", 9, "Regular", 0 }, ++ { "-Courier New", 0, "Regular", 'W' }, ++ { "-Courier New", 0, "Regular", 'K' }, ++ { "-Courier New", 0, "Regular", 'k' }, ++ { "-Courier New", 0, "Regular", 'V' }, ++ { "-Courier New", 0, "Regular", 'O' }, ++ { "-Courier New", 0, "Regular", 'X' }, ++ { "-Courier New", 0, "Regular", 'Y' }, ++ { "-Courier New", 0, "Regular", 'A' }, ++ { "-Courier New", 0, "Regular", 'v' }, ++ { "-Courier New", 0, "Regular", 'z' }, ++ { "-Courier New", 0, "Regular", 'x' }, ++ { "-Courier New", 0, "Regular", 'y' }, ++ { "Calibri", 0, "Italic", 0 }, ++ { "Calibri", 0, "Bold Italic", 0 }, ++}; ++ ++#define NORMAL_ROUND_MDAP_RULES_SIZE 16 ++SPH_TweakRule NORMAL_ROUND_MDAP_Rules[NORMAL_ROUND_MDAP_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++ { "-Tahoma", 9, "Regular", 0 }, ++ { "-Courier New", 0, "Regular", 'W' }, ++ { "-Courier New", 0, "Regular", 'K' }, ++ { "-Courier New", 0, "Regular", 'k' }, ++ { "-Courier New", 0, "Regular", 'V' }, ++ { "-Courier New", 0, "Regular", 'O' }, ++ { "-Courier New", 0, "Regular", 'X' }, ++ { "-Courier New", 0, "Regular", 'Y' }, ++ { "-Courier New", 0, "Regular", 'A' }, ++ { "-Courier New", 0, "Regular", 'v' }, ++ { "-Courier New", 0, "Regular", 'z' }, ++ { "-Courier New", 0, "Regular", 'x' }, ++ { "-Courier New", 0, "Regular", 'y' }, ++ { "Calibri", 0, "Italic", 0 }, ++ { "Calibri", 0, "Bold Italic", 0 }, ++}; ++ ++ ++/* Skip IUP instructions when matched */ ++#define SKIP_IUP_RULES_SIZE 6 ++SPH_TweakRule SKIP_IUP_Rules[SKIP_IUP_RULES_SIZE] = { ++ { "Arial", 13, "Regular", 'a' }, ++ { "-", 0, "Regular", '2' }, ++ { "-", 0, "", 0 }, ++ { "-", 0, "Regular", 'a' }, ++ { "-", 0, "Regular", 'V' }, ++ { "-", 0, "Light", 0 }, ++}; ++ ++/* Skip DELTAP instructions when matched */ ++#define ALWAYS_SKIP_DELTAP_RULES_SIZE 19 ++SPH_TweakRule ALWAYS_SKIP_DELTAP_Rules[ALWAYS_SKIP_DELTAP_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++ { "--Courier New", 0, "Regular", 'V' }, ++ { "Verdana", 10, "Regular", 0 }, ++ { "-Trebuchet MS", 0, "Regular", 'W' }, ++ { "-Trebuchet MS", 0, "Regular", 'w' }, ++ { "-Verdana", 0, "Italic", 'v' }, ++ { "-Verdana", 0, "Italic", 'w' }, ++ { "-Verdana", 0, "Italic", 'x' }, ++ { "-Verdana", 0, "Italic", 'y' }, ++ { "-Verdana", 0, "Italic", 'z' }, ++ { "-Verdana", 0, "Regular", 'v' }, ++ { "-Verdana", 10, "Regular", 'w' }, ++ { "-Verdana", 0, "Regular", 'y' }, ++ { "-Verdana", 0, "Regular", 'z' }, ++ { "-Arial Bold", 0, "Bold", 's' }, ++ { "Trebuchet MS", 14, "Regular", 'e' }, ++ { "Trebuchet MS", 0, "Italic", 0 }, ++ { "-Arial", 0, "Italic", 0 }, ++ { "-", 0, "Italic", 0 }, ++}; ++ ++/* Always do DELTAP instructions when matched */ ++#define ALWAYS_DO_DELTAP_RULES_SIZE 3 ++SPH_TweakRule ALWAYS_DO_DELTAP_Rules[ALWAYS_DO_DELTAP_RULES_SIZE] = { ++ { "-", 0, "", 0 }, ++ { "DejaVu Sans", 14, "Regular", 'k' }, ++ { "DejaVu Sans", 14, "Regular", 'K' }, ++}; ++ ++/* Do an extra RTG instruction in DELTAP when matched */ ++#define DELTAP_RTG_RULES_SIZE 4 ++SPH_TweakRule DELTAP_RTG_Rules[DELTAP_RTG_RULES_SIZE] = { ++ { "-Arial Unicode MS", 0, "Regular", 0 }, ++ { "-Microsoft Sans Serif", 0, "Regular", '0' }, ++ { "--Verdana", 0, "", 0 }, ++ { "-Trebuchet MS", 14, "Regular", 'e' }, ++}; ++ ++/* Do an extra RUTG instruction in DELTAP when matched */ ++#define DELTAP_RUTG_RULES_SIZE 2 ++SPH_TweakRule DELTAP_RUTG_Rules[DELTAP_RUTG_RULES_SIZE] = { ++ { "-", 14, "Regular", 'e' }, ++ { "-", 0, "", 0 }, ++}; ++ ++/* Do an extra RDTG instruction in DELTAP when matched */ ++#define DELTAP_RDTG_RULES_SIZE 28 ++SPH_TweakRule DELTAP_RDTG_Rules[DELTAP_RDTG_RULES_SIZE] = { ++ { "Calibri", 0, "Italic", 0 }, ++ { "Comic Sans MS", 0, "Regular", 0 }, ++ { "Lucida Grande", 0, "Regular", 'e' }, ++ { "Lucida Grande", 12, "Bold", 0 }, ++ { "Microsoft Sans Serif", 0, "Regular", '7' }, ++ { "Microsoft Sans Serif", 0, "Regular", 'O' }, ++ { "Microsoft Sans Serif", 0, "Regular", 'Q' }, ++ { "Microsoft Sans Serif", 0, "Regular", 'X' }, ++ { "Microsoft Sans Serif", 0, "Regular", 'e' }, ++ { "Microsoft Sans Serif", 0, "Regular", 'o' }, ++ { "-", 0, "", 0 }, ++ { "-", 0, "Regular", 'O' }, ++ { "-", 0, "Regular", 'U' }, ++ { "-", 0, "Regular", 'e' }, ++ { "-", 0, "Regular", 'g' }, ++ { "Tahoma", 0, "Bold", '0' }, ++ { "Tahoma", 16, "Bold", 'C' }, ++ { "Tahoma", 16, "Bold Italic", 'C' }, ++ { "Trebuchet MS", 0, "", '0' }, ++ { "-", 9, "", 'w' }, ++ { "Verdana", 0, "", '0' }, ++ { "Verdana", 0, "Bold Italic", '7' }, ++ { "Verdana", 0, "Bold Italic", 'v' }, ++ { "Verdana", 0, "Bold Italic", 'w' }, ++ { "Verdana", 0, "Bold", 0 }, ++ { "Verdana", 0, "Italic", 'o' }, ++ { "Verdana", 0, "Regular", 'x' }, ++ { "Trebuchet MS", 14, "Regular", 'e' }, ++}; ++ ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS */ ++#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ ++ ++#endif /* __TTSUBPIXEL_H__ */ |