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; + }