From ebe85f59c9540a37ff72ffe8aba9c08b9d8b28ef Mon Sep 17 00:00:00 2001
From: David Turner
Date: Fri, 11 May 2001 14:25:57 +0000
Subject: [PATCH] * include/freetype/fttrigon.h, src/base/fttrigon.c,
src/base/ftbase.c, src/base/Jamfile, src/base/rules.mk: adding
trigonometric functions to the core API (using Cordic algorithms).
* builds/top_level.mk, builds/newline, builds/detect.mk: fixed problems
with Make on Windows 2000, as well as problems when "make distclean" is
invoked on a non-Unix platform when there is no "config.mk" in the
current directory..
* builds/freetype.mk: fixed a problem with object deletions under
Dos/Windows/OS/2 systems
* src/tools: added new directory to hold tools and test programs
moved docmaker.py, glnames.py to it..
* src/tools/docmaker.py: improved the script to add the current date
at the footer of each web page (useful to distinguish between versions)
* Jamfile: fixed incorrect HDRMACRO argument.
* TODO: removed the cubic arc bbox computation note, since it has been
fixed recently..
* include/freetype/t1tables.h, include/freetype/config/ftoption.h:
formatting
---
ChangeLog | 39 ++-
builds/detect.mk | 23 +-
builds/freetype.mk | 9 +-
builds/link_std.mk | 2 +-
builds/newline | 1 +
builds/toplevel.mk | 9 +-
builds/unix/detect.mk | 1 +
include/freetype/config/ftconfig.h | 14 +
include/freetype/config/ftheader.h | 2 +-
include/freetype/fttrigon.h | 213 +++++++++++++++
include/freetype/t1tables.h | 10 +-
src/autohint/ahglyph.c | 4 +-
src/base/Jamfile | 2 +-
src/base/ftbase.c | 1 +
src/base/ftbbox.c | 77 ++++--
src/base/ftobjs.c | 7 +-
src/base/fttrigon.c | 404 +++++++++++++++++++++++++++++
src/base/rules.mk | 1 +
src/tools/cordic.py | 78 ++++++
{docs => src/tools}/docmaker.py | 8 +-
{docs => src/tools}/glnames.py | 0
src/tools/test_bbox.c | 160 ++++++++++++
src/tools/test_trig.c | 236 +++++++++++++++++
23 files changed, 1254 insertions(+), 47 deletions(-)
create mode 100644 builds/newline
create mode 100644 include/freetype/fttrigon.h
create mode 100644 src/base/fttrigon.c
create mode 100644 src/tools/cordic.py
rename {docs => src/tools}/docmaker.py (99%)
rename {docs => src/tools}/glnames.py (100%)
create mode 100644 src/tools/test_bbox.c
create mode 100644 src/tools/test_trig.c
diff --git a/ChangeLog b/ChangeLog
index cd3305442..6d9497961 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,36 @@
+2001-05-11 David Turner
+
+ * include/freetype/fttrigon.h, src/base/fttrigon.c, src/base/ftbase.c,
+ src/base/Jamfile, src/base/rules.mk: adding trigonometric functions
+ to the core API (using Cordic algorithms).
+
+ * builds/top_level.mk, builds/newline, builds/detect.mk: fixed problems
+ with Make on Windows 2000, as well as problems when "make distclean" is
+ invoked on a non-Unix platform when there is no "config.mk" in the
+ current directory..
+
+ * builds/freetype.mk: fixed a problem with object deletions under
+ Dos/Windows/OS/2 systems
+
+ * src/tools: added new directory to hold tools and test programs
+ moved docmaker.py, glnames.py to it..
+
+ * src/tools/docmaker.py: improved the script to add the current date
+ at the footer of each web page (useful to distinguish between versions)
+
+ * Jamfile: fixed incorrect HDRMACRO argument.
+
+ * TODO: removed the cubic arc bbox computation note, since it has been
+ fixed recently..
+
+ * include/freetype/t1tables.h, include/freetype/config/ftoption.h:
+ formatting
+
+2001-05-10 David Turner
+
+ * src/base/ftobjs.c (FT_Open_Face): fixed a small memory leaked
+ which happened when trying to open 0-size font files !!
+
2001-05-09 Werner Lemberg
* include/freetype/internal/ftcalc.h: Move declaration of
@@ -21,8 +54,8 @@
2001-04-27 David Turner
- * src/base/ftbbox.c (BBox_Cubic_Check): Fixed the coefficient
- normalization algorithm (invalid final bit position, and invalid
+ * src/base/ftbbox.c (BBox_Cubic_Check): Fixed the coefficient
+ normalization algorithm (invalid final bit position, and invalid
shift computation).
2001-04-26 Werner Lemberg
@@ -66,7 +99,7 @@
types on platforms where Autoconf is not available). Also removed
FTCALC_USE_LONG_LONG and replaced it with
FT_CONFIG_OPTION_FORCE_INT64.
-
+
* builds/win32/freetype.dsp: Updated the Visual C++ project file.
Doesn't create a DLL yet.
diff --git a/builds/detect.mk b/builds/detect.mk
index eaf1ddec5..fbd85d5c5 100644
--- a/builds/detect.mk
+++ b/builds/detect.mk
@@ -131,22 +131,25 @@ std_setup:
@echo ""
@$(COPY) $(CONFIG_RULES) $(CONFIG_MK)
+
+# special case for Dos, Windows, OS/2, where echo "" doesn't work correctly !!
+#
dos_setup:
- @echo ˙
+ @type builds\newline
@echo $(PROJECT_TITLE) build system -- automatic system detection
- @echo ˙
+ @type builds\newline
@echo The following settings are used:
- @echo ˙
- @echo ˙˙platform˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙$(PLATFORM)
- @echo ˙˙compiler˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙$(CC)
- @echo ˙˙configuration directory˙˙˙˙˙˙$(BUILD)
- @echo ˙˙configuration rules˙˙˙˙˙˙˙˙˙˙$(CONFIG_RULES)
- @echo ˙
+ @type builds\newline
+ @echo platform˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙$(PLATFORM)
+ @echo compiler˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙$(CC)
+ @echo configuration directory˙˙˙˙˙˙$(BUILD)
+ @echo configuration rules˙˙˙˙˙˙˙˙˙˙$(CONFIG_RULES)
+ @type builds\newline
@echo If this does not correspond to your system or settings please remove the file
@echo '$(CONFIG_MK)' from this directory then read the INSTALL file for help.
- @echo ˙
+ @type builds\newline
@echo Otherwise, simply type 'make' again to build the library.
- @echo ˙
+ @type builds\newline
@$(COPY) $(subst /,\,$(CONFIG_RULES) $(CONFIG_MK)) > nul
# EOF
diff --git a/builds/freetype.mk b/builds/freetype.mk
index 532de0f4b..a25ed2a27 100644
--- a/builds/freetype.mk
+++ b/builds/freetype.mk
@@ -273,13 +273,14 @@ distclean_project_std: clean_project_std
# The Dos command shell does not support very long list of arguments, so
# we are stuck with wildcards.
#
+# don't break the command lines with, this prevents the "del" command from
+# working correctly on Win9x
+#
clean_project_dos:
- -$(DELETE) $(subst $(SEP),$(HOSTSEP),$(OBJ_))*.$O \
- $(CLEAN) $(NO_OUTPUT)
+ -$(DELETE) $(subst $(SEP),$(HOSTSEP),$(OBJ_))*.$O $(CLEAN) $(NO_OUTPUT)
distclean_project_dos: clean_project_dos
- -$(DELETE) $(subst $(SEP),$(HOSTSEP),$(PROJECT_LIBRARY)) \
- $(DISTCLEAN) $(NO_OUTPUT)
+ -$(DELETE) $(subst $(SEP),$(HOSTSEP),$(PROJECT_LIBRARY)) $(DISTCLEAN) $(NO_OUTPUT)
.PHONY: remove_config_mk
diff --git a/builds/link_std.mk b/builds/link_std.mk
index 2a7b26df7..9cd6dba80 100644
--- a/builds/link_std.mk
+++ b/builds/link_std.mk
@@ -32,7 +32,7 @@ ifdef BUILD_PROJECT
#
$(PROJECT_LIBRARY): $(OBJECTS_LIST)
ifdef CLEAN_LIBRARY
- -$(CLEAN_LIBRARY) $(NO_OUTPUT)
+ -$(CLEAN_LIBRARY) xx $(NO_OUTPUT)
endif
$(LINK_LIBRARY)
diff --git a/builds/newline b/builds/newline
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/builds/newline
@@ -0,0 +1 @@
+
diff --git a/builds/toplevel.mk b/builds/toplevel.mk
index f05ca0dad..086f918e3 100644
--- a/builds/toplevel.mk
+++ b/builds/toplevel.mk
@@ -97,7 +97,12 @@ ifdef check_platform
# GNU make. Similarly, `nul' is created if e.g. `make setup win32' has
# been erroneously used.
#
- distclean:
+ # note: this test is duplicated in "builds/toplevel.mk"
+ is_unix := $(strip $(wildcard /sbin/init) $(wildcard /hurd/auth))
+ ifneq ($(is_unix),)
+
+
+ distclean:
$(RM) builds/unix/config.cache
$(RM) builds/unix/config.log
$(RM) builds/unix/config.status
@@ -105,6 +110,8 @@ ifdef check_platform
$(RM) builds/unix/unix-cc.mk
$(RM) nul
+ endif # test is_unix
+
# IMPORTANT:
#
# `setup' must be defined by the host platform detection rules to create
diff --git a/builds/unix/detect.mk b/builds/unix/detect.mk
index 32de899f1..52e0075db 100644
--- a/builds/unix/detect.mk
+++ b/builds/unix/detect.mk
@@ -16,6 +16,7 @@
ifeq ($(PLATFORM),ansi)
+ # note: this test is duplicated in "builds/toplevel.mk"
is_unix := $(strip $(wildcard /sbin/init) $(wildcard /hurd/auth))
ifneq ($(is_unix),)
diff --git a/include/freetype/config/ftconfig.h b/include/freetype/config/ftconfig.h
index 225bae5f5..1335587e0 100644
--- a/include/freetype/config/ftconfig.h
+++ b/include/freetype/config/ftconfig.h
@@ -127,6 +127,20 @@ FT_BEGIN_HEADER
#error "no 32bit type found -- please check your configuration files"
#endif
+/* now, lookup for an integer type that is at least 32 bits */
+#if FT_SIZEOF_INT >= 4
+
+ typedef int FT_Fast;
+ typedef unsigned int FT_UFast;
+
+#elif FT_SIZEOF_LONG >= 4
+
+ typedef long FT_Fast
+ typedef unsigned long FT_UFast
+
+#endif
+
+
/* determine whether we have a 64-bit int type for platforms without */
/* Autoconf */
diff --git a/include/freetype/config/ftheader.h b/include/freetype/config/ftheader.h
index c11d82e55..e39c3cd3c 100644
--- a/include/freetype/config/ftheader.h
+++ b/include/freetype/config/ftheader.h
@@ -436,7 +436,7 @@
/* */
-
+#define FT_TRIGONOMETRY_H
#define FT_SYNTHESIS_H
#define FT_CACHE_MANAGER_H
diff --git a/include/freetype/fttrigon.h b/include/freetype/fttrigon.h
new file mode 100644
index 000000000..311040f29
--- /dev/null
+++ b/include/freetype/fttrigon.h
@@ -0,0 +1,213 @@
+#ifndef __FT_TRIGONOMETRY_H__
+#define __FT_TRIGONOMETRY_H__
+
+FT_BEGIN_HEADER
+
+ /***************************************************************************
+ *
+ * @section: computations
+ *
+ */
+
+ /***************************************************************************
+ *
+ * @type: FT_Angle
+ *
+ * @description:
+ * this type is used to model angle values in FreeType. Note that
+ * the angle is a 16.16 fixed float value expressed in _degrees_
+ */
+ typedef FT_Fixed FT_Angle;
+
+ /***************************************************************************
+ *
+ * @macro: FT_ANGLE_PI
+ *
+ * @description:
+ * the angle pi expressed in @FT_Angle units
+ */
+#define FT_ANGLE_PI (180L << 16)
+
+ /***************************************************************************
+ *
+ * @macro: FT_ANGLE_2PI
+ *
+ * @description:
+ * the angle 2pi expressed in @FT_Angle units
+ */
+#define FT_ANGLE_2PI (FT_ANGLE_PI*2)
+
+ /***************************************************************************
+ *
+ * @macro: FT_ANGLE_PI2
+ *
+ * @description:
+ * the angle pi/2 expressed in @FT_Angle units
+ */
+#define FT_ANGLE_PI2 (FT_ANGLE_PI/2)
+
+ /***************************************************************************
+ *
+ * @macro: FT_ANGLE_PI4
+ *
+ * @description:
+ * the angle pi/4 expressed in @FT_Angle units
+ */
+#define FT_ANGLE_PI4 (FT_ANGLE_PI/4)
+
+
+ /***************************************************************************
+ *
+ * @function: FT_Sin
+ *
+ * @description:
+ * return the sinus of a given angle in fixed point format
+ *
+ * @input:
+ * angle :: input angle
+ *
+ * @return:
+ * sinus value
+ *
+ * @note:
+ * if you need both the sinus and cosinus for a given angle, you'd
+ * better use the function @FT_Vector_Unit
+ */
+ FT_EXPORT(FT_Fixed) FT_Sin( FT_Angle angle );
+
+ /***************************************************************************
+ *
+ * @function: FT_Cos
+ *
+ * @description:
+ * return the cosinus of a given angle in fixed point format
+ *
+ * @input:
+ * angle :: input angle
+ *
+ * @return:
+ * cosinus value
+ *
+ * @note:
+ * if you need both the sinus and cosinus for a given angle, you'd
+ * better use the function @FT_Vector_Unit
+ */
+ FT_EXPORT(FT_Fixed) FT_Cos( FT_Angle angle );
+
+ /***************************************************************************
+ *
+ * @function: FT_Tan
+ *
+ * @description:
+ * return the tangent of a given angle in fixed point format
+ *
+ * @input:
+ * angle :: input angle
+ *
+ * @return:
+ * tangent value
+ */
+ FT_EXPORT(FT_Fixed) FT_Tan( FT_Angle angle );
+
+
+ /***************************************************************************
+ *
+ * @function: FT_Atan2
+ *
+ * @description:
+ * return the arc-tangent corresponding to a given vector (x,y) in
+ * the 2d plane
+ *
+ * @input:
+ * x :: horizontal vector coordinate
+ * y :: vertical vector coordinate
+ *
+ * @return:
+ * arc-tangent value (i.e. angle)
+ */
+ FT_EXPORT(FT_Angle) FT_Atan2( FT_Fixed x, FT_Fixed y );
+
+
+ /***************************************************************************
+ *
+ * @function: FT_Vector_Unit
+ *
+ * @description:
+ * return the unit vector corresponding to a given angle. After the call,
+ * the value of "vec.x" will be "sin(theta)", and the value of "vec.y"
+ * will be "cos(angle)"
+ *
+ * this function is useful to retrieve both the sinus and cosinus
+ * of a given angle quickly
+ *
+ * @input:
+ * vec :: address of target vector
+ * angle :: address of angle
+ */
+ FT_EXPORT(void) FT_Vector_Unit( FT_Vector* vec,
+ FT_Angle angle );
+
+ /***************************************************************************
+ *
+ * @function: FT_Vector_Rotate
+ *
+ * @description:
+ * rotate a given vector by a given angle
+ *
+ * @input:
+ * vec :: address of target vector
+ * angle :: address of angle
+ */
+ FT_EXPORT(void) FT_Vector_Rotate( FT_Vector* vec,
+ FT_Angle angle );
+
+ /***************************************************************************
+ *
+ * @function: FT_Vector_Length
+ *
+ * @description:
+ * returns the length of a given vector
+ *
+ * @input:
+ * vec :: address of target vector
+ *
+ * @return:
+ * vector length, expressed in the same units that the original
+ * vector coordinates !!
+ */
+ FT_EXPORT(FT_Fixed) FT_Vector_Length( FT_Vector* vec );
+
+ /***************************************************************************
+ *
+ * @function: FT_Vector_Normalize
+ *
+ * @description:
+ * normalize a given vector (i.e. compute the equivalent unit vector)
+ *
+ * @input:
+ * vec :: address of target vector
+ */
+ FT_EXPORT(void) FT_Vector_Normalize( FT_Vector* vec );
+
+ /***************************************************************************
+ *
+ * @function: FT_Vector_Polarize
+ *
+ * @description:
+ * compute both the length and angle of a given vector
+ *
+ * @input:
+ * vec :: address of source vector
+ *
+ * @output:
+ * length :: vector length
+ * angle :: vector angle
+ */
+ FT_EXPORT(void) FT_Vector_Polarize( FT_Vector* vec,
+ FT_Fixed *length,
+ FT_Angle *angle );
+ /* */
+
+FT_END_HEADER
+
+#endif /* __FT_TRIGONOMETRY_H__ */
diff --git a/include/freetype/t1tables.h b/include/freetype/t1tables.h
index cc23ddeb5..2785fead1 100644
--- a/include/freetype/t1tables.h
+++ b/include/freetype/t1tables.h
@@ -113,8 +113,8 @@ FT_BEGIN_HEADER
FT_Bool force_bold;
FT_Bool round_stem_up;
- FT_Short snap_widths [13]; /* reserve one place for the std */
- FT_Short snap_heights[13]; /* reserve one place for the std */
+ FT_Short snap_widths [13]; /* including std width */
+ FT_Short snap_heights[13]; /* including std height */
FT_Long language_group;
FT_Long password;
@@ -136,12 +136,12 @@ FT_BEGIN_HEADER
/* */
typedef enum
{
- /* required fields in a FontInfo blend dictionary */
+ /*# required fields in a FontInfo blend dictionary */
t1_blend_underline_position = 0,
t1_blend_underline_thickness,
t1_blend_italic_angle,
- /* required fields in a Private blend dictionary */
+ /*# required fields in a Private blend dictionary */
t1_blend_blue_values,
t1_blend_other_blues,
t1_blend_standard_width,
@@ -154,7 +154,7 @@ FT_BEGIN_HEADER
t1_blend_family_other_blues,
t1_blend_force_bold,
- /* never remove */
+ /*# never remove */
t1_blend_max
} T1_Blend_Flags;
diff --git a/src/autohint/ahglyph.c b/src/autohint/ahglyph.c
index 23c26ed59..252572dfc 100644
--- a/src/autohint/ahglyph.c
+++ b/src/autohint/ahglyph.c
@@ -359,7 +359,7 @@
outline->horz_major_dir = ah_dir_right;
}
-#else
+#else /* !1 */
/* Compute the vertical and horizontal major directions; this is */
/* currently done by inspecting the `ft_outline_reverse_fill' flag. */
@@ -374,7 +374,7 @@
outline->horz_major_dir = ah_dir_right;
}
-#endif /* 1 */
+#endif /* !1 */
outline->x_scale = face->size->metrics.x_scale;
outline->y_scale = face->size->metrics.y_scale;
diff --git a/src/base/Jamfile b/src/base/Jamfile
index 8bacddb04..c6c13b315 100644
--- a/src/base/Jamfile
+++ b/src/base/Jamfile
@@ -10,7 +10,7 @@ SubDirHdrs [ FT2_SubDir src base ] ;
if $(FT2_MULTI)
{
- _sources = ftcalc ftextend ftlist ftobjs ftstream ftoutln ftnames ;
+ _sources = ftcalc ftextend ftlist ftobjs ftstream ftoutln ftnames fttrigon ;
}
else
{
diff --git a/src/base/ftbase.c b/src/base/ftbase.c
index 1d61b5aa8..f4b561832 100644
--- a/src/base/ftbase.c
+++ b/src/base/ftbase.c
@@ -21,6 +21,7 @@
#define FT_MAKE_OPTION_SINGLE_OBJECT
#include "ftcalc.c"
+#include "fttrigon.c"
#include "ftobjs.c"
#include "ftstream.c"
#include "ftlist.c"
diff --git a/src/base/ftbbox.c b/src/base/ftbbox.c
index 07700e500..67fcbdeab 100644
--- a/src/base/ftbbox.c
+++ b/src/base/ftbbox.c
@@ -278,13 +278,13 @@
#else
static void
- test_cubic_zero( FT_Pos y1,
- FT_Pos y2,
- FT_Pos y3,
- FT_Pos y4,
- FT_Fixed u,
- FT_Pos* min,
- FT_Pos* max )
+ test_cubic_extrema( FT_Pos y1,
+ FT_Pos y2,
+ FT_Pos y3,
+ FT_Pos y4,
+ FT_Fixed u,
+ FT_Pos* min,
+ FT_Pos* max )
{
/* FT_Pos a = y4 - 3*y3 + 3*y2 - y1; */
FT_Pos b = y3 - 2*y2 + y1;
@@ -373,34 +373,81 @@
int shift = 0;
+ /* technical explanation of what's happening there */
+ /* */
+ /* the following computation is based on the fact that for */
+ /* any value "y", if "n" is the position of the most */
+ /* significant bit of "abs(y)" (starting from 0 for the */
+ /* least significant bit), then y is in the range */
+ /* */
+ /* "-2^n..2^n-1" */
+ /* */
+ /* we want to shift "a", "b" and "c" concurrently in order */
+ /* to ensure that they all fit in 8.16 values, which maps */
+ /* to the integer range "-2^23..2^23-1" */
+ /* */
+ /* necessarily, we need to shift "a", "b" and "c" so that */
+ /* the most significant bit of their absolute values is at */
+ /* _most_ at position 23 */
+ /* */
+ /* we begin by computing "t1" as the bitwise "or" of the */
+ /* absolute values of "a", "b", "c" */
+ /* */
t1 = (FT_ULong)((a >= 0) ? a : -a );
t2 = (FT_ULong)((b >= 0) ? b : -b );
t1 |= t2;
t2 = (FT_ULong)((c >= 0) ? c : -c );
t1 |= t2;
+ /* now, the most significant bit of "t1" is sure to be the */
+ /* msb of one of "a", "b", "c", depending on which one is */
+ /* expressed in the greatest integer range.. */
+ /* */
+ /* we will now compute the "shift", by shifting "t1" as many */
+ /* times as necessary to move its msb to position 23. */
+ /* */
+ /* this corresponds to a value of t1 that is in the range */
+ /* 0x40_0000..0x7F_FFFF */
+ /* */
+ /* finally, we shift "a", "b" and "c" by the same amount. */
+ /* this ensure that all values are now in the range */
+ /* -2^23..2^23, i.e. that they're now expressed as 8.16 */
+ /* fixed float numbers.. */
+ /* */
+ /* this also means that we're using 24 bits of precision */
+ /* to compute the zeros, independently of the range of */
+ /* the original polynom coefficients. */
+ /* */
+ /* this should ensure reasonably accurate values for the */
+ /* zeros. Note that the latter are only expressed with */
+ /* 16 bits when computing the extrema (the zeros need to */
+ /* be in 0..1 exclusive to be considered part of the arc) */
+ /* */
+
if ( t1 == 0 ) /* all coefficients are 0! */
return;
- if ( t1 > 0x7FFFFFL )
+ if ( t1 > 0x7FFFFFUL )
{
do
{
shift++;
t1 >>= 1;
- } while ( t1 > 0x7FFFFFL );
+ } while ( t1 > 0x7FFFFFUL );
+ /* losing some bits of precision, but we'll use 24 of them */
+ /* for the computation anyway.. */
a >>= shift;
b >>= shift;
c >>= shift;
}
- else if ( t1 < 0x400000L )
+ else if ( t1 < 0x400000UL )
{
do
{
shift++;
t1 <<= 1;
- } while ( t1 < 0x400000L );
+ } while ( t1 < 0x400000UL );
a <<= shift;
b <<= shift;
@@ -414,7 +461,7 @@
if ( b != 0 )
{
t = - FT_DivFix( c, b ) / 2;
- test_cubic_zero( y1, y2, y3, y4, t, min, max );
+ test_cubic_extrema( y1, y2, y3, y4, t, min, max );
}
}
else
@@ -428,17 +475,17 @@
{
/* there is a single split point at -b/a */
t = - FT_DivFix( b, a );
- test_cubic_zero( y1, y2, y3, y4, t, min, max );
+ test_cubic_extrema( y1, y2, y3, y4, t, min, max );
}
else
{
/* there are two solutions; we need to filter them though */
d = FT_SqrtFixed( (FT_Int32)d );
t = - FT_DivFix( b - d, a );
- test_cubic_zero( y1, y2, y3, y4, t, min, max );
+ test_cubic_extrema( y1, y2, y3, y4, t, min, max );
t = - FT_DivFix( b + d, a );
- test_cubic_zero( y1, y2, y3, y4, t, min, max );
+ test_cubic_extrema( y1, y2, y3, y4, t, min, max );
}
}
}
diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c
index ecd99af01..64bc0beee 100644
--- a/src/base/ftobjs.c
+++ b/src/base/ftobjs.c
@@ -1240,14 +1240,15 @@
goto Success;
if ( error != FT_Err_Unknown_File_Format )
- goto Fail;
+ goto Fail2;
}
}
- ft_done_stream( &stream, external_stream );
-
/* no driver is able to handle this format */
error = FT_Err_Unknown_File_Format;
+
+ Fail2:
+ ft_done_stream( &stream, external_stream );
goto Fail;
}
diff --git a/src/base/fttrigon.c b/src/base/fttrigon.c
new file mode 100644
index 000000000..693551853
--- /dev/null
+++ b/src/base/fttrigon.c
@@ -0,0 +1,404 @@
+#include
+#include FT_TRIGONOMETRY_H
+
+/* the following is 0.2715717684432231 * 2^30 */
+#define FT_TRIG_COSCALE 0x11616E8E /* 291597966 = 0.2715717684432241 * 2^30, valid for j>13 */
+
+ /* this table was generated for FT_PI = 180L << 16, i.e. degrees */
+#define FT_TRIG_MAX_ITERS 23
+
+ static const FT_Fixed
+ ft_trig_arctan_table[ 24 ] =
+ {
+ 4157273, 2949120, 1740967, 919879, 466945, 234379, 117304, 58666,
+ 29335, 14668, 7334, 3667, 1833, 917, 458, 229, 115, 57, 29, 14, 7,
+ 4, 2, 1
+ };
+
+
+/* the Cordic shrink factor, multiplied by 2^32 */
+#define FT_TRIG_SCALE 1166391785 /* 0x4585BA38U */
+
+#ifdef FT_CONFIG_HAS_INT64
+
+ /* multiply a given value by the CORDIC shrink factor */
+ static FT_Fixed
+ ft_trig_downscale( FT_Fixed val )
+ {
+ FT_Fixed s;
+ FT_Int64 v;
+
+ s = val;
+ val = (val >= 0) ? val : -val;
+
+ v = (val * (FT_Int64)FT_TRIG_SCALE) + 0x100000000L;
+ val = (FT_Fixed)(v >> 32);
+
+ return ( s >= 0 ) ? val : -val;
+ }
+
+#else /* !FT_CONFIG_HAS_INT64 */
+
+ /* multiply a given value by the CORDIC shrink factor */
+ static FT_Fixed
+ ft_trig_downscale( FT_Fixed val )
+ {
+ FT_Fixed s;
+ FT_UInt32 v1, v2, k1, k2, hi, lo1, lo2, lo3;
+
+ s = val;
+ val = ( val >= 0 ) ? val : -val;
+
+ v1 = (FT_UInt32)val >> 16;
+ v2 = (FT_UInt32)val & 0xFFFF;
+
+ k1 = FT_TRIG_SCALE >> 16; /* constant */
+ k2 = FT_TRIG_SCALE & 0xFFFF; /* constant */
+
+ hi = k1*v1;
+ lo1 = k1*v2 + k2*v1; /* can't overflow */
+
+ lo2 = k2*v2 >> 16;
+ lo3 = ( lo1 >= lo2 ) ? lo1 : lo2;
+ lo1 += lo2;
+
+ hi += lo1 >> 16;
+ if (lo1 < lo3)
+ hi += 0x10000U;
+
+ val = (FT_Fixed)hi;
+
+ return ( s >= 0 ) ? val : -val;
+ }
+
+#endif /* !FT_CONFIG_HAS_INT64 */
+
+
+ static FT_Int
+ ft_trig_prenorm( FT_Vector* vec )
+ {
+ FT_Fixed x, y, z;
+ FT_Int shift;
+
+ x = vec->x;
+ y = vec->y;
+
+ z = (( x >= 0 ) ? x : - x) | ((y >= 0) ? y : -y);
+ shift = 0;
+
+ if ( z < (1L << 27) )
+ {
+ do
+ {
+ shift++;
+ z <<= 1;
+ }
+ while ( z < (1L << 27) );
+
+ vec->x = (x << shift);
+ vec->y = (y << shift);
+ }
+ else if ( z > (1L << 28 ) )
+ {
+ do
+ {
+ shift++;
+ z >>= 1;
+ }
+ while ( z > (1L << 28) );
+
+ vec->x = (x >> shift);
+ vec->y = (y >> shift);
+ shift = -shift;
+ }
+ return shift;
+ }
+
+
+
+
+ static void
+ ft_trig_pseudo_rotate( FT_Vector* vec, FT_Angle theta )
+ {
+ FT_Int i;
+ FT_Fixed x, y, xtemp;
+ const FT_Fixed *arctanptr;
+
+ x = vec->x;
+ y = vec->y;
+
+ /* Get angle between -90 and 90 degrees */
+ while (theta <= -FT_ANGLE_PI2)
+ {
+ x = -x;
+ y = -y;
+ theta += FT_ANGLE_PI;
+ }
+ while (theta > FT_ANGLE_PI2)
+ {
+ x = -x;
+ y = -y;
+ theta -= FT_ANGLE_PI;
+ }
+
+ /* Initial pseudorotation, with left shift */
+ arctanptr = ft_trig_arctan_table;
+ if (theta < 0)
+ {
+ xtemp = x + (y << 1);
+ y = y - (x << 1);
+ x = xtemp;
+ theta += *arctanptr++;
+ }
+ else
+ {
+ xtemp = x - (y << 1);
+ y = y + (x << 1);
+ x = xtemp;
+ theta -= *arctanptr++;
+ }
+
+ /* Subsequent pseudorotations, with right shifts */
+ i = 0;
+ do
+ {
+ if (theta < 0)
+ {
+ xtemp = x + (y >> i);
+ y = y - (x >> i);
+ x = xtemp;
+ theta += *arctanptr++;
+ }
+ else
+ {
+ xtemp = x - (y >> i);
+ y = y + (x >> i);
+ x = xtemp;
+ theta -= *arctanptr++;
+ }
+ }
+ while ( ++i < FT_TRIG_MAX_ITERS );
+
+ vec->x = x;
+ vec->y = y;
+ }
+
+
+ static void
+ ft_trig_pseudo_polarize( FT_Vector* vec )
+ {
+ FT_Fixed theta;
+ FT_Fixed yi, i;
+ FT_Fixed x, y;
+ const FT_Fixed *arctanptr;
+
+ x = vec->x;
+ y = vec->y;
+
+ /* Get the vector into the right half plane */
+ theta = 0;
+ if (x < 0)
+ {
+ x = -x;
+ y = -y;
+ theta = 2 * FT_ANGLE_PI2;
+ }
+
+ if (y > 0)
+ theta = - theta;
+
+ arctanptr = ft_trig_arctan_table;
+ if (y < 0)
+ {
+ /* Rotate positive */
+ yi = y + (x << 1);
+ x = x - (y << 1);
+ y = yi;
+ theta -= *arctanptr++; /* Subtract angle */
+ }
+ else
+ {
+ /* Rotate negative */
+ yi = y - (x << 1);
+ x = x + (y << 1);
+ y = yi;
+ theta += *arctanptr++; /* Add angle */
+ }
+
+ i = 0;
+ do
+ {
+ if (y < 0)
+ {
+ /* Rotate positive */
+ yi = y + (x >> i);
+ x = x - (y >> i);
+ y = yi;
+ theta -= *arctanptr++;
+ }
+ else
+ {
+ /* Rotate negative */
+ yi = y - (x >> i);
+ x = x + (y >> i);
+ y = yi;
+ theta += *arctanptr++;
+ }
+ }
+ while (++i < FT_TRIG_MAX_ITERS);
+
+ /* round theta */
+ if ( theta >= 0 )
+ theta = ( theta + 16 ) & -32;
+ else
+ theta = - (( -theta + 16 ) & -32);
+
+ vec->x = x;
+ vec->y = theta;
+ }
+
+
+ FT_EXPORT_DEF(FT_Fixed)
+ FT_Cos( FT_Angle angle )
+ {
+ FT_Vector v;
+
+ v.x = FT_TRIG_COSCALE >> 2;
+ v.y = 0;
+ ft_trig_pseudo_rotate( &v, angle );
+
+ return v.x >> 12;
+ }
+
+
+ FT_EXPORT_DEF(FT_Fixed)
+ FT_Sin( FT_Angle angle )
+ {
+ return FT_Cos( FT_ANGLE_PI2-angle );
+ }
+
+
+ FT_EXPORT_DEF(FT_Fixed)
+ FT_Tan( FT_Angle angle )
+ {
+ FT_Vector v;
+
+ v.x = FT_TRIG_COSCALE >> 2;
+ v.y = 0;
+ ft_trig_pseudo_rotate( &v, angle );
+
+ return FT_DivFix( v.y, v.x );
+ }
+
+
+
+ FT_EXPORT_DEF(FT_Angle)
+ FT_Atan2( FT_Fixed dx,
+ FT_Fixed dy )
+ {
+ FT_Vector v;
+
+ if ( dx == 0 && dy == 0 )
+ return 0;
+
+ v.x = dx;
+ v.y = dy;
+ ft_trig_prenorm( &v );
+ ft_trig_pseudo_polarize( &v );
+ return v.y;
+ }
+
+
+ FT_EXPORT_DEF(void)
+ FT_Vector_Unit( FT_Vector* vec,
+ FT_Angle angle )
+ {
+ vec->x = FT_TRIG_COSCALE >> 2;
+ vec->y = 0;
+ ft_trig_pseudo_rotate( vec, angle );
+ vec->x >>= 12;
+ vec->y >>= 12;
+ }
+
+
+ FT_EXPORT_DEF(void)
+ FT_Vector_Rotate( FT_Vector* vec,
+ FT_Angle angle )
+ {
+ FT_Int shift;
+ FT_Vector v;
+
+ v.x = vec->x;
+ v.y = vec->y;
+ if ( angle && ( v.x != 0 || v.y != 0 ) )
+ {
+ shift = ft_trig_prenorm( &v );
+ ft_trig_pseudo_rotate( &v, angle );
+ v.x = ft_trig_downscale( v.x );
+ v.y = ft_trig_downscale( v.y );
+
+ if ( shift >= 0 )
+ {
+ vec->x = v.x >> shift;
+ vec->y = v.y >> shift;
+ }
+ else
+ {
+ shift = -shift;
+ vec->x = v.x << shift;
+ vec->y = v.y << shift;
+ }
+ }
+ }
+
+
+ FT_EXPORT_DEF(FT_Fixed)
+ FT_Vector_Length( FT_Vector* vec )
+ {
+ FT_Int shift;
+ FT_Vector v;
+
+ v = *vec;
+
+ /* handle trivial cases */
+ if ( v.x == 0 )
+ {
+ return ( v.y >= 0 ) ? v.y : -v.y;
+ }
+ else if ( v.y == 0 )
+ {
+ return ( v.x >= 0 ) ? v.x : -v.x;
+ }
+
+ /* general case */
+ shift = ft_trig_prenorm( &v );
+ ft_trig_pseudo_polarize( &v );
+
+ v.x = ft_trig_downscale( v.x );
+ return ( shift >= 0 ) ? (v.x >> shift) : (v.x << -shift);
+ }
+
+
+ FT_EXPORT_DEF(void)
+ FT_Vector_Polarize( FT_Vector* vec,
+ FT_Fixed *length,
+ FT_Angle *angle )
+ {
+ FT_Int shift;
+ FT_Vector v;
+
+ v = *vec;
+
+ if ( v.x == 0 && v.y == 0 )
+ return;
+
+ shift = ft_trig_prenorm( &v );
+ ft_trig_pseudo_polarize( &v );
+
+ v.x = ft_trig_downscale( v.x );
+
+ *length = ( shift >= 0 ) ? (v.x >> shift) : (v.x << -shift);
+ *angle = v.y;
+ }
+
+
diff --git a/src/base/rules.mk b/src/base/rules.mk
index 7698c411c..440a2ffd3 100644
--- a/src/base/rules.mk
+++ b/src/base/rules.mk
@@ -33,6 +33,7 @@ BASE_COMPILE := $(FT_COMPILE) $I$(SRC_)base
# ftsystem, ftinit, and ftdebug are handled by freetype.mk
#
BASE_SRC := $(BASE_)ftcalc.c \
+ $(BASE_)fttrigon.c \
$(BASE_)ftextend.c \
$(BASE_)ftlist.c \
$(BASE_)ftobjs.c \
diff --git a/src/tools/cordic.py b/src/tools/cordic.py
new file mode 100644
index 000000000..515fbcc5d
--- /dev/null
+++ b/src/tools/cordic.py
@@ -0,0 +1,78 @@
+# compute arctangent table for CORDIC computations in fttrigon.c
+import sys, math
+
+units = 180*65536 # don't change !!
+scale = units/math.pi
+shrink = 1.0
+comma = ""
+
+def calc_val( x ):
+ global units, shrink
+ angle = math.atan(x)
+ shrink = shrink * math.cos(angle)
+ return angle/math.pi * units
+
+def print_val( n, x ):
+ global comma
+
+ lo = int(x)
+ hi = lo + 1
+ alo = math.atan(lo)
+ ahi = math.atan(hi)
+ ax = math.atan(2.0**n)
+
+ errlo = abs( alo - ax )
+ errhi = abs( ahi - ax )
+
+ if ( errlo < errhi ):
+ hi = lo
+
+ sys.stdout.write( comma + repr( int(hi) ) )
+ comma = ", "
+
+
+print ""
+print "table of arctan( 1/2^n ) for PI = " + repr(units/65536.0) + " units"
+
+# compute range of "i"
+r = [-1]
+r = r + range(32)
+
+for n in r:
+
+ if n >= 0:
+ x = 1.0/(2.0**n) # tangent value
+ else:
+ x = 2.0**(-n)
+
+ angle = math.atan(x) # arctangent
+ angle2 = angle*scale # arctangent in FT_Angle units
+
+ # determine which integer value for angle gives the best tangent
+ lo = int(angle2)
+ hi = lo + 1
+ tlo = math.tan(lo/scale)
+ thi = math.tan(hi/scale)
+
+ errlo = abs( tlo - x )
+ errhi = abs( thi - x )
+
+ angle2 = hi
+ if errlo < errhi:
+ angle2 = lo
+
+ if angle2 <= 0:
+ break
+
+ sys.stdout.write( comma + repr( int(angle2) ) )
+ comma = ", "
+
+ shrink = shrink * math.cos( angle2/scale)
+
+
+print
+print "shrink factor = " + repr( shrink )
+print "shrink factor 2 = " + repr( shrink * (2.0**32) )
+print "expansion factor = " + repr(1/shrink)
+print ""
+
\ No newline at end of file
diff --git a/docs/docmaker.py b/src/tools/docmaker.py
similarity index 99%
rename from docs/docmaker.py
rename to src/tools/docmaker.py
index 17288f31f..a20f22b5b 100644
--- a/docs/docmaker.py
+++ b/src/tools/docmaker.py
@@ -25,7 +25,7 @@
# - David
#
-import fileinput, sys, os, string, glob, getopt
+import fileinput, sys, os, time, string, glob, getopt
# The Project's title. This can be overridden from the command line with
# the options "-t" or "--title".
@@ -216,6 +216,11 @@ def check_output( ):
output_dir = None
+def compute_time_html( ):
+ global html_footer
+ time_string = time.asctime( time.localtime( time.time() ) )
+ html_footer = "generated on " + time_string + "
" + html_footer
+
# The FreeType 2 reference is extracted from the source files. These
# contain various comment blocks that follow one of the following formats:
#
@@ -1628,6 +1633,7 @@ def main( argv ):
html_header = html_header_1 + project_title + html_header_2 + project_title + html_header_3
check_output( )
+ compute_time_html()
# we begin by simply building a list of DocBlock elements
#
diff --git a/docs/glnames.py b/src/tools/glnames.py
similarity index 100%
rename from docs/glnames.py
rename to src/tools/glnames.py
diff --git a/src/tools/test_bbox.c b/src/tools/test_bbox.c
new file mode 100644
index 000000000..ec97a3899
--- /dev/null
+++ b/src/tools/test_bbox.c
@@ -0,0 +1,160 @@
+#include
+#include FT_FREETYPE_H
+#include FT_BBOX_H
+
+
+#include /* for clock() */
+
+/* SunOS 4.1.* does not define CLOCKS_PER_SEC, so include */
+/* to get the HZ macro which is the equivalent. */
+#if defined(__sun__) && !defined(SVR4) && !defined(__SVR4)
+#include
+#define CLOCKS_PER_SEC HZ
+#endif
+
+ static long
+ get_time( void )
+ {
+ return clock() * 10000L / CLOCKS_PER_SEC;
+ }
+
+
+
+
+ /* test bbox computations */
+
+#define XSCALE 65536
+#define XX(x) ((FT_Pos)(x*XSCALE))
+#define XVEC(x,y) { XX(x), XX(y) }
+#define XVAL(x) ((x)/(1.0*XSCALE))
+
+ /* dummy outline #1 */
+ static FT_Vector dummy_vec_1[4] =
+ {
+#if 1
+ XVEC( 408.9111, 535.3164 ),
+ XVEC( 455.8887, 634.396 ),
+ XVEC( -37.8765, 786.2207 ),
+ XVEC( 164.6074, 535.3164 )
+#else
+ { (FT_Int32)0x0198E93DL , (FT_Int32)0x021750FFL }, /* 408.9111, 535.3164 */
+ { (FT_Int32)0x01C7E312L , (FT_Int32)0x027A6560L }, /* 455.8887, 634.3960 */
+ { (FT_Int32)0xFFDA1F9EL , (FT_Int32)0x0312387FL }, /* -37.8765, 786.2207 */
+ { (FT_Int32)0x00A49B7EL , (FT_Int32)0x021750FFL } /* 164.6074, 535.3164 */
+#endif
+ };
+
+ static char dummy_tag_1[4] =
+ {
+ FT_Curve_Tag_On,
+ FT_Curve_Tag_Cubic,
+ FT_Curve_Tag_Cubic,
+ FT_Curve_Tag_On
+ };
+
+ static short dummy_contour_1[1] =
+ {
+ 3
+ };
+
+ static FT_Outline dummy_outline_1 =
+ {
+ 1,
+ 4,
+ dummy_vec_1,
+ dummy_tag_1,
+ dummy_contour_1,
+ 0
+ };
+
+
+ /* dummy outline #2 */
+ static FT_Vector dummy_vec_2[4] =
+ {
+ XVEC( 100.0, 100.0 ),
+ XVEC( 100.0, 200.0 ),
+ XVEC( 200.0, 200.0 ),
+ XVEC( 200.0, 133.0 )
+ };
+
+ static FT_Outline dummy_outline_2 =
+ {
+ 1,
+ 4,
+ dummy_vec_2,
+ dummy_tag_1,
+ dummy_contour_1,
+ 0
+ };
+
+
+ static void
+ dump_outline( FT_Outline* outline )
+ {
+ FT_BBox bbox;
+
+ /* compute and display cbox */
+ FT_Outline_Get_CBox( outline, &bbox );
+ printf( "cbox = [%.2f %.2f %.2f %.2f]\n",
+ XVAL( bbox.xMin ),
+ XVAL( bbox.yMin ),
+ XVAL( bbox.xMax ),
+ XVAL( bbox.yMax ) );
+
+ /* compute and display bbox */
+ FT_Outline_Get_BBox( outline, &bbox );
+ printf( "bbox = [%.2f %.2f %.2f %.2f]\n",
+ XVAL( bbox.xMin ),
+ XVAL( bbox.yMin ),
+ XVAL( bbox.xMax ),
+ XVAL( bbox.yMax ) );
+ }
+
+
+
+ static void
+ profile_outline( FT_Outline* outline,
+ long repeat )
+ {
+ FT_BBox bbox;
+ long count;
+ long time0;
+
+ time0 = get_time();
+ for ( count = repeat; count > 0; count-- )
+ FT_Outline_Get_CBox( outline, &bbox );
+
+ time0 = get_time() - time0;
+ printf( "time = %5.2f cbox = [%.2f %.2f %.2f %.2f]\n",
+ ((double)time0/10000.0),
+ XVAL( bbox.xMin ),
+ XVAL( bbox.yMin ),
+ XVAL( bbox.xMax ),
+ XVAL( bbox.yMax ) );
+
+
+ time0 = get_time();
+ for ( count = repeat; count > 0; count-- )
+ FT_Outline_Get_BBox( outline, &bbox );
+
+ time0 = get_time() - time0;
+ printf( "time = %5.2f bbox = [%.2f %.2f %.2f %.2f]\n",
+ ((double)time0/10000.0),
+ XVAL( bbox.xMin ),
+ XVAL( bbox.yMin ),
+ XVAL( bbox.xMax ),
+ XVAL( bbox.yMax ) );
+ }
+
+#define REPEAT 100000L
+
+ int main( int argc, char** argv )
+ {
+ printf( "outline #1\n" );
+ profile_outline( &dummy_outline_1, REPEAT );
+
+ printf( "outline #2\n" );
+ profile_outline( &dummy_outline_2, REPEAT );
+ return 0;
+ }
+
diff --git a/src/tools/test_trig.c b/src/tools/test_trig.c
new file mode 100644
index 000000000..e3399e7a6
--- /dev/null
+++ b/src/tools/test_trig.c
@@ -0,0 +1,236 @@
+#include
+#include FT_FREETYPE_H
+#include FT_TRIGONOMETRY_H
+
+#include
+#include
+
+#define PI 3.14159265358979323846
+#define SPI (PI/FT_ANGLE_PI)
+
+/* the precision in 16.16 fixed float points of the checks. Expect */
+/* between 2 and 5 noise LSB bits during operations, due to */
+/* rounding errors.. */
+#define THRESHOLD 64
+
+ static error = 0;
+
+ static void
+ test_cos( void )
+ {
+ FT_Fixed f1, f2;
+ double d1, d2;
+ int i;
+
+ for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000 )
+ {
+ f1 = FT_Cos(i);
+ d1 = f1/65536.0;
+ d2 = cos( i*SPI );
+ f2 = (FT_Fixed)(d2*65536.0);
+
+ if ( abs( f2-f1 ) > THRESHOLD )
+ {
+ error = 1;
+ printf( "FT_Cos[%3d] = %.7f cos[%3d] = %.7f\n",
+ (i >> 16), f1/65536.0, (i >> 16), d2 );
+ }
+ }
+ }
+
+
+
+ static void
+ test_sin( void )
+ {
+ FT_Fixed f1, f2;
+ double d1, d2;
+ int i;
+
+ for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000 )
+ {
+ f1 = FT_Sin(i);
+ d1 = f1/65536.0;
+ d2 = sin( i*SPI );
+ f2 = (FT_Fixed)(d2*65536.0);
+
+ if ( abs( f2-f1 ) > THRESHOLD )
+ {
+ error = 1;
+ printf( "FT_Sin[%3d] = %.7f sin[%3d] = %.7f\n",
+ (i >> 16), f1/65536.0, (i >> 16), d2 );
+ }
+ }
+ }
+
+
+ static void
+ test_tan( void )
+ {
+ FT_Fixed f1, f2;
+ double d1, d2;
+ int i;
+
+ for ( i = 0; i < FT_ANGLE_PI2-0x2000000; i += 0x10000 )
+ {
+ f1 = FT_Tan(i);
+ d1 = f1/65536.0;
+ d2 = tan( i*SPI );
+ f2 = (FT_Fixed)(d2*65536.0);
+
+ if ( abs( f2-f1 ) > THRESHOLD )
+ {
+ error = 1;
+ printf( "FT_Tan[%3d] = %.7f tan[%3d] = %.7f\n",
+ (i >> 16), f1/65536.0, (i >> 16), d2 );
+ }
+ }
+ }
+
+
+ static void
+ test_atan2( void )
+ {
+ FT_Fixed c2, s2;
+ double l, a, c1, s1;
+ int i, j;
+
+ for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000 )
+ {
+ l = 5.0;
+ a = i*SPI;
+
+ c1 = l * cos(a);
+ s1 = l * sin(a);
+
+ c2 = (FT_Fixed)(c1*65536.0);
+ s2 = (FT_Fixed)(s1*65536.0);
+
+ j = FT_Atan2( c2, s2 );
+ if ( j < 0 )
+ j += FT_ANGLE_2PI;
+
+ if ( abs( i - j ) > 1 )
+ {
+ printf( "FT_Atan2( %.7f, %.7f ) = %.5f, atan = %.5f\n",
+ c2/65536.0, s2/65536.0, j/65536.0, i/65536.0 );
+ }
+ }
+ }
+
+ static void
+ test_unit( void )
+ {
+ FT_Vector v;
+ double a, c1, s1;
+ FT_Fixed c2, s2;
+ int i;
+
+ for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000 )
+ {
+ FT_Vector_Unit( &v, i );
+ a = ( i*SPI );
+ c1 = cos(a);
+ s1 = sin(a);
+ c2 = (FT_Fixed)(c1*65536.0);
+ s2 = (FT_Fixed)(s1*65536.0);
+
+ if ( abs( v.x-c2 ) > THRESHOLD ||
+ abs( v.y-s2 ) > THRESHOLD )
+ {
+ error = 1;
+ printf( "FT_Vector_Unit[%3d] = ( %.7f, %.7f ) vec = ( %.7f, %.7f )\n",
+ (i >> 16),
+ v.x/65536.0, v.y/65536.0,
+ c1, s1 );
+ }
+ }
+ }
+
+
+ static void
+ test_length( void )
+ {
+ FT_Vector v;
+ FT_Fixed l, l2;
+ int i;
+
+ for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000 )
+ {
+ l = (FT_Fixed)(500.0*65536.0);
+ v.x = (FT_Fixed)( l * cos( i*SPI ) );
+ v.y = (FT_Fixed)( l * sin( i*SPI ) );
+ l2 = FT_Vector_Length( &v );
+
+ if ( abs( l2-l ) > THRESHOLD )
+ {
+ error = 1;
+ printf( "FT_Length( %.7f, %.7f ) = %.5f, length = %.5f\n",
+ v.x/65536.0, v.y/65536.0, l2/65536.0, l/65536.0 );
+ }
+ }
+ }
+
+
+ static void
+ test_rotate( void )
+ {
+ FT_Fixed c2, s2, c4, s4;
+ FT_Vector v;
+ double l, ra, a, c1, s1, cra, sra, c3, s3;
+ int i, j, rotate;
+
+ for ( rotate = 0; rotate < FT_ANGLE_2PI; rotate += 0x10000 )
+ {
+ ra = rotate*SPI;
+ cra = cos( ra );
+ sra = sin( ra );
+
+ for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000 )
+ {
+ l = 500.0;
+ a = i*SPI;
+
+ c1 = l * cos(a);
+ s1 = l * sin(a);
+
+ v.x = c2 = (FT_Fixed)(c1*65536.0);
+ v.y = s2 = (FT_Fixed)(s1*65536.0);
+
+ FT_Vector_Rotate( &v, rotate );
+
+ c3 = c1 * cra - s1 * sra;
+ s3 = c1 * sra + s1 * cra;
+
+ c4 = (FT_Fixed)(c3*65536.0);
+ s4 = (FT_Fixed)(s3*65536.0);
+
+ if ( abs( c4 - v.x ) > THRESHOLD ||
+ abs( s4 - v.y ) > THRESHOLD )
+ {
+ error = 1;
+ printf( "FT_Rotate( (%.7f,%.7f), %.5f ) = ( %.7f, %.7f ), rot = ( %.7f, %.7f )\n",
+ c1, s1, ra,
+ c2/65536.0, s2/65536.0,
+ c4/65536.0, s4/65536.0 );
+ }
+ }
+ }
+ }
+
+
+ int main( void )
+ {
+ test_cos();
+ test_sin();
+ test_tan();
+ test_atan2();
+ test_unit();
+ test_length();
+ test_rotate();
+
+ if (!error)
+ printf( "trigonometry test ok !\n" );
+
+ return !error;
+ }