diff -ru freetype-2.3.12.orig/include/freetype/config/ftoption.h freetype-2.3.12.new/include/freetype/config/ftoption.h --- freetype-2.3.12.orig/include/freetype/config/ftoption.h 2010-02-09 08:40:56.000000000 -0600 +++ freetype-2.3.12.new/include/freetype/config/ftoption.h 2010-04-16 20:02:38.000000000 -0500 @@ -93,7 +93,7 @@ /* This is done to allow FreeType clients to run unmodified, forcing */ /* them to display normal gray-level anti-aliased glyphs. */ /* */ -/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ +#define FT_CONFIG_OPTION_SUBPIXEL_RENDERING /*************************************************************************/ @@ -497,7 +497,7 @@ /* Do not #undef this macro here, since the build system might */ /* define it for certain configurations only. */ /* */ -/* #define TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ +#define TT_CONFIG_OPTION_BYTECODE_INTERPRETER /*************************************************************************/ diff -ru freetype-2.3.12.orig/include/freetype/freetype.h freetype-2.3.12.new/include/freetype/freetype.h --- freetype-2.3.12.orig/include/freetype/freetype.h 2010-02-13 00:55:07.000000000 -0600 +++ freetype-2.3.12.new/include/freetype/freetype.h 2010-04-24 18:57:36.000000000 -0500 @@ -2482,6 +2482,7 @@ #define FT_LOAD_MONOCHROME 0x1000 #define FT_LOAD_LINEAR_DESIGN 0x2000 #define FT_LOAD_NO_AUTOHINT 0x8000U +/*#define FT_LOAD_COMPATIBLE_WIDTHS 0x10000U*/ /* */ Only in freetype-2.3.12.new/include/freetype: freetype.h~ diff -ru freetype-2.3.12.orig/include/freetype/internal/ftobjs.h freetype-2.3.12.new/include/freetype/internal/ftobjs.h --- freetype-2.3.12.orig/include/freetype/internal/ftobjs.h 2009-07-03 08:28:24.000000000 -0500 +++ freetype-2.3.12.new/include/freetype/internal/ftobjs.h 2010-04-16 20:20:00.000000000 -0500 @@ -81,6 +81,13 @@ #define FT_PIX_ROUND( x ) FT_PIX_FLOOR( (x) + 32 ) #define FT_PIX_CEIL( x ) FT_PIX_FLOOR( (x) + 63 ) +#define FT_PIX_FLOOR_sph( x ) ( (x) & ~3 ) +#define FT_PIX_ROUND_sph( x ) FT_PIX_FLOOR_sph( (x) + 2 ) +#define FT_PIX_CEIL_sph( x ) FT_PIX_FLOOR_sph( (x) + 3 ) + +#define FT_PIX_FLOOR_sphn( x, n ) ( (x) & ~(64 / n - 1) ) +#define FT_PIX_ROUND_sphn( x, n ) FT_PIX_FLOOR_sph( (x) + 32 / n) +#define FT_PIX_CEIL_sphn( x, n ) FT_PIX_FLOOR_sph( (x) + 64 / n - 1) /* * Return the highest power of 2 that is <= value; this correspond to Only in freetype-2.3.12.new/src/base: ftsynth.c~ diff -ru freetype-2.3.12.orig/src/truetype/ttgload.c freetype-2.3.12.new/src/truetype/ttgload.c --- freetype-2.3.12.orig/src/truetype/ttgload.c 2010-02-09 23:38:53.000000000 -0600 +++ freetype-2.3.12.new/src/truetype/ttgload.c 2010-04-24 19:03:36.000000000 -0500 @@ -1606,7 +1606,6 @@ { FT_Pos advance = loader->linear; - /* the flag FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH was introduced to */ /* correctly support DynaLab fonts, which have an incorrect */ /* `advance_Width_Max' field! It is used, to my knowledge, */ @@ -1616,6 +1615,8 @@ ( loader->load_flags & FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ) == 0 ) advance = face->horizontal.advance_Width_Max; + + /* we need to return the advance in font units in linearHoriAdvance, */ /* it will be scaled later by the base layer. */ glyph->linearHoriAdvance = advance; @@ -1630,13 +1631,20 @@ IS_HINTED( loader->load_flags ) ) { FT_Byte* widthp; + FT_Bool subpixel; + FT_Bool compatible_widths; + subpixel = + FT_BOOL( FT_LOAD_TARGET_MODE( loader->load_flags ) != FT_RENDER_MODE_MONO ); + + compatible_widths = FALSE; + /*FT_BOOL( FT_LOAD_TARGET_MODE( loader->load_flags ) != FT_LOAD_COMPATIBLE_WIDTHS )*/ widthp = tt_face_get_device_metrics( face, size->root.metrics.x_ppem, glyph_index ); - if ( widthp ) + if ( !subpixel && widthp || compatible_widths ) glyph->metrics.horiAdvance = *widthp << 6; } @@ -1830,7 +1838,8 @@ { TT_ExecContext exec; FT_Bool grayscale; - + FT_Bool subpixel; + FT_Bool compatible_widths; if ( !size->cvt_ready ) { @@ -1848,10 +1857,31 @@ grayscale = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != FT_RENDER_MODE_MONO ); + subpixel = + FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != FT_RENDER_MODE_MONO ); + + compatible_widths = FALSE; + /*FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) != FT_LOAD_COMPATIBLE_WIDTHS)*/; + TT_Load_Context( exec, face, size ); /* a change from mono to grayscale rendering (and vice versa) */ /* requires a re-execution of the CVT program */ + if ( compatible_widths != exec->compatible_widths ) + { + FT_UInt i; + + + exec->compatible_widths = compatible_widths; + + 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 ) { FT_UInt i; @@ -1864,6 +1894,18 @@ tt_size_run_prep( size ); } + if ( subpixel != exec->subpixel ) + { + FT_UInt i; + + + exec->subpixel = subpixel; + + for ( i = 0; i < size->cvt_size; i++ ) + size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale ); + tt_size_run_prep( size ); + } + /* see whether the cvt program has disabled hinting */ if ( exec->GS.instruct_control & 1 ) load_flags |= FT_LOAD_NO_HINTING; Only in freetype-2.3.12.new/src/truetype: ttgload.c~ diff -ru freetype-2.3.12.orig/src/truetype/ttinterp.c freetype-2.3.12.new/src/truetype/ttinterp.c --- freetype-2.3.12.orig/src/truetype/ttinterp.c 2009-07-31 11:45:19.000000000 -0500 +++ freetype-2.3.12.new/src/truetype/ttinterp.c 2010-04-24 19:55:40.000000000 -0500 @@ -167,6 +167,9 @@ #define CUR_Func_round( d, c ) \ CUR.func_round( EXEC_ARG_ d, c ) +#define CUR_Func_round_sphn( d, c ) \ + CUR.func_round_sphn( EXEC_ARG_ d, c ) + #define CUR_Func_read_cvt( index ) \ CUR.func_read_cvt( EXEC_ARG_ index ) @@ -1554,7 +1557,7 @@ #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING FT_ASSERT( !CUR.face->unpatented_hinting ); #endif - +if (CUR.skip_x == 0){ v = CUR.GS.freeVector.x; if ( v != 0 ) @@ -1565,7 +1568,8 @@ zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; } - +} +if (CUR.skip_y == 0){ v = CUR.GS.freeVector.y; if ( v != 0 ) @@ -1577,6 +1581,7 @@ zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y; } } + } /*************************************************************************/ @@ -1607,14 +1612,15 @@ #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING FT_ASSERT( !CUR.face->unpatented_hinting ); #endif - +if (CUR.skip_x == 0){ v = CUR.GS.freeVector.x; if ( v != 0 ) zone->org[point].x += TT_MULDIV( distance, v * 0x10000L, CUR.F_dot_P ); - +} +if (CUR.skip_y==0){ v = CUR.GS.freeVector.y; if ( v != 0 ) @@ -1622,7 +1628,7 @@ v * 0x10000L, CUR.F_dot_P ); } - + } /*************************************************************************/ /* */ @@ -1640,9 +1646,10 @@ FT_F26Dot6 distance ) { FT_UNUSED_EXEC; - +if (CUR.skip_x == 0){ zone->cur[point].x += distance; zone->tags[point] |= FT_CURVE_TAG_TOUCH_X; +} } @@ -1652,11 +1659,11 @@ FT_F26Dot6 distance ) { FT_UNUSED_EXEC; - +if (CUR.skip_y ==0){ zone->cur[point].y += distance; zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y; } - + } /*************************************************************************/ /* */ @@ -1674,8 +1681,9 @@ FT_F26Dot6 distance ) { FT_UNUSED_EXEC; - +if (CUR.skip_x == 0){ zone->org[point].x += distance; +} } @@ -1685,9 +1693,10 @@ FT_F26Dot6 distance ) { FT_UNUSED_EXEC; - +if (CUR.skip_y == 0){ zone->org[point].y += distance; } + } /*************************************************************************/ @@ -1780,6 +1789,32 @@ } + static FT_F26Dot6 + Round_To_Grid_sphn( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + + FT_UNUSED_EXEC; + + if ( distance >= 0 ) + { + val = distance + compensation + 32 / CUR.grid_factor; + if ( distance && val > 0 ) + val &= ~(64 / CUR.grid_factor - 1); + else + val = 0; + } + else + { + val = -FT_PIX_ROUND_sphn( compensation - distance, CUR.grid_factor ); + if ( val > 0 ) + val = 0; + } + return val; + } + + /*************************************************************************/ /* */ /* */ @@ -1822,6 +1857,32 @@ } + static FT_F26Dot6 + Round_To_Half_Grid_sphn( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + + FT_UNUSED_EXEC; + + if ( distance >= 0 ) + { + val = FT_PIX_FLOOR_sphn( distance + compensation, CUR.grid_factor ) + + 32 / CUR.grid_factor; + if ( distance && val < 0 ) + val = 0; + } + else + { + val = -( FT_PIX_FLOOR_sphn( compensation - distance, CUR.grid_factor ) + + 32 / CUR.grid_factor); + if ( val > 0 ) + val = 0; + } + + return val; + } + /*************************************************************************/ /* */ /* */ @@ -1865,6 +1926,31 @@ return val; } + static FT_F26Dot6 + Round_Down_To_Grid_sphn( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + + FT_UNUSED_EXEC; + + if ( distance >= 0 ) + { + val = distance + compensation; + if ( distance && val > 0 ) + val &= ~(64 / CUR.grid_factor - 1); + else + val = 0; + } + else + { + val = -( ( compensation - distance ) & -(64 / CUR.grid_factor) ); + if ( val > 0 ) + val = 0; + } + + return val; + } /*************************************************************************/ /* */ @@ -1910,6 +1996,33 @@ } + + static FT_F26Dot6 + Round_Up_To_Grid_sphn( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + + FT_UNUSED_EXEC; + + if ( distance >= 0 ) + { + val = distance + compensation + (64 / CUR.grid_factor - 1); + if ( distance && val > 0 ) + val &= ~(64 / CUR.grid_factor - 1); + else + val = 0; + } + else + { + val = - FT_PIX_CEIL_sphn( compensation - distance, CUR.grid_factor ); + if ( val > 0 ) + val = 0; + } + + return val; + } + /*************************************************************************/ /* */ /* */ @@ -1954,6 +2067,32 @@ } + + static FT_F26Dot6 + Round_To_Double_Grid_sphn( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + FT_F26Dot6 val; + + FT_UNUSED_EXEC; + + if ( distance >= 0 ) + { + val = distance + compensation + 16 / CUR.grid_factor; + if ( distance && val > 0 ) + val &= ~(32 / CUR.grid_factor - 1); + else + val = 0; + } + else + { + val = -FT_PAD_ROUND( compensation - distance, 32 / CUR.grid_factor ); + if ( val > 0 ) + val = 0; + } + + return val; + } /*************************************************************************/ /* */ /* */ @@ -2004,6 +2143,14 @@ } + + static FT_F26Dot6 + Round_Super_sphn( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + return distance; + } + /*************************************************************************/ /* */ /* */ @@ -2052,6 +2199,15 @@ } + + static FT_F26Dot6 + Round_Super_45_sphn( EXEC_OP_ FT_F26Dot6 distance, + FT_F26Dot6 compensation ) + { + + return distance; + } + /*************************************************************************/ /* */ /* */ @@ -2074,30 +2230,37 @@ case TT_Round_To_Grid: CUR.func_round = (TT_Round_Func)Round_To_Grid; + CUR.func_round_sphn = (TT_Round_Func)Round_To_Grid_sphn; break; case TT_Round_Up_To_Grid: CUR.func_round = (TT_Round_Func)Round_Up_To_Grid; + CUR.func_round_sphn = (TT_Round_Func)Round_Up_To_Grid_sphn; break; case TT_Round_Down_To_Grid: CUR.func_round = (TT_Round_Func)Round_Down_To_Grid; + CUR.func_round_sphn = (TT_Round_Func)Round_Down_To_Grid_sphn; break; case TT_Round_To_Half_Grid: CUR.func_round = (TT_Round_Func)Round_To_Half_Grid; + CUR.func_round_sphn = (TT_Round_Func)Round_To_Half_Grid_sphn; break; case TT_Round_To_Double_Grid: CUR.func_round = (TT_Round_Func)Round_To_Double_Grid; + CUR.func_round_sphn = (TT_Round_Func)Round_To_Double_Grid_sphn; break; case TT_Round_Super: CUR.func_round = (TT_Round_Func)Round_Super; + CUR.func_round_sphn = (TT_Round_Func)Round_Super_sphn; break; case TT_Round_Super_45: CUR.func_round = (TT_Round_Func)Round_Super_45; + CUR.func_round_sphn = (TT_Round_Func)Round_Super_45_sphn; break; } } @@ -2748,44 +2911,52 @@ #define DO_RTHG \ CUR.GS.round_state = TT_Round_To_Half_Grid; \ - CUR.func_round = (TT_Round_Func)Round_To_Half_Grid; + CUR.func_round = (TT_Round_Func)Round_To_Half_Grid; \ + CUR.func_round_sphn = (TT_Round_Func)Round_To_Half_Grid_sphn; #define DO_RTG \ CUR.GS.round_state = TT_Round_To_Grid; \ - CUR.func_round = (TT_Round_Func)Round_To_Grid; + CUR.func_round = (TT_Round_Func)Round_To_Grid; \ + CUR.func_round_sphn = (TT_Round_Func)Round_To_Grid_sphn; #define DO_RTDG \ CUR.GS.round_state = TT_Round_To_Double_Grid; \ - CUR.func_round = (TT_Round_Func)Round_To_Double_Grid; + CUR.func_round = (TT_Round_Func)Round_To_Double_Grid; \ + CUR.func_round_sphn = (TT_Round_Func)Round_To_Double_Grid_sphn; #define DO_RUTG \ CUR.GS.round_state = TT_Round_Up_To_Grid; \ - CUR.func_round = (TT_Round_Func)Round_Up_To_Grid; + CUR.func_round = (TT_Round_Func)Round_Up_To_Grid; \ + CUR.func_round_sphn = (TT_Round_Func)Round_Up_To_Grid_sphn; #define DO_RDTG \ CUR.GS.round_state = TT_Round_Down_To_Grid; \ - CUR.func_round = (TT_Round_Func)Round_Down_To_Grid; + CUR.func_round = (TT_Round_Func)Round_Down_To_Grid; \ + CUR.func_round_sphn = (TT_Round_Func)Round_Down_To_Grid_sphn; #define DO_ROFF \ CUR.GS.round_state = TT_Round_Off; \ - CUR.func_round = (TT_Round_Func)Round_None; + CUR.func_round = (TT_Round_Func)Round_None; \ + CUR.func_round_sphn = (TT_Round_Func)Round_None; #define DO_SROUND \ SET_SuperRound( 0x4000, args[0] ); \ CUR.GS.round_state = TT_Round_Super; \ - CUR.func_round = (TT_Round_Func)Round_Super; + CUR.func_round = (TT_Round_Func)Round_Super; \ + CUR.func_round_sphn = (TT_Round_Func)Round_Super_sphn; #define DO_S45ROUND \ SET_SuperRound( 0x2D41, args[0] ); \ CUR.GS.round_state = TT_Round_Super_45; \ - CUR.func_round = (TT_Round_Func)Round_Super_45; + CUR.func_round = (TT_Round_Func)Round_Super_45; \ + CUR.func_round_sphn = (TT_Round_Func)Round_Super_45_sphn; #define DO_SLOOP \ @@ -3007,7 +3178,9 @@ args[0] = 0; \ } \ else \ - args[0] = CUR.storage[I]; \ + /* Subpixel Hinting- Typeman Dstroke and Istroke, Vacuform Rounds */ \ + if (CUR.subpixel && (I == 24 || I == 22 || I == 8)) args[0] = 0; \ + else args[0] = CUR.storage[I]; \ } @@ -4864,6 +5037,9 @@ } } + /* Subpixel Hinting - Type 2 Vacuform Rounds - Arial Narrow */ + if (CUR.subpixel && FT_ABS(D) == 64) D += 1; + args[0] = D; } @@ -5343,14 +5519,15 @@ return; } #endif - +if (CUR.skip_x == 0){ if ( CUR.GS.freeVector.x != 0 ) { CUR.zp2.cur[point].x += dx; if ( touch ) CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X; } - +} +if (CUR.skip_y == 0){ if ( CUR.GS.freeVector.y != 0 ) { CUR.zp2.cur[point].y += dy; @@ -5358,7 +5535,7 @@ CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y; } } - + } /*************************************************************************/ /* */ @@ -5573,7 +5750,18 @@ } } else - MOVE_Zp2_Point( point, dx, dy, TRUE ); + { + /* If freedom vector is Y, and point is touched, continue */ + if ( CUR.subpixel && CUR.GS.freeVector.y != 0 && CUR.iup_called == 0 + && ( ( CUR.pts.tags[point] & FT_CURVE_TAG_TOUCH_X ) != 0 + || ( CUR.pts.tags[point] & FT_CURVE_TAG_TOUCH_Y ) != 0 ) + ){ + MOVE_Zp2_Point( point, dx, dy, TRUE ); } + + else if ( !CUR.subpixel || CUR.is_composite ) + MOVE_Zp2_Point( point, dx, dy, TRUE ); + + } CUR.GS.loop--; } @@ -5618,6 +5806,15 @@ distance = CUR_Func_project( CUR.zp1.cur + point, CUR.zp0.cur + CUR.GS.rp0 ); + /* Subpixel Hinting - make MSIRP respect CVT cutin */ + /* Fixes "k" issue with Arial */ + /* Using 0 instead of CUR.GS.control_value_cutin/grid_factor */ + /* fixes Helvetica Neue */ + if (CUR.subpixel && CUR.GS.freeVector.x != 0 + && FT_ABS(distance - args[1]) >= 0 ) + distance = args[1]; + + CUR_Func_move( &CUR.zp1, point, args[1] - distance ); CUR.GS.rp1 = CUR.GS.rp0; @@ -5656,8 +5853,11 @@ if ( ( CUR.opcode & 1 ) != 0 ) { cur_dist = CUR_fast_project( &CUR.zp0.cur[point] ); - distance = CUR_Func_round( cur_dist, + if (!CUR.subpixel || CUR.GS.freeVector.x == 0) + distance = CUR_Func_round( cur_dist, CUR.tt_metrics.compensations[0] ) - cur_dist; + else distance = CUR_Func_round_sphn( cur_dist, + CUR.tt_metrics.compensations[0] ) - cur_dist; } else distance = 0; @@ -5730,10 +5930,20 @@ 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 ( !CUR.subpixel || CUR.GS.freeVector.x == 0 ) + { + if ( FT_ABS( distance - org_dist ) > CUR.GS.control_value_cutin) + distance = org_dist; + distance = CUR_Func_round( distance, CUR.tt_metrics.compensations[0] ); + } + else + { + if ( FT_ABS( distance - org_dist ) + > CUR.GS.control_value_cutin / CUR.grid_factor) + distance = org_dist; + distance = CUR_Func_round_sphn( distance, CUR.tt_metrics.compensations[0] ); + } } CUR_Func_move( &CUR.zp0, point, distance - org_dist ); @@ -5817,9 +6027,15 @@ /* round flag */ if ( ( CUR.opcode & 4 ) != 0 ) - distance = CUR_Func_round( + { + if ( !CUR.subpixel || CUR.GS.freeVector.x == 0 ) + distance = CUR_Func_round( org_dist, CUR.tt_metrics.compensations[CUR.opcode & 3] ); + else distance = CUR_Func_round_sphn( + org_dist, + CUR.tt_metrics.compensations[CUR.opcode & 3] ); + } else distance = ROUND_None( org_dist, @@ -5827,17 +6043,36 @@ /* minimum distance flag */ - if ( ( CUR.opcode & 8 ) != 0 ) - { - if ( org_dist >= 0 ) + /* Use 2/3 in x direction. Better results than documented 1/2 */ + if (CUR.GS.freeVector.x != 0 && CUR.subpixel ){ + if ( ( CUR.opcode & 8 ) != 0 ) { - if ( distance < CUR.GS.minimum_distance ) - distance = CUR.GS.minimum_distance; + if ( org_dist >= 0 ) + { + if ( distance < 2*CUR.GS.minimum_distance/3 ) + distance = 2*CUR.GS.minimum_distance/3; + } + else + { + if ( distance > -CUR.GS.minimum_distance/2 ) + distance = -CUR.GS.minimum_distance/2; + } } - else + } + else + { + if ( ( CUR.opcode & 8 ) != 0 ) { - if ( distance > -CUR.GS.minimum_distance ) - distance = -CUR.GS.minimum_distance; + if ( org_dist >= 0 ) + { + if ( distance < CUR.GS.minimum_distance ) + distance = CUR.GS.minimum_distance; + } + else + { + if ( distance > -CUR.GS.minimum_distance ) + distance = -CUR.GS.minimum_distance; + } } } @@ -5873,7 +6108,8 @@ cur_dist, org_dist; - + FT_Byte orig_round_state; + point = (FT_UShort)args[0]; cvtEntry = (FT_ULong)( args[1] + 1 ); @@ -5934,42 +6170,84 @@ /* control value cutin and round */ - if ( ( CUR.opcode & 4 ) != 0 ) + if ( !CUR.subpixel && ( CUR.opcode & 4 ) != 0 || CUR.subpixel ) { /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */ /* refer to the same zone. */ - if ( CUR.GS.gep0 == CUR.GS.gep1 ) - if ( FT_ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin ) - cvt_dist = org_dist; + if ( !CUR.subpixel && CUR.GS.gep0 == CUR.GS.gep1 || CUR.subpixel ) + if (CUR.subpixel && CUR.GS.freeVector.x == 0 || !CUR.subpixel ) + { + if ( FT_ABS(cvt_dist - org_dist) >= CUR.GS.control_value_cutin ) + cvt_dist = org_dist; + + distance = CUR_Func_round( + cvt_dist, + CUR.tt_metrics.compensations[CUR.opcode & 3] ); + } - distance = CUR_Func_round( + else if (CUR.subpixel) + { + if ( FT_ABS(cvt_dist - org_dist) + >= CUR.GS.control_value_cutin / CUR.grid_factor ) + cvt_dist = org_dist; + + distance = CUR_Func_round_sphn( + cvt_dist, + CUR.tt_metrics.compensations[CUR.opcode & 3] ); + } + + /* This fixes subpixel hinting italics (Verdana) but may be hacky */ + else + distance = ROUND_None( cvt_dist, CUR.tt_metrics.compensations[CUR.opcode & 3] ); + } - else + else if (!CUR.subpixel){ distance = ROUND_None( cvt_dist, CUR.tt_metrics.compensations[CUR.opcode & 3] ); + } /* minimum distance test */ - - if ( ( CUR.opcode & 8 ) != 0 ) + if (CUR.GS.freeVector.x != 0 && CUR.subpixel) { - if ( org_dist >= 0 ) + if ( ( CUR.opcode & 8 ) != 0 ) { - if ( distance < CUR.GS.minimum_distance ) - distance = CUR.GS.minimum_distance; + if ( org_dist >= 0 ) + { + if ( distance < 2 * CUR.GS.minimum_distance / 3 ) + distance = 2 * CUR.GS.minimum_distance / 3; + } + else + { + if ( distance > -2 * CUR.GS.minimum_distance / 3 ) + distance = -2 * CUR.GS.minimum_distance / 3; + } + } - else + } + else + { + if ( ( CUR.opcode & 8 ) != 0 ) { - if ( distance > -CUR.GS.minimum_distance ) - distance = -CUR.GS.minimum_distance; + if ( org_dist >= 0 ) + { + if ( distance < CUR.GS.minimum_distance ) + distance = CUR.GS.minimum_distance; + } + else + { + if ( distance > -CUR.GS.minimum_distance ) + distance = -CUR.GS.minimum_distance; + } } - } - CUR_Func_move( &CUR.zp1, point, distance - cur_dist ); + } + CUR_Func_move( &CUR.zp1, point, distance - cur_dist ); + CUR.GS.rp1 = CUR.GS.rp0; if ( ( CUR.opcode & 16 ) != 0 ) @@ -6437,7 +6715,8 @@ FT_UNUSED_ARG; - + CUR.iup_called = 1; + /* ignore empty outlines */ if ( CUR.pts.n_contours == 0 ) return; @@ -6531,7 +6810,7 @@ FT_UShort A; FT_ULong C; FT_Long B; - + FT_Byte orig_round_state; #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING /* Delta hinting is covered by US Patent 5159668. */ @@ -6601,7 +6880,28 @@ B++; B = B * 64 / ( 1L << CUR.GS.delta_shift ); - CUR_Func_move( &CUR.zp0, A, B ); + if (CUR.GS.freeVector.y != 0 && CUR.subpixel ) + { + orig_round_state= CUR.GS.round_state; + + COMPUTE_Round( TT_Round_Down_To_Grid ); + + /* This dirty hack fixes subpixel y-artifacts in trebuchet, */ + /* verdana bold, ms sans serif, due to bi-level deltas in y */ + /* direction, but breaks some glyphs (trebuchet e) */ + B = CUR_Func_round( B, CUR.tt_metrics.compensations[0] ); + + COMPUTE_Round( orig_round_state ); + } + + if ( CUR.subpixel && CUR.GS.freeVector.y != 0 && CUR.iup_called == 0 + && (( CUR.pts.tags[A] & FT_CURVE_TAG_TOUCH_X ) != 0 + || ( CUR.pts.tags[A] & FT_CURVE_TAG_TOUCH_Y ) != 0 ) + ){ + CUR_Func_move(&CUR.zp0, A, B); } + else if ( !CUR.subpixel || CUR.is_composite ) + CUR_Func_move(&CUR.zp0, A, B); + } } else @@ -6726,9 +7026,9 @@ K = 0; - /* We return MS rasterizer version 1.7 for the font scaler. */ + /* We return MS rasterizer version 1.8 for the font scaler. */ if ( ( args[0] & 1 ) != 0 ) - K = 35; + K = 37; /* Has the glyph been rotated? */ if ( ( args[0] & 2 ) != 0 && CUR.tt_metrics.rotated ) @@ -6742,6 +7042,27 @@ if ( ( args[0] & 32 ) != 0 && CUR.grayscale ) K |= 1 << 12; + /* Are we hinting for subpixel? */ + if ( ( args[0] & 64 ) != 0 && CUR.subpixel ) + K |= 1 << 13; + + /* Are we hinting for compatible_widths? */ + if ( ( args[0] & 128 ) != 0 && CUR.compatible_widths ){ + K |= 1 << 14; + CUR.skip_x = 0; + } + else CUR.skip_x = 1; + CUR.skip_y = 0; + + /* Are we hinting for symmetrical_smoothing? */ + /*if ( ( args[0] & 256 ) != 0 && CUR.symmetrical_smoothing )*/ + /* Forcibly setting to 0 fixes PALATINO */ + K |= 0 << 15; + + /* Are we hinting for bgr? */ + if ( ( args[0] & 512 ) != 0 && CUR.bgr ) + K |= 1 << 16; + args[0] = K; } @@ -7115,7 +7436,14 @@ #ifdef TT_CONFIG_OPTION_STATIC_RASTER cur = *exc; #endif + if (CUR.subpixel) + /* 1/32 of a pixel in y direction */ + CUR.grid_factor = 32; + else + CUR.grid_factor = 1; + CUR.iup_called = 0; + /* set CVT functions */ CUR.tt_metrics.ratio = 0; if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem ) Only in freetype-2.3.12.new/src/truetype: ttinterp.c~ diff -ru freetype-2.3.12.orig/src/truetype/ttinterp.h freetype-2.3.12.new/src/truetype/ttinterp.h --- freetype-2.3.12.orig/src/truetype/ttinterp.h 2009-03-14 08:45:26.000000000 -0500 +++ freetype-2.3.12.new/src/truetype/ttinterp.h 2010-04-24 19:54:01.000000000 -0500 @@ -203,6 +203,7 @@ FT_Long F_dot_P; /* dot product of freedom and projection */ /* vectors */ TT_Round_Func func_round; /* current rounding function */ + TT_Round_Func func_round_sphn; /* subpixel rounding fuction */ TT_Project_Func func_project, /* current projection function */ func_dualproj, /* current dual proj. function */ @@ -215,7 +216,16 @@ 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? */ + FT_Bool subpixel; /* are we hinting for subpixel? */ + 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_Bool grid_factor; /* freedom vector resol (1 < 32) */ + FT_Bool iup_called; /* IUP[] been called for this glyph? */ + FT_Bool skip_x; /* Skip all x moves? */ + FT_Bool skip_y; /* Skip all y moves? */ } TT_ExecContextRec; Only in freetype-2.3.12.new/src/truetype: ttinterp.h~