diff --git a/src/base/ftcalc.c b/src/base/ftcalc.c index ea486e1de..57b406793 100644 --- a/src/base/ftcalc.c +++ b/src/base/ftcalc.c @@ -189,7 +189,6 @@ #ifdef FT_CONFIG_OPTION_OLD_CALCS -#if 0 /* a helper function for FT_Sqrt64() */ static @@ -229,23 +228,99 @@ return r; } - - FT_EXPORT_DEF( FT_Int32 ) FT_SqrtFixed( FT_Int32 x ) - { - FT_Int64 z; - - - z = (FT_Int64)(x) << 16; - return FT_Sqrt64( z ); - } -#endif - #endif /* FT_CONFIG_OPTION_OLD_CALCS */ #else /* FT_LONG64 */ + static void + ft_multo64( FT_UInt32 x, + FT_UInt32 y, + FT_Int64 *z ) + { + { + FT_UInt32 lo1, hi1, lo2, hi2, lo, hi, i1, i2; + + + lo1 = x & 0x0000FFFFU; hi1 = x >> 16; + lo2 = y & 0x0000FFFFU; hi2 = y >> 16; + + lo = lo1 * lo2; + i1 = lo1 * hi2; + i2 = lo2 * hi1; + hi = hi1 * hi2; + + /* Check carry overflow of i1 + i2 */ + i1 += i2; + hi += (FT_UInt32)( i1 < i2 ) << 16; + + hi += i1 >> 16; + i1 = i1 << 16; + + /* Check carry overflow of i1 + lo */ + lo += i1; + hi += ( lo < i1 ); + + z->lo = lo; + z->hi = hi; + } + } + + + static FT_UInt32 + ft_div64by32( FT_UInt32 hi, + FT_UInt32 lo, + FT_UInt32 y ) + { + FT_UInt r, q; + FT_Int i; + + q = 0; + r = hi; + + if ( r >= y ) + return (FT_UInt32)0x7FFFFFFF; + + i = 32; + do + { + r <<= 1; + q <<= 1; + r |= lo >> 31; + + if ( r >= (FT_UInt32)y ) + { + r -= y; + q |= 1; + } + lo <<= 1; + } + while (--i); + + return q; + } + + + /* documentation is in ftcalc.h */ + + FT_EXPORT_DEF( void ) FT_Add64( FT_Int64* x, + FT_Int64* y, + FT_Int64 *z ) + { + register FT_UInt32 lo, hi, max; + + max = x->lo > y->lo ? x->lo : y->lo; + lo = x->lo + y->lo; + hi = x->hi + y->hi + ( lo < max ); + + z->lo = lo; + z->hi = hi; + } + + + + /* documentation is in freetype.h */ FT_EXPORT_DEF( FT_Long ) FT_MulDiv( FT_Long a, @@ -271,11 +346,12 @@ FT_Int64 temp, temp2; - FT_MulTo64( a, b, &temp ); - temp2.hi = (FT_Int32)( c >> 31 ); - temp2.lo = (FT_UInt32)( c / 2 ); - FT_Add64( &temp, &temp2, &temp ); - a = FT_Div64by32( &temp, c ); + ft_multo64( a, b, &temp ); + + temp2.hi = 0; + temp2.lo = (FT_UInt32)(c >> 1); + FT_Add64( &temp, &temp2, &temp ); + a = ft_div64by32( temp.hi, temp.lo, b ); } else a = 0x7FFFFFFFL; @@ -339,7 +415,7 @@ else if ( ( a >> 16 ) == 0 ) { /* compute result directly */ - q = (FT_UInt32)( a << 16 ) / (FT_UInt32)b; + q = (FT_UInt32)( (a << 16) + (b >> 1) ) / (FT_UInt32)b; } else { @@ -348,33 +424,16 @@ temp.hi = (FT_Int32) (a >> 16); temp.lo = (FT_UInt32)(a << 16); - temp2.hi = (FT_Int32)( b >> 31 ); - temp2.lo = (FT_UInt32)( b / 2 ); + temp2.hi = 0; + temp2.lo = (FT_UInt32)( b >> 1 ); FT_Add64( &temp, &temp2, &temp ); - q = FT_Div64by32( &temp, b ); + q = ft_div64by32( temp.hi, temp.lo, b ); } return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q ); } - /* documentation is in ftcalc.h */ - - FT_EXPORT_DEF( void ) FT_Add64( FT_Int64* x, - FT_Int64* y, - FT_Int64 *z ) - { - register FT_UInt32 lo, hi; - - - lo = x->lo + y->lo; - hi = x->hi + y->hi + ( lo < x->lo ); - - z->lo = lo; - z->hi = hi; - } - - /* documentation is in ftcalc.h */ FT_EXPORT_DEF( void ) FT_MulTo64( FT_Int32 x, @@ -387,34 +446,7 @@ s = x; x = ABS( x ); s ^= y; y = ABS( y ); - { - FT_UInt32 lo1, hi1, lo2, hi2, lo, hi, i1, i2; - - - lo1 = x & 0x0000FFFF; hi1 = x >> 16; - lo2 = y & 0x0000FFFF; hi2 = y >> 16; - - lo = lo1 * lo2; - i1 = lo1 * hi2; - i2 = lo2 * hi1; - hi = hi1 * hi2; - - /* Check carry overflow of i1 + i2 */ - i1 += i2; - if ( i1 < i2 ) - hi += 1L << 16; - - hi += i1 >> 16; - i1 = i1 << 16; - - /* Check carry overflow of i1 + lo */ - lo += i1; - hi += ( lo < i1 ); - - z->lo = lo; - z->hi = hi; - } - + ft_multo64( x, y, z ); if ( s < 0 ) { z->lo = (FT_UInt32)-(FT_Int32)z->lo; @@ -429,7 +461,7 @@ FT_Int32 y ) { FT_Int32 s; - FT_UInt32 q, r, i, lo; + FT_UInt32 q; s = x->hi; @@ -444,35 +476,14 @@ if ( x->hi == 0 ) { if ( y > 0 ) - q = x->lo / y; + q = (x->lo + (y >> 1)) / y; else q = 0x7FFFFFFFL; return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q ); } - r = x->hi; - lo = x->lo; - - if ( r >= (FT_UInt32)y ) /* we know y is to be treated as unsigned here */ - return ( s < 0 ? 0x80000001UL : 0x7FFFFFFFUL ); - /* Return Max/Min Int32 if division overflow. */ - /* This includes division by zero! */ - q = 0; - for ( i = 0; i < 32; i++ ) - { - r <<= 1; - q <<= 1; - r |= lo >> 31; - - if ( r >= (FT_UInt32)y ) - { - r -= y; - q |= 1; - } - lo <<= 1; - } - + q = ft_div64by32( x->hi, x->lo, y ); return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q ); }