diff options
-rw-r--r-- | ChangeLog | 18 | ||||
-rw-r--r-- | include/freetype/config/ftoption.h | 12 | ||||
-rw-r--r-- | include/freetype/internal/ftcalc.h | 153 | ||||
-rw-r--r-- | src/base/ftcalc.c | 160 | ||||
-rw-r--r-- | src/base/fttrigon.c | 6 | ||||
-rw-r--r-- | src/truetype/ttinterp.c | 259 |
6 files changed, 204 insertions, 404 deletions
@@ -1,3 +1,21 @@ +2002-03-25 David Turner <david@freetype.org> + + * src/base/fttrigon.c, src/truetype/ttinterp.c: fixing the TrueType + bytecode interpreter to compute the same values than FreeType 1. + + The difference came from distinct algorithm for computing the + dot product and vector lengths. It seems that TT bytecode + interpretation is _extremely_ sensitive to rounding 'errors' + of fixed-point arithmetic.. + + * include/freetype/config/ftoption.h, + include/freetype/internal/ftcalc.h, + src/base/ftcalc.c: + + gettting rid of the now obsolete FT_CONFIG_OPTION_OLD_CALCS + macro + + 2002-03-15 Werner Lemberg <wl@gnu.org> * builds/win32/visualc/{freetype.dsp,index.html}: Update to 2.0.9. diff --git a/include/freetype/config/ftoption.h b/include/freetype/config/ftoption.h index 506663b2e..6f0c5b4be 100644 --- a/include/freetype/config/ftoption.h +++ b/include/freetype/config/ftoption.h @@ -270,16 +270,6 @@ FT_BEGIN_HEADER /*************************************************************************/ /* */ - /* Computation Algorithms */ - /* */ - /* Used for debugging, this configuration macro should disappear */ - /* soon. */ - /* */ -#undef FT_CONFIG_OPTION_OLD_CALCS - - - /*************************************************************************/ - /* */ /* The size in bytes of the render pool used by the scan-line converter */ /* to do all of its work. */ /* */ @@ -375,7 +365,7 @@ FT_BEGIN_HEADER /* By undefining this, you will only compile the code necessary to load */ /* TrueType glyphs without hinting. */ /* */ -#undef TT_CONFIG_OPTION_BYTECODE_INTERPRETER +#define TT_CONFIG_OPTION_BYTECODE_INTERPRETER /*************************************************************************/ diff --git a/include/freetype/internal/ftcalc.h b/include/freetype/internal/ftcalc.h index 4cdf40fb1..f03f5962f 100644 --- a/include/freetype/internal/ftcalc.h +++ b/include/freetype/internal/ftcalc.h @@ -29,161 +29,10 @@ FT_BEGIN_HEADER /* OLD 64-bits internal API */ -#ifdef FT_CONFIG_OPTION_OLD_CALCS - -#ifdef FT_LONG64 - - typedef FT_INT64 FT_Int64; - -#define ADD_64( x, y, z ) z = (x) + (y) -#define MUL_64( x, y, z ) z = (FT_Int64)(x) * (y) -#define DIV_64( x, y ) ( (x) / (y) ) - -#define SQRT_64( z ) FT_Sqrt64( z ) - - - /*************************************************************************/ - /* */ - /* <Function> */ - /* FT_Sqrt64 */ - /* */ - /* <Description> */ - /* Computes the square root of a 64-bit value. That sounds stupid, */ - /* but it is needed to obtain maximal accuracy in the TrueType */ - /* bytecode interpreter. */ - /* */ - /* <Input> */ - /* l :: A 64-bit integer. */ - /* */ - /* <Return> */ - /* The 32-bit square-root. */ - /* */ - FT_EXPORT( FT_Int32 ) - FT_Sqrt64( FT_Int64 l ); - - -#else /* !FT_LONG64 */ - - - typedef struct FT_Int64_ - { - FT_UInt32 lo; - FT_UInt32 hi; - - } FT_Int64; - - -#define ADD_64( x, y, z ) FT_Add64( &x, &y, &z ) -#define MUL_64( x, y, z ) FT_MulTo64( x, y, &z ) -#define DIV_64( x, y ) FT_Div64by32( &x, y ) - - - /*************************************************************************/ - /* */ - /* <Function> */ - /* FT_Add64 */ - /* */ - /* <Description> */ - /* Add two Int64 values. */ - /* */ - /* <Input> */ - /* x :: A pointer to the first value to be added. */ - /* y :: A pointer to the second value to be added. */ - /* */ - /* <Output> */ - /* z :: A pointer to the result of `x + y'. */ - /* */ - /* <Note> */ - /* Will be wrapped by the ADD_64() macro. */ - /* */ - FT_EXPORT( void ) - FT_Add64( FT_Int64* x, - FT_Int64* y, - FT_Int64 *z ); - - - /*************************************************************************/ - /* */ - /* <Function> */ - /* FT_MulTo64 */ - /* */ - /* <Description> */ - /* Multiplies two Int32 integers. Returns an Int64 integer. */ - /* */ - /* <Input> */ - /* x :: The first multiplier. */ - /* y :: The second multiplier. */ - /* */ - /* <Output> */ - /* z :: A pointer to the result of `x * y'. */ - /* */ - /* <Note> */ - /* Will be wrapped by the MUL_64() macro. */ - /* */ - FT_EXPORT( void ) - FT_MulTo64( FT_Int32 x, - FT_Int32 y, - FT_Int64 *z ); - - - /*************************************************************************/ - /* */ - /* <Function> */ - /* FT_Div64by32 */ - /* */ - /* <Description> */ - /* Divides an Int64 value by an Int32 value. Returns an Int32 */ - /* integer. */ - /* */ - /* <Input> */ - /* x :: A pointer to the dividend. */ - /* y :: The divisor. */ - /* */ - /* <Return> */ - /* The result of `x / y'. */ - /* */ - /* <Note> */ - /* Will be wrapped by the DIV_64() macro. */ - /* */ - FT_EXPORT( FT_Int32 ) - FT_Div64by32( FT_Int64* x, - FT_Int32 y ); - - -#define SQRT_64( z ) FT_Sqrt64( &z ) - - - /*************************************************************************/ - /* */ - /* <Function> */ - /* FT_Sqrt64 */ - /* */ - /* <Description> */ - /* Computes the square root of a 64-bits value. That sounds stupid, */ - /* but it is needed to obtain maximal accuracy in the TrueType */ - /* bytecode interpreter. */ - /* */ - /* <Input> */ - /* z :: A pointer to a 64-bit integer. */ - /* */ - /* <Return> */ - /* The 32-bit square-root. */ - /* */ - FT_EXPORT( FT_Int32 ) - FT_Sqrt64( FT_Int64* x ); - - -#endif /* !FT_LONG64 */ - -#endif /* FT_CONFIG_OPTION_OLD_CALCS */ - - FT_EXPORT( FT_Int32 ) FT_SqrtFixed( FT_Int32 x ); -#ifndef FT_CONFIG_OPTION_OLD_CALCS - #define SQRT_32( x ) FT_Sqrt32( x ) @@ -206,8 +55,6 @@ FT_BEGIN_HEADER FT_Sqrt32( FT_Int32 x ); -#endif /* !FT_CONFIG_OPTION_OLD_CALCS */ - /*************************************************************************/ /* */ diff --git a/src/base/ftcalc.c b/src/base/ftcalc.c index 8f024673b..f4e349df1 100644 --- a/src/base/ftcalc.c +++ b/src/base/ftcalc.c @@ -39,13 +39,12 @@ /* we need to define a 64-bits data type here */ -#ifndef FT_CONFIG_OPTION_OLD_CALCS #ifdef FT_LONG64 typedef FT_INT64 FT_Int64; -#else +#else /* !FT_LONG64 */ typedef struct FT_Int64_ { @@ -54,9 +53,8 @@ } FT_Int64; -#endif /* FT_LONG64 */ +#endif /* !FT_LONG64 */ -#endif /* !FT_CONFIG_OPTION_OLD_CALCS */ /*************************************************************************/ @@ -102,27 +100,6 @@ } -#ifdef FT_CONFIG_OPTION_OLD_CALCS - - static const FT_Long ft_square_roots[63] = - { - 1L, 1L, 2L, 3L, 4L, 5L, 8L, 11L, - 16L, 22L, 32L, 45L, 64L, 90L, 128L, 181L, - 256L, 362L, 512L, 724L, 1024L, 1448L, 2048L, 2896L, - 4096L, 5892L, 8192L, 11585L, 16384L, 23170L, 32768L, 46340L, - - 65536L, 92681L, 131072L, 185363L, 262144L, 370727L, - 524288L, 741455L, 1048576L, 1482910L, 2097152L, 2965820L, - 4194304L, 5931641L, 8388608L, 11863283L, 16777216L, 23726566L, - - 33554432L, 47453132L, 67108864L, 94906265L, - 134217728L, 189812531L, 268435456L, 379625062L, - 536870912L, 759250125L, 1073741824L, 1518500250L, - 2147483647L - }; - -#else - /* documentation is in ftcalc.h */ FT_EXPORT_DEF( FT_Int32 ) @@ -152,7 +129,6 @@ return root; } -#endif /* FT_CONFIG_OPTION_OLD_CALCS */ #ifdef FT_LONG64 @@ -222,52 +198,7 @@ } -#ifdef FT_CONFIG_OPTION_OLD_CALCS - - /* a helper function for FT_Sqrt64() */ - - static int - ft_order64( FT_Int64 z ) - { - int j = 0; - - - while ( z ) - { - z = (unsigned FT_INT64)z >> 1; - j++; - } - return j - 1; - } - - - /* documentation is in ftcalc.h */ - - FT_EXPORT_DEF( FT_Int32 ) - FT_Sqrt64( FT_Int64 l ) - { - FT_Int64 r, s; - - - if ( l <= 0 ) return 0; - if ( l == 1 ) return 1; - - r = ft_square_roots[ft_order64( l )]; - - do - { - s = r; - r = ( r + l / r ) >> 1; - - } while ( r > s || r * r > l ); - - return (FT_Int32)r; - } - -#endif /* FT_CONFIG_OPTION_OLD_CALCS */ - - -#else /* FT_LONG64 */ +#else /* !FT_LONG64 */ static void @@ -550,7 +481,7 @@ return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q ); } -#else +#else /* 0 */ FT_EXPORT_DEF( FT_Int32 ) FT_Div64by32( FT_Int64* x, FT_Int32 y ) @@ -582,89 +513,10 @@ return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q ); } -#endif - - -#ifdef FT_CONFIG_OPTION_OLD_CALCS - - - /* two helper functions for FT_Sqrt64() */ - - static void - FT_Sub64( FT_Int64* x, - FT_Int64* y, - FT_Int64* z ) - { - register FT_UInt32 lo, hi; - - - lo = x->lo - y->lo; - hi = x->hi - y->hi - ( (FT_Int32)lo < 0 ); - - z->lo = lo; - z->hi = hi; - } - - - static int - ft_order64( FT_Int64* z ) - { - FT_UInt32 i; - int j; - - - i = z->lo; - j = 0; - if ( z->hi ) - { - i = z->hi; - j = 32; - } - - while ( i > 0 ) - { - i >>= 1; - j++; - } - return j - 1; - } - - - /* documentation is in ftcalc.h */ - - FT_EXPORT_DEF( FT_Int32 ) - FT_Sqrt64( FT_Int64* l ) - { - FT_Int64 l2; - FT_Int32 r, s; - - - if ( (FT_Int32)l->hi < 0 || - ( l->hi == 0 && l->lo == 0 ) ) - return 0; - - s = ft_order64( l ); - if ( s == 0 ) - return 1; - - r = ft_square_roots[s]; - do - { - s = r; - r = ( r + FT_Div64by32( l, r ) ) >> 1; - FT_MulTo64( r, r, &l2 ); - FT_Sub64 ( l, &l2, &l2 ); - - } while ( r > s || (FT_Int32)l2.hi < 0 ); - - return r; - } - - -#endif /* FT_CONFIG_OPTION_OLD_CALCS */ +#endif /* 0 */ -#endif /* FT_LONG64 */ +#endif /* !FT_LONG64 */ /* a not-so-fast but working 16.16 fixed point square root function */ diff --git a/src/base/fttrigon.c b/src/base/fttrigon.c index 8a2778b69..e647b0d06 100644 --- a/src/base/fttrigon.c +++ b/src/base/fttrigon.c @@ -417,7 +417,11 @@ ft_trig_pseudo_polarize( &v ); v.x = ft_trig_downscale( v.x ); - return ( shift >= 0 ) ? ( v.x >> shift ) : ( v.x << -shift ); + + if ( shift > 0 ) + return ( v.x + (1 << (shift-1)) ) >> shift; + + return v.x << -shift; } diff --git a/src/truetype/ttinterp.c b/src/truetype/ttinterp.c index 9748e9a4e..e3223b5fd 100644 --- a/src/truetype/ttinterp.c +++ b/src/truetype/ttinterp.c @@ -27,6 +27,8 @@ #include "tterrors.h" + + #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER @@ -825,38 +827,6 @@ } - /* return length of given vector */ -#ifdef FT_CONFIG_OPTION_OLD_CALCS - - static FT_F26Dot6 - Norm( FT_F26Dot6 X, - FT_F26Dot6 Y ) - { - TT_INT64 T1, T2; - - - MUL_64( X, X, T1 ); - MUL_64( Y, Y, T2 ); - - ADD_64( T1, T2, T1 ); - - return (FT_F26Dot6)SQRT_64( T1 ); - } - -#else /* !FT_CONFIG_OPTION_OLD_CALCS */ - - static FT_F26Dot6 - Norm( FT_F26Dot6 X, - FT_F26Dot6 Y ) - { - FT_Vector v; - - v.x = X; - v.y = Y; - return FT_Vector_Length( &v ); - } - -#endif /* FT_CONFIG_OPTION_OLD_CALCS */ /*************************************************************************/ @@ -1200,6 +1170,153 @@ #undef NULL_Vector #define NULL_Vector (FT_Vector*)&Null_Vector + + /* compute (a*b)/2^14 with maximal accuracy and rounding */ + static FT_Int32 + TT_MulFix14( FT_Int32 a, FT_Int b ) + { + FT_Int32 m, s, hi; + FT_UInt32 l, lo; + + /* compute ax*bx as 64-bit value */ + l = (FT_UInt32)( (a & 0xFFFF)*b ); + m = (a >> 16)*b; + + lo = l + (FT_UInt32)(m << 16); + hi = (m >> 16) + ((FT_Int32)l >> 31) + (lo < l); + + /* divide the result by 2^14 with rounding */ + s = (hi >> 31); + l = lo + (FT_UInt32)s; + hi += s + (l < lo); + lo = l; + + l = lo + 0x2000U; + hi += (l < lo); + + return ( (hi << 18) | (l >> 14) ); + } + + + /* compute (ax*bx+ay*by)/2^14 with maximal accuracy and rounding */ + static FT_Int32 + TT_DotFix14( FT_Int32 ax, FT_Int32 ay, FT_Int bx, FT_Int by ) + { + FT_Int32 m, s, hi1, hi2, hi; + FT_UInt32 l, lo1, lo2, lo; + + /* compute ax*bx as 64-bit value */ + l = (FT_UInt32)( (ax & 0xFFFF)*bx ); + m = (ax >> 16)*bx; + + lo1 = l + (FT_UInt32)(m << 16); + hi1 = (m >> 16) + ((FT_Int32)l >> 31) + (lo1 < l); + + /* compute ay*by as 64-bit value */ + l = (FT_UInt32)( (ay & 0xFFFF)*by ); + m = (ay >> 16)*by; + + lo2 = l + (FT_UInt32)(m << 16); + hi2 = (m >> 16) + ((FT_Int32)l >> 31) + (lo2 < l); + + /* add them */ + lo = lo1 + lo2; + hi = hi1 + hi2 + (lo < lo1); + + /* divide the result by 2^14 with rounding */ + s = (hi >> 31); + l = lo + (FT_UInt32)s; + hi += s + (l < lo); + lo = l; + + l = lo + 0x2000U; + hi += (l < lo); + + return ( (hi << 18) | (l >> 14) ); + } + + /* return length of given vector */ +#if 0 + + static FT_Int32 + TT_VecLen( FT_Int32 x, FT_Int32 y ) + { + FT_Int32 m, hi1, hi2, hi; + FT_UInt32 l, lo1, lo2, lo; + + /* compute x*x as 64-bit value */ + lo = (FT_UInt32)(x & 0xFFFF); + hi = (x >> 16); + + l = lo*lo; + m = hi*lo; + hi = hi*hi; + + lo1 = l + (FT_UInt32)(m << 17); + hi1 = hi + (m >> 15) + (lo1 < l); + + /* compute y*y as 64-bit value */ + lo = (FT_UInt32)( y & 0xFFFF ); + hi = (y >> 16); + + l = lo*lo; + m = hi*lo; + hi = hi*hi; + + lo2 = l + (FT_UInt32)(m << 17); + hi2 = hi + (m >> 15) + (lo2 < l); + + /* add them to get 'x*x+y*y' as 64-bit value */ + lo = lo1 + lo2; + hi = hi1 + hi2 + (lo < lo1); + + /* compute the square root of this value */ + { + FT_UInt32 root, rem, test_div; + FT_Int count; + + + root = 0; + + { + rem = 0; + count = 32; + do + { + rem = ( rem << 2 ) | ( (FT_UInt32)hi >> 30 ); + hi = ( hi << 2 ) | ( lo >> 30 ); + lo <<= 2; + root <<= 1; + test_div = ( root << 1 ) + 1; + + if ( rem >= test_div ) + { + rem -= test_div; + root += 1; + } + } while ( --count ); + } + + return (FT_Int32)root; + } + } +#else + + /* this version uses FT_Vector_Length which computes the same value */ + /* much, much faster.. */ + /* */ + static FT_F26Dot6 + TT_VecLen( FT_F26Dot6 X, + FT_F26Dot6 Y ) + { + FT_Vector v; + + v.x = X; + v.y = Y; + return FT_Vector_Length( &v ); + } + +#endif /*************************************************************************/ /* */ @@ -1229,9 +1346,10 @@ { FT_Long x, y; - x = TT_MULDIV( CUR.GS.projVector.x, CUR.tt_metrics.x_ratio, 0x4000 ); - y = TT_MULDIV( CUR.GS.projVector.y, CUR.tt_metrics.y_ratio, 0x4000 ); - CUR.tt_metrics.ratio = Norm( x, y ); + x = TT_MulFix14( CUR.tt_metrics.x_ratio, CUR.GS.projVector.x ); + y = TT_MulFix14( CUR.tt_metrics.y_ratio, CUR.GS.projVector.y ); + + CUR.tt_metrics.ratio = TT_VecLen( x, y ); } return CUR.tt_metrics.ratio; @@ -1982,8 +2100,10 @@ Project( EXEC_OP_ FT_Vector* v1, FT_Vector* v2 ) { - return TT_MULDIV( v1->x - v2->x, CUR.GS.projVector.x, 0x4000 ) + - TT_MULDIV( v1->y - v2->y, CUR.GS.projVector.y, 0x4000 ); + return TT_DotFix14( v1->x - v2->x, + v1->y - v2->y, + CUR.GS.projVector.x, + CUR.GS.projVector.y ); } @@ -2007,8 +2127,10 @@ Dual_Project( EXEC_OP_ FT_Vector* v1, FT_Vector* v2 ) { - return TT_MULDIV( v1->x - v2->x, CUR.GS.dualVector.x, 0x4000 ) + - TT_MULDIV( v1->y - v2->y, CUR.GS.dualVector.y, 0x4000 ); + return TT_DotFix14( v1->x - v2->x, + v1->y - v2->y, + CUR.GS.dualVector.x, + CUR.GS.dualVector.y ); } @@ -2032,8 +2154,10 @@ Free_Project( EXEC_OP_ FT_Vector* v1, FT_Vector* v2 ) { - return TT_MULDIV( v1->x - v2->x, CUR.GS.freeVector.x, 0x4000 ) + - TT_MULDIV( v1->y - v2->y, CUR.GS.freeVector.y, 0x4000 ); + return TT_DotFix14( v1->x - v2->x, + v1->y - v2->y, + CUR.GS.freeVector.x, + CUR.GS.freeVector.y ); } @@ -2188,8 +2312,6 @@ /* R is undefined. */ /* */ -#ifdef FT_CONFIG_OPTION_OLD_CALCS - static FT_Bool Normalize( EXEC_OP_ FT_F26Dot6 Vx, FT_F26Dot6 Vy, @@ -2206,7 +2328,7 @@ Vx *= 0x100; Vy *= 0x100; - W = Norm( Vx, Vy ); + W = TT_VecLen( Vx, Vy ); if ( W == 0 ) { @@ -2221,7 +2343,7 @@ return SUCCESS; } - W = Norm( Vx, Vy ); + W = TT_VecLen( Vx, Vy ); Vx = FT_MulDiv( Vx, 0x4000L, W ); Vy = FT_MulDiv( Vy, 0x4000L, W ); @@ -2284,29 +2406,6 @@ return SUCCESS; } -#else - - static FT_Bool - Normalize( EXEC_OP_ FT_F26Dot6 Vx, - FT_F26Dot6 Vy, - FT_UnitVector* R ) - { - FT_Vector v; - FT_Angle angle; - - FT_UNUSED_EXEC; - - angle = FT_Atan2( Vx, Vy ); - - FT_Vector_Unit( &v, angle ); - - R->x = (short)(v.x >> 2); - R->y = (short)(v.y >> 2); - - return SUCCESS; - } - -#endif /* FT_CONFIG_OPTION_OLD_CALCS */ /*************************************************************************/ @@ -5225,12 +5324,8 @@ return; } - dx = TT_MULDIV( args[0], - (FT_Long)CUR.GS.freeVector.x, - 0x4000 ); - dy = TT_MULDIV( args[0], - (FT_Long)CUR.GS.freeVector.y, - 0x4000 ); + dx = TT_MulFix14( args[0], CUR.GS.freeVector.x ); + dy = TT_MulFix14( args[0], CUR.GS.freeVector.y ); while ( CUR.GS.loop > 0 ) { @@ -5393,11 +5488,9 @@ if ( CUR.GS.gep0 == 0 ) /* If in twilight zone */ { - CUR.zp0.org[point].x = TT_MULDIV( CUR.GS.freeVector.x, - distance, 0x4000 ); - CUR.zp0.org[point].y = TT_MULDIV( CUR.GS.freeVector.y, - distance, 0x4000 ); - CUR.zp0.cur[point] = CUR.zp0.org[point]; + CUR.zp0.org[point].x = TT_MulFix14( distance, CUR.GS.freeVector.x ); + CUR.zp0.org[point].y = TT_MulFix14( distance, CUR.GS.freeVector.y ); + CUR.zp0.cur[point] = CUR.zp0.org[point]; } org_dist = CUR_Func_project( CUR.zp0.cur + point, NULL_Vector ); @@ -5550,14 +5643,10 @@ if ( CUR.GS.gep1 == 0 ) { CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x + - TT_MULDIV( cvt_dist, - CUR.GS.freeVector.x, - 0x4000 ); + TT_MulFix14( cvt_dist, CUR.GS.freeVector.x ); CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y + - TT_MULDIV( cvt_dist, - CUR.GS.freeVector.y, - 0x4000 ); + TT_MulFix14( cvt_dist, CUR.GS.freeVector.y ); CUR.zp1.cur[point] = CUR.zp1.org[point]; } |