diff -Nur freetype-orig/ChangeLog.rej freetype-subpixel/ChangeLog.rej --- freetype-orig/ChangeLog.rej 1969-12-31 18:00:00.000000000 -0600 +++ freetype-subpixel/ChangeLog.rej 2011-04-29 18:26:58.194160202 -0500 @@ -0,0 +1,53 @@ +--- ChangeLog ++++ ChangeLog +@@ -1,3 +1,50 @@ ++2011-04-25 Erik Johnson ++ ++ [truetype] Add subpixel hinting. ++ ++ See the detailed explanations in the new header file ++ `src/truetype/ttsubpix.h' for more. ++ ++ While working quite well in daily use, it is still experimental ++ code. ++ ++ * devel/ftoption.h, include/freetype/config/ftoption.h ++ (TT_CONFIG_OPTION_SUBPIXEL_HINTING, ++ TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS): New macros to ++ activate and control subpixel hinting. ++ ++ * include/freetype/internal/ftobjs.h (FT_PIX_FLOOR_GRID, ++ FT_PIX_ROUND_GRID, FT_PIX_CEIL_GRID): New macros. ++ ++ * src/truetype/ttsubpix.h, src/truetype/ttsubpix.c: New files. ++ ++ * src/truetype/truetype.c: Include `ttsubpix.c'. ++ * src/truetype/ttgload.c: Include `ttsubpix.h'. ++ (tt_get_metrics, compute_glyph_metrics, tt_loader_init) ++ [TT_CONFIG_OPTION_SUBPIXEL_HINTING]: Handle subpixel hinting. ++ ++ * src/truetype/ttinterp.c: Include `ttsubpix.h'. ++ (SET_SuperRound, ROUND_None, Round_None, Round_To_Grid, ++ Round_To_Half_Grid, Round_Down_To_Grid, Round_Up_To_Grid, ++ Round_To_Double_Grid, Round_Super, Round_Super_45, CUR_Func_round, ++ SetSuperRound): Add `resolution' as third argument. ++ Update all callers. ++ (Direct_Move, Direct_Move_X, DO_RS, Ins_FDEF, Ins_ENDF, Ins_CALL, ++ Ins_LOOPCALL, Ins_MD, Move_Zp2_Point, Ins_SHPIX, Ins_MSIRP, ++ Ins_MDAP, Ins_MIAP, Ins_MDRP, Ins_MIRP, Ins_IUP, Ins_DELTAP, ++ TT_RunIns): Handle subpixel hinting. ++ (Ins_GETINFO): Fix a typo. ++ Handle subpixel hinting. ++ ++ * src/truetype/ttinterp.h: Updated. ++ (SPH_TweakRule) [TT_CONFIG_OPTION_SUBPIXEL_HINTING]: New structure ++ to represent tweaks. ++ (TT_ExecContext) [TT_CONFIG_OPTION_SUBPIXEL_HINTING] ++ ++ * src/truetype/ttobjs.h (TT_DefRecord): Add `inline_delta' field. ++ ++ * src/truetype/rules.mk (TT_DRV_SRC): Updated. ++ + 2011-04-25 Kan-Ru Chen + + [truetype] Always check the checksum to identify tricky fonts. diff -Nur freetype-orig/devel/ftoption.h freetype-subpixel/devel/ftoption.h --- freetype-orig/devel/ftoption.h 2011-04-29 18:14:22.706916180 -0500 +++ freetype-subpixel/devel/ftoption.h 2011-04-29 18:26:58.214161348 -0500 @@ -549,6 +549,48 @@ /*************************************************************************/ /* */ + /* Define TT_CONFIG_OPTION_SUBPIXEL_HINTING if you want to compile */ + /* EXPERIMENTAL subpixel hinting support into the TrueType driver. This */ + /* replaces 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 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 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-orig/include/freetype/config/ftoption.h freetype-subpixel/include/freetype/config/ftoption.h --- freetype-orig/include/freetype/config/ftoption.h 2011-04-29 18:14:22.710916409 -0500 +++ freetype-subpixel/include/freetype/config/ftoption.h 2011-04-29 18:26:58.215161406 -0500 @@ -549,6 +549,48 @@ /*************************************************************************/ /* */ + /* Define TT_CONFIG_OPTION_SUBPIXEL_HINTING if you want to compile */ + /* EXPERIMENTAL subpixel hinting support into the TrueType driver. This */ + /* replaces 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 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 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-orig/include/freetype/internal/ftobjs.h freetype-subpixel/include/freetype/internal/ftobjs.h --- freetype-orig/include/freetype/internal/ftobjs.h 2011-04-29 18:14:22.722917096 -0500 +++ freetype-subpixel/include/freetype/internal/ftobjs.h 2011-04-29 18:26:58.218161577 -0500 @@ -4,7 +4,7 @@ /* */ /* The FreeType private base classes (specification). */ /* */ -/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2008, 2010 by */ +/* Copyright 1996-2006, 2008, 2010-2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -73,14 +73,22 @@ #define FT_ABS( a ) ( (a) < 0 ? -(a) : (a) ) -#define FT_PAD_FLOOR( x, n ) ( (x) & ~((n)-1) ) -#define FT_PAD_ROUND( x, n ) FT_PAD_FLOOR( (x) + ((n)/2), n ) -#define FT_PAD_CEIL( x, n ) FT_PAD_FLOOR( (x) + ((n)-1), n ) +#define FT_PAD_FLOOR( x, n ) ( (x) & ~( (n) - 1 ) ) +#define FT_PAD_ROUND( x, n ) FT_PAD_FLOOR( (x) + ( (n) / 2 ), n ) +#define FT_PAD_CEIL( x, n ) FT_PAD_FLOOR( (x) + ( (n) - 1 ), n ) #define FT_PIX_FLOOR( x ) ( (x) & ~63 ) #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-orig/src/truetype/rules.mk freetype-subpixel/src/truetype/rules.mk --- freetype-orig/src/truetype/rules.mk 2011-04-29 18:14:22.782920530 -0500 +++ freetype-subpixel/src/truetype/rules.mk 2011-04-29 18:26:58.221161748 -0500 @@ -31,7 +31,8 @@ $(TT_DIR)/ttinterp.c \ $(TT_DIR)/ttobjs.c \ $(TT_DIR)/ttpic.c \ - $(TT_DIR)/ttpload.c + $(TT_DIR)/ttpload.c \ + $(TT_DIR)/ttsubpix.c # TrueType driver headers # diff -Nur freetype-orig/src/truetype/truetype.c freetype-subpixel/src/truetype/truetype.c --- freetype-orig/src/truetype/truetype.c 2011-04-29 18:14:22.782920530 -0500 +++ freetype-subpixel/src/truetype/truetype.c 2011-04-29 18:26:58.222161805 -0500 @@ -4,7 +4,7 @@ /* */ /* FreeType TrueType driver component (body only). */ /* */ -/* Copyright 1996-2001, 2004, 2006 by */ +/* Copyright 1996-2001, 2004, 2006, 2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -27,6 +27,7 @@ #ifdef TT_USE_BYTECODE_INTERPRETER #include "ttinterp.c" +#include "ttsubpix.c" #endif #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT diff -Nur freetype-orig/src/truetype/ttgload.c freetype-subpixel/src/truetype/ttgload.c --- freetype-orig/src/truetype/ttgload.c 2011-04-29 18:14:22.783920587 -0500 +++ freetype-subpixel/src/truetype/ttgload.c 2011-04-29 18:26:58.224161920 -0500 @@ -32,6 +32,7 @@ #endif #include "tterrors.h" +#include "ttsubpix.h" /*************************************************************************/ @@ -149,6 +150,19 @@ loader->top_bearing = top_bearing; loader->vadvance = advance_height; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS + + if ( loader->exec ) + loader->exec->sph_tweak_flags = 0; + + /* 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_ADDITIONAL_TWEAKS */ +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + if ( !loader->linear_def ) { loader->linear_def = 1; @@ -1651,12 +1665,23 @@ { 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 || SPH_OPTION_BITMAP_WIDTHS ) && widthp ) +#else if ( widthp ) +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ glyph->metrics.horiAdvance = *widthp << 6; } @@ -1851,6 +1876,15 @@ { TT_ExecContext exec; FT_Bool grayscale; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + FT_Bool subpixel_hinting; + FT_Bool grayscale_hinting; +#if 0 + FT_Bool compatible_widths; + FT_Bool symmetrical_smoothing; + FT_Bool bgr; +#endif +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ if ( !size->cvt_ready ) @@ -1868,20 +1902,87 @@ 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 ) && + SPH_OPTION_SET_SUBPIXEL ); + + if ( subpixel_hinting ) + grayscale = grayscale_hinting = FALSE; + + else if ( SPH_OPTION_SET_GRAYSCALE ) + { + grayscale = grayscale_hinting = TRUE; + subpixel_hinting = FALSE; + } + + exec->enhanced = subpixel_hinting || grayscale_hinting; + exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION; + +#if 1 + exec->compatible_widths = SPH_OPTION_SET_COMPATIBLE_WIDTHS; + exec->symmetrical_smoothing = FALSE; + exec->bgr = FALSE; +#else /* 0 */ + exec->compatible_widths = + FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != + TT_LOAD_COMPATIBLE_WIDTHS ); + exec->symmetrical_smoothing = + FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != + TT_LOAD_SYMMETRICAL_SMOOTHING ); + exec->bgr = + FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != + TT_LOAD_BGR ); +#endif /* 0 */ + +#else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + 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 ); +#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 ( 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, pedantic ); + } + /* a change from mono to grayscale rendering (and vice versa) */ /* requires a re-execution of the CVT program */ - if ( grayscale != exec->grayscale ) + if ( grayscale != exec->grayscale_hinting ) { FT_UInt i; - FT_TRACE4(( "tt_loader_init: grayscale change," - " re-executing `prep' table\n" )); + exec->grayscale_hinting = grayscale_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, pedantic ); + } + +#else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + + /* 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; @@ -1890,6 +1991,8 @@ tt_size_run_prep( size, pedantic ); } +#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + /* see whether the cvt program has disabled hinting */ if ( exec->GS.instruct_control & 1 ) load_flags |= FT_LOAD_NO_HINTING; diff -Nur freetype-orig/src/truetype/ttinterp.c freetype-subpixel/src/truetype/ttinterp.c --- freetype-orig/src/truetype/ttinterp.c 2011-04-29 18:14:22.785920701 -0500 +++ freetype-subpixel/src/truetype/ttinterp.c 2011-04-29 18:26:58.233162434 -0500 @@ -23,13 +23,16 @@ #include FT_SYSTEM_H #include "ttinterp.h" - #include "tterrors.h" +#include "ttsubpix.h" #ifdef TT_USE_BYTECODE_INTERPRETER +#define xxxSPH_DEBUG + + #define TT_MULFIX FT_MulFix #define TT_MULDIV FT_MulDiv #define TT_MULDIV_NO_ROUND FT_MulDiv_No_Round @@ -149,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 ) @@ -164,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 ) @@ -245,6 +248,14 @@ #define GUESS_VECTOR( V ) #endif + +#ifdef SPH_DEBUG + FT_Int CUR.num_delta_funcs; + FT_ULong inline_delta_funcs[5]; + FT_Long CUR.infunc; +#endif + + /*************************************************************************/ /* */ /* CODERANGE FUNCTIONS */ @@ -1842,16 +1853,26 @@ 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, - v * 0x10000L, - CUR.F_dot_P ); +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + + v = CUR.GS.freeVector.x; - zone->tags[point] |= FT_CURVE_TAG_TOUCH_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; + } + +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING } +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ v = CUR.GS.freeVector.y; @@ -1928,8 +1949,18 @@ { 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 */ } @@ -1990,6 +2021,8 @@ /* */ /* compensation :: The engine compensation. */ /* */ + /* resolution :: The grid resolution. */ + /* */ /* */ /* The compensated distance. */ /* */ @@ -2001,11 +2034,13 @@ /* */ static FT_F26Dot6 Round_None( EXEC_OP_ FT_F26Dot6 distance, - FT_F26Dot6 compensation ) + FT_F26Dot6 compensation, + FT_Int resolution ) { FT_F26Dot6 val; FT_UNUSED_EXEC; + FT_UNUSED( resolution ); if ( distance >= 0 ) @@ -2020,6 +2055,7 @@ if ( val > 0 ) val = 0; } + return val; } @@ -2037,12 +2073,15 @@ /* */ /* compensation :: The engine compensation. */ /* */ + /* resolution :: The grid resolution. */ + /* */ /* */ /* Rounded distance. */ /* */ static FT_F26Dot6 Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance, - FT_F26Dot6 compensation ) + FT_F26Dot6 compensation, + FT_Int resolution ) { FT_F26Dot6 val; @@ -2051,15 +2090,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; } @@ -2081,12 +2120,15 @@ /* */ /* compensation :: The engine compensation. */ /* */ + /* resolution :: The grid resolution. */ + /* */ /* */ /* Rounded distance. */ /* */ static FT_F26Dot6 Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance, - FT_F26Dot6 compensation ) + FT_F26Dot6 compensation, + FT_Int resolution ) { FT_F26Dot6 val; @@ -2095,13 +2137,15 @@ 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; } @@ -2123,12 +2167,15 @@ /* */ /* compensation :: The engine compensation. */ /* */ + /* resolution :: The grid resolution. */ + /* */ /* */ /* Rounded distance. */ /* */ static FT_F26Dot6 Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance, - FT_F26Dot6 compensation ) + FT_F26Dot6 compensation, + FT_Int resolution ) { FT_F26Dot6 val; @@ -2139,13 +2186,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; } @@ -2167,12 +2214,15 @@ /* */ /* compensation :: The engine compensation. */ /* */ + /* resolution :: The grid resolution. */ + /* */ /* */ /* Rounded distance. */ /* */ static FT_F26Dot6 Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance, - FT_F26Dot6 compensation ) + FT_F26Dot6 compensation, + FT_Int resolution ) { FT_F26Dot6 val; @@ -2181,15 +2231,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; } @@ -2211,12 +2261,15 @@ /* */ /* compensation :: The engine compensation. */ /* */ + /* resolution :: The grid resolution. */ + /* */ /* */ /* Rounded distance. */ /* */ static FT_F26Dot6 Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance, - FT_F26Dot6 compensation ) + FT_F26Dot6 compensation, + FT_Int resolution ) { FT_F26Dot6 val; @@ -2225,15 +2278,15 @@ 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; } @@ -2255,6 +2308,8 @@ /* */ /* compensation :: The engine compensation. */ /* */ + /* resolution :: The grid resolution. */ + /* */ /* */ /* Rounded distance. */ /* */ @@ -2266,10 +2321,13 @@ /* */ static FT_F26Dot6 Round_Super( EXEC_OP_ FT_F26Dot6 distance, - FT_F26Dot6 compensation ) + FT_F26Dot6 compensation, + FT_Int resolution ) { FT_F26Dot6 val; + FT_UNUSED( resolution ); + if ( distance >= 0 ) { @@ -2305,6 +2363,8 @@ /* */ /* compensation :: The engine compensation. */ /* */ + /* resolution :: The grid resolution. */ + /* */ /* */ /* Rounded distance. */ /* */ @@ -2314,10 +2374,13 @@ /* */ static FT_F26Dot6 Round_Super_45( EXEC_OP_ FT_F26Dot6 distance, - FT_F26Dot6 compensation ) + FT_F26Dot6 compensation, + FT_Int resolution ) { FT_F26Dot6 val; + FT_UNUSED( resolution ); + if ( distance >= 0 ) { @@ -2400,32 +2463,38 @@ /* Sets Super Round parameters. */ /* */ /* */ - /* GridPeriod :: Grid period */ - /* selector :: SROUND opcode */ + /* GridPeriod :: The grid period. */ + /* */ + /* selector :: The SROUND opcode. */ + /* */ + /* resolution :: The grid resolution. */ /* */ static void SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod, - FT_Long selector ) + FT_Long selector, + FT_Int resolution ) { + FT_UNUSED( resolution ); + switch ( (FT_Int)( selector & 0xC0 ) ) { - case 0: - CUR.period = GridPeriod / 2; - break; + case 0: + CUR.period = GridPeriod / 2; + break; - case 0x40: - CUR.period = GridPeriod; - break; + case 0x40: + CUR.period = GridPeriod; + break; - case 0x80: - CUR.period = GridPeriod * 2; - break; + case 0x80: + CUR.period = GridPeriod * 2; + break; - /* This opcode is reserved, but... */ + /* This opcode is reserved, but... */ - case 0xC0: - CUR.period = GridPeriod; - break; + case 0xC0: + CUR.period = GridPeriod; + break; } switch ( (FT_Int)( selector & 0x30 ) ) @@ -3065,13 +3134,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; @@ -3241,12 +3310,12 @@ args[0] = ( args[0] != args[1] ); -#define DO_ODD \ - args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 ); +#define DO_ODD \ + args[0] = ( ( CUR_Func_round( args[0], 0, 1 ) & 127 ) == 64 ); -#define DO_EVEN \ - args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 ); +#define DO_EVEN \ + args[0] = ( ( CUR_Func_round( args[0], 0, 1 ) & 127 ) == 0 ); #define DO_AND \ @@ -3295,6 +3364,35 @@ #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 /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ #define DO_RS \ { \ @@ -3304,9 +3402,7 @@ if ( BOUNDSL( I, CUR.storeSize ) ) \ { \ if ( CUR.pedantic_hinting ) \ - { \ ARRAY_BOUND_ERROR; \ - } \ else \ args[0] = 0; \ } \ @@ -3314,6 +3410,8 @@ args[0] = CUR.storage[I]; \ } +#endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + #define DO_WS \ { \ @@ -3323,9 +3421,7 @@ if ( BOUNDSL( I, CUR.storeSize ) ) \ { \ if ( CUR.pedantic_hinting ) \ - { \ ARRAY_BOUND_ERROR; \ - } \ } \ else \ CUR.storage[I] = args[1]; \ @@ -3340,9 +3436,7 @@ if ( BOUNDSL( I, CUR.cvtSize ) ) \ { \ if ( CUR.pedantic_hinting ) \ - { \ ARRAY_BOUND_ERROR; \ - } \ else \ args[0] = 0; \ } \ @@ -3359,9 +3453,7 @@ if ( BOUNDSL( I, CUR.cvtSize ) ) \ { \ if ( CUR.pedantic_hinting ) \ - { \ ARRAY_BOUND_ERROR; \ - } \ } \ else \ CUR_Func_write_cvt( I, args[1] ); \ @@ -3376,9 +3468,7 @@ if ( BOUNDSL( I, CUR.cvtSize ) ) \ { \ if ( CUR.pedantic_hinting ) \ - { \ ARRAY_BOUND_ERROR; \ - } \ } \ else \ CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \ @@ -3389,15 +3479,17 @@ CUR.error = TT_Err_Debug_OpCode; -#define DO_ROUND \ - args[0] = CUR_Func_round( \ - args[0], \ - CUR.tt_metrics.compensations[CUR.opcode - 0x68] ); +#define DO_ROUND \ + args[0] = CUR_Func_round( \ + args[0], \ + CUR.tt_metrics.compensations[CUR.opcode - 0x68], \ + 1 ); -#define DO_NROUND \ - args[0] = ROUND_None( args[0], \ - CUR.tt_metrics.compensations[CUR.opcode - 0x6C] ); +#define DO_NROUND \ + args[0] = ROUND_None( args[0], \ + CUR.tt_metrics.compensations[CUR.opcode - 0x6C], \ + 1 ); #define DO_MAX \ @@ -3415,10 +3507,11 @@ #undef ARRAY_BOUND_ERROR #define ARRAY_BOUND_ERROR \ + do \ { \ CUR.error = TT_Err_Invalid_Reference; \ return; \ - } + } while ( 0 ) /*************************************************************************/ @@ -4571,6 +4664,23 @@ 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. */ @@ -4604,10 +4714,11 @@ return; } - rec->range = CUR.curRange; - rec->opc = (FT_UInt16)n; - rec->start = CUR.IP + 1; - rec->active = TRUE; + rec->range = CUR.curRange; + rec->opc = (FT_UInt16)n; + rec->start = CUR.IP + 1; + rec->active = TRUE; + rec->inline_delta = FALSE; if ( n > CUR.maxFunc ) CUR.maxFunc = (FT_UInt16)n; @@ -4617,6 +4728,89 @@ while ( SKIP_Code() == SUCCESS ) { +#ifdef SPH_DEBUG + printf ("%d ", CUR.opcode); +#endif + +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + + for ( i = 0; i < opcode_patterns; i++ ) + { + if ( CUR.opcode == opcode_pattern[i][opcode_pointer[i]] ) + { +#ifdef SPH_DEBUG + printf( "function %d, opcode ptrn: %d" + " op# %d: %d FOUND -------------\n", + n, i, opcode_pointer[i], CUR.opcode ); +#endif + + opcode_pointer[i] += 1; + + if ( i == 0 && opcode_pointer[0] == 5 ) + { +#ifdef SPH_DEBUG + inline_delta_funcs[CUR.num_delta_funcs] = n; + CUR.num_delta_funcs++; + printf( "Vacuform Round FUNCTION %d detected\n", n); +#endif + + if ( CUR.enhanced ) + { +#ifdef SPH_DEBUG + rec->active = FALSE; +#endif + + opcode_pointer[i] = 0; + } + } + + if ( i == 1 && opcode_pointer[1] == 12 ) + { +#ifdef SPH_DEBUG + *rec->active = FALSE; + CUR.inline_delta_funcs[CUR.num_delta_funcs] = n; + CUR.num_delta_funcs++; + printf( "inline delta FUNCTION1 %d detected\n", + n, CUR.num_delta_funcs); +#endif + + rec->inline_delta = TRUE; + opcode_pointer[i] = 0; + } + + if ( i == 2 && opcode_pointer[1] == 9 ) + { +#ifdef SPH_DEBUG + CUR.inline_delta_funcs[CUR.num_delta_funcs] = n; + CUR.num_delta_funcs++; + rec->inline_delta = TRUE; + printf( "inline delta2 FUNCTION2 %d detected\n", + n, CUR.num_delta_funcs); +#endif + + opcode_pointer[i] = 0; + } + + if ( i == 4 && opcode_pointer[1] == 8 ) + { +#ifdef SPH_DEBUG + CUR.inline_delta_funcs[CUR.num_delta_funcs] = n; + CUR.num_delta_funcs++; + rec->inline_delta = TRUE; + printf( "diagonal stroke function %d detected\n", + n, CUR.num_delta_funcs); +#endif + + opcode_pointer[i] = 0; + } + } + + else + opcode_pointer[i] = 0; + } + +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + switch ( CUR.opcode ) { case 0x89: /* IDEF */ @@ -4659,6 +4853,14 @@ 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++; @@ -4692,6 +4894,10 @@ 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 */ @@ -4729,6 +4935,24 @@ if ( !def->active ) goto Fail; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + /* This is test code used to detect inline delta functions */ + oldF = def->inline_delta; + if ( CUR.enhanced ) + { + if ( def->inline_delta ) + CUR.infunc = TRUE; + } + +#ifdef SPH_DEBUG + if ( F == 35 || F == 34 ) + { + CUR.enhanced = 0; + printf("Entering %d\n", F); + } +#endif +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + /* check the call stack */ if ( CUR.callTop >= CUR.callSize ) { @@ -4749,6 +4973,16 @@ def->start ); CUR.step_ins = FALSE; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + CUR.infunc = oldF; +#ifdef SPH_DEBUG + if ( F == 35 || F == 34 ) + { + CUR.enhanced = 1; + printf("Leaving %d\n", F); + } +#endif +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ return; Fail: @@ -4769,6 +5003,10 @@ 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]; @@ -4805,6 +5043,15 @@ if ( !def->active ) goto Fail; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + oldF = def->inline_delta; + if ( CUR.enhanced ) + { + if ( def->inline_delta ) + CUR.infunc = TRUE; + } +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + /* check stack */ if ( CUR.callTop >= CUR.callSize ) { @@ -4827,6 +5074,11 @@ CUR.step_ins = FALSE; } + +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + CUR.infunc = oldF; +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + return; Fail: @@ -5163,6 +5415,12 @@ } } +#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; } @@ -5645,12 +5903,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 ) { @@ -5841,6 +6108,9 @@ { FT_F26Dot6 dx, dy; FT_UShort point; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + FT_Int B1, B2; +#endif if ( CUR.top < CUR.GS.loop + 1 ) @@ -5886,11 +6156,81 @@ } } else - MOVE_Zp2_Point( point, dx, dy, TRUE ); + { +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + /* + * The conditionals here still do 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.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 ) + { +#ifdef SPH_DEBUG + printf( "Reversing ZP2 move\n" ); +#endif + MOVE_Zp2_Point( point, -dx, -dy, TRUE ); + } + } + else +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + MOVE_Zp2_Point( point, dx, dy, TRUE ); + } CUR.GS.loop--; } +#ifdef SPH_DEBUG + printf( "SHPIX: %d\n", CUR.infunc ); +#endif + Fail: CUR.GS.loop = 1; CUR.new_top = CUR.args; @@ -5908,7 +6248,18 @@ { 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 = SPH_OPTION_GRIDS_PER_PIXEL_X; + else if ( CUR.GS.freeVector.y != 0 ) + resolution = SPH_OPTION_GRIDS_PER_PIXEL_Y; + } +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ point = (FT_UShort)args[0]; @@ -5932,6 +6283,16 @@ 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 cut-in; */ + /* this 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; @@ -5954,7 +6315,21 @@ 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 = SPH_OPTION_GRIDS_PER_PIXEL_X; + + else if ( CUR.GS.freeVector.y != 0 && + !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND_MDAP ) ) + resolution = SPH_OPTION_GRIDS_PER_PIXEL_Y; + } +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ point = (FT_UShort)args[0]; @@ -5971,7 +6346,8 @@ { cur_dist = CUR_fast_project( &CUR.zp0.cur[point] ); distance = CUR_Func_round( cur_dist, - CUR.tt_metrics.compensations[0] ) - cur_dist; + CUR.tt_metrics.compensations[0], + resolution ) - cur_dist; } else distance = 0; @@ -5996,7 +6372,21 @@ 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 = SPH_OPTION_GRIDS_PER_PIXEL_X; + + else if ( CUR.GS.freeVector.y != 0 && + !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND_MIAP ) ) + resolution = SPH_OPTION_GRIDS_PER_PIXEL_Y; + } +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ cvtEntry = (FT_ULong)args[1]; point = (FT_UShort)args[0]; @@ -6042,12 +6432,15 @@ org_dist = CUR_fast_project( &CUR.zp0.cur[point] ); - if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cutin flag */ + if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cut-in flag */ { - if ( FT_ABS( distance - org_dist ) > CUR.GS.control_value_cutin ) + 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] ); + distance = CUR_Func_round( distance, + CUR.tt_metrics.compensations[0], + resolution ); } CUR_Func_move( &CUR.zp0, point, distance - org_dist ); @@ -6069,6 +6462,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 = SPH_OPTION_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 = SPH_OPTION_GRIDS_PER_PIXEL_Y; + } +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ point = (FT_UShort)args[0]; @@ -6134,11 +6545,13 @@ 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 */ @@ -6146,13 +6559,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 ); } } @@ -6189,10 +6606,36 @@ cur_dist, org_dist; + FT_Int minimum_distance_factor = 64; + FT_Int resolution = 1; + + FT_Int B1; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + FT_Int B2; +#endif 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 = SPH_OPTION_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 = SPH_OPTION_GRIDS_PER_PIXEL_Y; + } +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */ if ( BOUNDS( point, CUR.zp1.n_points ) || @@ -6248,7 +6691,7 @@ cvt_dist = -cvt_dist; } - /* control value cutin and round */ + /* control value cut-in and round */ if ( ( CUR.opcode & 4 ) != 0 ) { @@ -6269,18 +6712,21 @@ /* `ttinst2.doc', version 1.66, is thus incorrect since */ /* it implies `>=' instead of `>'. */ - 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 */ @@ -6288,18 +6734,39 @@ { 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 */ + Fail: CUR.GS.rp1 = CUR.GS.rp0; @@ -6796,6 +7263,15 @@ 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; @@ -6865,7 +7341,19 @@ FT_UShort A; FT_ULong C; FT_Long B; +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + FT_Int resolution = 1; + FT_UShort B1, B2; + + if (CUR.enhanced ) + { + if ( CUR.GS.freeVector.x != 0 ) + resolution = SPH_OPTION_GRIDS_PER_PIXEL_X; + else if ( CUR.GS.freeVector.y != 0 ) + resolution = SPH_OPTION_GRIDS_PER_PIXEL_Y; + } +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING /* Delta hinting is covered by US Patent 5159668. */ @@ -6938,7 +7426,89 @@ 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 rounds 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 ) + { + FT_Byte 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 @@ -7068,22 +7638,107 @@ K = 0; - /* We return MS rasterizer version 1.7 for the font scaler. */ + /********************************/ + /* 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; +#ifdef SPH_DEBUG + printf(" SETTING AS 37\n" ); +#endif + } + else +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ if ( ( args[0] & 1 ) != 0 ) + { K = 35; +#ifdef SPH_DEBUG + printf(" SETTING AS 35\n" ); +#endif + } - /* Has the glyph been rotated? */ + /********************************/ + /* 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 << 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 stuff below is 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; } @@ -7458,6 +8113,13 @@ 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 ) @@ -7747,8 +8409,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-orig/src/truetype/ttinterp.h freetype-subpixel/src/truetype/ttinterp.h --- freetype-orig/src/truetype/ttinterp.h 2011-04-29 18:14:22.785920701 -0500 +++ freetype-subpixel/src/truetype/ttinterp.h 2011-04-29 18:26:58.236162608 -0500 @@ -4,7 +4,7 @@ /* */ /* TrueType bytecode interpreter (specification). */ /* */ -/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2010 by */ +/* Copyright 1996-2007, 2010-2011 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -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,26 @@ } 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 */ @@ -206,9 +227,9 @@ TT_Project_Func func_project, /* current projection function */ func_dualproj, /* current dual proj. function */ - func_freeProj; /* current freedom proj. func */ + func_freeProj; /* current freedom proj. func. */ - TT_Move_Func func_move; /* current point move function */ + TT_Move_Func func_move; /* current point move function */ TT_Move_Func func_move_orig; /* move original position function */ TT_Get_CVT_Func func_read_cvt; /* read a cvt entry */ @@ -217,6 +238,32 @@ FT_Bool grayscale; /* are we hinting for grayscale? */ +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING + TT_Round_Func func_round_sphn; /* subpixel rounding function */ + + FT_Bool grayscale_hinting; /* grayscale hinting? */ + FT_Bool subpixel_hinting; /* subpixel hinting? */ + FT_Bool enhanced; /* enhanced rendering (grayscale */ + /* or subpixel_hinting)? */ + FT_Bool native_hinting; /* native hinting? */ + + /* the following 3 are unimplemented but here for future reference */ + FT_Bool compatible_widths; /* compatible widths? */ + FT_Bool symmetrical_smoothing; /* symmetrical_smoothing? */ + FT_Bool bgr; /* bgr instead of rgb? */ + + FT_Int rasterizer_version; /* 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-orig/src/truetype/ttobjs.h freetype-subpixel/src/truetype/ttobjs.h --- freetype-orig/src/truetype/ttobjs.h 2011-04-29 18:14:22.786920759 -0500 +++ freetype-subpixel/src/truetype/ttobjs.h 2011-04-29 18:26:58.237162665 -0500 @@ -173,10 +173,11 @@ /* */ typedef struct TT_DefRecord_ { - FT_Int range; /* in which code range is it located? */ - FT_Long start; /* where does it start? */ - FT_UInt opc; /* function #, or instruction code */ - FT_Bool active; /* is it active? */ + FT_Int range; /* in which code range is it located? */ + FT_Long start; /* where does it start? */ + FT_UInt opc; /* function #, or instruction code */ + FT_Bool active; /* is it active? */ + FT_Bool inline_delta; /* is function that defines inline delta? */ } TT_DefRecord, *TT_DefArray; @@ -189,7 +190,7 @@ { FT_Fixed xx, xy; /* transformation matrix coefficients */ FT_Fixed yx, yy; - FT_F26Dot6 ox, oy; /* offsets */ + FT_F26Dot6 ox, oy; /* offsets */ } TT_Transform; diff -Nur freetype-orig/src/truetype/ttsubpix.c freetype-subpixel/src/truetype/ttsubpix.c --- freetype-orig/src/truetype/ttsubpix.c 1969-12-31 18:00:00.000000000 -0600 +++ freetype-subpixel/src/truetype/ttsubpix.c 2011-04-29 18:26:58.238162722 -0500 @@ -0,0 +1,129 @@ +/***************************************************************************/ +/* */ +/* ttsubpix.c */ +/* */ +/* TrueType Subpixel Hinting. */ +/* */ +/* Copyright 2010-2011 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +#include +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_CALC_H +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_SFNT_H +#include FT_TRUETYPE_TAGS_H +#include FT_OUTLINE_H + +#include "ttsubpix.h" + + +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS + + FT_LOCAL_DEF( FT_Bool ) + sph_test_tweak( TT_Face face, + FT_String* family, + int ppem, + FT_String* style, + FT_UInt glyph_index, + SPH_TweakRule* rule, + FT_UInt num_rules ) + { + FT_UInt i; + + + /* rule checks may be able to be optimized further */ + for ( i = 0; i < num_rules; i++ ) + { + if ( family && + ( 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; + } + + +#define TWEAK_RULES( x ) \ + if ( sph_test_tweak( face, family, ppem, style, glyph_index, \ + x##_Rules, x##_RULES_SIZE ) ) \ + loader->exec->sph_tweak_flags |= SPH_TWEAK_##x; + +#define TWEAK_RULES_EXCEPTIONS( x ) \ + if ( sph_test_tweak( face, family, ppem, style, glyph_index, \ + x##_Rules_Exceptions, x##_RULES_EXCEPTIONS_SIZE ) ) \ + loader->exec->sph_tweak_flags &= ~SPH_TWEAK_##x; + + + FT_LOCAL_DEF( void ) + sph_set_tweaks( TT_Loader loader, + FT_UInt glyph_index ) + { + TT_Face face = (TT_Face)loader->face; + FT_String* family = face->root.family_name; + int ppem = loader->size->metrics.x_ppem; + FT_String* style = face->root.style_name; + + + /* loader->exec->sph_tweak_flags = 0; */ + + /* printf( "%s,%d,%s,%c ", family, ppem, style, glyph_index ); */ + + TWEAK_RULES( NORMAL_ROUND_MIRP ); + TWEAK_RULES( NORMAL_ROUND_MDRP ); + TWEAK_RULES( NORMAL_ROUND_MDAP ); + TWEAK_RULES( NORMAL_ROUND_MIAP ); + + TWEAK_RULES( SKIP_IUP ); + + TWEAK_RULES( ALWAYS_SKIP_DELTAP ); + TWEAK_RULES( ALWAYS_DO_DELTAP ); + TWEAK_RULES( DELTAP_RTG ); + TWEAK_RULES( DELTAP_RUTG ); + TWEAK_RULES( DELTAP_RDTG ); + + TWEAK_RULES( ALLOW_DMOVEX_FREEV ); + TWEAK_RULES( ALLOW_DMOVE_FREEV ); + TWEAK_RULES_EXCEPTIONS( ALLOW_DMOVEX_FREEV ); + TWEAK_RULES_EXCEPTIONS( ALLOW_DMOVE_FREEV ); + + TWEAK_RULES( RASTERIZER_35 ); + + TWEAK_RULES( ALLOW_MOVEZP2_FREEV ); + TWEAK_RULES_EXCEPTIONS( ALLOW_MOVEZP2_FREEV ); + + TWEAK_RULES( DO_RS ); + + TWEAK_RULES( DO_SHPIX ); + + TWEAK_RULES( SKIP_NONPIXEL_INLINE_MOVES ); + + TWEAK_RULES( SHPIX_CLASS_A ); + TWEAK_RULES_EXCEPTIONS( SHPIX_CLASS_A ); + } + +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS */ +#endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */ + + +/* END */ diff -Nur freetype-orig/src/truetype/ttsubpix.h freetype-subpixel/src/truetype/ttsubpix.h --- freetype-orig/src/truetype/ttsubpix.h 1969-12-31 18:00:00.000000000 -0600 +++ freetype-subpixel/src/truetype/ttsubpix.h 2011-04-29 18:26:58.241162893 -0500 @@ -0,0 +1,912 @@ +/***************************************************************************/ +/* */ +/* ttsubpix.h */ +/* */ +/* TrueType Subpixel Hinting. */ +/* */ +/* Copyright 2010-2011 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +#ifndef __TTSUBPIX_H__ +#define __TTSUBPIX_H__ + +#include +#include "ttobjs.h" +#include "ttinterp.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 + + + FT_LOCAL( FT_Bool ) + sph_test_tweak( TT_Face face, + FT_String* family, + int ppem, + FT_String* style, + FT_UInt glyph_index, + SPH_TweakRule* rule, + FT_UInt num_rules ); + + FT_LOCAL( 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 functionality described here */ + /* and nothing more: */ + /* */ + /* http://www.microsoft.com/typography/cleartype/truetypecleartype.aspx */ + /* */ + /* This mode is enabled if */ + /* TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS */ + /* is undefined */ + /* */ + + +#ifndef TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS + +#if 0 /* this ruleset is not currently being used */ + +#define SPH_OPTION_BITMAP_WIDTHS FALSE +#define SPH_OPTION_SET_SUBPIXEL FALSE +#define SPH_OPTION_SET_GRAYSCALE TRUE +#define SPH_OPTION_SET_COMPATIBLE_WIDTHS TRUE +#define SPH_OPTION_SET_RASTERIZER_VERSION 35 +#define SPH_OPTION_GRIDS_PER_PIXEL_X 1 +#define SPH_OPTION_GRIDS_PER_PIXEL_Y 1 + + + /********** MOVE RULES *************/ + + /* allow a Direct_Move_X along freedom vector if 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 if 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 if 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 if 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 }, + }; + + /* indicate 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 if matched */ +#define SKIP_IUP_RULES_SIZE 1 + SPH_TweakRule SKIP_IUP_Rules + [SKIP_IUP_RULES_SIZE] = + { + { "-", 0, "", 0 }, + }; + + /* skip DELTAP instructions if 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 if 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 if 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 if 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 if matched */ +#define DELTAP_RDTG_RULES_SIZE 1 + SPH_TweakRule DELTAP_RDTG_Rules + [DELTAP_RDTG_RULES_SIZE] = + { + { "-", 0, "", 0 }, + }; + + /* return MS rasterizer version 35 if matched */ +#define RASTERIZER_35_RULES_SIZE 1 + SPH_TweakRule RASTERIZER_35_Rules + [RASTERIZER_35_RULES_SIZE] = + { + { "-", 0, "", 0 }, + }; + + +#else /* 1 */ + + +#define SPH_OPTION_BITMAP_WIDTHS FALSE +#define SPH_OPTION_SET_SUBPIXEL TRUE +#define SPH_OPTION_SET_GRAYSCALE FALSE +#define SPH_OPTION_SET_COMPATIBLE_WIDTHS FALSE +#define SPH_OPTION_SET_RASTERIZER_VERSION 37 +#define SPH_OPTION_GRIDS_PER_PIXEL_X 64 +#define SPH_OPTION_GRIDS_PER_PIXEL_Y 1 + + +/********** MOVE RULES *************/ + + /* allow a Direct_Move_X along freedom vector if 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 if 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 if 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 if 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 }, + }; + + /* indicate 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 if matched */ +#define SKIP_IUP_RULES_SIZE 1 + SPH_TweakRule SKIP_IUP_Rules + [SKIP_IUP_RULES_SIZE] = + { + { "-", 0, "", 0 }, + }; + + /* skip DELTAP instructions if 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 if 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 if 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 if 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 if matched */ +#define DELTAP_RDTG_RULES_SIZE 1 + SPH_TweakRule DELTAP_RDTG_Rules + [DELTAP_RDTG_RULES_SIZE] = + { + { "-", 0, "", 0 }, + }; + + /* return MS rasterizer version 35 if matched */ +#define RASTERIZER_35_RULES_SIZE 1 + SPH_TweakRule RASTERIZER_35_Rules + [RASTERIZER_35_RULES_SIZE] = + { + { "-", 0, "", 0 }, + }; + + +#endif /* 1 */ + + +#else /* TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS */ + + + /*************************************************************************/ + /* */ + /* 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 if */ + /* TT_CONFIG_OPTION_SUBPIXEL_HINTING_ADDITIONAL_TWEAKS */ + /* is defined */ + /* */ + /* ****************** WORK IN PROGRESS ******************* */ + /* */ + +#define SPH_OPTION_BITMAP_WIDTHS FALSE +#define SPH_OPTION_SET_SUBPIXEL TRUE +#define SPH_OPTION_SET_GRAYSCALE FALSE +#define SPH_OPTION_SET_COMPATIBLE_WIDTHS FALSE +#define SPH_OPTION_SET_RASTERIZER_VERSION 37 +#define SPH_OPTION_GRIDS_PER_PIXEL_X 64 +#define SPH_OPTION_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 if 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 line 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; */ + /* this 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 if 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 if 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 if 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 version 35 if 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 */ + /* (see above); it appears that 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 if 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 if 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 if 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 if 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 if 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 if 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 /* __TTSUBPIX_H__ */ + + +/* END */