aboutsummaryrefslogtreecommitdiff
path: root/freetype/src/base/fttrigon.c
diff options
context:
space:
mode:
Diffstat (limited to 'freetype/src/base/fttrigon.c')
-rw-r--r--freetype/src/base/fttrigon.c100
1 files changed, 67 insertions, 33 deletions
diff --git a/freetype/src/base/fttrigon.c b/freetype/src/base/fttrigon.c
index 9e0af81b0..aa191fd2f 100644
--- a/freetype/src/base/fttrigon.c
+++ b/freetype/src/base/fttrigon.c
@@ -4,7 +4,7 @@
/* */
/* FreeType trigonometric functions (body). */
/* */
-/* Copyright 2001-2005, 2012-2013 by */
+/* Copyright 2001-2005, 2012-2014 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -45,7 +45,7 @@
/* this table was generated for FT_PI = 180L << 16, i.e. degrees */
#define FT_TRIG_MAX_ITERS 23
- static const FT_Fixed
+ static const FT_Angle
ft_trig_arctan_table[] =
{
1740967L, 919879L, 466945L, 234379L, 117304L, 58666L, 29335L,
@@ -60,17 +60,20 @@
static FT_Fixed
ft_trig_downscale( FT_Fixed val )
{
- FT_Fixed s;
- FT_Int64 v;
+ FT_Int s = 1;
- s = val;
- val = FT_ABS( val );
+ if ( val < 0 )
+ {
+ val = -val;
+ s = -1;
+ }
- v = ( val * (FT_Int64)FT_TRIG_SCALE ) + 0x100000000UL;
- val = (FT_Fixed)( v >> 32 );
+ /* 0x40000000 comes from regression analysis between true */
+ /* and CORDIC hypotenuse, so it minimizes the error */
+ val = (FT_Fixed)( ( (FT_Int64)val * FT_TRIG_SCALE + 0x40000000UL ) >> 32 );
- return ( s >= 0 ) ? val : -val;
+ return s < 0 ? -val : val;
}
#else /* !FT_LONG64 */
@@ -79,38 +82,53 @@
static FT_Fixed
ft_trig_downscale( FT_Fixed val )
{
- FT_Fixed s;
- FT_UInt32 v1, v2, k1, k2, hi, lo1, lo2, lo3;
+ FT_Int s = 1;
+ FT_UInt32 lo1, hi1, lo2, hi2, lo, hi, i1, i2;
+
+
+ if ( val < 0 )
+ {
+ val = -val;
+ s = -1;
+ }
+ lo1 = val & 0x0000FFFFU;
+ hi1 = val >> 16;
+ lo2 = FT_TRIG_SCALE & 0x0000FFFFU;
+ hi2 = FT_TRIG_SCALE >> 16;
- s = val;
- val = FT_ABS( val );
+ lo = lo1 * lo2;
+ i1 = lo1 * hi2;
+ i2 = lo2 * hi1;
+ hi = hi1 * hi2;
- v1 = (FT_UInt32)val >> 16;
- v2 = (FT_UInt32)( val & 0xFFFFL );
+ /* Check carry overflow of i1 + i2 */
+ i1 += i2;
+ hi += (FT_UInt32)( i1 < i2 ) << 16;
- k1 = (FT_UInt32)FT_TRIG_SCALE >> 16; /* constant */
- k2 = (FT_UInt32)( FT_TRIG_SCALE & 0xFFFFL ); /* constant */
+ hi += i1 >> 16;
+ i1 = i1 << 16;
- hi = k1 * v1;
- lo1 = k1 * v2 + k2 * v1; /* can't overflow */
+ /* Check carry overflow of i1 + lo */
+ lo += i1;
+ hi += ( lo < i1 );
- lo2 = ( k2 * v2 ) >> 16;
- lo3 = FT_MAX( lo1, lo2 );
- lo1 += lo2;
+ /* 0x40000000 comes from regression analysis between true */
+ /* and CORDIC hypotenuse, so it minimizes the error */
- hi += lo1 >> 16;
- if ( lo1 < lo3 )
- hi += (FT_UInt32)0x10000UL;
+ /* Check carry overflow of lo + 0x40000000 */
+ lo += 0x40000000UL;
+ hi += ( lo < 0x40000000UL );
val = (FT_Fixed)hi;
- return ( s >= 0 ) ? val : -val;
+ return s < 0 ? -val : val;
}
#endif /* !FT_LONG64 */
+ /* undefined and never called for zero vector */
static FT_Int
ft_trig_prenorm( FT_Vector* vec )
{
@@ -147,7 +165,7 @@
{
FT_Int i;
FT_Fixed x, y, xtemp, b;
- const FT_Fixed *arctanptr;
+ const FT_Angle *arctanptr;
x = vec->x;
@@ -202,7 +220,7 @@
FT_Angle theta;
FT_Int i;
FT_Fixed x, y, xtemp, b;
- const FT_Fixed *arctanptr;
+ const FT_Angle *arctanptr;
x = vec->x;
@@ -261,11 +279,12 @@
}
}
- /* round theta */
+ /* round theta to acknowledge its error that mostly comes */
+ /* from accumulated rounding errors in the arctan table */
if ( theta >= 0 )
- theta = FT_PAD_ROUND( theta, 32 );
+ theta = FT_PAD_ROUND( theta, 16 );
else
- theta = -FT_PAD_ROUND( -theta, 32 );
+ theta = -FT_PAD_ROUND( -theta, 16 );
vec->x = x;
vec->y = theta;
@@ -340,6 +359,9 @@
FT_Vector_Unit( FT_Vector* vec,
FT_Angle angle )
{
+ if ( !vec )
+ return;
+
vec->x = FT_TRIG_SCALE >> 8;
vec->y = 0;
ft_trig_pseudo_rotate( vec, angle );
@@ -366,6 +388,9 @@
FT_Vector v;
+ if ( !vec )
+ return;
+
v.x = vec->x;
v.y = vec->y;
@@ -403,6 +428,9 @@
FT_Vector v;
+ if ( !vec )
+ return 0;
+
v = *vec;
/* handle trivial cases */
@@ -439,6 +467,9 @@
FT_Vector v;
+ if ( !vec || !length || !angle )
+ return;
+
v = *vec;
if ( v.x == 0 && v.y == 0 )
@@ -449,8 +480,8 @@
v.x = ft_trig_downscale( v.x );
- *length = ( shift >= 0 ) ? ( v.x >> shift )
- : (FT_Fixed)( (FT_UInt32)v.x << -shift );
+ *length = shift >= 0 ? ( v.x >> shift )
+ : (FT_Fixed)( (FT_UInt32)v.x << -shift );
*angle = v.y;
}
@@ -462,6 +493,9 @@
FT_Fixed length,
FT_Angle angle )
{
+ if ( !vec )
+ return;
+
vec->x = length;
vec->y = 0;