summaryrefslogtreecommitdiffstats
path: root/unmaintained/freetype-infinality/freetype-add-subpixel-hinting-infinality-20101114-1.patch
diff options
context:
space:
mode:
Diffstat (limited to 'unmaintained/freetype-infinality/freetype-add-subpixel-hinting-infinality-20101114-1.patch')
-rw-r--r--unmaintained/freetype-infinality/freetype-add-subpixel-hinting-infinality-20101114-1.patch2776
1 files changed, 2776 insertions, 0 deletions
diff --git a/unmaintained/freetype-infinality/freetype-add-subpixel-hinting-infinality-20101114-1.patch b/unmaintained/freetype-infinality/freetype-add-subpixel-hinting-infinality-20101114-1.patch
new file mode 100644
index 000000000..05e9c4414
--- /dev/null
+++ b/unmaintained/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__ */