the following free software products:
Perl by Larry Wall
- gd library by Thomas Boutell
- gifcode from David Koblas
+ libart by Raph Levien
+ freetype by David Turner, Robert Wilhelm, and Werner Lemberg
libpng by Glenn Randers-Pehrson / Andreas Eric Dilger / Guy Eric Schalnat
cgilib by Martin Schulze
zlib by Jean-loup Gailly and Mark Adler
# makefiles and friends
set -x
#
-automake --foreign --verbose
-autoconf --localdir=./config
+find . -name Makefile | xargs rm
+find . -name Makefile.in | xargs rm
+
+# libtool 1.4.2
+libtoolize --automake
+# automake 2.12
+aclocal
+autoheader --warnings=all
+automake --foreign --add-missing --force-missing --copy
+# autoconf 2.52
+autoconf
+
+
CLEANFILES = config.cache
# use relaxed rules when building dists
-AUTOMAKE_OPTIONS= foreign no-dependencies
+AUTOMAKE_OPTIONS= foreign
# where we keep local rules for automake
-ACLOCAL_M4= $(top_srcdir)/config/aclocal.m4
+
+ACLOCAL_M4= $(top_srcdir)/aclocal.m4
AUTOHEADER = @AUTOHEADER@ --localdir=$(top_srcdir)/config
AUTOCONF = @AUTOCONF@ --localdir=$(top_srcdir)/config
In this file I am noting the Major changes to rrdtool
for details check the cvs ChangeLog
+2002/01/15 Tobias Oetiker <tobi@oetiker.ch>
+ The BIG graph update
+ * Replace libgd with libart
+ * Added freetype
+ * Updated zlib and libpng
+ * rrd_gfx.c intrduced as libart wrapper
+ * LINE takes now a float as argument
+ * rrdtool uses truetype for fonts
+ * thanks to libart there is now full alpha transparenc
+ and antialiasing.
+ * the new option --font lets customize the font
+ and size for various graph elements
+ * Updated to -> libtool 1.4.2 automake 2.12 autoconf 2.52
+ * new --zoom commandline option for zoom ans shrinking
+ ---- Still missing is rotatet text for the yaxis description
+ ---- Still missing is tab support in the text rendere
+ ---- Still missing is autoconf support for a default truetype font
2001/07/26 Alex van den Bogaerdt <alex@ergens.op.Het.Net>
Added TOTAL to the VDEF functions.
+++ /dev/null
-#ifndef CONFIG_H
-#define CONFIG_H
-
-@TOP@
-
-/* IEEE can be prevented from raising signals with fpsetmask(0) */
-#undef MUST_DISABLE_FPMASK
-
-/* IEEE math only works if SIGFPE gets actively set to IGNORE */
-
-#undef MUST_DISABLE_SIGFPE
-
-/* realloc does not support NULL as argument */
-#undef NO_NULL_REALLOC
-
-@BOTTOM@
-
-/* define strrchr, strchr and memcpy, memmove in terms of bsd funcs
- make sure you are NOT using bcopy, index or rindex in the code */
-
-#if STDC_HEADERS
-# include <string.h>
-#else
-# ifndef HAVE_STRCHR
-# define strchr index
-# define strrchr rindex
-# endif
-char *strchr (), *strrchr ();
-# ifndef HAVE_MEMMOVE
-# define memcpy(d, s, n) bcopy ((s), (d), (n))
-# define memmove(d, s, n) bcopy ((s), (d), (n))
-# endif
-#endif
-
-
-#if NO_NULL_REALLOC
-# define rrd_realloc(a,b) ( (a) == NULL ? malloc( (b) ) : realloc( (a) , (b) ))
-#else
-# define rrd_realloc(a,b) realloc((a), (b))
-#endif
-
-#if HAVE_MATH_H
-# include <math.h>
-#endif
-
-#if HAVE_FLOAT_H
-# include <float.h>
-#endif
-
-#if HAVE_IEEEFP_H
-# include <ieeefp.h>
-#endif
-
-#if HAVE_FP_CLASS_H
-# include <fp_class.h>
-#endif
-
-/* for Solaris */
-#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASS))
-# define HAVE_ISINF 1
-# define isinf(a) (fpclass(a) == FP_NINF || fpclass(a) == FP_PINF)
-#endif
-
-/* for OSF1 Digital Unix */
-#if (! defined(HAVE_ISINF) && defined(HAVE_FP_CLASS) && defined(HAVE_FP_CLASS_H))
-# define HAVE_ISINF 1
-# define isinf(a) (fp_class(a) == FP_NEG_INF || fp_class(a) == FP_POS_INF)
-#endif
-
-#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY) && defined(FP_PLUS_INF) && defined(FP_MINUS_INF))
-# define HAVE_ISINF 1
-# define isinf(a) (fpclassify(a) == FP_MINUS_INF || fpclassify(a) == FP_PLUS_INF)
-#endif
-
-#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY) && defined(FP_INFINITE))
-# define HAVE_ISINF 1
-# define isinf(a) (fpclassify(a) == FP_INFINITE)
-#endif
-
-/* for AIX */
-#if (! defined(HAVE_ISINF) && defined(HAVE_CLASS))
-# define HAVE_ISINF 1
-# define isinf(a) (class(a) == FP_MINUS_INF || class(a) == FP_PLUS_INF)
-#endif
-
-#if (! defined (HAVE_FINITE) && defined (HAVE_ISFINITE))
-# define HAVE_FINITE 1
-# define finite(a) isfinite(a)
-#endif
-
-#if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
-# define HAVE_FINITE 1
-# define finite(a) (! isnan(a) && ! isinf(a))
-#endif
-
-#ifndef HAVE_FINITE
-#error "Can't compile without finite function"
-#endif
-
-#ifndef HAVE_ISINF
-#error "Can't compile without isinf function"
-#endif
-
-#endif /* CONFIG_H */
-
+++ /dev/null
-dnl aclocal.m4 generated automatically by aclocal 1.4
-
-dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
-dnl This file is free software; the Free Software Foundation
-dnl gives unlimited permission to copy and/or distribute it,
-dnl with or without modifications, as long as this notice is preserved.
-
-dnl This program is distributed in the hope that it will be useful,
-dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-dnl PARTICULAR PURPOSE.
-
-# Do all the work for Automake. This macro actually does too much --
-# some checks are only needed if your package does certain things.
-# But this isn't really a big deal.
-
-# serial 1
-
-dnl Usage:
-dnl AM_INIT_AUTOMAKE(package,version, [no-define])
-
-AC_DEFUN(AM_INIT_AUTOMAKE,
-[AC_REQUIRE([AC_PROG_INSTALL])
-PACKAGE=[$1]
-AC_SUBST(PACKAGE)
-VERSION=[$2]
-AC_SUBST(VERSION)
-dnl test to see if srcdir already configured
-if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
- AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
-fi
-ifelse([$3],,
-AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
-AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package]))
-AC_REQUIRE([AM_SANITY_CHECK])
-AC_REQUIRE([AC_ARG_PROGRAM])
-dnl FIXME This is truly gross.
-missing_dir=`cd $ac_aux_dir && pwd`
-AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
-AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
-AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
-AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
-AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
-AC_REQUIRE([AC_PROG_MAKE_SET])])
-
-#
-# Check to make sure that the build environment is sane.
-#
-
-AC_DEFUN(AM_SANITY_CHECK,
-[AC_MSG_CHECKING([whether build environment is sane])
-# Just in case
-sleep 1
-echo timestamp > conftestfile
-# Do `set' in a subshell so we don't clobber the current shell's
-# arguments. Must try -L first in case configure is actually a
-# symlink; some systems play weird games with the mod time of symlinks
-# (eg FreeBSD returns the mod time of the symlink's containing
-# directory).
-if (
- set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
- if test "[$]*" = "X"; then
- # -L didn't work.
- set X `ls -t $srcdir/configure conftestfile`
- fi
- if test "[$]*" != "X $srcdir/configure conftestfile" \
- && test "[$]*" != "X conftestfile $srcdir/configure"; then
-
- # If neither matched, then we have a broken ls. This can happen
- # if, for instance, CONFIG_SHELL is bash and it inherits a
- # broken ls alias from the environment. This has actually
- # happened. Such a system could not be considered "sane".
- AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
-alias in your environment])
- fi
-
- test "[$]2" = conftestfile
- )
-then
- # Ok.
- :
-else
- AC_MSG_ERROR([newly created file is older than distributed files!
-Check your system clock])
-fi
-rm -f conftest*
-AC_MSG_RESULT(yes)])
-
-dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY)
-dnl The program must properly implement --version.
-AC_DEFUN(AM_MISSING_PROG,
-[AC_MSG_CHECKING(for working $2)
-# Run test in a subshell; some versions of sh will print an error if
-# an executable is not found, even if stderr is redirected.
-# Redirect stdin to placate older versions of autoconf. Sigh.
-if ($2 --version) < /dev/null > /dev/null 2>&1; then
- $1=$2
- AC_MSG_RESULT(found)
-else
- $1="$3/missing $2"
- AC_MSG_RESULT(missing)
-fi
-AC_SUBST($1)])
-
-# Like AC_CONFIG_HEADER, but automatically create stamp file.
-
-AC_DEFUN(AM_CONFIG_HEADER,
-[AC_PREREQ([2.12])
-AC_CONFIG_HEADER([$1])
-dnl When config.status generates a header, we must update the stamp-h file.
-dnl This file resides in the same directory as the config header
-dnl that is generated. We must strip everything past the first ":",
-dnl and everything past the last "/".
-AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl
-ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>,
-<<test -z "<<$>>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>,
-<<am_indx=1
-for am_file in <<$1>>; do
- case " <<$>>CONFIG_HEADERS " in
- *" <<$>>am_file "*<<)>>
- echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx
- ;;
- esac
- am_indx=`expr "<<$>>am_indx" + 1`
-done<<>>dnl>>)
-changequote([,]))])
-
-# Define a conditional.
-
-AC_DEFUN(AM_CONDITIONAL,
-[AC_SUBST($1_TRUE)
-AC_SUBST($1_FALSE)
-if $2; then
- $1_TRUE=
- $1_FALSE='#'
-else
- $1_TRUE='#'
- $1_FALSE=
-fi])
-
-
-# serial 40 AC_PROG_LIBTOOL
-AC_DEFUN(AC_PROG_LIBTOOL,
-[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl
-
-# Save cache, so that ltconfig can load it
-AC_CACHE_SAVE
-
-# Actually configure libtool. ac_aux_dir is where install-sh is found.
-CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \
-LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \
-LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" \
-DLLTOOL="$DLLTOOL" AS="$AS" OBJDUMP="$OBJDUMP" \
-${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig --no-reexec \
-$libtool_flags --no-verify $ac_aux_dir/ltmain.sh $lt_target \
-|| AC_MSG_ERROR([libtool configure failed])
-
-# Reload cache, that may have been modified by ltconfig
-AC_CACHE_LOAD
-
-# This can be used to rebuild libtool when needed
-LIBTOOL_DEPS="$ac_aux_dir/ltconfig $ac_aux_dir/ltmain.sh"
-
-# Always use our own libtool.
-LIBTOOL='$(SHELL) $(top_builddir)/libtool'
-AC_SUBST(LIBTOOL)dnl
-
-# Redirect the config.log output again, so that the ltconfig log is not
-# clobbered by the next message.
-exec 5>>./config.log
-])
-
-AC_DEFUN(AC_LIBTOOL_SETUP,
-[AC_PREREQ(2.13)dnl
-AC_REQUIRE([AC_ENABLE_SHARED])dnl
-AC_REQUIRE([AC_ENABLE_STATIC])dnl
-AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl
-AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-AC_REQUIRE([AC_PROG_RANLIB])dnl
-AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([AC_PROG_LD])dnl
-AC_REQUIRE([AC_PROG_NM])dnl
-AC_REQUIRE([AC_PROG_LN_S])dnl
-dnl
-
-case "$target" in
-NONE) lt_target="$host" ;;
-*) lt_target="$target" ;;
-esac
-
-# Check for any special flags to pass to ltconfig.
-libtool_flags="--cache-file=$cache_file"
-test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared"
-test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static"
-test "$enable_fast_install" = no && libtool_flags="$libtool_flags --disable-fast-install"
-test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc"
-test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld"
-ifdef([AC_PROVIDE_AC_LIBTOOL_DLOPEN],
-[libtool_flags="$libtool_flags --enable-dlopen"])
-ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL],
-[libtool_flags="$libtool_flags --enable-win32-dll"])
-AC_ARG_ENABLE(libtool-lock,
- [ --disable-libtool-lock avoid locking (might break parallel builds)])
-test "x$enable_libtool_lock" = xno && libtool_flags="$libtool_flags --disable-lock"
-test x"$silent" = xyes && libtool_flags="$libtool_flags --silent"
-
-# Some flags need to be propagated to the compiler or linker for good
-# libtool support.
-case "$lt_target" in
-*-*-irix6*)
- # Find out which ABI we are using.
- echo '[#]line __oline__ "configure"' > conftest.$ac_ext
- if AC_TRY_EVAL(ac_compile); then
- case "`/usr/bin/file conftest.o`" in
- *32-bit*)
- LD="${LD-ld} -32"
- ;;
- *N32*)
- LD="${LD-ld} -n32"
- ;;
- *64-bit*)
- LD="${LD-ld} -64"
- ;;
- esac
- fi
- rm -rf conftest*
- ;;
-
-*-*-sco3.2v5*)
- # On SCO OpenServer 5, we need -belf to get full-featured binaries.
- SAVE_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS -belf"
- AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
- [AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])])
- if test x"$lt_cv_cc_needs_belf" != x"yes"; then
- # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
- CFLAGS="$SAVE_CFLAGS"
- fi
- ;;
-
-ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL],
-[*-*-cygwin* | *-*-mingw*)
- AC_CHECK_TOOL(DLLTOOL, dlltool, false)
- AC_CHECK_TOOL(AS, as, false)
- AC_CHECK_TOOL(OBJDUMP, objdump, false)
- ;;
-])
-esac
-])
-
-# AC_LIBTOOL_DLOPEN - enable checks for dlopen support
-AC_DEFUN(AC_LIBTOOL_DLOPEN, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])])
-
-# AC_LIBTOOL_WIN32_DLL - declare package support for building win32 dll's
-AC_DEFUN(AC_LIBTOOL_WIN32_DLL, [AC_BEFORE([$0], [AC_LIBTOOL_SETUP])])
-
-# AC_ENABLE_SHARED - implement the --enable-shared flag
-# Usage: AC_ENABLE_SHARED[(DEFAULT)]
-# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to
-# `yes'.
-AC_DEFUN(AC_ENABLE_SHARED, [dnl
-define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl
-AC_ARG_ENABLE(shared,
-changequote(<<, >>)dnl
-<< --enable-shared[=PKGS] build shared libraries [default=>>AC_ENABLE_SHARED_DEFAULT],
-changequote([, ])dnl
-[p=${PACKAGE-default}
-case "$enableval" in
-yes) enable_shared=yes ;;
-no) enable_shared=no ;;
-*)
- enable_shared=no
- # Look at the argument we got. We use all the common list separators.
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
- for pkg in $enableval; do
- if test "X$pkg" = "X$p"; then
- enable_shared=yes
- fi
- done
- IFS="$ac_save_ifs"
- ;;
-esac],
-enable_shared=AC_ENABLE_SHARED_DEFAULT)dnl
-])
-
-# AC_DISABLE_SHARED - set the default shared flag to --disable-shared
-AC_DEFUN(AC_DISABLE_SHARED, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
-AC_ENABLE_SHARED(no)])
-
-# AC_ENABLE_STATIC - implement the --enable-static flag
-# Usage: AC_ENABLE_STATIC[(DEFAULT)]
-# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to
-# `yes'.
-AC_DEFUN(AC_ENABLE_STATIC, [dnl
-define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl
-AC_ARG_ENABLE(static,
-changequote(<<, >>)dnl
-<< --enable-static[=PKGS] build static libraries [default=>>AC_ENABLE_STATIC_DEFAULT],
-changequote([, ])dnl
-[p=${PACKAGE-default}
-case "$enableval" in
-yes) enable_static=yes ;;
-no) enable_static=no ;;
-*)
- enable_static=no
- # Look at the argument we got. We use all the common list separators.
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
- for pkg in $enableval; do
- if test "X$pkg" = "X$p"; then
- enable_static=yes
- fi
- done
- IFS="$ac_save_ifs"
- ;;
-esac],
-enable_static=AC_ENABLE_STATIC_DEFAULT)dnl
-])
-
-# AC_DISABLE_STATIC - set the default static flag to --disable-static
-AC_DEFUN(AC_DISABLE_STATIC, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
-AC_ENABLE_STATIC(no)])
-
-
-# AC_ENABLE_FAST_INSTALL - implement the --enable-fast-install flag
-# Usage: AC_ENABLE_FAST_INSTALL[(DEFAULT)]
-# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to
-# `yes'.
-AC_DEFUN(AC_ENABLE_FAST_INSTALL, [dnl
-define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl
-AC_ARG_ENABLE(fast-install,
-changequote(<<, >>)dnl
-<< --enable-fast-install[=PKGS] optimize for fast installation [default=>>AC_ENABLE_FAST_INSTALL_DEFAULT],
-changequote([, ])dnl
-[p=${PACKAGE-default}
-case "$enableval" in
-yes) enable_fast_install=yes ;;
-no) enable_fast_install=no ;;
-*)
- enable_fast_install=no
- # Look at the argument we got. We use all the common list separators.
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:,"
- for pkg in $enableval; do
- if test "X$pkg" = "X$p"; then
- enable_fast_install=yes
- fi
- done
- IFS="$ac_save_ifs"
- ;;
-esac],
-enable_fast_install=AC_ENABLE_FAST_INSTALL_DEFAULT)dnl
-])
-
-# AC_ENABLE_FAST_INSTALL - set the default to --disable-fast-install
-AC_DEFUN(AC_DISABLE_FAST_INSTALL, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
-AC_ENABLE_FAST_INSTALL(no)])
-
-# AC_PROG_LD - find the path to the GNU or non-GNU linker
-AC_DEFUN(AC_PROG_LD,
-[AC_ARG_WITH(gnu-ld,
-[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]],
-test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no)
-AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-ac_prog=ld
-if test "$ac_cv_prog_gcc" = yes; then
- # Check if gcc -print-prog-name=ld gives a path.
- AC_MSG_CHECKING([for ld used by GCC])
- ac_prog=`($CC -print-prog-name=ld) 2>&5`
- case "$ac_prog" in
- # Accept absolute paths.
-changequote(,)dnl
- [\\/]* | [A-Za-z]:[\\/]*)
- re_direlt='/[^/][^/]*/\.\./'
-changequote([,])dnl
- # Canonicalize the path of ld
- ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
- while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
- ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
- done
- test -z "$LD" && LD="$ac_prog"
- ;;
- "")
- # If it fails, then pretend we aren't using GCC.
- ac_prog=ld
- ;;
- *)
- # If it is relative, then search for the first ld in PATH.
- with_gnu_ld=unknown
- ;;
- esac
-elif test "$with_gnu_ld" = yes; then
- AC_MSG_CHECKING([for GNU ld])
-else
- AC_MSG_CHECKING([for non-GNU ld])
-fi
-AC_CACHE_VAL(ac_cv_path_LD,
-[if test -z "$LD"; then
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
- for ac_dir in $PATH; do
- test -z "$ac_dir" && ac_dir=.
- if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
- ac_cv_path_LD="$ac_dir/$ac_prog"
- # Check to see if the program is GNU ld. I'd rather use --version,
- # but apparently some GNU ld's only accept -v.
- # Break only if it was the GNU/non-GNU ld that we prefer.
- if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then
- test "$with_gnu_ld" != no && break
- else
- test "$with_gnu_ld" != yes && break
- fi
- fi
- done
- IFS="$ac_save_ifs"
-else
- ac_cv_path_LD="$LD" # Let the user override the test with a path.
-fi])
-LD="$ac_cv_path_LD"
-if test -n "$LD"; then
- AC_MSG_RESULT($LD)
-else
- AC_MSG_RESULT(no)
-fi
-test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
-AC_PROG_LD_GNU
-])
-
-AC_DEFUN(AC_PROG_LD_GNU,
-[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], ac_cv_prog_gnu_ld,
-[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
-if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then
- ac_cv_prog_gnu_ld=yes
-else
- ac_cv_prog_gnu_ld=no
-fi])
-])
-
-# AC_PROG_NM - find the path to a BSD-compatible name lister
-AC_DEFUN(AC_PROG_NM,
-[AC_MSG_CHECKING([for BSD-compatible nm])
-AC_CACHE_VAL(ac_cv_path_NM,
-[if test -n "$NM"; then
- # Let the user override the test.
- ac_cv_path_NM="$NM"
-else
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
- for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/nm || test -f $ac_dir/nm$ac_exeext ; then
- # Check to see if the nm accepts a BSD-compat flag.
- # Adding the `sed 1q' prevents false positives on HP-UX, which says:
- # nm: unknown option "B" ignored
- if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
- ac_cv_path_NM="$ac_dir/nm -B"
- break
- elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
- ac_cv_path_NM="$ac_dir/nm -p"
- break
- else
- ac_cv_path_NM=${ac_cv_path_NM="$ac_dir/nm"} # keep the first match, but
- continue # so that we can try to find one that supports BSD flags
- fi
- fi
- done
- IFS="$ac_save_ifs"
- test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm
-fi])
-NM="$ac_cv_path_NM"
-AC_MSG_RESULT([$NM])
-])
-
-# AC_CHECK_LIBM - check for math library
-AC_DEFUN(AC_CHECK_LIBM,
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-LIBM=
-case "$lt_target" in
-*-*-beos* | *-*-cygwin*)
- # These system don't have libm
- ;;
-*-ncr-sysv4.3*)
- AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
- AC_CHECK_LIB(m, main, LIBM="$LIBM -lm")
- ;;
-*)
- AC_CHECK_LIB(m, main, LIBM="-lm")
- ;;
-esac
-])
-
-# AC_LIBLTDL_CONVENIENCE[(dir)] - sets LIBLTDL to the link flags for
-# the libltdl convenience library, adds --enable-ltdl-convenience to
-# the configure arguments. Note that LIBLTDL is not AC_SUBSTed, nor
-# is AC_CONFIG_SUBDIRS called. If DIR is not provided, it is assumed
-# to be `${top_builddir}/libltdl'. Make sure you start DIR with
-# '${top_builddir}/' (note the single quotes!) if your package is not
-# flat, and, if you're not using automake, define top_builddir as
-# appropriate in the Makefiles.
-AC_DEFUN(AC_LIBLTDL_CONVENIENCE, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
- case "$enable_ltdl_convenience" in
- no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;;
- "") enable_ltdl_convenience=yes
- ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;;
- esac
- LIBLTDL=ifelse($#,1,$1,['${top_builddir}/libltdl'])/libltdlc.la
- INCLTDL=ifelse($#,1,-I$1,['-I${top_builddir}/libltdl'])
-])
-
-# AC_LIBLTDL_INSTALLABLE[(dir)] - sets LIBLTDL to the link flags for
-# the libltdl installable library, and adds --enable-ltdl-install to
-# the configure arguments. Note that LIBLTDL is not AC_SUBSTed, nor
-# is AC_CONFIG_SUBDIRS called. If DIR is not provided, it is assumed
-# to be `${top_builddir}/libltdl'. Make sure you start DIR with
-# '${top_builddir}/' (note the single quotes!) if your package is not
-# flat, and, if you're not using automake, define top_builddir as
-# appropriate in the Makefiles.
-# In the future, this macro may have to be called after AC_PROG_LIBTOOL.
-AC_DEFUN(AC_LIBLTDL_INSTALLABLE, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl
- AC_CHECK_LIB(ltdl, main,
- [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no],
- [if test x"$enable_ltdl_install" = xno; then
- AC_MSG_WARN([libltdl not installed, but installation disabled])
- else
- enable_ltdl_install=yes
- fi
- ])
- if test x"$enable_ltdl_install" = x"yes"; then
- ac_configure_args="$ac_configure_args --enable-ltdl-install"
- LIBLTDL=ifelse($#,1,$1,['${top_builddir}/libltdl'])/libltdl.la
- INCLTDL=ifelse($#,1,-I$1,['-I${top_builddir}/libltdl'])
- else
- ac_configure_args="$ac_configure_args --enable-ltdl-install=no"
- LIBLTDL="-lltdl"
- INCLTDL=
- fi
-])
-
-dnl old names
-AC_DEFUN(AM_PROG_LIBTOOL, [indir([AC_PROG_LIBTOOL])])dnl
-AC_DEFUN(AM_ENABLE_SHARED, [indir([AC_ENABLE_SHARED], $@)])dnl
-AC_DEFUN(AM_ENABLE_STATIC, [indir([AC_ENABLE_STATIC], $@)])dnl
-AC_DEFUN(AM_DISABLE_SHARED, [indir([AC_DISABLE_SHARED], $@)])dnl
-AC_DEFUN(AM_DISABLE_STATIC, [indir([AC_DISABLE_STATIC], $@)])dnl
-AC_DEFUN(AM_PROG_LD, [indir([AC_PROG_LD])])dnl
-AC_DEFUN(AM_PROG_NM, [indir([AC_PROG_NM])])dnl
-
-dnl This is just to silence aclocal about the macro not being used
-ifelse([AC_DISABLE_FAST_INSTALL])dnl
-
+++ /dev/null
-#! /bin/sh
-# Attempt to guess a canonical system name.
-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999
-# Free Software Foundation, Inc.
-#
-# This file is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# Written by Per Bothner <bothner@cygnus.com>.
-# The master version of this file is at the FSF in /home/gd/gnu/lib.
-# Please send patches to the Autoconf mailing list <autoconf@gnu.org>.
-#
-# This script attempts to guess a canonical system name similar to
-# config.sub. If it succeeds, it prints the system name on stdout, and
-# exits with 0. Otherwise, it exits with 1.
-#
-# The plan is that this can be called by configure scripts if you
-# don't specify an explicit system type (host/target name).
-#
-# Only a few systems have been added to this list; please add others
-# (but try to keep the structure clean).
-#
-
-# Use $HOST_CC if defined. $CC may point to a cross-compiler
-if test x"$CC_FOR_BUILD" = x; then
- if test x"$HOST_CC" != x; then
- CC_FOR_BUILD="$HOST_CC"
- else
- if test x"$CC" != x; then
- CC_FOR_BUILD="$CC"
- else
- CC_FOR_BUILD=cc
- fi
- fi
-fi
-
-
-# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
-# (ghazi@noc.rutgers.edu 8/24/94.)
-if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
- PATH=$PATH:/.attbin ; export PATH
-fi
-
-UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
-UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
-UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
-UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
-
-dummy=dummy-$$
-trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15
-
-# Note: order is significant - the case branches are not exclusive.
-
-case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
- alpha:OSF1:*:*)
- if test $UNAME_RELEASE = "V4.0"; then
- UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
- fi
- # A Vn.n version is a released version.
- # A Tn.n version is a released field test version.
- # A Xn.n version is an unreleased experimental baselevel.
- # 1.2 uses "1.2" for uname -r.
- cat <<EOF >$dummy.s
- .globl main
- .ent main
-main:
- .frame \$30,0,\$26,0
- .prologue 0
- .long 0x47e03d80 # implver $0
- lda \$2,259
- .long 0x47e20c21 # amask $2,$1
- srl \$1,8,\$2
- sll \$2,2,\$2
- sll \$0,3,\$0
- addl \$1,\$0,\$0
- addl \$2,\$0,\$0
- ret \$31,(\$26),1
- .end main
-EOF
- $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
- if test "$?" = 0 ; then
- ./$dummy
- case "$?" in
- 7)
- UNAME_MACHINE="alpha"
- ;;
- 15)
- UNAME_MACHINE="alphaev5"
- ;;
- 14)
- UNAME_MACHINE="alphaev56"
- ;;
- 10)
- UNAME_MACHINE="alphapca56"
- ;;
- 16)
- UNAME_MACHINE="alphaev6"
- ;;
- esac
- fi
- rm -f $dummy.s $dummy
- echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- exit 0 ;;
- Alpha\ *:Windows_NT*:*)
- # How do we know it's Interix rather than the generic POSIX subsystem?
- # Should we change UNAME_MACHINE based on the output of uname instead
- # of the specific Alpha model?
- echo alpha-pc-interix
- exit 0 ;;
- 21064:Windows_NT:50:3)
- echo alpha-dec-winnt3.5
- exit 0 ;;
- Amiga*:UNIX_System_V:4.0:*)
- echo m68k-cbm-sysv4
- exit 0;;
- amiga:NetBSD:*:*)
- echo m68k-cbm-netbsd${UNAME_RELEASE}
- exit 0 ;;
- amiga:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- *:[Aa]miga[Oo][Ss]:*:*)
- echo ${UNAME_MACHINE}-unknown-amigaos
- exit 0 ;;
- arc64:OpenBSD:*:*)
- echo mips64el-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- arc:OpenBSD:*:*)
- echo mipsel-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- hkmips:OpenBSD:*:*)
- echo mips-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- pmax:OpenBSD:*:*)
- echo mipsel-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- sgi:OpenBSD:*:*)
- echo mips-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- wgrisc:OpenBSD:*:*)
- echo mipsel-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
- echo arm-acorn-riscix${UNAME_RELEASE}
- exit 0;;
- arm32:NetBSD:*:*)
- echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
- exit 0 ;;
- SR2?01:HI-UX/MPP:*:*)
- echo hppa1.1-hitachi-hiuxmpp
- exit 0;;
- Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
- # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
- if test "`(/bin/universe) 2>/dev/null`" = att ; then
- echo pyramid-pyramid-sysv3
- else
- echo pyramid-pyramid-bsd
- fi
- exit 0 ;;
- NILE*:*:*:dcosx)
- echo pyramid-pyramid-svr4
- exit 0 ;;
- sun4H:SunOS:5.*:*)
- echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit 0 ;;
- sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
- echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit 0 ;;
- i86pc:SunOS:5.*:*)
- echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit 0 ;;
- sun4*:SunOS:6*:*)
- # According to config.sub, this is the proper way to canonicalize
- # SunOS6. Hard to guess exactly what SunOS6 will be like, but
- # it's likely to be more like Solaris than SunOS4.
- echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit 0 ;;
- sun4*:SunOS:*:*)
- case "`/usr/bin/arch -k`" in
- Series*|S4*)
- UNAME_RELEASE=`uname -v`
- ;;
- esac
- # Japanese Language versions have a version number like `4.1.3-JL'.
- echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
- exit 0 ;;
- sun3*:SunOS:*:*)
- echo m68k-sun-sunos${UNAME_RELEASE}
- exit 0 ;;
- sun*:*:4.2BSD:*)
- UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
- test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
- case "`/bin/arch`" in
- sun3)
- echo m68k-sun-sunos${UNAME_RELEASE}
- ;;
- sun4)
- echo sparc-sun-sunos${UNAME_RELEASE}
- ;;
- esac
- exit 0 ;;
- aushp:SunOS:*:*)
- echo sparc-auspex-sunos${UNAME_RELEASE}
- exit 0 ;;
- atari*:NetBSD:*:*)
- echo m68k-atari-netbsd${UNAME_RELEASE}
- exit 0 ;;
- atari*:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- # The situation for MiNT is a little confusing. The machine name
- # can be virtually everything (everything which is not
- # "atarist" or "atariste" at least should have a processor
- # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
- # to the lowercase version "mint" (or "freemint"). Finally
- # the system name "TOS" denotes a system which is actually not
- # MiNT. But MiNT is downward compatible to TOS, so this should
- # be no problem.
- atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
- exit 0 ;;
- atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
- exit 0 ;;
- *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
- exit 0 ;;
- milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
- echo m68k-milan-mint${UNAME_RELEASE}
- exit 0 ;;
- hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
- echo m68k-hades-mint${UNAME_RELEASE}
- exit 0 ;;
- *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
- echo m68k-unknown-mint${UNAME_RELEASE}
- exit 0 ;;
- sun3*:NetBSD:*:*)
- echo m68k-sun-netbsd${UNAME_RELEASE}
- exit 0 ;;
- sun3*:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- mac68k:NetBSD:*:*)
- echo m68k-apple-netbsd${UNAME_RELEASE}
- exit 0 ;;
- mac68k:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- mvme68k:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- mvme88k:OpenBSD:*:*)
- echo m88k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- powerpc:machten:*:*)
- echo powerpc-apple-machten${UNAME_RELEASE}
- exit 0 ;;
- macppc:NetBSD:*:*)
- echo powerpc-apple-netbsd${UNAME_RELEASE}
- exit 0 ;;
- RISC*:Mach:*:*)
- echo mips-dec-mach_bsd4.3
- exit 0 ;;
- RISC*:ULTRIX:*:*)
- echo mips-dec-ultrix${UNAME_RELEASE}
- exit 0 ;;
- VAX*:ULTRIX*:*:*)
- echo vax-dec-ultrix${UNAME_RELEASE}
- exit 0 ;;
- 2020:CLIX:*:* | 2430:CLIX:*:*)
- echo clipper-intergraph-clix${UNAME_RELEASE}
- exit 0 ;;
- mips:*:*:UMIPS | mips:*:*:RISCos)
- sed 's/^ //' << EOF >$dummy.c
-#ifdef __cplusplus
- int main (int argc, char *argv[]) {
-#else
- int main (argc, argv) int argc; char *argv[]; {
-#endif
- #if defined (host_mips) && defined (MIPSEB)
- #if defined (SYSTYPE_SYSV)
- printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
- #endif
- #if defined (SYSTYPE_SVR4)
- printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
- #endif
- #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
- printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
- #endif
- #endif
- exit (-1);
- }
-EOF
- $CC_FOR_BUILD $dummy.c -o $dummy \
- && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
- && rm $dummy.c $dummy && exit 0
- rm -f $dummy.c $dummy
- echo mips-mips-riscos${UNAME_RELEASE}
- exit 0 ;;
- Night_Hawk:Power_UNIX:*:*)
- echo powerpc-harris-powerunix
- exit 0 ;;
- m88k:CX/UX:7*:*)
- echo m88k-harris-cxux7
- exit 0 ;;
- m88k:*:4*:R4*)
- echo m88k-motorola-sysv4
- exit 0 ;;
- m88k:*:3*:R3*)
- echo m88k-motorola-sysv3
- exit 0 ;;
- AViiON:dgux:*:*)
- # DG/UX returns AViiON for all architectures
- UNAME_PROCESSOR=`/usr/bin/uname -p`
- if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then
- if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
- -o ${TARGET_BINARY_INTERFACE}x = x ] ; then
- echo m88k-dg-dgux${UNAME_RELEASE}
- else
- echo m88k-dg-dguxbcs${UNAME_RELEASE}
- fi
- else echo i586-dg-dgux${UNAME_RELEASE}
- fi
- exit 0 ;;
- M88*:DolphinOS:*:*) # DolphinOS (SVR3)
- echo m88k-dolphin-sysv3
- exit 0 ;;
- M88*:*:R3*:*)
- # Delta 88k system running SVR3
- echo m88k-motorola-sysv3
- exit 0 ;;
- XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
- echo m88k-tektronix-sysv3
- exit 0 ;;
- Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
- echo m68k-tektronix-bsd
- exit 0 ;;
- *:IRIX*:*:*)
- echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
- exit 0 ;;
- ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
- echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
- exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
- i?86:AIX:*:*)
- echo i386-ibm-aix
- exit 0 ;;
- *:AIX:2:3)
- if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
- sed 's/^ //' << EOF >$dummy.c
- #include <sys/systemcfg.h>
-
- main()
- {
- if (!__power_pc())
- exit(1);
- puts("powerpc-ibm-aix3.2.5");
- exit(0);
- }
-EOF
- $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
- rm -f $dummy.c $dummy
- echo rs6000-ibm-aix3.2.5
- elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
- echo rs6000-ibm-aix3.2.4
- else
- echo rs6000-ibm-aix3.2
- fi
- exit 0 ;;
- *:AIX:*:4)
- IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
- if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then
- IBM_ARCH=rs6000
- else
- IBM_ARCH=powerpc
- fi
- if [ -x /usr/bin/oslevel ] ; then
- IBM_REV=`/usr/bin/oslevel`
- else
- IBM_REV=4.${UNAME_RELEASE}
- fi
- echo ${IBM_ARCH}-ibm-aix${IBM_REV}
- exit 0 ;;
- *:AIX:*:*)
- echo rs6000-ibm-aix
- exit 0 ;;
- ibmrt:4.4BSD:*|romp-ibm:BSD:*)
- echo romp-ibm-bsd4.4
- exit 0 ;;
- ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and
- echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
- exit 0 ;; # report: romp-ibm BSD 4.3
- *:BOSX:*:*)
- echo rs6000-bull-bosx
- exit 0 ;;
- DPX/2?00:B.O.S.:*:*)
- echo m68k-bull-sysv3
- exit 0 ;;
- 9000/[34]??:4.3bsd:1.*:*)
- echo m68k-hp-bsd
- exit 0 ;;
- hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
- echo m68k-hp-bsd4.4
- exit 0 ;;
- 9000/[34678]??:HP-UX:*:*)
- case "${UNAME_MACHINE}" in
- 9000/31? ) HP_ARCH=m68000 ;;
- 9000/[34]?? ) HP_ARCH=m68k ;;
- 9000/[678][0-9][0-9])
- sed 's/^ //' << EOF >$dummy.c
- #include <stdlib.h>
- #include <unistd.h>
-
- int main ()
- {
- #if defined(_SC_KERNEL_BITS)
- long bits = sysconf(_SC_KERNEL_BITS);
- #endif
- long cpu = sysconf (_SC_CPU_VERSION);
-
- switch (cpu)
- {
- case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
- case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
- case CPU_PA_RISC2_0:
- #if defined(_SC_KERNEL_BITS)
- switch (bits)
- {
- case 64: puts ("hppa2.0w"); break;
- case 32: puts ("hppa2.0n"); break;
- default: puts ("hppa2.0"); break;
- } break;
- #else /* !defined(_SC_KERNEL_BITS) */
- puts ("hppa2.0"); break;
- #endif
- default: puts ("hppa1.0"); break;
- }
- exit (0);
- }
-EOF
- ($CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
- rm -f $dummy.c $dummy
- esac
- HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
- echo ${HP_ARCH}-hp-hpux${HPUX_REV}
- exit 0 ;;
- 3050*:HI-UX:*:*)
- sed 's/^ //' << EOF >$dummy.c
- #include <unistd.h>
- int
- main ()
- {
- long cpu = sysconf (_SC_CPU_VERSION);
- /* The order matters, because CPU_IS_HP_MC68K erroneously returns
- true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
- results, however. */
- if (CPU_IS_PA_RISC (cpu))
- {
- switch (cpu)
- {
- case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
- case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
- case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
- default: puts ("hppa-hitachi-hiuxwe2"); break;
- }
- }
- else if (CPU_IS_HP_MC68K (cpu))
- puts ("m68k-hitachi-hiuxwe2");
- else puts ("unknown-hitachi-hiuxwe2");
- exit (0);
- }
-EOF
- $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
- rm -f $dummy.c $dummy
- echo unknown-hitachi-hiuxwe2
- exit 0 ;;
- 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
- echo hppa1.1-hp-bsd
- exit 0 ;;
- 9000/8??:4.3bsd:*:*)
- echo hppa1.0-hp-bsd
- exit 0 ;;
- *9??*:MPE/iX:*:*)
- echo hppa1.0-hp-mpeix
- exit 0 ;;
- hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
- echo hppa1.1-hp-osf
- exit 0 ;;
- hp8??:OSF1:*:*)
- echo hppa1.0-hp-osf
- exit 0 ;;
- i?86:OSF1:*:*)
- if [ -x /usr/sbin/sysversion ] ; then
- echo ${UNAME_MACHINE}-unknown-osf1mk
- else
- echo ${UNAME_MACHINE}-unknown-osf1
- fi
- exit 0 ;;
- parisc*:Lites*:*:*)
- echo hppa1.1-hp-lites
- exit 0 ;;
- hppa*:OpenBSD:*:*)
- echo hppa-unknown-openbsd
- exit 0 ;;
- C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
- echo c1-convex-bsd
- exit 0 ;;
- C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
- if getsysinfo -f scalar_acc
- then echo c32-convex-bsd
- else echo c2-convex-bsd
- fi
- exit 0 ;;
- C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
- echo c34-convex-bsd
- exit 0 ;;
- C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
- echo c38-convex-bsd
- exit 0 ;;
- C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
- echo c4-convex-bsd
- exit 0 ;;
- CRAY*X-MP:*:*:*)
- echo xmp-cray-unicos
- exit 0 ;;
- CRAY*Y-MP:*:*:*)
- echo ymp-cray-unicos${UNAME_RELEASE}
- exit 0 ;;
- CRAY*[A-Z]90:*:*:*)
- echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
- | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
- -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
- exit 0 ;;
- CRAY*TS:*:*:*)
- echo t90-cray-unicos${UNAME_RELEASE}
- exit 0 ;;
- CRAY*T3E:*:*:*)
- echo t3e-cray-unicosmk${UNAME_RELEASE}
- exit 0 ;;
- CRAY-2:*:*:*)
- echo cray2-cray-unicos
- exit 0 ;;
- F300:UNIX_System_V:*:*)
- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
- FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
- echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
- exit 0 ;;
- F301:UNIX_System_V:*:*)
- echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'`
- exit 0 ;;
- hp3[0-9][05]:NetBSD:*:*)
- echo m68k-hp-netbsd${UNAME_RELEASE}
- exit 0 ;;
- hp300:OpenBSD:*:*)
- echo m68k-unknown-openbsd${UNAME_RELEASE}
- exit 0 ;;
- i?86:BSD/386:*:* | i?86:BSD/OS:*:*)
- echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
- exit 0 ;;
- sparc*:BSD/OS:*:*)
- echo sparc-unknown-bsdi${UNAME_RELEASE}
- exit 0 ;;
- *:BSD/OS:*:*)
- echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
- exit 0 ;;
- *:FreeBSD:*:*)
- if test -x /usr/bin/objformat; then
- if test "elf" = "`/usr/bin/objformat`"; then
- echo ${UNAME_MACHINE}-unknown-freebsdelf`echo ${UNAME_RELEASE}|sed -e 's/[-_].*//'`
- exit 0
- fi
- fi
- echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
- exit 0 ;;
- *:NetBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
- exit 0 ;;
- *:OpenBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
- exit 0 ;;
- i*:CYGWIN*:*)
- echo ${UNAME_MACHINE}-pc-cygwin
- exit 0 ;;
- i*:MINGW*:*)
- echo ${UNAME_MACHINE}-pc-mingw32
- exit 0 ;;
- i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
- # How do we know it's Interix rather than the generic POSIX subsystem?
- # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
- # UNAME_MACHINE based on the output of uname instead of i386?
- echo i386-pc-interix
- exit 0 ;;
- i*:UWIN*:*)
- echo ${UNAME_MACHINE}-pc-uwin
- exit 0 ;;
- p*:CYGWIN*:*)
- echo powerpcle-unknown-cygwin
- exit 0 ;;
- prep*:SunOS:5.*:*)
- echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit 0 ;;
- *:GNU:*:*)
- echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
- exit 0 ;;
- *:Linux:*:*)
- # uname on the ARM produces all sorts of strangeness, and we need to
- # filter it out.
- case "$UNAME_MACHINE" in
- armv*) UNAME_MACHINE=$UNAME_MACHINE ;;
- arm* | sa110*) UNAME_MACHINE="arm" ;;
- esac
-
- # The BFD linker knows what the default object file format is, so
- # first see if it will tell us. cd to the root directory to prevent
- # problems with other programs or directories called `ld' in the path.
- ld_help_string=`cd /; ld --help 2>&1`
- ld_supported_emulations=`echo $ld_help_string \
- | sed -ne '/supported emulations:/!d
- s/[ ][ ]*/ /g
- s/.*supported emulations: *//
- s/ .*//
- p'`
- case "$ld_supported_emulations" in
- i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 ;;
- i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 ;;
- sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
- armlinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
- m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
- elf32ppc)
- # Determine Lib Version
- cat >$dummy.c <<EOF
-#include <features.h>
-#if defined(__GLIBC__)
-extern char __libc_version[];
-extern char __libc_release[];
-#endif
-main(argc, argv)
- int argc;
- char *argv[];
-{
-#if defined(__GLIBC__)
- printf("%s %s\n", __libc_version, __libc_release);
-#else
- printf("unkown\n");
-#endif
- return 0;
-}
-EOF
- LIBC=""
- $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null
- if test "$?" = 0 ; then
- ./$dummy | grep 1\.99 > /dev/null
- if test "$?" = 0 ; then
- LIBC="libc1"
- fi
- fi
- rm -f $dummy.c $dummy
- echo powerpc-unknown-linux-gnu${LIBC} ; exit 0 ;;
- esac
-
- if test "${UNAME_MACHINE}" = "alpha" ; then
- sed 's/^ //' <<EOF >$dummy.s
- .globl main
- .ent main
- main:
- .frame \$30,0,\$26,0
- .prologue 0
- .long 0x47e03d80 # implver $0
- lda \$2,259
- .long 0x47e20c21 # amask $2,$1
- srl \$1,8,\$2
- sll \$2,2,\$2
- sll \$0,3,\$0
- addl \$1,\$0,\$0
- addl \$2,\$0,\$0
- ret \$31,(\$26),1
- .end main
-EOF
- LIBC=""
- $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
- if test "$?" = 0 ; then
- ./$dummy
- case "$?" in
- 7)
- UNAME_MACHINE="alpha"
- ;;
- 15)
- UNAME_MACHINE="alphaev5"
- ;;
- 14)
- UNAME_MACHINE="alphaev56"
- ;;
- 10)
- UNAME_MACHINE="alphapca56"
- ;;
- 16)
- UNAME_MACHINE="alphaev6"
- ;;
- esac
-
- objdump --private-headers $dummy | \
- grep ld.so.1 > /dev/null
- if test "$?" = 0 ; then
- LIBC="libc1"
- fi
- fi
- rm -f $dummy.s $dummy
- echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0
- elif test "${UNAME_MACHINE}" = "mips" ; then
- cat >$dummy.c <<EOF
-#ifdef __cplusplus
- int main (int argc, char *argv[]) {
-#else
- int main (argc, argv) int argc; char *argv[]; {
-#endif
-#ifdef __MIPSEB__
- printf ("%s-unknown-linux-gnu\n", argv[1]);
-#endif
-#ifdef __MIPSEL__
- printf ("%sel-unknown-linux-gnu\n", argv[1]);
-#endif
- return 0;
-}
-EOF
- $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
- rm -f $dummy.c $dummy
- else
- # Either a pre-BFD a.out linker (linux-gnuoldld)
- # or one that does not give us useful --help.
- # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
- # If ld does not provide *any* "supported emulations:"
- # that means it is gnuoldld.
- echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:"
- test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
-
- case "${UNAME_MACHINE}" in
- i?86)
- VENDOR=pc;
- ;;
- *)
- VENDOR=unknown;
- ;;
- esac
- # Determine whether the default compiler is a.out or elf
- cat >$dummy.c <<EOF
-#include <features.h>
-#ifdef __cplusplus
- int main (int argc, char *argv[]) {
-#else
- int main (argc, argv) int argc; char *argv[]; {
-#endif
-#ifdef __ELF__
-# ifdef __GLIBC__
-# if __GLIBC__ >= 2
- printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
-# else
- printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
-# endif
-# else
- printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
-# endif
-#else
- printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
-#endif
- return 0;
-}
-EOF
- $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
- rm -f $dummy.c $dummy
- fi ;;
-# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions
-# are messed up and put the nodename in both sysname and nodename.
- i?86:DYNIX/ptx:4*:*)
- echo i386-sequent-sysv4
- exit 0 ;;
- i?86:UNIX_SV:4.2MP:2.*)
- # Unixware is an offshoot of SVR4, but it has its own version
- # number series starting with 2...
- # I am not positive that other SVR4 systems won't match this,
- # I just have to hope. -- rms.
- # Use sysv4.2uw... so that sysv4* matches it.
- echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
- exit 0 ;;
- i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
- if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
- echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
- else
- echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
- fi
- exit 0 ;;
- i?86:*:5:7*)
- UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
- (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
- (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) && UNAME_MACHINE=i586
- (/bin/uname -X|egrep '^Machine.*Pent.*II' >/dev/null) && UNAME_MACHINE=i686
- (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) && UNAME_MACHINE=i585
- echo ${UNAME_MACHINE}-${UNAME_SYSTEM}${UNAME_VERSION}-sysv${UNAME_RELEASE}
- exit 0 ;;
- i?86:*:3.2:*)
- if test -f /usr/options/cb.name; then
- UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
- echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
- elif /bin/uname -X 2>/dev/null >/dev/null ; then
- UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
- (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
- (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
- && UNAME_MACHINE=i586
- (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
- && UNAME_MACHINE=i686
- (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
- && UNAME_MACHINE=i686
- echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
- else
- echo ${UNAME_MACHINE}-pc-sysv32
- fi
- exit 0 ;;
- pc:*:*:*)
- # uname -m prints for DJGPP always 'pc', but it prints nothing about
- # the processor, so we play safe by assuming i386.
- echo i386-pc-msdosdjgpp
- exit 0 ;;
- Intel:Mach:3*:*)
- echo i386-pc-mach3
- exit 0 ;;
- paragon:*:*:*)
- echo i860-intel-osf1
- exit 0 ;;
- i860:*:4.*:*) # i860-SVR4
- if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
- echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
- else # Add other i860-SVR4 vendors below as they are discovered.
- echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
- fi
- exit 0 ;;
- mini*:CTIX:SYS*5:*)
- # "miniframe"
- echo m68010-convergent-sysv
- exit 0 ;;
- M68*:*:R3V[567]*:*)
- test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
- 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
- OS_REL=''
- test -r /etc/.relid \
- && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
- /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
- && echo i486-ncr-sysv4.3${OS_REL} && exit 0
- /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
- && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
- 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
- /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
- && echo i486-ncr-sysv4 && exit 0 ;;
- m68*:LynxOS:2.*:*)
- echo m68k-unknown-lynxos${UNAME_RELEASE}
- exit 0 ;;
- mc68030:UNIX_System_V:4.*:*)
- echo m68k-atari-sysv4
- exit 0 ;;
- i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*)
- echo i386-unknown-lynxos${UNAME_RELEASE}
- exit 0 ;;
- TSUNAMI:LynxOS:2.*:*)
- echo sparc-unknown-lynxos${UNAME_RELEASE}
- exit 0 ;;
- rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*)
- echo rs6000-unknown-lynxos${UNAME_RELEASE}
- exit 0 ;;
- SM[BE]S:UNIX_SV:*:*)
- echo mips-dde-sysv${UNAME_RELEASE}
- exit 0 ;;
- RM*:ReliantUNIX-*:*:*)
- echo mips-sni-sysv4
- exit 0 ;;
- RM*:SINIX-*:*:*)
- echo mips-sni-sysv4
- exit 0 ;;
- *:SINIX-*:*:*)
- if uname -p 2>/dev/null >/dev/null ; then
- UNAME_MACHINE=`(uname -p) 2>/dev/null`
- echo ${UNAME_MACHINE}-sni-sysv4
- else
- echo ns32k-sni-sysv
- fi
- exit 0 ;;
- PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
- # says <Richard.M.Bartel@ccMail.Census.GOV>
- echo i586-unisys-sysv4
- exit 0 ;;
- *:UNIX_System_V:4*:FTX*)
- # From Gerald Hewes <hewes@openmarket.com>.
- # How about differentiating between stratus architectures? -djm
- echo hppa1.1-stratus-sysv4
- exit 0 ;;
- *:*:*:FTX*)
- # From seanf@swdc.stratus.com.
- echo i860-stratus-sysv4
- exit 0 ;;
- mc68*:A/UX:*:*)
- echo m68k-apple-aux${UNAME_RELEASE}
- exit 0 ;;
- news*:NEWS-OS:*:6*)
- echo mips-sony-newsos6
- exit 0 ;;
- R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
- if [ -d /usr/nec ]; then
- echo mips-nec-sysv${UNAME_RELEASE}
- else
- echo mips-unknown-sysv${UNAME_RELEASE}
- fi
- exit 0 ;;
- BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
- echo powerpc-be-beos
- exit 0 ;;
- BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
- echo powerpc-apple-beos
- exit 0 ;;
- BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
- echo i586-pc-beos
- exit 0 ;;
- SX-4:SUPER-UX:*:*)
- echo sx4-nec-superux${UNAME_RELEASE}
- exit 0 ;;
- SX-5:SUPER-UX:*:*)
- echo sx5-nec-superux${UNAME_RELEASE}
- exit 0 ;;
- Power*:Rhapsody:*:*)
- echo powerpc-apple-rhapsody${UNAME_RELEASE}
- exit 0 ;;
- *:Rhapsody:*:*)
- echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
- exit 0 ;;
-esac
-
-#echo '(No uname command or uname output not recognized.)' 1>&2
-#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
-
-cat >$dummy.c <<EOF
-#ifdef _SEQUENT_
-# include <sys/types.h>
-# include <sys/utsname.h>
-#endif
-main ()
-{
-#if defined (sony)
-#if defined (MIPSEB)
- /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
- I don't know.... */
- printf ("mips-sony-bsd\n"); exit (0);
-#else
-#include <sys/param.h>
- printf ("m68k-sony-newsos%s\n",
-#ifdef NEWSOS4
- "4"
-#else
- ""
-#endif
- ); exit (0);
-#endif
-#endif
-
-#if defined (__arm) && defined (__acorn) && defined (__unix)
- printf ("arm-acorn-riscix"); exit (0);
-#endif
-
-#if defined (hp300) && !defined (hpux)
- printf ("m68k-hp-bsd\n"); exit (0);
-#endif
-
-#if defined (NeXT)
-#if !defined (__ARCHITECTURE__)
-#define __ARCHITECTURE__ "m68k"
-#endif
- int version;
- version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
- if (version < 4)
- printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
- else
- printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
- exit (0);
-#endif
-
-#if defined (MULTIMAX) || defined (n16)
-#if defined (UMAXV)
- printf ("ns32k-encore-sysv\n"); exit (0);
-#else
-#if defined (CMU)
- printf ("ns32k-encore-mach\n"); exit (0);
-#else
- printf ("ns32k-encore-bsd\n"); exit (0);
-#endif
-#endif
-#endif
-
-#if defined (__386BSD__)
- printf ("i386-pc-bsd\n"); exit (0);
-#endif
-
-#if defined (sequent)
-#if defined (i386)
- printf ("i386-sequent-dynix\n"); exit (0);
-#endif
-#if defined (ns32000)
- printf ("ns32k-sequent-dynix\n"); exit (0);
-#endif
-#endif
-
-#if defined (_SEQUENT_)
- struct utsname un;
-
- uname(&un);
-
- if (strncmp(un.version, "V2", 2) == 0) {
- printf ("i386-sequent-ptx2\n"); exit (0);
- }
- if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
- printf ("i386-sequent-ptx1\n"); exit (0);
- }
- printf ("i386-sequent-ptx\n"); exit (0);
-
-#endif
-
-#if defined (vax)
-#if !defined (ultrix)
- printf ("vax-dec-bsd\n"); exit (0);
-#else
- printf ("vax-dec-ultrix\n"); exit (0);
-#endif
-#endif
-
-#if defined (alliant) && defined (i860)
- printf ("i860-alliant-bsd\n"); exit (0);
-#endif
-
- exit (1);
-}
-EOF
-
-$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0
-rm -f $dummy.c $dummy
-
-# Apollos put the system type in the environment.
-
-test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
-
-# Convex versions that predate uname can use getsysinfo(1)
-
-if [ -x /usr/convex/getsysinfo ]
-then
- case `getsysinfo -f cpu_type` in
- c1*)
- echo c1-convex-bsd
- exit 0 ;;
- c2*)
- if getsysinfo -f scalar_acc
- then echo c32-convex-bsd
- else echo c2-convex-bsd
- fi
- exit 0 ;;
- c34*)
- echo c34-convex-bsd
- exit 0 ;;
- c38*)
- echo c38-convex-bsd
- exit 0 ;;
- c4*)
- echo c4-convex-bsd
- exit 0 ;;
- esac
-fi
-
-#echo '(Unable to guess system type)' 1>&2
-
-exit 1
+++ /dev/null
-/* config/config.h.in. Generated automatically from configure.in by autoheader. */
-#ifndef CONFIG_H
-#define CONFIG_H
-
-
-/* Define to empty if the keyword does not work. */
-#undef const
-
-/* Define if you don't have vprintf but do have _doprnt. */
-#undef HAVE_DOPRNT
-
-/* Define if you have the strftime function. */
-#undef HAVE_STRFTIME
-
-/* Define if you have the vprintf function. */
-#undef HAVE_VPRINTF
-
-/* Define if you have the ANSI C header files. */
-#undef STDC_HEADERS
-
-/* Define if you can safely include both <sys/time.h> and <time.h>. */
-#undef TIME_WITH_SYS_TIME
-
-/* Define if your <sys/time.h> declares struct tm. */
-#undef TM_IN_SYS_TIME
-
-/* IEEE can be prevented from raising signals with fpsetmask(0) */
-#undef MUST_DISABLE_FPMASK
-
-#undef MUST_DISABLE_SIGFPE
-
-/* realloc does not support NULL as argument */
-#undef NO_NULL_REALLOC
-
-/* Define if you have the class function. */
-#undef HAVE_CLASS
-
-/* Define if you have the finite function. */
-#undef HAVE_FINITE
-
-/* Define if you have the fp_class function. */
-#undef HAVE_FP_CLASS
-
-/* Define if you have the fpclass function. */
-#undef HAVE_FPCLASS
-
-/* Define if you have the fpclassify function. */
-#undef HAVE_FPCLASSIFY
-
-/* Define if you have the getrusage function. */
-#undef HAVE_GETRUSAGE
-
-/* Define if you have the gettimeofday function. */
-#undef HAVE_GETTIMEOFDAY
-
-/* Define if you have the isinf function. */
-#undef HAVE_ISINF
-
-/* Define if you have the isnan function. */
-#undef HAVE_ISNAN
-
-/* Define if you have the memmove function. */
-#undef HAVE_MEMMOVE
-
-/* Define if you have the mktime function. */
-#undef HAVE_MKTIME
-
-/* Define if you have the snprintf function. */
-#undef HAVE_SNPRINTF
-
-/* Define if you have the strchr function. */
-#undef HAVE_STRCHR
-
-/* Define if you have the strerror function. */
-#undef HAVE_STRERROR
-
-/* Define if you have the vsnprintf function. */
-#undef HAVE_VSNPRINTF
-
-/* Define if you have the <fcntl.h> header file. */
-#undef HAVE_FCNTL_H
-
-/* Define if you have the <float.h> header file. */
-#undef HAVE_FLOAT_H
-
-/* Define if you have the <fp_class.h> header file. */
-#undef HAVE_FP_CLASS_H
-
-/* Define if you have the <ieeefp.h> header file. */
-#undef HAVE_IEEEFP_H
-
-/* Define if you have the <malloc.h> header file. */
-#undef HAVE_MALLOC_H
-
-/* Define if you have the <math.h> header file. */
-#undef HAVE_MATH_H
-
-/* Define if you have the <sys/param.h> header file. */
-#undef HAVE_SYS_PARAM_H
-
-/* Define if you have the <sys/resource.h> header file. */
-#undef HAVE_SYS_RESOURCE_H
-
-/* Define if you have the <sys/time.h> header file. */
-#undef HAVE_SYS_TIME_H
-
-/* Define if you have the <sys/times.h> header file. */
-#undef HAVE_SYS_TIMES_H
-
-/* Define if you have the <unistd.h> header file. */
-#undef HAVE_UNISTD_H
-
-/* Define if you have the m library (-lm). */
-#undef HAVE_LIBM
-
-/* Name of package */
-#undef PACKAGE
-
-/* Version number of package */
-#undef VERSION
-
-
-/* define strrchr, strchr and memcpy, memmove in terms of bsd funcs
- make sure you are NOT using bcopy, index or rindex in the code */
-
-#if STDC_HEADERS
-# include <string.h>
-#else
-# ifndef HAVE_STRCHR
-# define strchr index
-# define strrchr rindex
-# endif
-char *strchr (), *strrchr ();
-# ifndef HAVE_MEMMOVE
-# define memcpy(d, s, n) bcopy ((s), (d), (n))
-# define memmove(d, s, n) bcopy ((s), (d), (n))
-# endif
-#endif
-
-
-#if NO_NULL_REALLOC
-# define rrd_realloc(a,b) ( (a) == NULL ? malloc( (b) ) : realloc( (a) , (b) ))
-#else
-# define rrd_realloc(a,b) realloc((a), (b))
-#endif
-
-#if HAVE_MATH_H
-# include <math.h>
-#endif
-
-#if HAVE_FLOAT_H
-# include <float.h>
-#endif
-
-#if HAVE_IEEEFP_H
-# include <ieeefp.h>
-#endif
-
-#if HAVE_FP_CLASS_H
-# include <fp_class.h>
-#endif
-
-/* for Solaris */
-#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASS))
-# define HAVE_ISINF 1
-# define isinf(a) (fpclass(a) == FP_NINF || fpclass(a) == FP_PINF)
-#endif
-
-/* for OSF1 Digital Unix */
-#if (! defined(HAVE_ISINF) && defined(HAVE_FP_CLASS) && defined(HAVE_FP_CLASS_H))
-# define HAVE_ISINF 1
-# define isinf(a) (fp_class(a) == FP_NEG_INF || fp_class(a) == FP_POS_INF)
-#endif
-
-#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY) && defined(FP_PLUS_INF) && defined(FP_MINUS_INF))
-# define HAVE_ISINF 1
-# define isinf(a) (fpclassify(a) == FP_MINUS_INF || fpclassify(a) == FP_PLUS_INF)
-#endif
-
-#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY) && defined(FP_INFINITE))
-# define HAVE_ISINF 1
-# define isinf(a) (fpclassify(a) == FP_INFINITE)
-#endif
-
-/* for AIX */
-#if (! defined(HAVE_ISINF) && defined(HAVE_CLASS))
-# define HAVE_ISINF 1
-# define isinf(a) (class(a) == FP_MINUS_INF || class(a) == FP_PLUS_INF)
-#endif
-
-#if (! defined (HAVE_FINITE) && defined (HAVE_ISFINITE))
-# define HAVE_FINITE 1
-# define finite(a) isfinite(a)
-#endif
-
-#if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
-# define HAVE_FINITE 1
-# define finite(a) (! isnan(a) && ! isinf(a))
-#endif
-
-#ifndef HAVE_FINITE
-#error "Can't compile without finite function"
-#endif
-
-#ifndef HAVE_ISINF
-#error "Can't compile without isinf function"
-#endif
-
-#endif /* CONFIG_H */
-
+++ /dev/null
-#! /bin/sh
-# Configuration validation subroutine script, version 1.1.
-# Copyright (C) 1991, 92-97, 1998, 1999 Free Software Foundation, Inc.
-# This file is (in principle) common to ALL GNU software.
-# The presence of a machine in this file suggests that SOME GNU software
-# can handle that machine. It does not imply ALL GNU software can.
-#
-# This file is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330,
-# Boston, MA 02111-1307, USA.
-
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# Configuration subroutine to validate and canonicalize a configuration type.
-# Supply the specified configuration type as an argument.
-# If it is invalid, we print an error message on stderr and exit with code 1.
-# Otherwise, we print the canonical config type on stdout and succeed.
-
-# This file is supposed to be the same for all GNU packages
-# and recognize all the CPU types, system types and aliases
-# that are meaningful with *any* GNU software.
-# Each package is responsible for reporting which valid configurations
-# it does not support. The user should be able to distinguish
-# a failure to support a valid configuration from a meaningless
-# configuration.
-
-# The goal of this file is to map all the various variations of a given
-# machine specification into a single specification in the form:
-# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
-# or in some cases, the newer four-part form:
-# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
-# It is wrong to echo any other type of specification.
-
-if [ x$1 = x ]
-then
- echo Configuration name missing. 1>&2
- echo "Usage: $0 CPU-MFR-OPSYS" 1>&2
- echo "or $0 ALIAS" 1>&2
- echo where ALIAS is a recognized configuration type. 1>&2
- exit 1
-fi
-
-# First pass through any local machine types.
-case $1 in
- *local*)
- echo $1
- exit 0
- ;;
- *)
- ;;
-esac
-
-# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
-# Here we must recognize all the valid KERNEL-OS combinations.
-maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
-case $maybe_os in
- linux-gnu*)
- os=-$maybe_os
- basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
- ;;
- *)
- basic_machine=`echo $1 | sed 's/-[^-]*$//'`
- if [ $basic_machine != $1 ]
- then os=`echo $1 | sed 's/.*-/-/'`
- else os=; fi
- ;;
-esac
-
-### Let's recognize common machines as not being operating systems so
-### that things like config.sub decstation-3100 work. We also
-### recognize some manufacturers as not being operating systems, so we
-### can provide default operating systems below.
-case $os in
- -sun*os*)
- # Prevent following clause from handling this invalid input.
- ;;
- -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
- -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
- -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
- -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
- -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
- -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
- -apple)
- os=
- basic_machine=$1
- ;;
- -sim | -cisco | -oki | -wec | -winbond)
- os=
- basic_machine=$1
- ;;
- -scout)
- ;;
- -wrs)
- os=vxworks
- basic_machine=$1
- ;;
- -hiux*)
- os=-hiuxwe2
- ;;
- -sco5)
- os=-sco3.2v5
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco4)
- os=-sco3.2v4
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco3.2.[4-9]*)
- os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco3.2v[4-9]*)
- # Don't forget version if it is 3.2v4 or newer.
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco*)
- os=-sco3.2v2
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -udk*)
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -isc)
- os=-isc2.2
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -clix*)
- basic_machine=clipper-intergraph
- ;;
- -isc*)
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -lynx*)
- os=-lynxos
- ;;
- -ptx*)
- basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
- ;;
- -windowsnt*)
- os=`echo $os | sed -e 's/windowsnt/winnt/'`
- ;;
- -psos*)
- os=-psos
- ;;
-esac
-
-# Decode aliases for certain CPU-COMPANY combinations.
-case $basic_machine in
- # Recognize the basic CPU types without company name.
- # Some are omitted here because they have special meanings below.
- tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
- | arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \
- | 580 | i960 | h8300 \
- | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
- | alpha | alphaev[4-7] | alphaev56 | alphapca5[67] \
- | we32k | ns16k | clipper | i370 | sh | powerpc | powerpcle \
- | 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \
- | mips64orion | mips64orionel | mipstx39 | mipstx39el \
- | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \
- | mips64vr5000 | miprs64vr5000el \
- | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \
- | thumb | d10v)
- basic_machine=$basic_machine-unknown
- ;;
- m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65)
- ;;
-
- # We use `pc' rather than `unknown'
- # because (1) that's what they normally are, and
- # (2) the word "unknown" tends to confuse beginning users.
- i[34567]86)
- basic_machine=$basic_machine-pc
- ;;
- # Object if more than one company name word.
- *-*-*)
- echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
- exit 1
- ;;
- # Recognize the basic CPU types with company name.
- vax-* | tahoe-* | i[34567]86-* | i860-* | m32r-* | m68k-* | m68000-* \
- | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \
- | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
- | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \
- | xmp-* | ymp-* \
- | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* | hppa2.0n-* \
- | alpha-* | alphaev[4-7]-* | alphaev56-* | alphapca5[67]-* \
- | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \
- | clipper-* | orion-* \
- | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
- | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \
- | mips64el-* | mips64orion-* | mips64orionel-* \
- | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \
- | mipstx39-* | mipstx39el-* \
- | f301-* | armv*-* | t3e-* \
- | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \
- | thumb-* | v850-* | d30v-* | tic30-* | c30-* )
- ;;
- # Recognize the various machine names and aliases which stand
- # for a CPU type and a company and sometimes even an OS.
- 386bsd)
- basic_machine=i386-unknown
- os=-bsd
- ;;
- 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
- basic_machine=m68000-att
- ;;
- 3b*)
- basic_machine=we32k-att
- ;;
- a29khif)
- basic_machine=a29k-amd
- os=-udi
- ;;
- adobe68k)
- basic_machine=m68010-adobe
- os=-scout
- ;;
- alliant | fx80)
- basic_machine=fx80-alliant
- ;;
- altos | altos3068)
- basic_machine=m68k-altos
- ;;
- am29k)
- basic_machine=a29k-none
- os=-bsd
- ;;
- amdahl)
- basic_machine=580-amdahl
- os=-sysv
- ;;
- amiga | amiga-*)
- basic_machine=m68k-cbm
- ;;
- amigaos | amigados)
- basic_machine=m68k-cbm
- os=-amigaos
- ;;
- amigaunix | amix)
- basic_machine=m68k-cbm
- os=-sysv4
- ;;
- apollo68)
- basic_machine=m68k-apollo
- os=-sysv
- ;;
- apollo68bsd)
- basic_machine=m68k-apollo
- os=-bsd
- ;;
- aux)
- basic_machine=m68k-apple
- os=-aux
- ;;
- balance)
- basic_machine=ns32k-sequent
- os=-dynix
- ;;
- convex-c1)
- basic_machine=c1-convex
- os=-bsd
- ;;
- convex-c2)
- basic_machine=c2-convex
- os=-bsd
- ;;
- convex-c32)
- basic_machine=c32-convex
- os=-bsd
- ;;
- convex-c34)
- basic_machine=c34-convex
- os=-bsd
- ;;
- convex-c38)
- basic_machine=c38-convex
- os=-bsd
- ;;
- cray | ymp)
- basic_machine=ymp-cray
- os=-unicos
- ;;
- cray2)
- basic_machine=cray2-cray
- os=-unicos
- ;;
- [ctj]90-cray)
- basic_machine=c90-cray
- os=-unicos
- ;;
- crds | unos)
- basic_machine=m68k-crds
- ;;
- da30 | da30-*)
- basic_machine=m68k-da30
- ;;
- decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
- basic_machine=mips-dec
- ;;
- delta | 3300 | motorola-3300 | motorola-delta \
- | 3300-motorola | delta-motorola)
- basic_machine=m68k-motorola
- ;;
- delta88)
- basic_machine=m88k-motorola
- os=-sysv3
- ;;
- dpx20 | dpx20-*)
- basic_machine=rs6000-bull
- os=-bosx
- ;;
- dpx2* | dpx2*-bull)
- basic_machine=m68k-bull
- os=-sysv3
- ;;
- ebmon29k)
- basic_machine=a29k-amd
- os=-ebmon
- ;;
- elxsi)
- basic_machine=elxsi-elxsi
- os=-bsd
- ;;
- encore | umax | mmax)
- basic_machine=ns32k-encore
- ;;
- es1800 | OSE68k | ose68k | ose | OSE)
- basic_machine=m68k-ericsson
- os=-ose
- ;;
- fx2800)
- basic_machine=i860-alliant
- ;;
- genix)
- basic_machine=ns32k-ns
- ;;
- gmicro)
- basic_machine=tron-gmicro
- os=-sysv
- ;;
- h3050r* | hiux*)
- basic_machine=hppa1.1-hitachi
- os=-hiuxwe2
- ;;
- h8300hms)
- basic_machine=h8300-hitachi
- os=-hms
- ;;
- h8300xray)
- basic_machine=h8300-hitachi
- os=-xray
- ;;
- h8500hms)
- basic_machine=h8500-hitachi
- os=-hms
- ;;
- harris)
- basic_machine=m88k-harris
- os=-sysv3
- ;;
- hp300-*)
- basic_machine=m68k-hp
- ;;
- hp300bsd)
- basic_machine=m68k-hp
- os=-bsd
- ;;
- hp300hpux)
- basic_machine=m68k-hp
- os=-hpux
- ;;
- hp3k9[0-9][0-9] | hp9[0-9][0-9])
- basic_machine=hppa1.0-hp
- ;;
- hp9k2[0-9][0-9] | hp9k31[0-9])
- basic_machine=m68000-hp
- ;;
- hp9k3[2-9][0-9])
- basic_machine=m68k-hp
- ;;
- hp9k6[0-9][0-9] | hp6[0-9][0-9])
- basic_machine=hppa1.0-hp
- ;;
- hp9k7[0-79][0-9] | hp7[0-79][0-9])
- basic_machine=hppa1.1-hp
- ;;
- hp9k78[0-9] | hp78[0-9])
- # FIXME: really hppa2.0-hp
- basic_machine=hppa1.1-hp
- ;;
- hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
- # FIXME: really hppa2.0-hp
- basic_machine=hppa1.1-hp
- ;;
- hp9k8[0-9][13679] | hp8[0-9][13679])
- basic_machine=hppa1.1-hp
- ;;
- hp9k8[0-9][0-9] | hp8[0-9][0-9])
- basic_machine=hppa1.0-hp
- ;;
- hppa-next)
- os=-nextstep3
- ;;
- hppaosf)
- basic_machine=hppa1.1-hp
- os=-osf
- ;;
- hppro)
- basic_machine=hppa1.1-hp
- os=-proelf
- ;;
- i370-ibm* | ibm*)
- basic_machine=i370-ibm
- os=-mvs
- ;;
-# I'm not sure what "Sysv32" means. Should this be sysv3.2?
- i[34567]86v32)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-sysv32
- ;;
- i[34567]86v4*)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-sysv4
- ;;
- i[34567]86v)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-sysv
- ;;
- i[34567]86sol2)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-solaris2
- ;;
- i386mach)
- basic_machine=i386-mach
- os=-mach
- ;;
- i386-vsta | vsta)
- basic_machine=i386-unknown
- os=-vsta
- ;;
- i386-go32 | go32)
- basic_machine=i386-unknown
- os=-go32
- ;;
- i386-mingw32 | mingw32)
- basic_machine=i386-unknown
- os=-mingw32
- ;;
- iris | iris4d)
- basic_machine=mips-sgi
- case $os in
- -irix*)
- ;;
- *)
- os=-irix4
- ;;
- esac
- ;;
- isi68 | isi)
- basic_machine=m68k-isi
- os=-sysv
- ;;
- m88k-omron*)
- basic_machine=m88k-omron
- ;;
- magnum | m3230)
- basic_machine=mips-mips
- os=-sysv
- ;;
- merlin)
- basic_machine=ns32k-utek
- os=-sysv
- ;;
- miniframe)
- basic_machine=m68000-convergent
- ;;
- *mint | *MiNT)
- basic_machine=m68k-atari
- os=-mint
- ;;
- mipsel*-linux*)
- basic_machine=mipsel-unknown
- os=-linux-gnu
- ;;
- mips*-linux*)
- basic_machine=mips-unknown
- os=-linux-gnu
- ;;
- mips3*-*)
- basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
- ;;
- mips3*)
- basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
- ;;
- monitor)
- basic_machine=m68k-rom68k
- os=-coff
- ;;
- msdos)
- basic_machine=i386-unknown
- os=-msdos
- ;;
- ncr3000)
- basic_machine=i486-ncr
- os=-sysv4
- ;;
- netbsd386)
- basic_machine=i386-unknown
- os=-netbsd
- ;;
- netwinder)
- basic_machine=armv4l-corel
- os=-linux
- ;;
- news | news700 | news800 | news900)
- basic_machine=m68k-sony
- os=-newsos
- ;;
- news1000)
- basic_machine=m68030-sony
- os=-newsos
- ;;
- news-3600 | risc-news)
- basic_machine=mips-sony
- os=-newsos
- ;;
- necv70)
- basic_machine=v70-nec
- os=-sysv
- ;;
- next | m*-next )
- basic_machine=m68k-next
- case $os in
- -nextstep* )
- ;;
- -ns2*)
- os=-nextstep2
- ;;
- *)
- os=-nextstep3
- ;;
- esac
- ;;
- nh3000)
- basic_machine=m68k-harris
- os=-cxux
- ;;
- nh[45]000)
- basic_machine=m88k-harris
- os=-cxux
- ;;
- nindy960)
- basic_machine=i960-intel
- os=-nindy
- ;;
- mon960)
- basic_machine=i960-intel
- os=-mon960
- ;;
- np1)
- basic_machine=np1-gould
- ;;
- op50n-* | op60c-*)
- basic_machine=hppa1.1-oki
- os=-proelf
- ;;
- OSE68000 | ose68000)
- basic_machine=m68000-ericsson
- os=-ose
- ;;
- os68k)
- basic_machine=m68k-none
- os=-os68k
- ;;
- pa-hitachi)
- basic_machine=hppa1.1-hitachi
- os=-hiuxwe2
- ;;
- paragon)
- basic_machine=i860-intel
- os=-osf
- ;;
- pbd)
- basic_machine=sparc-tti
- ;;
- pbb)
- basic_machine=m68k-tti
- ;;
- pc532 | pc532-*)
- basic_machine=ns32k-pc532
- ;;
- pentium | p5 | k5 | k6 | nexen)
- basic_machine=i586-pc
- ;;
- pentiumpro | p6 | 6x86)
- basic_machine=i686-pc
- ;;
- pentiumii | pentium2)
- basic_machine=i786-pc
- ;;
- pentium-* | p5-* | k5-* | k6-* | nexen-*)
- basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pentiumpro-* | p6-* | 6x86-*)
- basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pentiumii-* | pentium2-*)
- basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pn)
- basic_machine=pn-gould
- ;;
- power) basic_machine=rs6000-ibm
- ;;
- ppc) basic_machine=powerpc-unknown
- ;;
- ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- ppcle | powerpclittle | ppc-le | powerpc-little)
- basic_machine=powerpcle-unknown
- ;;
- ppcle-* | powerpclittle-*)
- basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- ps2)
- basic_machine=i386-ibm
- ;;
- rom68k)
- basic_machine=m68k-rom68k
- os=-coff
- ;;
- rm[46]00)
- basic_machine=mips-siemens
- ;;
- rtpc | rtpc-*)
- basic_machine=romp-ibm
- ;;
- sa29200)
- basic_machine=a29k-amd
- os=-udi
- ;;
- sequent)
- basic_machine=i386-sequent
- ;;
- sh)
- basic_machine=sh-hitachi
- os=-hms
- ;;
- sparclite-wrs)
- basic_machine=sparclite-wrs
- os=-vxworks
- ;;
- sps7)
- basic_machine=m68k-bull
- os=-sysv2
- ;;
- spur)
- basic_machine=spur-unknown
- ;;
- st2000)
- basic_machine=m68k-tandem
- ;;
- stratus)
- basic_machine=i860-stratus
- os=-sysv4
- ;;
- sun2)
- basic_machine=m68000-sun
- ;;
- sun2os3)
- basic_machine=m68000-sun
- os=-sunos3
- ;;
- sun2os4)
- basic_machine=m68000-sun
- os=-sunos4
- ;;
- sun3os3)
- basic_machine=m68k-sun
- os=-sunos3
- ;;
- sun3os4)
- basic_machine=m68k-sun
- os=-sunos4
- ;;
- sun4os3)
- basic_machine=sparc-sun
- os=-sunos3
- ;;
- sun4os4)
- basic_machine=sparc-sun
- os=-sunos4
- ;;
- sun4sol2)
- basic_machine=sparc-sun
- os=-solaris2
- ;;
- sun3 | sun3-*)
- basic_machine=m68k-sun
- ;;
- sun4)
- basic_machine=sparc-sun
- ;;
- sun386 | sun386i | roadrunner)
- basic_machine=i386-sun
- ;;
- symmetry)
- basic_machine=i386-sequent
- os=-dynix
- ;;
- t3e)
- basic_machine=t3e-cray
- os=-unicos
- ;;
- tx39)
- basic_machine=mipstx39-unknown
- ;;
- tx39el)
- basic_machine=mipstx39el-unknown
- ;;
- tower | tower-32)
- basic_machine=m68k-ncr
- ;;
- udi29k)
- basic_machine=a29k-amd
- os=-udi
- ;;
- ultra3)
- basic_machine=a29k-nyu
- os=-sym1
- ;;
- v810 | necv810)
- basic_machine=v810-nec
- os=-none
- ;;
- vaxv)
- basic_machine=vax-dec
- os=-sysv
- ;;
- vms)
- basic_machine=vax-dec
- os=-vms
- ;;
- vpp*|vx|vx-*)
- basic_machine=f301-fujitsu
- ;;
- vxworks960)
- basic_machine=i960-wrs
- os=-vxworks
- ;;
- vxworks68)
- basic_machine=m68k-wrs
- os=-vxworks
- ;;
- vxworks29k)
- basic_machine=a29k-wrs
- os=-vxworks
- ;;
- w65*)
- basic_machine=w65-wdc
- os=-none
- ;;
- w89k-*)
- basic_machine=hppa1.1-winbond
- os=-proelf
- ;;
- xmp)
- basic_machine=xmp-cray
- os=-unicos
- ;;
- xps | xps100)
- basic_machine=xps100-honeywell
- ;;
- z8k-*-coff)
- basic_machine=z8k-unknown
- os=-sim
- ;;
- none)
- basic_machine=none-none
- os=-none
- ;;
-
-# Here we handle the default manufacturer of certain CPU types. It is in
-# some cases the only manufacturer, in others, it is the most popular.
- w89k)
- basic_machine=hppa1.1-winbond
- ;;
- op50n)
- basic_machine=hppa1.1-oki
- ;;
- op60c)
- basic_machine=hppa1.1-oki
- ;;
- mips)
- if [ x$os = x-linux-gnu ]; then
- basic_machine=mips-unknown
- else
- basic_machine=mips-mips
- fi
- ;;
- romp)
- basic_machine=romp-ibm
- ;;
- rs6000)
- basic_machine=rs6000-ibm
- ;;
- vax)
- basic_machine=vax-dec
- ;;
- pdp11)
- basic_machine=pdp11-dec
- ;;
- we32k)
- basic_machine=we32k-att
- ;;
- sparc | sparcv9)
- basic_machine=sparc-sun
- ;;
- cydra)
- basic_machine=cydra-cydrome
- ;;
- orion)
- basic_machine=orion-highlevel
- ;;
- orion105)
- basic_machine=clipper-highlevel
- ;;
- mac | mpw | mac-mpw)
- basic_machine=m68k-apple
- ;;
- pmac | pmac-mpw)
- basic_machine=powerpc-apple
- ;;
- c4x*)
- basic_machine=c4x-none
- os=-coff
- ;;
- *)
- echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
- exit 1
- ;;
-esac
-
-# Here we canonicalize certain aliases for manufacturers.
-case $basic_machine in
- *-digital*)
- basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
- ;;
- *-commodore*)
- basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
- ;;
- *)
- ;;
-esac
-
-# Decode manufacturer-specific aliases for certain operating systems.
-
-if [ x"$os" != x"" ]
-then
-case $os in
- # First match some system type aliases
- # that might get confused with valid system types.
- # -solaris* is a basic system type, with this one exception.
- -solaris1 | -solaris1.*)
- os=`echo $os | sed -e 's|solaris1|sunos4|'`
- ;;
- -solaris)
- os=-solaris2
- ;;
- -svr4*)
- os=-sysv4
- ;;
- -unixware*)
- os=-sysv4.2uw
- ;;
- -gnu/linux*)
- os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
- ;;
- # First accept the basic system types.
- # The portable systems comes first.
- # Each alternative MUST END IN A *, to match a version number.
- # -sysv* is not here because it comes later, after sysvr4.
- -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
- | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
- | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
- | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
- | -aos* \
- | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
- | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
- | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
- | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
- | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
- | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
- | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
- | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
- | -interix* | -uwin* | -rhapsody* | -openstep* | -oskit*)
- # Remember, each alternative MUST END IN *, to match a version number.
- ;;
- -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
- | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
- | -macos* | -mpw* | -magic* | -mon960* | -lnews*)
- ;;
- -mac*)
- os=`echo $os | sed -e 's|mac|macos|'`
- ;;
- -linux*)
- os=`echo $os | sed -e 's|linux|linux-gnu|'`
- ;;
- -sunos5*)
- os=`echo $os | sed -e 's|sunos5|solaris2|'`
- ;;
- -sunos6*)
- os=`echo $os | sed -e 's|sunos6|solaris3|'`
- ;;
- -osfrose*)
- os=-osfrose
- ;;
- -osf*)
- os=-osf
- ;;
- -utek*)
- os=-bsd
- ;;
- -dynix*)
- os=-bsd
- ;;
- -acis*)
- os=-aos
- ;;
- -386bsd)
- os=-bsd
- ;;
- -ctix* | -uts*)
- os=-sysv
- ;;
- -ns2 )
- os=-nextstep2
- ;;
- # Preserve the version number of sinix5.
- -sinix5.*)
- os=`echo $os | sed -e 's|sinix|sysv|'`
- ;;
- -sinix*)
- os=-sysv4
- ;;
- -triton*)
- os=-sysv3
- ;;
- -oss*)
- os=-sysv3
- ;;
- -svr4)
- os=-sysv4
- ;;
- -svr3)
- os=-sysv3
- ;;
- -sysvr4)
- os=-sysv4
- ;;
- # This must come after -sysvr4.
- -sysv*)
- ;;
- -ose*)
- os=-ose
- ;;
- -es1800*)
- os=-ose
- ;;
- -xenix)
- os=-xenix
- ;;
- -*mint | -*MiNT)
- os=-mint
- ;;
- -none)
- ;;
- *)
- # Get rid of the `-' at the beginning of $os.
- os=`echo $os | sed 's/[^-]*-//'`
- echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
- exit 1
- ;;
-esac
-else
-
-# Here we handle the default operating systems that come with various machines.
-# The value should be what the vendor currently ships out the door with their
-# machine or put another way, the most popular os provided with the machine.
-
-# Note that if you're going to try to match "-MANUFACTURER" here (say,
-# "-sun"), then you have to tell the case statement up towards the top
-# that MANUFACTURER isn't an operating system. Otherwise, code above
-# will signal an error saying that MANUFACTURER isn't an operating
-# system, and we'll never get to this point.
-
-case $basic_machine in
- *-acorn)
- os=-riscix1.2
- ;;
- arm*-corel)
- os=-linux
- ;;
- arm*-semi)
- os=-aout
- ;;
- pdp11-*)
- os=-none
- ;;
- *-dec | vax-*)
- os=-ultrix4.2
- ;;
- m68*-apollo)
- os=-domain
- ;;
- i386-sun)
- os=-sunos4.0.2
- ;;
- m68000-sun)
- os=-sunos3
- # This also exists in the configure program, but was not the
- # default.
- # os=-sunos4
- ;;
- m68*-cisco)
- os=-aout
- ;;
- mips*-cisco)
- os=-elf
- ;;
- mips*-*)
- os=-elf
- ;;
- *-tti) # must be before sparc entry or we get the wrong os.
- os=-sysv3
- ;;
- sparc-* | *-sun)
- os=-sunos4.1.1
- ;;
- *-be)
- os=-beos
- ;;
- *-ibm)
- os=-aix
- ;;
- *-wec)
- os=-proelf
- ;;
- *-winbond)
- os=-proelf
- ;;
- *-oki)
- os=-proelf
- ;;
- *-hp)
- os=-hpux
- ;;
- *-hitachi)
- os=-hiux
- ;;
- i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
- os=-sysv
- ;;
- *-cbm)
- os=-amigaos
- ;;
- *-dg)
- os=-dgux
- ;;
- *-dolphin)
- os=-sysv3
- ;;
- m68k-ccur)
- os=-rtu
- ;;
- m88k-omron*)
- os=-luna
- ;;
- *-next )
- os=-nextstep
- ;;
- *-sequent)
- os=-ptx
- ;;
- *-crds)
- os=-unos
- ;;
- *-ns)
- os=-genix
- ;;
- i370-*)
- os=-mvs
- ;;
- *-next)
- os=-nextstep3
- ;;
- *-gould)
- os=-sysv
- ;;
- *-highlevel)
- os=-bsd
- ;;
- *-encore)
- os=-bsd
- ;;
- *-sgi)
- os=-irix
- ;;
- *-siemens)
- os=-sysv4
- ;;
- *-masscomp)
- os=-rtu
- ;;
- f301-fujitsu)
- os=-uxpv
- ;;
- *-rom68k)
- os=-coff
- ;;
- *-*bug)
- os=-coff
- ;;
- *-apple)
- os=-macos
- ;;
- *-atari*)
- os=-mint
- ;;
- *)
- os=-none
- ;;
-esac
-fi
-
-# Here we handle the case where we know the os, and the CPU type, but not the
-# manufacturer. We pick the logical manufacturer.
-vendor=unknown
-case $basic_machine in
- *-unknown)
- case $os in
- -riscix*)
- vendor=acorn
- ;;
- -sunos*)
- vendor=sun
- ;;
- -aix*)
- vendor=ibm
- ;;
- -beos*)
- vendor=be
- ;;
- -hpux*)
- vendor=hp
- ;;
- -mpeix*)
- vendor=hp
- ;;
- -hiux*)
- vendor=hitachi
- ;;
- -unos*)
- vendor=crds
- ;;
- -dgux*)
- vendor=dg
- ;;
- -luna*)
- vendor=omron
- ;;
- -genix*)
- vendor=ns
- ;;
- -mvs*)
- vendor=ibm
- ;;
- -ptx*)
- vendor=sequent
- ;;
- -vxsim* | -vxworks*)
- vendor=wrs
- ;;
- -aux*)
- vendor=apple
- ;;
- -hms*)
- vendor=hitachi
- ;;
- -mpw* | -macos*)
- vendor=apple
- ;;
- -*mint | -*MiNT)
- vendor=atari
- ;;
- esac
- basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
- ;;
-esac
-
-echo $basic_machine$os
+++ /dev/null
-#!/bin/sh
-#
-# install - install a program, script, or datafile
-# This comes from X11R5 (mit/util/scripts/install.sh).
-#
-# Copyright 1991 by the Massachusetts Institute of Technology
-#
-# Permission to use, copy, modify, distribute, and sell this software and its
-# documentation for any purpose is hereby granted without fee, provided that
-# the above copyright notice appear in all copies and that both that
-# copyright notice and this permission notice appear in supporting
-# documentation, and that the name of M.I.T. not be used in advertising or
-# publicity pertaining to distribution of the software without specific,
-# written prior permission. M.I.T. makes no representations about the
-# suitability of this software for any purpose. It is provided "as is"
-# without express or implied warranty.
-#
-# Calling this script install-sh is preferred over install.sh, to prevent
-# `make' implicit rules from creating a file called install from it
-# when there is no Makefile.
-#
-# This script is compatible with the BSD install script, but was written
-# from scratch. It can only install one file at a time, a restriction
-# shared with many OS's install programs.
-
-
-# set DOITPROG to echo to test this script
-
-# Don't use :- since 4.3BSD and earlier shells don't like it.
-doit="${DOITPROG-}"
-
-
-# put in absolute paths if you don't have them in your path; or use env. vars.
-
-mvprog="${MVPROG-mv}"
-cpprog="${CPPROG-cp}"
-chmodprog="${CHMODPROG-chmod}"
-chownprog="${CHOWNPROG-chown}"
-chgrpprog="${CHGRPPROG-chgrp}"
-stripprog="${STRIPPROG-strip}"
-rmprog="${RMPROG-rm}"
-mkdirprog="${MKDIRPROG-mkdir}"
-
-transformbasename=""
-transform_arg=""
-instcmd="$mvprog"
-chmodcmd="$chmodprog 0755"
-chowncmd=""
-chgrpcmd=""
-stripcmd=""
-rmcmd="$rmprog -f"
-mvcmd="$mvprog"
-src=""
-dst=""
-dir_arg=""
-
-while [ x"$1" != x ]; do
- case $1 in
- -c) instcmd="$cpprog"
- shift
- continue;;
-
- -d) dir_arg=true
- shift
- continue;;
-
- -m) chmodcmd="$chmodprog $2"
- shift
- shift
- continue;;
-
- -o) chowncmd="$chownprog $2"
- shift
- shift
- continue;;
-
- -g) chgrpcmd="$chgrpprog $2"
- shift
- shift
- continue;;
-
- -s) stripcmd="$stripprog"
- shift
- continue;;
-
- -t=*) transformarg=`echo $1 | sed 's/-t=//'`
- shift
- continue;;
-
- -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
- shift
- continue;;
-
- *) if [ x"$src" = x ]
- then
- src=$1
- else
- # this colon is to work around a 386BSD /bin/sh bug
- :
- dst=$1
- fi
- shift
- continue;;
- esac
-done
-
-if [ x"$src" = x ]
-then
- echo "install: no input file specified"
- exit 1
-else
- true
-fi
-
-if [ x"$dir_arg" != x ]; then
- dst=$src
- src=""
-
- if [ -d $dst ]; then
- instcmd=:
- chmodcmd=""
- else
- instcmd=mkdir
- fi
-else
-
-# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
-# might cause directories to be created, which would be especially bad
-# if $src (and thus $dsttmp) contains '*'.
-
- if [ -f $src -o -d $src ]
- then
- true
- else
- echo "install: $src does not exist"
- exit 1
- fi
-
- if [ x"$dst" = x ]
- then
- echo "install: no destination specified"
- exit 1
- else
- true
- fi
-
-# If destination is a directory, append the input filename; if your system
-# does not like double slashes in filenames, you may need to add some logic
-
- if [ -d $dst ]
- then
- dst="$dst"/`basename $src`
- else
- true
- fi
-fi
-
-## this sed command emulates the dirname command
-dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
-
-# Make sure that the destination directory exists.
-# this part is taken from Noah Friedman's mkinstalldirs script
-
-# Skip lots of stat calls in the usual case.
-if [ ! -d "$dstdir" ]; then
-defaultIFS='
-'
-IFS="${IFS-${defaultIFS}}"
-
-oIFS="${IFS}"
-# Some sh's can't handle IFS=/ for some reason.
-IFS='%'
-set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
-IFS="${oIFS}"
-
-pathcomp=''
-
-while [ $# -ne 0 ] ; do
- pathcomp="${pathcomp}${1}"
- shift
-
- if [ ! -d "${pathcomp}" ] ;
- then
- $mkdirprog "${pathcomp}"
- else
- true
- fi
-
- pathcomp="${pathcomp}/"
-done
-fi
-
-if [ x"$dir_arg" != x ]
-then
- $doit $instcmd $dst &&
-
- if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
- if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
- if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
- if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
-else
-
-# If we're going to rename the final executable, determine the name now.
-
- if [ x"$transformarg" = x ]
- then
- dstfile=`basename $dst`
- else
- dstfile=`basename $dst $transformbasename |
- sed $transformarg`$transformbasename
- fi
-
-# don't allow the sed command to completely eliminate the filename
-
- if [ x"$dstfile" = x ]
- then
- dstfile=`basename $dst`
- else
- true
- fi
-
-# Make a temp file name in the proper directory.
-
- dsttmp=$dstdir/#inst.$$#
-
-# Move or copy the file name to the temp name
-
- $doit $instcmd $src $dsttmp &&
-
- trap "rm -f ${dsttmp}" 0 &&
-
-# and set any options; do chmod last to preserve setuid bits
-
-# If any of these fail, we abort the whole thing. If we want to
-# ignore errors from any of these, just make sure not to ignore
-# errors from the above "$doit $instcmd $src $dsttmp" command.
-
- if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
- if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
- if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
- if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
-
-# Now rename the file to the real destination.
-
- $doit $rmcmd -f $dstdir/$dstfile &&
- $doit $mvcmd $dsttmp $dstdir/$dstfile
-
-fi &&
-
-
-exit 0
+++ /dev/null
-#! /bin/sh
-
-# ltconfig - Create a system-specific libtool.
-# Copyright (C) 1996-1999 Free Software Foundation, Inc.
-# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
-#
-# This file is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# A lot of this script is taken from autoconf-2.10.
-
-# Check that we are running under the correct shell.
-SHELL=${CONFIG_SHELL-/bin/sh}
-echo=echo
-if test "X$1" = X--no-reexec; then
- # Discard the --no-reexec flag, and continue.
- shift
-elif test "X$1" = X--fallback-echo; then
- # Avoid inline document here, it may be left over
- :
-elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
- # Yippee, $echo works!
- :
-else
- # Restart under the correct shell.
- exec "$SHELL" "$0" --no-reexec ${1+"$@"}
-fi
-
-if test "X$1" = X--fallback-echo; then
- # used as fallback echo
- shift
- cat <<EOF
-$*
-EOF
- exit 0
-fi
-
-# Find the correct PATH separator. Usually this is `:', but
-# DJGPP uses `;' like DOS.
-if test "X${PATH_SEPARATOR+set}" != "Xset"; then
- UNAME=${UNAME-`uname 2>/dev/null`}
- case X$UNAME in
- *-DOS) PATH_SEPARATOR=';' ;;
- *) PATH_SEPARATOR=':' ;;
- esac
-fi
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-if test "${CDPATH+set}" = set; then CDPATH=; export CDPATH; fi
-
-if test "X${echo_test_string+set}" != "Xset"; then
- # find a string as large as possible, as long as the shell can cope with it
- for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do
- # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
- if (echo_test_string="`eval $cmd`") 2>/dev/null &&
- echo_test_string="`eval $cmd`" &&
- (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null; then
- break
- fi
- done
-fi
-
-if test "X`($echo '\t') 2>/dev/null`" != 'X\t' ||
- test "X`($echo "$echo_test_string") 2>/dev/null`" != X"$echo_test_string"; then
- # The Solaris, AIX, and Digital Unix default echo programs unquote
- # backslashes. This makes it impossible to quote backslashes using
- # echo "$something" | sed 's/\\/\\\\/g'
- #
- # So, first we look for a working echo in the user's PATH.
-
- IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}"
- for dir in $PATH /usr/ucb; do
- if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
- test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
- test "X`($dir/echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then
- echo="$dir/echo"
- break
- fi
- done
- IFS="$save_ifs"
-
- if test "X$echo" = Xecho; then
- # We didn't find a better echo, so look for alternatives.
- if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' &&
- test "X`(print -r "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then
- # This shell has a builtin print -r that does the trick.
- echo='print -r'
- elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) &&
- test "X$CONFIG_SHELL" != X/bin/ksh; then
- # If we have ksh, try running ltconfig again with it.
- ORIGINAL_CONFIG_SHELL="${CONFIG_SHELL-/bin/sh}"
- export ORIGINAL_CONFIG_SHELL
- CONFIG_SHELL=/bin/ksh
- export CONFIG_SHELL
- exec "$CONFIG_SHELL" "$0" --no-reexec ${1+"$@"}
- else
- # Try using printf.
- echo='printf "%s\n"'
- if test "X`($echo '\t') 2>/dev/null`" = 'X\t' &&
- test "X`($echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then
- # Cool, printf works
- :
- elif test "X`("$ORIGINAL_CONFIG_SHELL" "$0" --fallback-echo '\t') 2>/dev/null`" = 'X\t' &&
- test "X`("$ORIGINAL_CONFIG_SHELL" "$0" --fallback-echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then
- CONFIG_SHELL="$ORIGINAL_CONFIG_SHELL"
- export CONFIG_SHELL
- SHELL="$CONFIG_SHELL"
- export SHELL
- echo="$CONFIG_SHELL $0 --fallback-echo"
- elif test "X`("$CONFIG_SHELL" "$0" --fallback-echo '\t') 2>/dev/null`" = 'X\t' &&
- test "X`("$CONFIG_SHELL" "$0" --fallback-echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then
- echo="$CONFIG_SHELL $0 --fallback-echo"
- else
- # maybe with a smaller string...
- prev=:
-
- for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do
- if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null; then
- break
- fi
- prev="$cmd"
- done
-
- if test "$prev" != 'sed 50q "$0"'; then
- echo_test_string=`eval $prev`
- export echo_test_string
- exec "${ORIGINAL_CONFIG_SHELL}" "$0" ${1+"$@"}
- else
- # Oops. We lost completely, so just stick with echo.
- echo=echo
- fi
- fi
- fi
- fi
-fi
-
-# Sed substitution that helps us do robust quoting. It backslashifies
-# metacharacters that are still active within double-quoted strings.
-Xsed='sed -e s/^X//'
-sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'
-
-# Same as above, but do not quote variable references.
-double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'
-
-# Sed substitution to delay expansion of an escaped shell variable in a
-# double_quote_subst'ed string.
-delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
-
-# The name of this program.
-progname=`$echo "X$0" | $Xsed -e 's%^.*/%%'`
-
-# Constants:
-PROGRAM=ltconfig
-PACKAGE=libtool
-VERSION=1.3.3
-TIMESTAMP=" (1.385.2.181 1999/07/02 15:49:11)"
-ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.c 1>&5'
-ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.c $LIBS 1>&5'
-rm="rm -f"
-
-help="Try \`$progname --help' for more information."
-
-# Global variables:
-default_ofile=libtool
-can_build_shared=yes
-enable_shared=yes
-# All known linkers require a `.a' archive for static linking (except M$VC,
-# which needs '.lib').
-enable_static=yes
-enable_fast_install=yes
-enable_dlopen=unknown
-enable_win32_dll=no
-ltmain=
-silent=
-srcdir=
-ac_config_guess=
-ac_config_sub=
-host=
-nonopt=
-ofile="$default_ofile"
-verify_host=yes
-with_gcc=no
-with_gnu_ld=no
-need_locks=yes
-ac_ext=c
-objext=o
-libext=a
-exeext=
-cache_file=
-
-old_AR="$AR"
-old_CC="$CC"
-old_CFLAGS="$CFLAGS"
-old_CPPFLAGS="$CPPFLAGS"
-old_LDFLAGS="$LDFLAGS"
-old_LD="$LD"
-old_LN_S="$LN_S"
-old_LIBS="$LIBS"
-old_NM="$NM"
-old_RANLIB="$RANLIB"
-old_DLLTOOL="$DLLTOOL"
-old_OBJDUMP="$OBJDUMP"
-old_AS="$AS"
-
-# Parse the command line options.
-args=
-prev=
-for option
-do
- case "$option" in
- -*=*) optarg=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
- *) optarg= ;;
- esac
-
- # If the previous option needs an argument, assign it.
- if test -n "$prev"; then
- eval "$prev=\$option"
- prev=
- continue
- fi
-
- case "$option" in
- --help) cat <<EOM
-Usage: $progname [OPTION]... [HOST [LTMAIN]]
-
-Generate a system-specific libtool script.
-
- --debug enable verbose shell tracing
- --disable-shared do not build shared libraries
- --disable-static do not build static libraries
- --disable-fast-install do not optimize for fast installation
- --enable-dlopen enable dlopen support
- --enable-win32-dll enable building dlls on win32 hosts
- --help display this help and exit
- --no-verify do not verify that HOST is a valid host type
--o, --output=FILE specify the output file [default=$default_ofile]
- --quiet same as \`--silent'
- --silent do not print informational messages
- --srcdir=DIR find \`config.guess' in DIR
- --version output version information and exit
- --with-gcc assume that the GNU C compiler will be used
- --with-gnu-ld assume that the C compiler uses the GNU linker
- --disable-lock disable file locking
- --cache-file=FILE configure cache file
-
-LTMAIN is the \`ltmain.sh' shell script fragment or \`ltmain.c' program
-that provides basic libtool functionality.
-
-HOST is the canonical host system name [default=guessed].
-EOM
- exit 0
- ;;
-
- --debug)
- echo "$progname: enabling shell trace mode"
- set -x
- ;;
-
- --disable-shared) enable_shared=no ;;
-
- --disable-static) enable_static=no ;;
-
- --disable-fast-install) enable_fast_install=no ;;
-
- --enable-dlopen) enable_dlopen=yes ;;
-
- --enable-win32-dll) enable_win32_dll=yes ;;
-
- --quiet | --silent) silent=yes ;;
-
- --srcdir) prev=srcdir ;;
- --srcdir=*) srcdir="$optarg" ;;
-
- --no-verify) verify_host=no ;;
-
- --output | -o) prev=ofile ;;
- --output=*) ofile="$optarg" ;;
-
- --version) echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP"; exit 0 ;;
-
- --with-gcc) with_gcc=yes ;;
- --with-gnu-ld) with_gnu_ld=yes ;;
-
- --disable-lock) need_locks=no ;;
-
- --cache-file=*) cache_file="$optarg" ;;
-
- -*)
- echo "$progname: unrecognized option \`$option'" 1>&2
- echo "$help" 1>&2
- exit 1
- ;;
-
- *)
- if test -z "$ltmain"; then
- ltmain="$option"
- elif test -z "$host"; then
-# This generates an unnecessary warning for sparc-sun-solaris4.1.3_U1
-# if test -n "`echo $option| sed 's/[-a-z0-9.]//g'`"; then
-# echo "$progname: warning \`$option' is not a valid host type" 1>&2
-# fi
- host="$option"
- else
- echo "$progname: too many arguments" 1>&2
- echo "$help" 1>&2
- exit 1
- fi ;;
- esac
-done
-
-if test -z "$ltmain"; then
- echo "$progname: you must specify a LTMAIN file" 1>&2
- echo "$help" 1>&2
- exit 1
-fi
-
-if test ! -f "$ltmain"; then
- echo "$progname: \`$ltmain' does not exist" 1>&2
- echo "$help" 1>&2
- exit 1
-fi
-
-# Quote any args containing shell metacharacters.
-ltconfig_args=
-for arg
-do
- case "$arg" in
- *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
- ltconfig_args="$ltconfig_args '$arg'" ;;
- *) ltconfig_args="$ltconfig_args $arg" ;;
- esac
-done
-
-# A relevant subset of AC_INIT.
-
-# File descriptor usage:
-# 0 standard input
-# 1 file creation
-# 2 errors and warnings
-# 3 some systems may open it to /dev/tty
-# 4 used on the Kubota Titan
-# 5 compiler messages saved in config.log
-# 6 checking for... messages and results
-if test "$silent" = yes; then
- exec 6>/dev/null
-else
- exec 6>&1
-fi
-exec 5>>./config.log
-
-# NLS nuisances.
-# Only set LANG and LC_ALL to C if already set.
-# These must not be set unconditionally because not all systems understand
-# e.g. LANG=C (notably SCO).
-if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
-if test "${LANG+set}" = set; then LANG=C; export LANG; fi
-
-if test -n "$cache_file" && test -r "$cache_file"; then
- echo "loading cache $cache_file within ltconfig"
- . $cache_file
-fi
-
-if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
- # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
- if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
- ac_n= ac_c='
-' ac_t=' '
- else
- ac_n=-n ac_c= ac_t=
- fi
-else
- ac_n= ac_c='\c' ac_t=
-fi
-
-if test -z "$srcdir"; then
- # Assume the source directory is the same one as the path to LTMAIN.
- srcdir=`$echo "X$ltmain" | $Xsed -e 's%/[^/]*$%%'`
- test "$srcdir" = "$ltmain" && srcdir=.
-fi
-
-trap "$rm conftest*; exit 1" 1 2 15
-if test "$verify_host" = yes; then
- # Check for config.guess and config.sub.
- ac_aux_dir=
- for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
- if test -f $ac_dir/config.guess; then
- ac_aux_dir=$ac_dir
- break
- fi
- done
- if test -z "$ac_aux_dir"; then
- echo "$progname: cannot find config.guess in $srcdir $srcdir/.. $srcdir/../.." 1>&2
- echo "$help" 1>&2
- exit 1
- fi
- ac_config_guess=$ac_aux_dir/config.guess
- ac_config_sub=$ac_aux_dir/config.sub
-
- # Make sure we can run config.sub.
- if $SHELL $ac_config_sub sun4 >/dev/null 2>&1; then :
- else
- echo "$progname: cannot run $ac_config_sub" 1>&2
- echo "$help" 1>&2
- exit 1
- fi
-
- echo $ac_n "checking host system type""... $ac_c" 1>&6
-
- host_alias=$host
- case "$host_alias" in
- "")
- if host_alias=`$SHELL $ac_config_guess`; then :
- else
- echo "$progname: cannot guess host type; you must specify one" 1>&2
- echo "$help" 1>&2
- exit 1
- fi ;;
- esac
- host=`$SHELL $ac_config_sub $host_alias`
- echo "$ac_t$host" 1>&6
-
- # Make sure the host verified.
- test -z "$host" && exit 1
-
-elif test -z "$host"; then
- echo "$progname: you must specify a host type if you use \`--no-verify'" 1>&2
- echo "$help" 1>&2
- exit 1
-else
- host_alias=$host
-fi
-
-# Transform linux* to *-*-linux-gnu*, to support old configure scripts.
-case "$host_os" in
-linux-gnu*) ;;
-linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'`
-esac
-
-host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
-host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
-host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
-
-case "$host_os" in
-aix3*)
- # AIX sometimes has problems with the GCC collect2 program. For some
- # reason, if we set the COLLECT_NAMES environment variable, the problems
- # vanish in a puff of smoke.
- if test "${COLLECT_NAMES+set}" != set; then
- COLLECT_NAMES=
- export COLLECT_NAMES
- fi
- ;;
-esac
-
-# Determine commands to create old-style static archives.
-old_archive_cmds='$AR cru $oldlib$oldobjs'
-old_postinstall_cmds='chmod 644 $oldlib'
-old_postuninstall_cmds=
-
-# Set a sane default for `AR'.
-test -z "$AR" && AR=ar
-
-# Set a sane default for `OBJDUMP'.
-test -z "$OBJDUMP" && OBJDUMP=objdump
-
-# If RANLIB is not set, then run the test.
-if test "${RANLIB+set}" != "set"; then
- result=no
-
- echo $ac_n "checking for ranlib... $ac_c" 1>&6
- IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}"
- for dir in $PATH; do
- test -z "$dir" && dir=.
- if test -f $dir/ranlib || test -f $dir/ranlib$ac_exeext; then
- RANLIB="ranlib"
- result="ranlib"
- break
- fi
- done
- IFS="$save_ifs"
-
- echo "$ac_t$result" 1>&6
-fi
-
-if test -n "$RANLIB"; then
- old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
- old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds"
-fi
-
-# Set sane defaults for `DLLTOOL', `OBJDUMP', and `AS', used on cygwin.
-test -z "$DLLTOOL" && DLLTOOL=dlltool
-test -z "$OBJDUMP" && OBJDUMP=objdump
-test -z "$AS" && AS=as
-
-# Check to see if we are using GCC.
-if test "$with_gcc" != yes || test -z "$CC"; then
- # If CC is not set, then try to find GCC or a usable CC.
- if test -z "$CC"; then
- echo $ac_n "checking for gcc... $ac_c" 1>&6
- IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}"
- for dir in $PATH; do
- test -z "$dir" && dir=.
- if test -f $dir/gcc || test -f $dir/gcc$ac_exeext; then
- CC="gcc"
- break
- fi
- done
- IFS="$save_ifs"
-
- if test -n "$CC"; then
- echo "$ac_t$CC" 1>&6
- else
- echo "$ac_t"no 1>&6
- fi
- fi
-
- # Not "gcc", so try "cc", rejecting "/usr/ucb/cc".
- if test -z "$CC"; then
- echo $ac_n "checking for cc... $ac_c" 1>&6
- IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}"
- cc_rejected=no
- for dir in $PATH; do
- test -z "$dir" && dir=.
- if test -f $dir/cc || test -f $dir/cc$ac_exeext; then
- if test "$dir/cc" = "/usr/ucb/cc"; then
- cc_rejected=yes
- continue
- fi
- CC="cc"
- break
- fi
- done
- IFS="$save_ifs"
- if test $cc_rejected = yes; then
- # We found a bogon in the path, so make sure we never use it.
- set dummy $CC
- shift
- if test $# -gt 0; then
- # We chose a different compiler from the bogus one.
- # However, it has the same name, so the bogon will be chosen
- # first if we set CC to just the name; use the full file name.
- shift
- set dummy "$dir/cc" "$@"
- shift
- CC="$@"
- fi
- fi
-
- if test -n "$CC"; then
- echo "$ac_t$CC" 1>&6
- else
- echo "$ac_t"no 1>&6
- fi
-
- if test -z "$CC"; then
- echo "$progname: error: no acceptable cc found in \$PATH" 1>&2
- exit 1
- fi
- fi
-
- # Now see if the compiler is really GCC.
- with_gcc=no
- echo $ac_n "checking whether we are using GNU C... $ac_c" 1>&6
- echo "$progname:581: checking whether we are using GNU C" >&5
-
- $rm conftest.c
- cat > conftest.c <<EOF
-#ifdef __GNUC__
- yes;
-#endif
-EOF
- if { ac_try='${CC-cc} -E conftest.c'; { (eval echo $progname:589: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
- with_gcc=yes
- fi
- $rm conftest.c
- echo "$ac_t$with_gcc" 1>&6
-fi
-
-# Allow CC to be a program name with arguments.
-set dummy $CC
-compiler="$2"
-
-echo $ac_n "checking for object suffix... $ac_c" 1>&6
-$rm conftest*
-echo 'int i = 1;' > conftest.c
-echo "$progname:603: checking for object suffix" >& 5
-if { (eval echo $progname:604: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; }; then
- # Append any warnings to the config.log.
- cat conftest.err 1>&5
-
- for ac_file in conftest.*; do
- case $ac_file in
- *.c) ;;
- *) objext=`echo $ac_file | sed -e s/conftest.//` ;;
- esac
- done
-else
- cat conftest.err 1>&5
- echo "$progname: failed program was:" >&5
- cat conftest.c >&5
-fi
-$rm conftest*
-echo "$ac_t$objext" 1>&6
-
-echo $ac_n "checking for executable suffix... $ac_c" 1>&6
-if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- ac_cv_exeext="no"
- $rm conftest*
- echo 'main () { return 0; }' > conftest.c
- echo "$progname:629: checking for executable suffix" >& 5
- if { (eval echo $progname:630: \"$ac_link\") 1>&5; (eval $ac_link) 2>conftest.err; }; then
- # Append any warnings to the config.log.
- cat conftest.err 1>&5
-
- for ac_file in conftest.*; do
- case $ac_file in
- *.c | *.err | *.$objext ) ;;
- *) ac_cv_exeext=.`echo $ac_file | sed -e s/conftest.//` ;;
- esac
- done
- else
- cat conftest.err 1>&5
- echo "$progname: failed program was:" >&5
- cat conftest.c >&5
- fi
- $rm conftest*
-fi
-if test "X$ac_cv_exeext" = Xno; then
- exeext=""
-else
- exeext="$ac_cv_exeext"
-fi
-echo "$ac_t$ac_cv_exeext" 1>&6
-
-echo $ac_n "checking for $compiler option to produce PIC... $ac_c" 1>&6
-pic_flag=
-special_shlib_compile_flags=
-wl=
-link_static_flag=
-no_builtin_flag=
-
-if test "$with_gcc" = yes; then
- wl='-Wl,'
- link_static_flag='-static'
-
- case "$host_os" in
- beos* | irix5* | irix6* | osf3* | osf4* | bsdi3* )
- # PIC is the default for these OSes.
- ;;
- aix*)
- # Below there is a dirty hack to force normal static linking with -ldl
- # The problem is because libdl dynamically linked with both libc and
- # libC (AIX C++ library), which obviously doesn't included in libraries
- # list by gcc. This cause undefined symbols with -static flags.
- # This hack allows C programs to be linked with "-static -ldl", but
- # we not sure about C++ programs.
- link_static_flag="$link_static_flag ${wl}-lC"
- ;;
- cygwin* | mingw* | os2*)
- # We can build DLLs from non-PIC.
- ;;
- amigaos*)
- # FIXME: we need at least 68020 code to build shared libraries, but
- # adding the `-m68020' flag to GCC prevents building anything better,
- # like `-m68040'.
- pic_flag='-m68020 -resident32 -malways-restore-a4'
- ;;
- sysv4*MP*)
- if test -d /usr/nec; then
- pic_flag=-Kconform_pic
- fi
- ;;
- *)
- pic_flag='-fPIC'
- ;;
- esac
-else
- # PORTME Check for PIC flags for the system compiler.
- case "$host_os" in
- aix3* | aix4*)
- # All AIX code is PIC.
- link_static_flag='-bnso -bI:/lib/syscalls.exp'
- ;;
-
- hpux9* | hpux10* | hpux11*)
- # Is there a better link_static_flag that works with the bundled CC?
- wl='-Wl,'
- link_static_flag="${wl}-a ${wl}archive"
- pic_flag='+Z'
- ;;
-
- irix5* | irix6*)
- wl='-Wl,'
- link_static_flag='-non_shared'
- # PIC (with -KPIC) is the default.
- ;;
-
- cygwin* | mingw* | os2*)
- # We can build DLLs from non-PIC.
- ;;
-
- osf3* | osf4*)
- # All OSF/1 code is PIC.
- wl='-Wl,'
- link_static_flag='-non_shared'
- ;;
-
- sco3.2v5*)
- pic_flag='-Kpic'
- link_static_flag='-dn'
- special_shlib_compile_flags='-belf'
- ;;
-
- solaris*)
- pic_flag='-KPIC'
- link_static_flag='-Bstatic'
- wl='-Wl,'
- ;;
-
- sunos4*)
- pic_flag='-PIC'
- link_static_flag='-Bstatic'
- wl='-Qoption ld '
- ;;
-
- sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
- pic_flag='-KPIC'
- link_static_flag='-Bstatic'
- wl='-Wl,'
- ;;
-
- uts4*)
- pic_flag='-pic'
- link_static_flag='-Bstatic'
- ;;
- sysv4*MP*)
- if test -d /usr/nec ;then
- pic_flag='-Kconform_pic'
- link_static_flag='-Bstatic'
- fi
- ;;
- *)
- can_build_shared=no
- ;;
- esac
-fi
-
-if test -n "$pic_flag"; then
- echo "$ac_t$pic_flag" 1>&6
-
- # Check to make sure the pic_flag actually works.
- echo $ac_n "checking if $compiler PIC flag $pic_flag works... $ac_c" 1>&6
- $rm conftest*
- echo "int some_variable = 0;" > conftest.c
- save_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS $pic_flag -DPIC"
- echo "$progname:776: checking if $compiler PIC flag $pic_flag works" >&5
- if { (eval echo $progname:777: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.$objext; then
- # Append any warnings to the config.log.
- cat conftest.err 1>&5
-
- case "$host_os" in
- hpux9* | hpux10* | hpux11*)
- # On HP-UX, both CC and GCC only warn that PIC is supported... then they
- # create non-PIC objects. So, if there were any warnings, we assume that
- # PIC is not supported.
- if test -s conftest.err; then
- echo "$ac_t"no 1>&6
- can_build_shared=no
- pic_flag=
- else
- echo "$ac_t"yes 1>&6
- pic_flag=" $pic_flag"
- fi
- ;;
- *)
- echo "$ac_t"yes 1>&6
- pic_flag=" $pic_flag"
- ;;
- esac
- else
- # Append any errors to the config.log.
- cat conftest.err 1>&5
- can_build_shared=no
- pic_flag=
- echo "$ac_t"no 1>&6
- fi
- CFLAGS="$save_CFLAGS"
- $rm conftest*
-else
- echo "$ac_t"none 1>&6
-fi
-
-# Check to see if options -o and -c are simultaneously supported by compiler
-echo $ac_n "checking if $compiler supports -c -o file.o... $ac_c" 1>&6
-$rm -r conftest 2>/dev/null
-mkdir conftest
-cd conftest
-$rm conftest*
-echo "int some_variable = 0;" > conftest.c
-mkdir out
-# According to Tom Tromey, Ian Lance Taylor reported there are C compilers
-# that will create temporary files in the current directory regardless of
-# the output directory. Thus, making CWD read-only will cause this test
-# to fail, enabling locking or at least warning the user not to do parallel
-# builds.
-chmod -w .
-save_CFLAGS="$CFLAGS"
-CFLAGS="$CFLAGS -o out/conftest2.o"
-echo "$progname:829: checking if $compiler supports -c -o file.o" >&5
-if { (eval echo $progname:830: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.o; then
-
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings
- if test -s out/conftest.err; then
- echo "$ac_t"no 1>&6
- compiler_c_o=no
- else
- echo "$ac_t"yes 1>&6
- compiler_c_o=yes
- fi
-else
- # Append any errors to the config.log.
- cat out/conftest.err 1>&5
- compiler_c_o=no
- echo "$ac_t"no 1>&6
-fi
-CFLAGS="$save_CFLAGS"
-chmod u+w .
-$rm conftest* out/*
-rmdir out
-cd ..
-rmdir conftest
-$rm -r conftest 2>/dev/null
-
-if test x"$compiler_c_o" = x"yes"; then
- # Check to see if we can write to a .lo
- echo $ac_n "checking if $compiler supports -c -o file.lo... $ac_c" 1>&6
- $rm conftest*
- echo "int some_variable = 0;" > conftest.c
- save_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS -c -o conftest.lo"
- echo "$progname:862: checking if $compiler supports -c -o file.lo" >&5
-if { (eval echo $progname:863: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.lo; then
-
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings
- if test -s conftest.err; then
- echo "$ac_t"no 1>&6
- compiler_o_lo=no
- else
- echo "$ac_t"yes 1>&6
- compiler_o_lo=yes
- fi
- else
- # Append any errors to the config.log.
- cat conftest.err 1>&5
- compiler_o_lo=no
- echo "$ac_t"no 1>&6
- fi
- CFLAGS="$save_CFLAGS"
- $rm conftest*
-else
- compiler_o_lo=no
-fi
-
-# Check to see if we can do hard links to lock some files if needed
-hard_links="nottested"
-if test "$compiler_c_o" = no && test "$need_locks" != no; then
- # do not overwrite the value of need_locks provided by the user
- echo $ac_n "checking if we can lock with hard links... $ac_c" 1>&6
- hard_links=yes
- $rm conftest*
- ln conftest.a conftest.b 2>/dev/null && hard_links=no
- touch conftest.a
- ln conftest.a conftest.b 2>&5 || hard_links=no
- ln conftest.a conftest.b 2>/dev/null && hard_links=no
- echo "$ac_t$hard_links" 1>&6
- $rm conftest*
- if test "$hard_links" = no; then
- echo "*** WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2
- need_locks=warn
- fi
-else
- need_locks=no
-fi
-
-if test "$with_gcc" = yes; then
- # Check to see if options -fno-rtti -fno-exceptions are supported by compiler
- echo $ac_n "checking if $compiler supports -fno-rtti -fno-exceptions ... $ac_c" 1>&6
- $rm conftest*
- echo "int some_variable = 0;" > conftest.c
- save_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -c conftest.c"
- echo "$progname:914: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
- if { (eval echo $progname:915: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.o; then
-
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings
- if test -s conftest.err; then
- echo "$ac_t"no 1>&6
- compiler_rtti_exceptions=no
- else
- echo "$ac_t"yes 1>&6
- compiler_rtti_exceptions=yes
- fi
- else
- # Append any errors to the config.log.
- cat conftest.err 1>&5
- compiler_rtti_exceptions=no
- echo "$ac_t"no 1>&6
- fi
- CFLAGS="$save_CFLAGS"
- $rm conftest*
-
- if test "$compiler_rtti_exceptions" = "yes"; then
- no_builtin_flag=' -fno-builtin -fno-rtti -fno-exceptions'
- else
- no_builtin_flag=' -fno-builtin'
- fi
-
-fi
-
-# Check for any special shared library compilation flags.
-if test -n "$special_shlib_compile_flags"; then
- echo "$progname: warning: \`$CC' requires \`$special_shlib_compile_flags' to build shared libraries" 1>&2
- if echo "$old_CC $old_CFLAGS " | egrep -e "[ ]$special_shlib_compile_flags[ ]" >/dev/null; then :
- else
- echo "$progname: add \`$special_shlib_compile_flags' to the CC or CFLAGS env variable and reconfigure" 1>&2
- can_build_shared=no
- fi
-fi
-
-echo $ac_n "checking if $compiler static flag $link_static_flag works... $ac_c" 1>&6
-$rm conftest*
-echo 'main(){return(0);}' > conftest.c
-save_LDFLAGS="$LDFLAGS"
-LDFLAGS="$LDFLAGS $link_static_flag"
-echo "$progname:958: checking if $compiler static flag $link_static_flag works" >&5
-if { (eval echo $progname:959: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
- echo "$ac_t$link_static_flag" 1>&6
-else
- echo "$ac_t"none 1>&6
- link_static_flag=
-fi
-LDFLAGS="$save_LDFLAGS"
-$rm conftest*
-
-if test -z "$LN_S"; then
- # Check to see if we can use ln -s, or we need hard links.
- echo $ac_n "checking whether ln -s works... $ac_c" 1>&6
- $rm conftest.dat
- if ln -s X conftest.dat 2>/dev/null; then
- $rm conftest.dat
- LN_S="ln -s"
- else
- LN_S=ln
- fi
- if test "$LN_S" = "ln -s"; then
- echo "$ac_t"yes 1>&6
- else
- echo "$ac_t"no 1>&6
- fi
-fi
-
-# Make sure LD is an absolute path.
-if test -z "$LD"; then
- ac_prog=ld
- if test "$with_gcc" = yes; then
- # Check if gcc -print-prog-name=ld gives a path.
- echo $ac_n "checking for ld used by GCC... $ac_c" 1>&6
- echo "$progname:991: checking for ld used by GCC" >&5
- ac_prog=`($CC -print-prog-name=ld) 2>&5`
- case "$ac_prog" in
- # Accept absolute paths.
- [\\/]* | [A-Za-z]:[\\/]*)
- re_direlt='/[^/][^/]*/\.\./'
- # Canonicalize the path of ld
- ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
- while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
- ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
- done
- test -z "$LD" && LD="$ac_prog"
- ;;
- "")
- # If it fails, then pretend we are not using GCC.
- ac_prog=ld
- ;;
- *)
- # If it is relative, then search for the first ld in PATH.
- with_gnu_ld=unknown
- ;;
- esac
- elif test "$with_gnu_ld" = yes; then
- echo $ac_n "checking for GNU ld... $ac_c" 1>&6
- echo "$progname:1015: checking for GNU ld" >&5
- else
- echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6
- echo "$progname:1018: checking for non-GNU ld" >&5
- fi
-
- if test -z "$LD"; then
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}"
- for ac_dir in $PATH; do
- test -z "$ac_dir" && ac_dir=.
- if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
- LD="$ac_dir/$ac_prog"
- # Check to see if the program is GNU ld. I'd rather use --version,
- # but apparently some GNU ld's only accept -v.
- # Break only if it was the GNU/non-GNU ld that we prefer.
- if "$LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then
- test "$with_gnu_ld" != no && break
- else
- test "$with_gnu_ld" != yes && break
- fi
- fi
- done
- IFS="$ac_save_ifs"
- fi
-
- if test -n "$LD"; then
- echo "$ac_t$LD" 1>&6
- else
- echo "$ac_t"no 1>&6
- fi
-
- if test -z "$LD"; then
- echo "$progname: error: no acceptable ld found in \$PATH" 1>&2
- exit 1
- fi
-fi
-
-# Check to see if it really is or is not GNU ld.
-echo $ac_n "checking if the linker ($LD) is GNU ld... $ac_c" 1>&6
-# I'd rather use --version here, but apparently some GNU ld's only accept -v.
-if $LD -v 2>&1 </dev/null | egrep '(GNU|with BFD)' 1>&5; then
- with_gnu_ld=yes
-else
- with_gnu_ld=no
-fi
-echo "$ac_t$with_gnu_ld" 1>&6
-
-# See if the linker supports building shared libraries.
-echo $ac_n "checking whether the linker ($LD) supports shared libraries... $ac_c" 1>&6
-
-allow_undefined_flag=
-no_undefined_flag=
-need_lib_prefix=unknown
-need_version=unknown
-# when you set need_version to no, make sure it does not cause -set_version
-# flags to be left without arguments
-archive_cmds=
-archive_expsym_cmds=
-old_archive_from_new_cmds=
-export_dynamic_flag_spec=
-whole_archive_flag_spec=
-thread_safe_flag_spec=
-hardcode_libdir_flag_spec=
-hardcode_libdir_separator=
-hardcode_direct=no
-hardcode_minus_L=no
-hardcode_shlibpath_var=unsupported
-runpath_var=
-always_export_symbols=no
-export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols'
-# include_expsyms should be a list of space-separated symbols to be *always*
-# included in the symbol list
-include_expsyms=
-# exclude_expsyms can be an egrep regular expression of symbols to exclude
-# it will be wrapped by ` (' and `)$', so one must not match beginning or
-# end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
-# as well as any symbol that contains `d'.
-exclude_expsyms="_GLOBAL_OFFSET_TABLE_"
-# Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
-# platforms (ab)use it in PIC code, but their linkers get confused if
-# the symbol is explicitly referenced. Since portable code cannot
-# rely on this symbol name, it's probably fine to never include it in
-# preloaded symbol tables.
-
-case "$host_os" in
-cygwin* | mingw*)
- # FIXME: the MSVC++ port hasn't been tested in a loooong time
- # When not using gcc, we currently assume that we are using
- # Microsoft Visual C++.
- if test "$with_gcc" != yes; then
- with_gnu_ld=no
- fi
- ;;
-
-esac
-
-ld_shlibs=yes
-if test "$with_gnu_ld" = yes; then
- # If archive_cmds runs LD, not CC, wlarc should be empty
- wlarc='${wl}'
-
- # See if GNU ld supports shared libraries.
- case "$host_os" in
- aix3* | aix4*)
- # On AIX, the GNU linker is very broken
- ld_shlibs=no
- cat <<EOF 1>&2
-
-*** Warning: the GNU linker, at least up to release 2.9.1, is reported
-*** to be unable to reliably create shared libraries on AIX.
-*** Therefore, libtool is disabling shared libraries support. If you
-*** really care for shared libraries, you may want to modify your PATH
-*** so that a non-GNU linker is found, and then restart.
-
-EOF
- ;;
-
- amigaos*)
- archive_cmds='$rm $objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $objdir/a2ixlibrary.data~$AR cru $lib $libobjs~$RANLIB $lib~(cd $objdir && a2ixlibrary -32)'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_minus_L=yes
-
- # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
- # that the semantics of dynamic libraries on AmigaOS, at least up
- # to version 4, is to share data among multiple programs linked
- # with the same dynamic library. Since this doesn't match the
- # behavior of shared libraries on other platforms, we can use
- # them.
- ld_shlibs=no
- ;;
-
- beos*)
- if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
- allow_undefined_flag=unsupported
- # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
- # support --undefined. This deserves some investigation. FIXME
- archive_cmds='$CC -nostart $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib'
- else
- ld_shlibs=no
- fi
- ;;
-
- cygwin* | mingw*)
- # hardcode_libdir_flag_spec is actually meaningless, as there is
- # no search path for DLLs.
- hardcode_libdir_flag_spec='-L$libdir'
- allow_undefined_flag=unsupported
- always_export_symbols=yes
-
- # Extract the symbol export list from an `--export-all' def file,
- # then regenerate the def file from the symbol export list, so that
- # the compiled dll only exports the symbol export list.
- export_symbols_cmds='test -f $objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $0 > $objdir/$soname-ltdll.c~
- test -f $objdir/$soname-ltdll.$objext || (cd $objdir && $CC -c $soname-ltdll.c)~
- $DLLTOOL --export-all --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --output-def $objdir/$soname-def $objdir/$soname-ltdll.$objext $libobjs $convenience~
- sed -e "1,/EXPORTS/d" -e "s/ @ [0-9]* ; *//" < $objdir/$soname-def > $export_symbols'
-
- archive_expsym_cmds='echo EXPORTS > $objdir/$soname-def~
- _lt_hint=1;
- for symbol in `cat $export_symbols`; do
- echo " \$symbol @ \$_lt_hint ; " >> $objdir/$soname-def;
- _lt_hint=`expr 1 + \$_lt_hint`;
- done~
- test -f $objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $0 > $objdir/$soname-ltdll.c~
- test -f $objdir/$soname-ltdll.$objext || (cd $objdir && $CC -c $soname-ltdll.c)~
- $CC -Wl,--base-file,$objdir/$soname-base -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts~
- $DLLTOOL --as=$AS --dllname $soname --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --def $objdir/$soname-def --base-file $objdir/$soname-base --output-exp $objdir/$soname-exp~
- $CC -Wl,--base-file,$objdir/$soname-base $objdir/$soname-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts~
- $DLLTOOL --as=$AS --dllname $soname --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --def $objdir/$soname-def --base-file $objdir/$soname-base --output-exp $objdir/$soname-exp~
- $CC $objdir/$soname-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts'
-
- old_archive_from_new_cmds='$DLLTOOL --as=$AS --dllname $soname --def $objdir/$soname-def --output-lib $objdir/$libname.a'
- ;;
-
- netbsd*)
- if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
- archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib'
- archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
- else
- archive_cmds='$LD -Bshareable $libobjs $deplibs $linkopts -o $lib'
- # can we support soname and/or expsyms with a.out? -oliva
- fi
- ;;
-
- solaris*)
- if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then
- ld_shlibs=no
- cat <<EOF 1>&2
-
-*** Warning: The releases 2.8.* of the GNU linker cannot reliably
-*** create shared libraries on Solaris systems. Therefore, libtool
-*** is disabling shared libraries support. We urge you to upgrade GNU
-*** binutils to release 2.9.1 or newer. Another option is to modify
-*** your PATH or compiler configuration so that the native linker is
-*** used, and then restart.
-
-EOF
- elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
- archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib'
- archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
- else
- ld_shlibs=no
- fi
- ;;
-
- sunos4*)
- archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linkopts'
- wlarc=
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- *)
- if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
- archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib'
- archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
- else
- ld_shlibs=no
- fi
- ;;
- esac
-
- if test "$ld_shlibs" = yes; then
- runpath_var=LD_RUN_PATH
- hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir'
- export_dynamic_flag_spec='${wl}--export-dynamic'
- case $host_os in
- cygwin* | mingw*)
- # dlltool doesn't understand --whole-archive et. al.
- whole_archive_flag_spec=
- ;;
- *)
- whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
- ;;
- esac
- fi
-else
- # PORTME fill in a description of your system's linker (not GNU ld)
- case "$host_os" in
- aix3*)
- allow_undefined_flag=unsupported
- always_export_symbols=yes
- archive_expsym_cmds='$LD -o $objdir/$soname $libobjs $deplibs $linkopts -bE:$export_symbols -T512 -H512 -bM:SRE~$AR cru $lib $objdir/$soname'
- # Note: this linker hardcodes the directories in LIBPATH if there
- # are no directories specified by -L.
- hardcode_minus_L=yes
- if test "$with_gcc" = yes && test -z "$link_static_flag"; then
- # Neither direct hardcoding nor static linking is supported with a
- # broken collect2.
- hardcode_direct=unsupported
- fi
- ;;
-
- aix4*)
- hardcode_libdir_flag_spec='${wl}-b ${wl}nolibpath ${wl}-b ${wl}libpath:$libdir:/usr/lib:/lib'
- hardcode_libdir_separator=':'
- if test "$with_gcc" = yes; then
- collect2name=`${CC} -print-prog-name=collect2`
- if test -f "$collect2name" && \
- strings "$collect2name" | grep resolve_lib_name >/dev/null
- then
- # We have reworked collect2
- hardcode_direct=yes
- else
- # We have old collect2
- hardcode_direct=unsupported
- # It fails to find uninstalled libraries when the uninstalled
- # path is not listed in the libpath. Setting hardcode_minus_L
- # to unsupported forces relinking
- hardcode_minus_L=yes
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_libdir_separator=
- fi
- shared_flag='-shared'
- else
- shared_flag='${wl}-bM:SRE'
- hardcode_direct=yes
- fi
- allow_undefined_flag=' ${wl}-berok'
- archive_cmds="\$CC $shared_flag"' -o $objdir/$soname $libobjs $deplibs $linkopts ${wl}-bexpall ${wl}-bnoentry${allow_undefined_flag}'
- archive_expsym_cmds="\$CC $shared_flag"' -o $objdir/$soname $libobjs $deplibs $linkopts ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}'
- case "$host_os" in aix4.[01]|aix4.[01].*)
- # According to Greg Wooledge, -bexpall is only supported from AIX 4.2 on
- always_export_symbols=yes ;;
- esac
- ;;
-
- amigaos*)
- archive_cmds='$rm $objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $objdir/a2ixlibrary.data~$AR cru $lib $libobjs~$RANLIB $lib~(cd $objdir && a2ixlibrary -32)'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_minus_L=yes
- # see comment about different semantics on the GNU ld section
- ld_shlibs=no
- ;;
-
- cygwin* | mingw*)
- # When not using gcc, we currently assume that we are using
- # Microsoft Visual C++.
- # hardcode_libdir_flag_spec is actually meaningless, as there is
- # no search path for DLLs.
- hardcode_libdir_flag_spec=' '
- allow_undefined_flag=unsupported
- # Tell ltmain to make .lib files, not .a files.
- libext=lib
- # FIXME: Setting linknames here is a bad hack.
- archive_cmds='$CC -o $lib $libobjs $linkopts `echo "$deplibs" | sed -e '\''s/ -lc$//'\''` -link -dll~linknames='
- # The linker will automatically build a .lib file if we build a DLL.
- old_archive_from_new_cmds='true'
- # FIXME: Should let the user specify the lib program.
- old_archive_cmds='lib /OUT:$oldlib$oldobjs'
- fix_srcfile_path='`cygpath -w $srcfile`'
- ;;
-
- freebsd1*)
- ld_shlibs=no
- ;;
-
- # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
- # support. Future versions do this automatically, but an explicit c++rt0.o
- # does not break anything, and helps significantly (at the cost of a little
- # extra space).
- freebsd2.2*)
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts /usr/lib/c++rt0.o'
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- # Unfortunately, older versions of FreeBSD 2 do not have this feature.
- freebsd2*)
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts'
- hardcode_direct=yes
- hardcode_minus_L=yes
- hardcode_shlibpath_var=no
- ;;
-
- # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
- freebsd*)
- archive_cmds='$CC -shared -o $lib $libobjs $deplibs $linkopts'
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- hpux9* | hpux10* | hpux11*)
- case "$host_os" in
- hpux9*) archive_cmds='$rm $objdir/$soname~$LD -b +b $install_libdir -o $objdir/$soname $libobjs $deplibs $linkopts~test $objdir/$soname = $lib || mv $objdir/$soname $lib' ;;
- *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linkopts' ;;
- esac
- hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
- hardcode_libdir_separator=:
- hardcode_direct=yes
- hardcode_minus_L=yes # Not in the search PATH, but as the default
- # location of the library.
- export_dynamic_flag_spec='${wl}-E'
- ;;
-
- irix5* | irix6*)
- if test "$with_gcc" = yes; then
- archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
- else
- archive_cmds='$LD -shared $libobjs $deplibs $linkopts -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
- fi
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
- hardcode_libdir_separator=:
- ;;
-
- netbsd*)
- if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts' # a.out
- else
- archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linkopts' # ELF
- fi
- hardcode_libdir_flag_spec='${wl}-R$libdir'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- openbsd*)
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts'
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- os2*)
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_minus_L=yes
- allow_undefined_flag=unsupported
- archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $objdir/$libname.def~$echo DATA >> $objdir/$libname.def~$echo " SINGLE NONSHARED" >> $objdir/$libname.def~$echo EXPORTS >> $objdir/$libname.def~emxexp $libobjs >> $objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $linkopts $objdir/$libname.def'
- old_archive_from_new_cmds='emximp -o $objdir/$libname.a $objdir/$libname.def'
- ;;
-
- osf3* | osf4*)
- if test "$with_gcc" = yes; then
- allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
- archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $linkopts ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib'
- else
- allow_undefined_flag=' -expect_unresolved \*'
- archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linkopts -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib'
- fi
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
- hardcode_libdir_separator=:
- ;;
-
- sco3.2v5*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts'
- hardcode_shlibpath_var=no
- runpath_var=LD_RUN_PATH
- hardcode_runpath_var=yes
- ;;
-
- solaris*)
- no_undefined_flag=' -z text'
- # $CC -shared without GNU ld will not create a library from C++
- # object files and a static libstdc++, better avoid it by now
- archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linkopts'
- archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~
- $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linkopts~$rm $lib.exp'
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_shlibpath_var=no
- case "$host_os" in
- solaris2.[0-5] | solaris2.[0-5].*) ;;
- *) # Supported since Solaris 2.6 (maybe 2.5.1?)
- whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;;
- esac
- ;;
-
- sunos4*)
- archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linkopts'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_direct=yes
- hardcode_minus_L=yes
- hardcode_shlibpath_var=no
- ;;
-
- sysv4)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts'
- runpath_var='LD_RUN_PATH'
- hardcode_shlibpath_var=no
- hardcode_direct=no #Motorola manual says yes, but my tests say they lie
- ;;
-
- sysv4.3*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts'
- hardcode_shlibpath_var=no
- export_dynamic_flag_spec='-Bexport'
- ;;
-
- uts4*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_shlibpath_var=no
- ;;
-
- dgux*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_shlibpath_var=no
- ;;
-
- sysv4*MP*)
- if test -d /usr/nec ;then
- # archive_cmds='$LD -G -z text -h $soname -o $lib$libobjs$deplibs'
- archive_cmds='$LD -G -h $soname -o $lib$libobjs$deplibs'
- hardcode_shlibpath_var=no
- runpath_var=LD_RUN_PATH
- hardcode_runpath_var=yes
- ld_shlibs=yes
- fi
- ;;
-
- *)
- ld_shlibs=no
- ;;
- esac
-fi
-echo "$ac_t$ld_shlibs" 1>&6
-test "$ld_shlibs" = no && can_build_shared=no
-
-if test -z "$NM"; then
- echo $ac_n "checking for BSD-compatible nm... $ac_c" 1>&6
- case "$NM" in
- [\\/]* | [A-Za-z]:[\\/]*) ;; # Let the user override the test with a path.
- *)
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}"
- for ac_dir in $PATH /usr/ucb /usr/ccs/bin /bin; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/nm || test -f $ac_dir/nm$ac_exeext; then
- # Check to see if the nm accepts a BSD-compat flag.
- # Adding the `sed 1q' prevents false positives on HP-UX, which says:
- # nm: unknown option "B" ignored
- if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
- NM="$ac_dir/nm -B"
- break
- elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
- NM="$ac_dir/nm -p"
- break
- else
- NM=${NM="$ac_dir/nm"} # keep the first match, but
- continue # so that we can try to find one that supports BSD flags
- fi
- fi
- done
- IFS="$ac_save_ifs"
- test -z "$NM" && NM=nm
- ;;
- esac
- echo "$ac_t$NM" 1>&6
-fi
-
-# Check for command to grab the raw symbol name followed by C symbol from nm.
-echo $ac_n "checking command to parse $NM output... $ac_c" 1>&6
-
-# These are sane defaults that work on at least a few old systems.
-# [They come from Ultrix. What could be older than Ultrix?!! ;)]
-
-# Character class describing NM global symbol codes.
-symcode='[BCDEGRST]'
-
-# Regexp to match symbols that can be accessed directly from C.
-sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
-
-# Transform the above into a raw symbol and a C symbol.
-symxfrm='\1 \2\3 \3'
-
-# Transform an extracted symbol line into a proper C declaration
-global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'"
-
-# Define system-specific variables.
-case "$host_os" in
-aix*)
- symcode='[BCDT]'
- ;;
-cygwin* | mingw*)
- symcode='[ABCDGISTW]'
- ;;
-hpux*) # Its linker distinguishes data from code symbols
- global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^. .* \(.*\)$/extern char \1;/p'"
- ;;
-irix*)
- symcode='[BCDEGRST]'
- ;;
-solaris*)
- symcode='[BDT]'
- ;;
-sysv4)
- symcode='[DFNSTU]'
- ;;
-esac
-
-# If we're using GNU nm, then use its standard symbol codes.
-if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then
- symcode='[ABCDGISTW]'
-fi
-
-# Try without a prefix undercore, then with it.
-for ac_symprfx in "" "_"; do
-
- # Write the raw and C identifiers.
- global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode\)[ ][ ]*\($ac_symprfx\)$sympat$/$symxfrm/p'"
-
- # Check to see that the pipe works correctly.
- pipe_works=no
- $rm conftest*
- cat > conftest.c <<EOF
-#ifdef __cplusplus
-extern "C" {
-#endif
-char nm_test_var;
-void nm_test_func(){}
-#ifdef __cplusplus
-}
-#endif
-main(){nm_test_var='a';nm_test_func();return(0);}
-EOF
-
- echo "$progname:1592: checking if global_symbol_pipe works" >&5
- if { (eval echo $progname:1593: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; } && test -s conftest.$objext; then
- # Now try to grab the symbols.
- nlist=conftest.nm
- if { echo "$progname:1596: eval \"$NM conftest.$objext | $global_symbol_pipe > $nlist\"" >&5; eval "$NM conftest.$objext | $global_symbol_pipe > $nlist 2>&5"; } && test -s "$nlist"; then
-
- # Try sorting and uniquifying the output.
- if sort "$nlist" | uniq > "$nlist"T; then
- mv -f "$nlist"T "$nlist"
- else
- rm -f "$nlist"T
- fi
-
- # Make sure that we snagged all the symbols we need.
- if egrep ' nm_test_var$' "$nlist" >/dev/null; then
- if egrep ' nm_test_func$' "$nlist" >/dev/null; then
- cat <<EOF > conftest.c
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-EOF
- # Now generate the symbol file.
- eval "$global_symbol_to_cdecl"' < "$nlist" >> conftest.c'
-
- cat <<EOF >> conftest.c
-#if defined (__STDC__) && __STDC__
-# define lt_ptr_t void *
-#else
-# define lt_ptr_t char *
-# define const
-#endif
-
-/* The mapping between symbol names and symbols. */
-const struct {
- const char *name;
- lt_ptr_t address;
-}
-lt_preloaded_symbols[] =
-{
-EOF
- sed 's/^. \(.*\) \(.*\)$/ {"\2", (lt_ptr_t) \&\2},/' < "$nlist" >> conftest.c
- cat <<\EOF >> conftest.c
- {0, (lt_ptr_t) 0}
-};
-
-#ifdef __cplusplus
-}
-#endif
-EOF
- # Now try linking the two files.
- mv conftest.$objext conftstm.$objext
- save_LIBS="$LIBS"
- save_CFLAGS="$CFLAGS"
- LIBS="conftstm.$objext"
- CFLAGS="$CFLAGS$no_builtin_flag"
- if { (eval echo $progname:1648: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
- pipe_works=yes
- else
- echo "$progname: failed program was:" >&5
- cat conftest.c >&5
- fi
- LIBS="$save_LIBS"
- else
- echo "cannot find nm_test_func in $nlist" >&5
- fi
- else
- echo "cannot find nm_test_var in $nlist" >&5
- fi
- else
- echo "cannot run $global_symbol_pipe" >&5
- fi
- else
- echo "$progname: failed program was:" >&5
- cat conftest.c >&5
- fi
- $rm conftest* conftst*
-
- # Do not use the global_symbol_pipe unless it works.
- if test "$pipe_works" = yes; then
- break
- else
- global_symbol_pipe=
- fi
-done
-if test "$pipe_works" = yes; then
- echo "${ac_t}ok" 1>&6
-else
- echo "${ac_t}failed" 1>&6
-fi
-
-if test -z "$global_symbol_pipe"; then
- global_symbol_to_cdecl=
-fi
-
-# Check hardcoding attributes.
-echo $ac_n "checking how to hardcode library paths into programs... $ac_c" 1>&6
-hardcode_action=
-if test -n "$hardcode_libdir_flag_spec" || \
- test -n "$runpath_var"; then
-
- # We can hardcode non-existant directories.
- if test "$hardcode_direct" != no &&
- # If the only mechanism to avoid hardcoding is shlibpath_var, we
- # have to relink, otherwise we might link with an installed library
- # when we should be linking with a yet-to-be-installed one
- ## test "$hardcode_shlibpath_var" != no &&
- test "$hardcode_minus_L" != no; then
- # Linking always hardcodes the temporary library directory.
- hardcode_action=relink
- else
- # We can link without hardcoding, and we can hardcode nonexisting dirs.
- hardcode_action=immediate
- fi
-else
- # We cannot hardcode anything, or else we can only hardcode existing
- # directories.
- hardcode_action=unsupported
-fi
-echo "$ac_t$hardcode_action" 1>&6
-
-
-reload_flag=
-reload_cmds='$LD$reload_flag -o $output$reload_objs'
-echo $ac_n "checking for $LD option to reload object files... $ac_c" 1>&6
-# PORTME Some linkers may need a different reload flag.
-reload_flag='-r'
-echo "$ac_t$reload_flag" 1>&6
-test -n "$reload_flag" && reload_flag=" $reload_flag"
-
-# PORTME Fill in your ld.so characteristics
-library_names_spec=
-libname_spec='lib$name'
-soname_spec=
-postinstall_cmds=
-postuninstall_cmds=
-finish_cmds=
-finish_eval=
-shlibpath_var=
-shlibpath_overrides_runpath=unknown
-version_type=none
-dynamic_linker="$host_os ld.so"
-sys_lib_dlsearch_path_spec="/lib /usr/lib"
-sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
-file_magic_cmd=
-file_magic_test_file=
-deplibs_check_method='unknown'
-# Need to set the preceding variable on all platforms that support
-# interlibrary dependencies.
-# 'none' -- dependencies not supported.
-# `unknown' -- same as none, but documents that we really don't know.
-# 'pass_all' -- all dependencies passed with no checks.
-# 'test_compile' -- check by making test program.
-# 'file_magic [regex]' -- check by looking for files in library path
-# which responds to the $file_magic_cmd with a given egrep regex.
-# If you have `file' or equivalent on your system and you're not sure
-# whether `pass_all' will *always* work, you probably want this one.
-echo $ac_n "checking dynamic linker characteristics... $ac_c" 1>&6
-case "$host_os" in
-aix3*)
- version_type=linux
- library_names_spec='${libname}${release}.so$versuffix $libname.a'
- shlibpath_var=LIBPATH
-
- # AIX has no versioning support, so we append a major version to the name.
- soname_spec='${libname}${release}.so$major'
- ;;
-
-aix4*)
- version_type=linux
- # AIX has no versioning support, so currently we can not hardcode correct
- # soname into executable. Probably we can add versioning support to
- # collect2, so additional links can be useful in future.
- # We preserve .a as extension for shared libraries though AIX4.2
- # and later linker supports .so
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.a'
- shlibpath_var=LIBPATH
- deplibs_check_method=pass_all
- ;;
-
-amigaos*)
- library_names_spec='$libname.ixlibrary $libname.a'
- # Create ${libname}_ixlibrary.a entries in /sys/libs.
- finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done'
- ;;
-
-beos*)
- library_names_spec='${libname}.so'
- dynamic_linker="$host_os ld.so"
- shlibpath_var=LIBRARY_PATH
- deplibs_check_method=pass_all
- lt_cv_dlopen="load_add_on"
- lt_cv_dlopen_libs=
- lt_cv_dlopen_self=yes
- ;;
-
-bsdi4*)
- version_type=linux
- library_names_spec='${libname}.so$major ${libname}.so'
- soname_spec='${libname}.so'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
- file_magic_cmd=/usr/bin/file
- file_magic_test_file=/shlib/libc.so
- sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
- sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
- # the default ld.so.conf also contains /usr/contrib/lib and
- # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
- # libtool to hard-code these into programs
- ;;
-
-cygwin* | mingw*)
- version_type=windows
- need_version=no
- need_lib_prefix=no
- if test "$with_gcc" = yes; then
- library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.a'
- else
- library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.lib'
- fi
- dynamic_linker='Win32 ld.exe'
- deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
- file_magic_cmd='${OBJDUMP} -f'
- # FIXME: first we should search . and the directory the executable is in
- shlibpath_var=PATH
- lt_cv_dlopen="LoadLibrary"
- lt_cv_dlopen_libs=
- ;;
-
-freebsd1*)
- dynamic_linker=no
- ;;
-
-freebsd*)
- objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout`
- version_type=freebsd-$objformat
- case "$version_type" in
- freebsd-elf*)
- deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB shared object'
- file_magic_cmd=/usr/bin/file
- file_magic_test_file=`echo /usr/lib/libc.so*`
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so'
- need_version=no
- need_lib_prefix=no
- ;;
- freebsd-*)
- deplibs_check_method=unknown
- library_names_spec='${libname}${release}.so$versuffix $libname.so$versuffix'
- need_version=yes
- ;;
- esac
- finish_cmds='PATH="\$PATH:/sbin" OBJFORMAT="'"$objformat"'" ldconfig -m $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- case "$host_os" in
- freebsd2* | freebsd3.[01]*)
- shlibpath_overrides_runpath=yes
- ;;
- *) # from 3.2 on
- shlibpath_overrides_runpath=no
- ;;
- esac
- ;;
-
-gnu*)
- version_type=linux
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so${major} ${libname}.so'
- soname_spec='${libname}${release}.so$major'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-hpux9* | hpux10* | hpux11*)
- # Give a soname corresponding to the major version so that dld.sl refuses to
- # link against other versions.
- dynamic_linker="$host_os dld.sl"
- version_type=sunos
- need_lib_prefix=no
- need_version=no
- shlibpath_var=SHLIB_PATH
- shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
- library_names_spec='${libname}${release}.sl$versuffix ${libname}${release}.sl$major $libname.sl'
- soname_spec='${libname}${release}.sl$major'
- # HP-UX runs *really* slowly unless shared libraries are mode 555.
- postinstall_cmds='chmod 555 $lib'
- ;;
-
-irix5* | irix6*)
- version_type=irix
- need_lib_prefix=no
- need_version=no
- soname_spec='${libname}${release}.so.$major'
- library_names_spec='${libname}${release}.so.$versuffix ${libname}${release}.so.$major ${libname}${release}.so $libname.so'
- case "$host_os" in
- irix5*)
- libsuff= shlibsuff=
- # this will be overridden with pass_all, but let us keep it just in case
- deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1"
- ;;
- *)
- case "$LD" in # libtool.m4 will add one of these switches to LD
- *-32|*"-32 ") libsuff= shlibsuff= libmagic=32-bit;;
- *-n32|*"-n32 ") libsuff=32 shlibsuff=N32 libmagic=N32;;
- *-64|*"-64 ") libsuff=64 shlibsuff=64 libmagic=64-bit;;
- *) libsuff= shlibsuff= libmagic=never-match;;
- esac
- # this will be overridden with pass_all, but let us keep it just in case
- deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[1234] dynamic lib MIPS - version 1"
- ;;
- esac
- shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
- shlibpath_overrides_runpath=no
- sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
- sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
- file_magic_cmd=/usr/bin/file
- file_magic_test_file=`echo /lib${libsuff}/libc.so*`
- deplibs_check_method='pass_all'
- ;;
-
-# No shared lib support for Linux oldld, aout, or coff.
-linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*)
- dynamic_linker=no
- ;;
-
-# This must be Linux ELF.
-linux-gnu*)
- version_type=linux
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
- file_magic_cmd=/usr/bin/file
- file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so`
-
- if test -f /lib/ld.so.1; then
- dynamic_linker='GNU ld.so'
- else
- # Only the GNU ld.so supports shared libraries on MkLinux.
- case "$host_cpu" in
- powerpc*) dynamic_linker=no ;;
- *) dynamic_linker='Linux ld.so' ;;
- esac
- fi
- ;;
-
-netbsd*)
- version_type=sunos
- if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then
- library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
- dynamic_linker='NetBSD (a.out) ld.so'
- else
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so ${libname}.so'
- soname_spec='${libname}${release}.so$major'
- dynamic_linker='NetBSD ld.elf_so'
- fi
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-openbsd*)
- version_type=sunos
- if test "$with_gnu_ld" = yes; then
- need_lib_prefix=no
- need_version=no
- fi
- library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-os2*)
- libname_spec='$name'
- need_lib_prefix=no
- library_names_spec='$libname.dll $libname.a'
- dynamic_linker='OS/2 ld.exe'
- shlibpath_var=LIBPATH
- ;;
-
-osf3* | osf4*)
- version_type=osf
- need_version=no
- soname_spec='${libname}${release}.so'
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so'
- shlibpath_var=LD_LIBRARY_PATH
- # this will be overridden with pass_all, but let us keep it just in case
- deplibs_check_method='file_magic COFF format alpha shared library'
- file_magic_cmd=/usr/bin/file
- file_magic_test_file=/shlib/libc.so
- deplibs_check_method='pass_all'
- sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
- sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
- ;;
-
-sco3.2v5*)
- version_type=osf
- soname_spec='${libname}${release}.so$major'
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-solaris*)
- version_type=linux
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- # ldd complains unless libraries are executable
- postinstall_cmds='chmod +x $lib'
- deplibs_check_method="file_magic ELF [0-9][0-9]-bit [LM]SB dynamic lib"
- file_magic_cmd=/usr/bin/file
- file_magic_test_file=/lib/libc.so
- ;;
-
-sunos4*)
- version_type=sunos
- library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix'
- finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- if test "$with_gnu_ld" = yes; then
- need_lib_prefix=no
- fi
- need_version=yes
- ;;
-
-sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
- version_type=linux
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- shlibpath_var=LD_LIBRARY_PATH
- case "$host_vendor" in
- ncr)
- deplibs_check_method='pass_all'
- ;;
- motorola)
- need_lib_prefix=no
- need_version=no
- shlibpath_overrides_runpath=no
- sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
- deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
- file_magic_cmd=/usr/bin/file
- file_magic_test_file=`echo /usr/lib/libc.so*`
- ;;
- esac
- ;;
-
-uts4*)
- version_type=linux
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-dgux*)
- version_type=linux
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
- soname_spec='${libname}${release}.so$major'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-sysv4*MP*)
- if test -d /usr/nec ;then
- version_type=linux
- library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so'
- soname_spec='$libname.so.$major'
- shlibpath_var=LD_LIBRARY_PATH
- fi
- ;;
-
-*)
- dynamic_linker=no
- ;;
-esac
-echo "$ac_t$dynamic_linker" 1>&6
-test "$dynamic_linker" = no && can_build_shared=no
-
-# Report the final consequences.
-echo "checking if libtool supports shared libraries... $can_build_shared" 1>&6
-
-# Only try to build win32 dlls if AC_LIBTOOL_WIN32_DLL was used in
-# configure.in, otherwise build static only libraries.
-case "$host_os" in
-cygwin* | mingw* | os2*)
- if test x$can_build_shared = xyes; then
- test x$enable_win32_dll = xno && can_build_shared=no
- echo "checking if package supports dlls... $can_build_shared" 1>&6
- fi
-;;
-esac
-
-if test -n "$file_magic_test_file" && test -n "$file_magic_cmd"; then
- case "$deplibs_check_method" in
- "file_magic "*)
- file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`"
- if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
- egrep "$file_magic_regex" > /dev/null; then
- :
- else
- cat <<EOF 1>&2
-
-*** Warning: the command libtool uses to detect shared libraries,
-*** $file_magic_cmd, produces output that libtool cannot recognize.
-*** The result is that libtool may fail to recognize shared libraries
-*** as such. This will affect the creation of libtool libraries that
-*** depend on shared libraries, but programs linked with such libtool
-*** libraries will work regardless of this problem. Nevertheless, you
-*** may want to report the problem to your system manager and/or to
-*** bug-libtool@gnu.org
-
-EOF
- fi ;;
- esac
-fi
-
-echo $ac_n "checking whether to build shared libraries... $ac_c" 1>&6
-test "$can_build_shared" = "no" && enable_shared=no
-
-# On AIX, shared libraries and static libraries use the same namespace, and
-# are all built from PIC.
-case "$host_os" in
-aix3*)
- test "$enable_shared" = yes && enable_static=no
- if test -n "$RANLIB"; then
- archive_cmds="$archive_cmds~\$RANLIB \$lib"
- postinstall_cmds='$RANLIB $lib'
- fi
- ;;
-
-aix4*)
- test "$enable_shared" = yes && enable_static=no
- ;;
-esac
-
-echo "$ac_t$enable_shared" 1>&6
-
-# Make sure either enable_shared or enable_static is yes.
-test "$enable_shared" = yes || enable_static=yes
-
-echo "checking whether to build static libraries... $enable_static" 1>&6
-
-if test "$hardcode_action" = relink; then
- # Fast installation is not supported
- enable_fast_install=no
-elif test "$shlibpath_overrides_runpath" = yes ||
- test "$enable_shared" = no; then
- # Fast installation is not necessary
- enable_fast_install=needless
-fi
-
-echo $ac_n "checking for objdir... $ac_c" 1>&6
-rm -f .libs 2>/dev/null
-mkdir .libs 2>/dev/null
-if test -d .libs; then
- objdir=.libs
-else
- # MS-DOS does not allow filenames that begin with a dot.
- objdir=_libs
-fi
-rmdir .libs 2>/dev/null
-echo "$ac_t$objdir" 1>&6
-
-if test "x$enable_dlopen" != xyes; then
- enable_dlopen=unknown
- enable_dlopen_self=unknown
- enable_dlopen_self_static=unknown
-else
-if eval "test \"`echo '$''{'lt_cv_dlopen'+set}'`\" != set"; then
- lt_cv_dlopen=no lt_cv_dlopen_libs=
-echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6
-echo "$progname:2170: checking for dlopen in -ldl" >&5
-ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- ac_save_LIBS="$LIBS"
-LIBS="-ldl $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2178 "ltconfig"
-/* Override any gcc2 internal prototype to avoid an error. */
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char dlopen();
-
-int main() {
-dlopen()
-; return 0; }
-EOF
-if { (eval echo $progname:2188: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "$progname: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
-else
- echo "$ac_t""no" 1>&6
-echo $ac_n "checking for dlopen""... $ac_c" 1>&6
-echo "$progname:2207: checking for dlopen" >&5
-if eval "test \"`echo '$''{'ac_cv_func_dlopen'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 2212 "ltconfig"
-/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char dlopen(); below. */
-#include <assert.h>
-/* Override any gcc2 internal prototype to avoid an error. */
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char dlopen();
-
-int main() {
-
-/* The GNU C library defines this for functions which it implements
- to always fail with ENOSYS. Some functions are actually named
- something starting with __ and the normal name is an alias. */
-#if defined (__stub_dlopen) || defined (__stub___dlopen)
-choke me
-#else
-dlopen();
-#endif
-
-; return 0; }
-EOF
-if { (eval echo $progname:2234: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_func_dlopen=yes"
-else
- echo "$progname: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_func_dlopen=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_func_'dlopen`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- lt_cv_dlopen="dlopen"
-else
- echo "$ac_t""no" 1>&6
-echo $ac_n "checking for dld_link in -ldld""... $ac_c" 1>&6
-echo "$progname:2251: checking for dld_link in -ldld" >&5
-ac_lib_var=`echo dld'_'dld_link | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- ac_save_LIBS="$LIBS"
-LIBS="-ldld $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2259 "ltconfig"
-/* Override any gcc2 internal prototype to avoid an error. */
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char dld_link();
-
-int main() {
-dld_link()
-; return 0; }
-EOF
-if { (eval echo $progname:2269: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "$progname: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
-else
- echo "$ac_t""no" 1>&6
-echo $ac_n "checking for shl_load""... $ac_c" 1>&6
-echo "$progname:2288: checking for shl_load" >&5
-if eval "test \"`echo '$''{'ac_cv_func_shl_load'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 2293 "ltconfig"
-/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char shl_load(); below. */
-#include <assert.h>
-/* Override any gcc2 internal prototype to avoid an error. */
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char shl_load();
-
-int main() {
-
-/* The GNU C library defines this for functions which it implements
- to always fail with ENOSYS. Some functions are actually named
- something starting with __ and the normal name is an alias. */
-#if defined (__stub_shl_load) || defined (__stub___shl_load)
-choke me
-#else
-shl_load();
-#endif
-
-; return 0; }
-EOF
-if { (eval echo $progname:2315: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_func_shl_load=yes"
-else
- echo "$progname: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_func_shl_load=no"
-fi
-rm -f conftest*
-fi
-
-if eval "test \"`echo '$ac_cv_func_'shl_load`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- lt_cv_dlopen="shl_load"
-else
- echo "$ac_t""no" 1>&6
-echo $ac_n "checking for shl_load in -ldld""... $ac_c" 1>&6
-echo "$progname:2333: checking for shl_load in -ldld" >&5
-ac_lib_var=`echo dld'_'shl_load | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- ac_save_LIBS="$LIBS"
-LIBS="-ldld $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2341 "ltconfig"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error. */
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char shl_load();
-
-int main() {
-shl_load()
-; return 0; }
-EOF
-if { (eval echo $progname:2352: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "$progname: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
-else
- echo "$ac_t""no" 1>&6
-fi
-
-
-fi
-
-
-fi
-
-
-fi
-
-
-fi
-
-fi
-
- if test "x$lt_cv_dlopen" != xno; then
- enable_dlopen=yes
- fi
-
- case "$lt_cv_dlopen" in
- dlopen)
-for ac_hdr in dlfcn.h; do
-ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "$progname:2395: checking for $ac_hdr" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 2400 "ltconfig"
-#include <$ac_hdr>
-int fnord = 0;
-EOF
-ac_try="$ac_compile conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo $progname:2405: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=yes"
-else
- echo "$ac_err" >&5
- echo "$progname: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
- echo "$ac_t""yes" 1>&6
-else
- echo "$ac_t""no" 1>&6
-fi
-done
-
- if test "x$ac_cv_header_dlfcn_h" = xyes; then
- CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
- fi
- eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
- LIBS="$lt_cv_dlopen_libs $LIBS"
-
- echo $ac_n "checking whether a program can dlopen itself""... $ac_c" 1>&6
-echo "$progname:2433: checking whether a program can dlopen itself" >&5
-if test "${lt_cv_dlopen_self+set}" = set; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- if test "$cross_compiling" = yes; then
- lt_cv_dlopen_self=cross
- else
- cat > conftest.c <<EOF
-#line 2441 "ltconfig"
-
-#if HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
-#include <stdio.h>
-
-#ifdef RTLD_GLOBAL
-# define LTDL_GLOBAL RTLD_GLOBAL
-#else
-# ifdef DL_GLOBAL
-# define LTDL_GLOBAL DL_GLOBAL
-# else
-# define LTDL_GLOBAL 0
-# endif
-#endif
-
-/* We may have to define LTDL_LAZY_OR_NOW in the command line if we
- find out it does not work in some platform. */
-#ifndef LTDL_LAZY_OR_NOW
-# ifdef RTLD_LAZY
-# define LTDL_LAZY_OR_NOW RTLD_LAZY
-# else
-# ifdef DL_LAZY
-# define LTDL_LAZY_OR_NOW DL_LAZY
-# else
-# ifdef RTLD_NOW
-# define LTDL_LAZY_OR_NOW RTLD_NOW
-# else
-# ifdef DL_NOW
-# define LTDL_LAZY_OR_NOW DL_NOW
-# else
-# define LTDL_LAZY_OR_NOW 0
-# endif
-# endif
-# endif
-# endif
-#endif
-
-fnord() { int i=42;}
-main() { void *self, *ptr1, *ptr2; self=dlopen(0,LTDL_GLOBAL|LTDL_LAZY_OR_NOW);
- if(self) { ptr1=dlsym(self,"fnord"); ptr2=dlsym(self,"_fnord");
- if(ptr1 || ptr2) { dlclose(self); exit(0); } } exit(1); }
-
-EOF
-if { (eval echo $progname:2487: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
-then
- lt_cv_dlopen_self=yes
-else
- echo "$progname: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -fr conftest*
- lt_cv_dlopen_self=no
-fi
-rm -fr conftest*
-fi
-
-fi
-
-echo "$ac_t""$lt_cv_dlopen_self" 1>&6
-
- if test "$lt_cv_dlopen_self" = yes; then
- LDFLAGS="$LDFLAGS $link_static_flag"
- echo $ac_n "checking whether a statically linked program can dlopen itself""... $ac_c" 1>&6
-echo "$progname:2506: checking whether a statically linked program can dlopen itself" >&5
-if test "${lt_cv_dlopen_self_static+set}" = set; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- if test "$cross_compiling" = yes; then
- lt_cv_dlopen_self_static=cross
- else
- cat > conftest.c <<EOF
-#line 2514 "ltconfig"
-
-#if HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
-#include <stdio.h>
-
-#ifdef RTLD_GLOBAL
-# define LTDL_GLOBAL RTLD_GLOBAL
-#else
-# ifdef DL_GLOBAL
-# define LTDL_GLOBAL DL_GLOBAL
-# else
-# define LTDL_GLOBAL 0
-# endif
-#endif
-
-/* We may have to define LTDL_LAZY_OR_NOW in the command line if we
- find out it does not work in some platform. */
-#ifndef LTDL_LAZY_OR_NOW
-# ifdef RTLD_LAZY
-# define LTDL_LAZY_OR_NOW RTLD_LAZY
-# else
-# ifdef DL_LAZY
-# define LTDL_LAZY_OR_NOW DL_LAZY
-# else
-# ifdef RTLD_NOW
-# define LTDL_LAZY_OR_NOW RTLD_NOW
-# else
-# ifdef DL_NOW
-# define LTDL_LAZY_OR_NOW DL_NOW
-# else
-# define LTDL_LAZY_OR_NOW 0
-# endif
-# endif
-# endif
-# endif
-#endif
-
-fnord() { int i=42;}
-main() { void *self, *ptr1, *ptr2; self=dlopen(0,LTDL_GLOBAL|LTDL_LAZY_OR_NOW);
- if(self) { ptr1=dlsym(self,"fnord"); ptr2=dlsym(self,"_fnord");
- if(ptr1 || ptr2) { dlclose(self); exit(0); } } exit(1); }
-
-EOF
-if { (eval echo $progname:2560: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
-then
- lt_cv_dlopen_self_static=yes
-else
- echo "$progname: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -fr conftest*
- lt_cv_dlopen_self_static=no
-fi
-rm -fr conftest*
-fi
-
-fi
-
-echo "$ac_t""$lt_cv_dlopen_self_static" 1>&6
-fi
- ;;
- esac
-
- case "$lt_cv_dlopen_self" in
- yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
- *) enable_dlopen_self=unknown ;;
- esac
-
- case "$lt_cv_dlopen_self_static" in
- yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
- *) enable_dlopen_self_static=unknown ;;
- esac
-fi
-
-# Copy echo and quote the copy, instead of the original, because it is
-# used later.
-ltecho="$echo"
-if test "X$ltecho" = "X$CONFIG_SHELL $0 --fallback-echo"; then
- ltecho="$CONFIG_SHELL \$0 --fallback-echo"
-fi
-LTSHELL="$SHELL"
-
-LTCONFIG_VERSION="$VERSION"
-
-# Only quote variables if we're using ltmain.sh.
-case "$ltmain" in
-*.sh)
- # Now quote all the things that may contain metacharacters.
- for var in ltecho old_CC old_CFLAGS old_CPPFLAGS \
- old_LD old_LDFLAGS old_LIBS \
- old_NM old_RANLIB old_LN_S old_DLLTOOL old_OBJDUMP old_AS \
- AR CC LD LN_S NM LTSHELL LTCONFIG_VERSION \
- reload_flag reload_cmds wl \
- pic_flag link_static_flag no_builtin_flag export_dynamic_flag_spec \
- thread_safe_flag_spec whole_archive_flag_spec libname_spec \
- library_names_spec soname_spec \
- RANLIB old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \
- old_postuninstall_cmds archive_cmds archive_expsym_cmds postinstall_cmds postuninstall_cmds \
- file_magic_cmd export_symbols_cmds deplibs_check_method allow_undefined_flag no_undefined_flag \
- finish_cmds finish_eval global_symbol_pipe global_symbol_to_cdecl \
- hardcode_libdir_flag_spec hardcode_libdir_separator \
- sys_lib_search_path_spec sys_lib_dlsearch_path_spec \
- compiler_c_o compiler_o_lo need_locks exclude_expsyms include_expsyms; do
-
- case "$var" in
- reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \
- old_postinstall_cmds | old_postuninstall_cmds | \
- export_symbols_cmds | archive_cmds | archive_expsym_cmds | \
- postinstall_cmds | postuninstall_cmds | \
- finish_cmds | sys_lib_search_path_spec | sys_lib_dlsearch_path_spec)
- # Double-quote double-evaled strings.
- eval "$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\""
- ;;
- *)
- eval "$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\""
- ;;
- esac
- done
-
- case "$ltecho" in
- *'\$0 --fallback-echo"')
- ltecho=`$echo "X$ltecho" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'`
- ;;
- esac
-
- trap "$rm \"$ofile\"; exit 1" 1 2 15
- echo "creating $ofile"
- $rm "$ofile"
- cat <<EOF > "$ofile"
-#! $SHELL
-
-# `$echo "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
-# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
-# NOTE: Changes made to this file will be lost: look at ltconfig or ltmain.sh.
-#
-# Copyright (C) 1996-1999 Free Software Foundation, Inc.
-# Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# Sed that helps us avoid accidentally triggering echo(1) options like -n.
-Xsed="sed -e s/^X//"
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-if test "\${CDPATH+set}" = set; then CDPATH=; export CDPATH; fi
-
-### BEGIN LIBTOOL CONFIG
-EOF
- cfgfile="$ofile"
- ;;
-
-*)
- # Double-quote the variables that need it (for aesthetics).
- for var in old_CC old_CFLAGS old_CPPFLAGS \
- old_LD old_LDFLAGS old_LIBS \
- old_NM old_RANLIB old_LN_S old_DLLTOOL old_OBJDUMP old_AS; do
- eval "$var=\\\"\$var\\\""
- done
-
- # Just create a config file.
- cfgfile="$ofile.cfg"
- trap "$rm \"$cfgfile\"; exit 1" 1 2 15
- echo "creating $cfgfile"
- $rm "$cfgfile"
- cat <<EOF > "$cfgfile"
-# `$echo "$cfgfile" | sed 's%^.*/%%'` - Libtool configuration file.
-# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP)
-EOF
- ;;
-esac
-
-cat <<EOF >> "$cfgfile"
-# Libtool was configured as follows, on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
-#
-# CC=$old_CC CFLAGS=$old_CFLAGS CPPFLAGS=$old_CPPFLAGS \\
-# LD=$old_LD LDFLAGS=$old_LDFLAGS LIBS=$old_LIBS \\
-# NM=$old_NM RANLIB=$old_RANLIB LN_S=$old_LN_S \\
-# DLLTOOL=$old_DLLTOOL OBJDUMP=$old_OBJDUMP AS=$old_AS \\
-# $0$ltconfig_args
-#
-# Compiler and other test output produced by $progname, useful for
-# debugging $progname, is in ./config.log if it exists.
-
-# The version of $progname that generated this script.
-LTCONFIG_VERSION=$LTCONFIG_VERSION
-
-# Shell to use when invoking shell scripts.
-SHELL=$LTSHELL
-
-# Whether or not to build shared libraries.
-build_libtool_libs=$enable_shared
-
-# Whether or not to build static libraries.
-build_old_libs=$enable_static
-
-# Whether or not to optimize for fast installation.
-fast_install=$enable_fast_install
-
-# The host system.
-host_alias=$host_alias
-host=$host
-
-# An echo program that does not interpret backslashes.
-echo=$ltecho
-
-# The archiver.
-AR=$AR
-
-# The default C compiler.
-CC=$CC
-
-# The linker used to build libraries.
-LD=$LD
-
-# Whether we need hard or soft links.
-LN_S=$LN_S
-
-# A BSD-compatible nm program.
-NM=$NM
-
-# Used on cygwin: DLL creation program.
-DLLTOOL="$DLLTOOL"
-
-# Used on cygwin: object dumper.
-OBJDUMP="$OBJDUMP"
-
-# Used on cygwin: assembler.
-AS="$AS"
-
-# The name of the directory that contains temporary libtool files.
-objdir=$objdir
-
-# How to create reloadable object files.
-reload_flag=$reload_flag
-reload_cmds=$reload_cmds
-
-# How to pass a linker flag through the compiler.
-wl=$wl
-
-# Object file suffix (normally "o").
-objext="$objext"
-
-# Old archive suffix (normally "a").
-libext="$libext"
-
-# Executable file suffix (normally "").
-exeext="$exeext"
-
-# Additional compiler flags for building library objects.
-pic_flag=$pic_flag
-
-# Does compiler simultaneously support -c and -o options?
-compiler_c_o=$compiler_c_o
-
-# Can we write directly to a .lo ?
-compiler_o_lo=$compiler_o_lo
-
-# Must we lock files when doing compilation ?
-need_locks=$need_locks
-
-# Do we need the lib prefix for modules?
-need_lib_prefix=$need_lib_prefix
-
-# Do we need a version for libraries?
-need_version=$need_version
-
-# Whether dlopen is supported.
-dlopen=$enable_dlopen
-
-# Whether dlopen of programs is supported.
-dlopen_self=$enable_dlopen_self
-
-# Whether dlopen of statically linked programs is supported.
-dlopen_self_static=$enable_dlopen_self_static
-
-# Compiler flag to prevent dynamic linking.
-link_static_flag=$link_static_flag
-
-# Compiler flag to turn off builtin functions.
-no_builtin_flag=$no_builtin_flag
-
-# Compiler flag to allow reflexive dlopens.
-export_dynamic_flag_spec=$export_dynamic_flag_spec
-
-# Compiler flag to generate shared objects directly from archives.
-whole_archive_flag_spec=$whole_archive_flag_spec
-
-# Compiler flag to generate thread-safe objects.
-thread_safe_flag_spec=$thread_safe_flag_spec
-
-# Library versioning type.
-version_type=$version_type
-
-# Format of library name prefix.
-libname_spec=$libname_spec
-
-# List of archive names. First name is the real one, the rest are links.
-# The last name is the one that the linker finds with -lNAME.
-library_names_spec=$library_names_spec
-
-# The coded name of the library, if different from the real name.
-soname_spec=$soname_spec
-
-# Commands used to build and install an old-style archive.
-RANLIB=$RANLIB
-old_archive_cmds=$old_archive_cmds
-old_postinstall_cmds=$old_postinstall_cmds
-old_postuninstall_cmds=$old_postuninstall_cmds
-
-# Create an old-style archive from a shared archive.
-old_archive_from_new_cmds=$old_archive_from_new_cmds
-
-# Commands used to build and install a shared archive.
-archive_cmds=$archive_cmds
-archive_expsym_cmds=$archive_expsym_cmds
-postinstall_cmds=$postinstall_cmds
-postuninstall_cmds=$postuninstall_cmds
-
-# Method to check whether dependent libraries are shared objects.
-deplibs_check_method=$deplibs_check_method
-
-# Command to use when deplibs_check_method == file_magic.
-file_magic_cmd=$file_magic_cmd
-
-# Flag that allows shared libraries with undefined symbols to be built.
-allow_undefined_flag=$allow_undefined_flag
-
-# Flag that forces no undefined symbols.
-no_undefined_flag=$no_undefined_flag
-
-# Commands used to finish a libtool library installation in a directory.
-finish_cmds=$finish_cmds
-
-# Same as above, but a single script fragment to be evaled but not shown.
-finish_eval=$finish_eval
-
-# Take the output of nm and produce a listing of raw symbols and C names.
-global_symbol_pipe=$global_symbol_pipe
-
-# Transform the output of nm in a proper C declaration
-global_symbol_to_cdecl=$global_symbol_to_cdecl
-
-# This is the shared library runtime path variable.
-runpath_var=$runpath_var
-
-# This is the shared library path variable.
-shlibpath_var=$shlibpath_var
-
-# Is shlibpath searched before the hard-coded library search path?
-shlibpath_overrides_runpath=$shlibpath_overrides_runpath
-
-# How to hardcode a shared library path into an executable.
-hardcode_action=$hardcode_action
-
-# Flag to hardcode \$libdir into a binary during linking.
-# This must work even if \$libdir does not exist.
-hardcode_libdir_flag_spec=$hardcode_libdir_flag_spec
-
-# Whether we need a single -rpath flag with a separated argument.
-hardcode_libdir_separator=$hardcode_libdir_separator
-
-# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
-# resulting binary.
-hardcode_direct=$hardcode_direct
-
-# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
-# resulting binary.
-hardcode_minus_L=$hardcode_minus_L
-
-# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
-# the resulting binary.
-hardcode_shlibpath_var=$hardcode_shlibpath_var
-
-# Compile-time system search path for libraries
-sys_lib_search_path_spec=$sys_lib_search_path_spec
-
-# Run-time system search path for libraries
-sys_lib_dlsearch_path_spec=$sys_lib_dlsearch_path_spec
-
-# Fix the shell variable \$srcfile for the compiler.
-fix_srcfile_path="$fix_srcfile_path"
-
-# Set to yes if exported symbols are required.
-always_export_symbols=$always_export_symbols
-
-# The commands to list exported symbols.
-export_symbols_cmds=$export_symbols_cmds
-
-# Symbols that should not be listed in the preloaded symbols.
-exclude_expsyms=$exclude_expsyms
-
-# Symbols that must always be exported.
-include_expsyms=$include_expsyms
-
-EOF
-
-case "$ltmain" in
-*.sh)
- echo '### END LIBTOOL CONFIG' >> "$ofile"
- echo >> "$ofile"
- case "$host_os" in
- aix3*)
- cat <<\EOF >> "$ofile"
-
-# AIX sometimes has problems with the GCC collect2 program. For some
-# reason, if we set the COLLECT_NAMES environment variable, the problems
-# vanish in a puff of smoke.
-if test "${COLLECT_NAMES+set}" != set; then
- COLLECT_NAMES=
- export COLLECT_NAMES
-fi
-EOF
- ;;
- esac
-
- # Append the ltmain.sh script.
- sed '$q' "$ltmain" >> "$ofile" || (rm -f "$ofile"; exit 1)
-
- chmod +x "$ofile"
- ;;
-
-*)
- # Compile the libtool program.
- echo "FIXME: would compile $ltmain"
- ;;
-esac
-
-test -n "$cache_file" || exit 0
-
-# AC_CACHE_SAVE
-trap '' 1 2 15
-cat > confcache <<\EOF
-# This file is a shell script that caches the results of configure
-# tests run on this system so they can be shared between configure
-# scripts and configure runs. It is not useful on other systems.
-# If it contains results you don't want to keep, you may remove or edit it.
-#
-# By default, configure uses ./config.cache as the cache file,
-# creating it if it does not exist already. You can give configure
-# the --cache-file=FILE option to use a different cache file; that is
-# what configure does when it calls configure scripts in
-# subdirectories, so they share the cache.
-# Giving --cache-file=/dev/null disables caching, for debugging configure.
-# config.status only pays attention to the cache file if you give it the
-# --recheck option to rerun configure.
-#
-EOF
-# The following way of writing the cache mishandles newlines in values,
-# but we know of no workaround that is simple, portable, and efficient.
-# So, don't put newlines in cache variables' values.
-# Ultrix sh set writes to stderr and can't be redirected directly,
-# and sets the high bit in the cache file unless we assign to the vars.
-(set) 2>&1 |
- case `(ac_space=' '; set | grep ac_space) 2>&1` in
- *ac_space=\ *)
- # `set' does not quote correctly, so add quotes (double-quote substitution
- # turns \\\\ into \\, and sed turns \\ into \).
- sed -n \
- -e "s/'/'\\\\''/g" \
- -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
- ;;
- *)
- # `set' quotes correctly as required by POSIX, so do not add quotes.
- sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
- ;;
- esac >> confcache
-if cmp -s $cache_file confcache; then
- :
-else
- if test -w $cache_file; then
- echo "updating cache $cache_file"
- cat confcache > $cache_file
- else
- echo "not updating unwritable cache $cache_file"
- fi
-fi
-rm -f confcache
-
-exit 0
-
-# Local Variables:
-# mode:shell-script
-# sh-indentation:2
-# End:
+++ /dev/null
-# ltmain.sh - Provide generalized library-building support services.
-# NOTE: Changing this file will not affect anything until you rerun ltconfig.
-#
-# Copyright (C) 1996-1999 Free Software Foundation, Inc.
-# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# Check that we have a working $echo.
-if test "X$1" = X--no-reexec; then
- # Discard the --no-reexec flag, and continue.
- shift
-elif test "X$1" = X--fallback-echo; then
- # Avoid inline document here, it may be left over
- :
-elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
- # Yippee, $echo works!
- :
-else
- # Restart under the correct shell, and then maybe $echo will work.
- exec $SHELL "$0" --no-reexec ${1+"$@"}
-fi
-
-if test "X$1" = X--fallback-echo; then
- # used as fallback echo
- shift
- cat <<EOF
-$*
-EOF
- exit 0
-fi
-
-# The name of this program.
-progname=`$echo "$0" | sed 's%^.*/%%'`
-modename="$progname"
-
-# Constants.
-PROGRAM=ltmain.sh
-PACKAGE=libtool
-VERSION=1.3.3
-TIMESTAMP=" (1.385.2.181 1999/07/02 15:49:11)"
-
-default_mode=
-help="Try \`$progname --help' for more information."
-magic="%%%MAGIC variable%%%"
-mkdir="mkdir"
-mv="mv -f"
-rm="rm -f"
-
-# Sed substitution that helps us do robust quoting. It backslashifies
-# metacharacters that are still active within double-quoted strings.
-Xsed='sed -e 1s/^X//'
-sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g'
-SP2NL='tr \040 \012'
-NL2SP='tr \015\012 \040\040'
-
-# NLS nuisances.
-# Only set LANG and LC_ALL to C if already set.
-# These must not be set unconditionally because not all systems understand
-# e.g. LANG=C (notably SCO).
-# We save the old values to restore during execute mode.
-if test "${LC_ALL+set}" = set; then
- save_LC_ALL="$LC_ALL"; LC_ALL=C; export LC_ALL
-fi
-if test "${LANG+set}" = set; then
- save_LANG="$LANG"; LANG=C; export LANG
-fi
-
-if test "$LTCONFIG_VERSION" != "$VERSION"; then
- echo "$modename: ltconfig version \`$LTCONFIG_VERSION' does not match $PROGRAM version \`$VERSION'" 1>&2
- echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
- exit 1
-fi
-
-if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
- echo "$modename: not configured to build any kind of library" 1>&2
- echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
- exit 1
-fi
-
-# Global variables.
-mode=$default_mode
-nonopt=
-prev=
-prevopt=
-run=
-show="$echo"
-show_help=
-execute_dlfiles=
-lo2o="s/\\.lo\$/.${objext}/"
-o2lo="s/\\.${objext}\$/.lo/"
-
-# Parse our command line options once, thoroughly.
-while test $# -gt 0
-do
- arg="$1"
- shift
-
- case "$arg" in
- -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;;
- *) optarg= ;;
- esac
-
- # If the previous option needs an argument, assign it.
- if test -n "$prev"; then
- case "$prev" in
- execute_dlfiles)
- eval "$prev=\"\$$prev \$arg\""
- ;;
- *)
- eval "$prev=\$arg"
- ;;
- esac
-
- prev=
- prevopt=
- continue
- fi
-
- # Have we seen a non-optional argument yet?
- case "$arg" in
- --help)
- show_help=yes
- ;;
-
- --version)
- echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP"
- exit 0
- ;;
-
- --config)
- sed -e '1,/^### BEGIN LIBTOOL CONFIG/d' -e '/^### END LIBTOOL CONFIG/,$d' $0
- exit 0
- ;;
-
- --debug)
- echo "$progname: enabling shell trace mode"
- set -x
- ;;
-
- --dry-run | -n)
- run=:
- ;;
-
- --features)
- echo "host: $host"
- if test "$build_libtool_libs" = yes; then
- echo "enable shared libraries"
- else
- echo "disable shared libraries"
- fi
- if test "$build_old_libs" = yes; then
- echo "enable static libraries"
- else
- echo "disable static libraries"
- fi
- exit 0
- ;;
-
- --finish) mode="finish" ;;
-
- --mode) prevopt="--mode" prev=mode ;;
- --mode=*) mode="$optarg" ;;
-
- --quiet | --silent)
- show=:
- ;;
-
- -dlopen)
- prevopt="-dlopen"
- prev=execute_dlfiles
- ;;
-
- -*)
- $echo "$modename: unrecognized option \`$arg'" 1>&2
- $echo "$help" 1>&2
- exit 1
- ;;
-
- *)
- nonopt="$arg"
- break
- ;;
- esac
-done
-
-if test -n "$prevopt"; then
- $echo "$modename: option \`$prevopt' requires an argument" 1>&2
- $echo "$help" 1>&2
- exit 1
-fi
-
-if test -z "$show_help"; then
-
- # Infer the operation mode.
- if test -z "$mode"; then
- case "$nonopt" in
- *cc | *++ | gcc* | *-gcc*)
- mode=link
- for arg
- do
- case "$arg" in
- -c)
- mode=compile
- break
- ;;
- esac
- done
- ;;
- *db | *dbx | *strace | *truss)
- mode=execute
- ;;
- *install*|cp|mv)
- mode=install
- ;;
- *rm)
- mode=uninstall
- ;;
- *)
- # If we have no mode, but dlfiles were specified, then do execute mode.
- test -n "$execute_dlfiles" && mode=execute
-
- # Just use the default operation mode.
- if test -z "$mode"; then
- if test -n "$nonopt"; then
- $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2
- else
- $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2
- fi
- fi
- ;;
- esac
- fi
-
- # Only execute mode is allowed to have -dlopen flags.
- if test -n "$execute_dlfiles" && test "$mode" != execute; then
- $echo "$modename: unrecognized option \`-dlopen'" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- # Change the help message to a mode-specific one.
- generic_help="$help"
- help="Try \`$modename --help --mode=$mode' for more information."
-
- # These modes are in order of execution frequency so that they run quickly.
- case "$mode" in
- # libtool compile mode
- compile)
- modename="$modename: compile"
- # Get the compilation command and the source file.
- base_compile=
- lastarg=
- srcfile="$nonopt"
- suppress_output=
-
- user_target=no
- for arg
- do
- # Accept any command-line options.
- case "$arg" in
- -o)
- if test "$user_target" != "no"; then
- $echo "$modename: you cannot specify \`-o' more than once" 1>&2
- exit 1
- fi
- user_target=next
- ;;
-
- -static)
- build_old_libs=yes
- continue
- ;;
- esac
-
- case "$user_target" in
- next)
- # The next one is the -o target name
- user_target=yes
- continue
- ;;
- yes)
- # We got the output file
- user_target=set
- libobj="$arg"
- continue
- ;;
- esac
-
- # Accept the current argument as the source file.
- lastarg="$srcfile"
- srcfile="$arg"
-
- # Aesthetically quote the previous argument.
-
- # Backslashify any backslashes, double quotes, and dollar signs.
- # These are the only characters that are still specially
- # interpreted inside of double-quoted scrings.
- lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"`
-
- # Double-quote args containing other shell metacharacters.
- # Many Bourne shells cannot handle close brackets correctly in scan
- # sets, so we specify it separately.
- case "$lastarg" in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
- lastarg="\"$lastarg\""
- ;;
- esac
-
- # Add the previous argument to base_compile.
- if test -z "$base_compile"; then
- base_compile="$lastarg"
- else
- base_compile="$base_compile $lastarg"
- fi
- done
-
- case "$user_target" in
- set)
- ;;
- no)
- # Get the name of the library object.
- libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'`
- ;;
- *)
- $echo "$modename: you must specify a target with \`-o'" 1>&2
- exit 1
- ;;
- esac
-
- # Recognize several different file suffixes.
- # If the user specifies -o file.o, it is replaced with file.lo
- xform='[cCFSfmso]'
- case "$libobj" in
- *.ada) xform=ada ;;
- *.adb) xform=adb ;;
- *.ads) xform=ads ;;
- *.asm) xform=asm ;;
- *.c++) xform=c++ ;;
- *.cc) xform=cc ;;
- *.cpp) xform=cpp ;;
- *.cxx) xform=cxx ;;
- *.f90) xform=f90 ;;
- *.for) xform=for ;;
- esac
-
- libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"`
-
- case "$libobj" in
- *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;;
- *)
- $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2
- exit 1
- ;;
- esac
-
- if test -z "$base_compile"; then
- $echo "$modename: you must specify a compilation command" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- # Delete any leftover library objects.
- if test "$build_old_libs" = yes; then
- removelist="$obj $libobj"
- else
- removelist="$libobj"
- fi
-
- $run $rm $removelist
- trap "$run $rm $removelist; exit 1" 1 2 15
-
- # Calculate the filename of the output object if compiler does
- # not support -o with -c
- if test "$compiler_c_o" = no; then
- output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\..*$%%'`.${objext}
- lockfile="$output_obj.lock"
- removelist="$removelist $output_obj $lockfile"
- trap "$run $rm $removelist; exit 1" 1 2 15
- else
- need_locks=no
- lockfile=
- fi
-
- # Lock this critical section if it is needed
- # We use this script file to make the link, it avoids creating a new file
- if test "$need_locks" = yes; then
- until ln "$0" "$lockfile" 2>/dev/null; do
- $show "Waiting for $lockfile to be removed"
- sleep 2
- done
- elif test "$need_locks" = warn; then
- if test -f "$lockfile"; then
- echo "\
-*** ERROR, $lockfile exists and contains:
-`cat $lockfile 2>/dev/null`
-
-This indicates that another process is trying to use the same
-temporary object file, and libtool could not work around it because
-your compiler does not support \`-c' and \`-o' together. If you
-repeat this compilation, it may succeed, by chance, but you had better
-avoid parallel builds (make -j) in this platform, or get a better
-compiler."
-
- $run $rm $removelist
- exit 1
- fi
- echo $srcfile > "$lockfile"
- fi
-
- if test -n "$fix_srcfile_path"; then
- eval srcfile=\"$fix_srcfile_path\"
- fi
-
- # Only build a PIC object if we are building libtool libraries.
- if test "$build_libtool_libs" = yes; then
- # Without this assignment, base_compile gets emptied.
- fbsd_hideous_sh_bug=$base_compile
-
- # All platforms use -DPIC, to notify preprocessed assembler code.
- command="$base_compile $pic_flag -DPIC $srcfile"
- if test "$build_old_libs" = yes; then
- lo_libobj="$libobj"
- dir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$dir" = "X$libobj"; then
- dir="$objdir"
- else
- dir="$dir/$objdir"
- fi
- libobj="$dir/"`$echo "X$libobj" | $Xsed -e 's%^.*/%%'`
-
- if test -d "$dir"; then
- $show "$rm $libobj"
- $run $rm $libobj
- else
- $show "$mkdir $dir"
- $run $mkdir $dir
- status=$?
- if test $status -ne 0 && test ! -d $dir; then
- exit $status
- fi
- fi
- fi
- if test "$compiler_o_lo" = yes; then
- output_obj="$libobj"
- command="$command -o $output_obj"
- elif test "$compiler_c_o" = yes; then
- output_obj="$obj"
- command="$command -o $output_obj"
- fi
-
- $run $rm "$output_obj"
- $show "$command"
- if $run eval "$command"; then :
- else
- test -n "$output_obj" && $run $rm $removelist
- exit 1
- fi
-
- if test "$need_locks" = warn &&
- test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then
- echo "\
-*** ERROR, $lockfile contains:
-`cat $lockfile 2>/dev/null`
-
-but it should contain:
-$srcfile
-
-This indicates that another process is trying to use the same
-temporary object file, and libtool could not work around it because
-your compiler does not support \`-c' and \`-o' together. If you
-repeat this compilation, it may succeed, by chance, but you had better
-avoid parallel builds (make -j) in this platform, or get a better
-compiler."
-
- $run $rm $removelist
- exit 1
- fi
-
- # Just move the object if needed, then go on to compile the next one
- if test x"$output_obj" != x"$libobj"; then
- $show "$mv $output_obj $libobj"
- if $run $mv $output_obj $libobj; then :
- else
- error=$?
- $run $rm $removelist
- exit $error
- fi
- fi
-
- # If we have no pic_flag, then copy the object into place and finish.
- if test -z "$pic_flag" && test "$build_old_libs" = yes; then
- # Rename the .lo from within objdir to obj
- if test -f $obj; then
- $show $rm $obj
- $run $rm $obj
- fi
-
- $show "$mv $libobj $obj"
- if $run $mv $libobj $obj; then :
- else
- error=$?
- $run $rm $removelist
- exit $error
- fi
-
- # Now arrange that obj and lo_libobj become the same file
- $show "$LN_S $obj $lo_libobj"
- if $run $LN_S $obj $lo_libobj; then
- exit 0
- else
- error=$?
- $run $rm $removelist
- exit $error
- fi
- fi
-
- # Allow error messages only from the first compilation.
- suppress_output=' >/dev/null 2>&1'
- fi
-
- # Only build a position-dependent object if we build old libraries.
- if test "$build_old_libs" = yes; then
- command="$base_compile $srcfile"
- if test "$compiler_c_o" = yes; then
- command="$command -o $obj"
- output_obj="$obj"
- fi
-
- # Suppress compiler output if we already did a PIC compilation.
- command="$command$suppress_output"
- $run $rm "$output_obj"
- $show "$command"
- if $run eval "$command"; then :
- else
- $run $rm $removelist
- exit 1
- fi
-
- if test "$need_locks" = warn &&
- test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then
- echo "\
-*** ERROR, $lockfile contains:
-`cat $lockfile 2>/dev/null`
-
-but it should contain:
-$srcfile
-
-This indicates that another process is trying to use the same
-temporary object file, and libtool could not work around it because
-your compiler does not support \`-c' and \`-o' together. If you
-repeat this compilation, it may succeed, by chance, but you had better
-avoid parallel builds (make -j) in this platform, or get a better
-compiler."
-
- $run $rm $removelist
- exit 1
- fi
-
- # Just move the object if needed
- if test x"$output_obj" != x"$obj"; then
- $show "$mv $output_obj $obj"
- if $run $mv $output_obj $obj; then :
- else
- error=$?
- $run $rm $removelist
- exit $error
- fi
- fi
-
- # Create an invalid libtool object if no PIC, so that we do not
- # accidentally link it into a program.
- if test "$build_libtool_libs" != yes; then
- $show "echo timestamp > $libobj"
- $run eval "echo timestamp > \$libobj" || exit $?
- else
- # Move the .lo from within objdir
- $show "$mv $libobj $lo_libobj"
- if $run $mv $libobj $lo_libobj; then :
- else
- error=$?
- $run $rm $removelist
- exit $error
- fi
- fi
- fi
-
- # Unlock the critical section if it was locked
- if test "$need_locks" != no; then
- $rm "$lockfile"
- fi
-
- exit 0
- ;;
-
- # libtool link mode
- link)
- modename="$modename: link"
- C_compiler="$CC" # save it, to compile generated C sources
- CC="$nonopt"
- case "$host" in
- *-*-cygwin* | *-*-mingw* | *-*-os2*)
- # It is impossible to link a dll without this setting, and
- # we shouldn't force the makefile maintainer to figure out
- # which system we are compiling for in order to pass an extra
- # flag for every libtool invokation.
- # allow_undefined=no
-
- # FIXME: Unfortunately, there are problems with the above when trying
- # to make a dll which has undefined symbols, in which case not
- # even a static library is built. For now, we need to specify
- # -no-undefined on the libtool link line when we can be certain
- # that all symbols are satisfied, otherwise we get a static library.
- allow_undefined=yes
-
- # This is a source program that is used to create dlls on Windows
- # Don't remove nor modify the starting and closing comments
-# /* ltdll.c starts here */
-# #define WIN32_LEAN_AND_MEAN
-# #include <windows.h>
-# #undef WIN32_LEAN_AND_MEAN
-# #include <stdio.h>
-#
-# #ifndef __CYGWIN__
-# # ifdef __CYGWIN32__
-# # define __CYGWIN__ __CYGWIN32__
-# # endif
-# #endif
-#
-# #ifdef __cplusplus
-# extern "C" {
-# #endif
-# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved);
-# #ifdef __cplusplus
-# }
-# #endif
-#
-# #ifdef __CYGWIN__
-# #include <cygwin/cygwin_dll.h>
-# DECLARE_CYGWIN_DLL( DllMain );
-# #endif
-# HINSTANCE __hDllInstance_base;
-#
-# BOOL APIENTRY
-# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved)
-# {
-# __hDllInstance_base = hInst;
-# return TRUE;
-# }
-# /* ltdll.c ends here */
- # This is a source program that is used to create import libraries
- # on Windows for dlls which lack them. Don't remove nor modify the
- # starting and closing comments
-# /* impgen.c starts here */
-# /* Copyright (C) 1999 Free Software Foundation, Inc.
-#
-# This file is part of GNU libtool.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-# */
-#
-# #include <stdio.h> /* for printf() */
-# #include <unistd.h> /* for open(), lseek(), read() */
-# #include <fcntl.h> /* for O_RDONLY, O_BINARY */
-# #include <string.h> /* for strdup() */
-#
-# static unsigned int
-# pe_get16 (fd, offset)
-# int fd;
-# int offset;
-# {
-# unsigned char b[2];
-# lseek (fd, offset, SEEK_SET);
-# read (fd, b, 2);
-# return b[0] + (b[1]<<8);
-# }
-#
-# static unsigned int
-# pe_get32 (fd, offset)
-# int fd;
-# int offset;
-# {
-# unsigned char b[4];
-# lseek (fd, offset, SEEK_SET);
-# read (fd, b, 4);
-# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
-# }
-#
-# static unsigned int
-# pe_as32 (ptr)
-# void *ptr;
-# {
-# unsigned char *b = ptr;
-# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24);
-# }
-#
-# int
-# main (argc, argv)
-# int argc;
-# char *argv[];
-# {
-# int dll;
-# unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
-# unsigned long export_rva, export_size, nsections, secptr, expptr;
-# unsigned long name_rvas, nexp;
-# unsigned char *expdata, *erva;
-# char *filename, *dll_name;
-#
-# filename = argv[1];
-#
-# dll = open(filename, O_RDONLY|O_BINARY);
-# if (!dll)
-# return 1;
-#
-# dll_name = filename;
-#
-# for (i=0; filename[i]; i++)
-# if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':')
-# dll_name = filename + i +1;
-#
-# pe_header_offset = pe_get32 (dll, 0x3c);
-# opthdr_ofs = pe_header_offset + 4 + 20;
-# num_entries = pe_get32 (dll, opthdr_ofs + 92);
-#
-# if (num_entries < 1) /* no exports */
-# return 1;
-#
-# export_rva = pe_get32 (dll, opthdr_ofs + 96);
-# export_size = pe_get32 (dll, opthdr_ofs + 100);
-# nsections = pe_get16 (dll, pe_header_offset + 4 +2);
-# secptr = (pe_header_offset + 4 + 20 +
-# pe_get16 (dll, pe_header_offset + 4 + 16));
-#
-# expptr = 0;
-# for (i = 0; i < nsections; i++)
-# {
-# char sname[8];
-# unsigned long secptr1 = secptr + 40 * i;
-# unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
-# unsigned long vsize = pe_get32 (dll, secptr1 + 16);
-# unsigned long fptr = pe_get32 (dll, secptr1 + 20);
-# lseek(dll, secptr1, SEEK_SET);
-# read(dll, sname, 8);
-# if (vaddr <= export_rva && vaddr+vsize > export_rva)
-# {
-# expptr = fptr + (export_rva - vaddr);
-# if (export_rva + export_size > vaddr + vsize)
-# export_size = vsize - (export_rva - vaddr);
-# break;
-# }
-# }
-#
-# expdata = (unsigned char*)malloc(export_size);
-# lseek (dll, expptr, SEEK_SET);
-# read (dll, expdata, export_size);
-# erva = expdata - export_rva;
-#
-# nexp = pe_as32 (expdata+24);
-# name_rvas = pe_as32 (expdata+32);
-#
-# printf ("EXPORTS\n");
-# for (i = 0; i<nexp; i++)
-# {
-# unsigned long name_rva = pe_as32 (erva+name_rvas+i*4);
-# printf ("\t%s @ %ld ;\n", erva+name_rva, 1+ i);
-# }
-#
-# return 0;
-# }
-# /* impgen.c ends here */
- ;;
- *)
- allow_undefined=yes
- ;;
- esac
- compile_command="$CC"
- finalize_command="$CC"
-
- compile_rpath=
- finalize_rpath=
- compile_shlibpath=
- finalize_shlibpath=
- convenience=
- old_convenience=
- deplibs=
- linkopts=
-
- if test -n "$shlibpath_var"; then
- # get the directories listed in $shlibpath_var
- eval lib_search_path=\`\$echo \"X \${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\`
- else
- lib_search_path=
- fi
- # now prepend the system-specific ones
- eval lib_search_path=\"$sys_lib_search_path_spec\$lib_search_path\"
- eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
-
- avoid_version=no
- dlfiles=
- dlprefiles=
- dlself=no
- export_dynamic=no
- export_symbols=
- export_symbols_regex=
- generated=
- libobjs=
- link_against_libtool_libs=
- ltlibs=
- module=no
- objs=
- prefer_static_libs=no
- preload=no
- prev=
- prevarg=
- release=
- rpath=
- xrpath=
- perm_rpath=
- temp_rpath=
- thread_safe=no
- vinfo=
-
- # We need to know -static, to get the right output filenames.
- for arg
- do
- case "$arg" in
- -all-static | -static)
- if test "X$arg" = "X-all-static"; then
- if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
- $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2
- fi
- if test -n "$link_static_flag"; then
- dlopen_self=$dlopen_self_static
- fi
- else
- if test -z "$pic_flag" && test -n "$link_static_flag"; then
- dlopen_self=$dlopen_self_static
- fi
- fi
- build_libtool_libs=no
- build_old_libs=yes
- prefer_static_libs=yes
- break
- ;;
- esac
- done
-
- # See if our shared archives depend on static archives.
- test -n "$old_archive_from_new_cmds" && build_old_libs=yes
-
- # Go through the arguments, transforming them on the way.
- while test $# -gt 0; do
- arg="$1"
- shift
-
- # If the previous option needs an argument, assign it.
- if test -n "$prev"; then
- case "$prev" in
- output)
- compile_command="$compile_command @OUTPUT@"
- finalize_command="$finalize_command @OUTPUT@"
- ;;
- esac
-
- case "$prev" in
- dlfiles|dlprefiles)
- if test "$preload" = no; then
- # Add the symbol object into the linking commands.
- compile_command="$compile_command @SYMFILE@"
- finalize_command="$finalize_command @SYMFILE@"
- preload=yes
- fi
- case "$arg" in
- *.la | *.lo) ;; # We handle these cases below.
- force)
- if test "$dlself" = no; then
- dlself=needless
- export_dynamic=yes
- fi
- prev=
- continue
- ;;
- self)
- if test "$prev" = dlprefiles; then
- dlself=yes
- elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
- dlself=yes
- else
- dlself=needless
- export_dynamic=yes
- fi
- prev=
- continue
- ;;
- *)
- if test "$prev" = dlfiles; then
- dlfiles="$dlfiles $arg"
- else
- dlprefiles="$dlprefiles $arg"
- fi
- prev=
- ;;
- esac
- ;;
- expsyms)
- export_symbols="$arg"
- if test ! -f "$arg"; then
- $echo "$modename: symbol file \`$arg' does not exist"
- exit 1
- fi
- prev=
- continue
- ;;
- expsyms_regex)
- export_symbols_regex="$arg"
- prev=
- continue
- ;;
- release)
- release="-$arg"
- prev=
- continue
- ;;
- rpath | xrpath)
- # We need an absolute path.
- case "$arg" in
- [\\/]* | [A-Za-z]:[\\/]*) ;;
- *)
- $echo "$modename: only absolute run-paths are allowed" 1>&2
- exit 1
- ;;
- esac
- if test "$prev" = rpath; then
- case "$rpath " in
- *" $arg "*) ;;
- *) rpath="$rpath $arg" ;;
- esac
- else
- case "$xrpath " in
- *" $arg "*) ;;
- *) xrpath="$xrpath $arg" ;;
- esac
- fi
- prev=
- continue
- ;;
- *)
- eval "$prev=\"\$arg\""
- prev=
- continue
- ;;
- esac
- fi
-
- prevarg="$arg"
-
- case "$arg" in
- -all-static)
- if test -n "$link_static_flag"; then
- compile_command="$compile_command $link_static_flag"
- finalize_command="$finalize_command $link_static_flag"
- fi
- continue
- ;;
-
- -allow-undefined)
- # FIXME: remove this flag sometime in the future.
- $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2
- continue
- ;;
-
- -avoid-version)
- avoid_version=yes
- continue
- ;;
-
- -dlopen)
- prev=dlfiles
- continue
- ;;
-
- -dlpreopen)
- prev=dlprefiles
- continue
- ;;
-
- -export-dynamic)
- export_dynamic=yes
- continue
- ;;
-
- -export-symbols | -export-symbols-regex)
- if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
- $echo "$modename: not more than one -exported-symbols argument allowed"
- exit 1
- fi
- if test "X$arg" = "X-export-symbols"; then
- prev=expsyms
- else
- prev=expsyms_regex
- fi
- continue
- ;;
-
- -L*)
- dir=`$echo "X$arg" | $Xsed -e 's/^-L//'`
- # We need an absolute path.
- case "$dir" in
- [\\/]* | [A-Za-z]:[\\/]*) ;;
- *)
- absdir=`cd "$dir" && pwd`
- if test -z "$absdir"; then
- $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2
- $echo "$modename: passing it literally to the linker, although it might fail" 1>&2
- absdir="$dir"
- fi
- dir="$absdir"
- ;;
- esac
- case " $deplibs " in
- *" $arg "*) ;;
- *) deplibs="$deplibs $arg";;
- esac
- case " $lib_search_path " in
- *" $dir "*) ;;
- *) lib_search_path="$lib_search_path $dir";;
- esac
- case "$host" in
- *-*-cygwin* | *-*-mingw* | *-*-os2*)
- dllsearchdir=`cd "$dir" && pwd || echo "$dir"`
- case ":$dllsearchpath:" in
- ::) dllsearchpath="$dllsearchdir";;
- *":$dllsearchdir:"*) ;;
- *) dllsearchpath="$dllsearchpath:$dllsearchdir";;
- esac
- ;;
- esac
- ;;
-
- -l*)
- if test "$arg" = "-lc"; then
- case "$host" in
- *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos*)
- # These systems don't actually have c library (as such)
- continue
- ;;
- esac
- elif test "$arg" = "-lm"; then
- case "$host" in
- *-*-cygwin* | *-*-beos*)
- # These systems don't actually have math library (as such)
- continue
- ;;
- esac
- fi
- deplibs="$deplibs $arg"
- ;;
-
- -module)
- module=yes
- continue
- ;;
-
- -no-undefined)
- allow_undefined=no
- continue
- ;;
-
- -o) prev=output ;;
-
- -release)
- prev=release
- continue
- ;;
-
- -rpath)
- prev=rpath
- continue
- ;;
-
- -R)
- prev=xrpath
- continue
- ;;
-
- -R*)
- dir=`$echo "X$arg" | $Xsed -e 's/^-R//'`
- # We need an absolute path.
- case "$dir" in
- [\\/]* | [A-Za-z]:[\\/]*) ;;
- *)
- $echo "$modename: only absolute run-paths are allowed" 1>&2
- exit 1
- ;;
- esac
- case "$xrpath " in
- *" $dir "*) ;;
- *) xrpath="$xrpath $dir" ;;
- esac
- continue
- ;;
-
- -static)
- # If we have no pic_flag, then this is the same as -all-static.
- if test -z "$pic_flag" && test -n "$link_static_flag"; then
- compile_command="$compile_command $link_static_flag"
- finalize_command="$finalize_command $link_static_flag"
- fi
- continue
- ;;
-
- -thread-safe)
- thread_safe=yes
- continue
- ;;
-
- -version-info)
- prev=vinfo
- continue
- ;;
-
- # Some other compiler flag.
- -* | +*)
- # Unknown arguments in both finalize_command and compile_command need
- # to be aesthetically quoted because they are evaled later.
- arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
- case "$arg" in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
- arg="\"$arg\""
- ;;
- esac
- ;;
-
- *.o | *.obj | *.a | *.lib)
- # A standard object.
- objs="$objs $arg"
- ;;
-
- *.lo)
- # A library object.
- if test "$prev" = dlfiles; then
- dlfiles="$dlfiles $arg"
- if test "$build_libtool_libs" = yes && test "$dlopen" = yes; then
- prev=
- continue
- else
- # If libtool objects are unsupported, then we need to preload.
- prev=dlprefiles
- fi
- fi
-
- if test "$prev" = dlprefiles; then
- # Preload the old-style object.
- dlprefiles="$dlprefiles "`$echo "X$arg" | $Xsed -e "$lo2o"`
- prev=
- fi
- libobjs="$libobjs $arg"
- ;;
-
- *.la)
- # A libtool-controlled library.
-
- dlname=
- libdir=
- library_names=
- old_library=
-
- # Check to see that this really is a libtool archive.
- if (sed -e '2q' $arg | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
- else
- $echo "$modename: \`$arg' is not a valid libtool archive" 1>&2
- exit 1
- fi
-
- # If the library was installed with an old release of libtool,
- # it will not redefine variable installed.
- installed=yes
-
- # Read the .la file
- # If there is no directory component, then add one.
- case "$arg" in
- */* | *\\*) . $arg ;;
- *) . ./$arg ;;
- esac
-
- # Get the name of the library we link against.
- linklib=
- for l in $old_library $library_names; do
- linklib="$l"
- done
-
- if test -z "$linklib"; then
- $echo "$modename: cannot find name of link library for \`$arg'" 1>&2
- exit 1
- fi
-
- # Find the relevant object directory and library name.
- name=`$echo "X$arg" | $Xsed -e 's%^.*/%%' -e 's/\.la$//' -e 's/^lib//'`
-
- if test "X$installed" = Xyes; then
- dir="$libdir"
- else
- dir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$dir" = "X$arg"; then
- dir="$objdir"
- else
- dir="$dir/$objdir"
- fi
- fi
-
- if test -n "$dependency_libs"; then
- # Extract -R and -L from dependency_libs
- temp_deplibs=
- for deplib in $dependency_libs; do
- case "$deplib" in
- -R*) temp_xrpath=`$echo "X$deplib" | $Xsed -e 's/^-R//'`
- case " $rpath $xrpath " in
- *" $temp_xrpath "*) ;;
- *) xrpath="$xrpath $temp_xrpath";;
- esac;;
- -L*) case "$compile_command $temp_deplibs " in
- *" $deplib "*) ;;
- *) temp_deplibs="$temp_deplibs $deplib";;
- esac
- temp_dir=`$echo "X$deplib" | $Xsed -e 's/^-L//'`
- case " $lib_search_path " in
- *" $temp_dir "*) ;;
- *) lib_search_path="$lib_search_path $temp_dir";;
- esac
- ;;
- *) temp_deplibs="$temp_deplibs $deplib";;
- esac
- done
- dependency_libs="$temp_deplibs"
- fi
-
- if test -z "$libdir"; then
- # It is a libtool convenience library, so add in its objects.
- convenience="$convenience $dir/$old_library"
- old_convenience="$old_convenience $dir/$old_library"
- deplibs="$deplibs$dependency_libs"
- compile_command="$compile_command $dir/$old_library$dependency_libs"
- finalize_command="$finalize_command $dir/$old_library$dependency_libs"
- continue
- fi
-
- # This library was specified with -dlopen.
- if test "$prev" = dlfiles; then
- dlfiles="$dlfiles $arg"
- if test -z "$dlname" || test "$dlopen" != yes || test "$build_libtool_libs" = no; then
- # If there is no dlname, no dlopen support or we're linking statically,
- # we need to preload.
- prev=dlprefiles
- else
- # We should not create a dependency on this library, but we
- # may need any libraries it requires.
- compile_command="$compile_command$dependency_libs"
- finalize_command="$finalize_command$dependency_libs"
- prev=
- continue
- fi
- fi
-
- # The library was specified with -dlpreopen.
- if test "$prev" = dlprefiles; then
- # Prefer using a static library (so that no silly _DYNAMIC symbols
- # are required to link).
- if test -n "$old_library"; then
- dlprefiles="$dlprefiles $dir/$old_library"
- else
- dlprefiles="$dlprefiles $dir/$linklib"
- fi
- prev=
- fi
-
- if test -n "$library_names" &&
- { test "$prefer_static_libs" = no || test -z "$old_library"; }; then
- link_against_libtool_libs="$link_against_libtool_libs $arg"
- if test -n "$shlibpath_var"; then
- # Make sure the rpath contains only unique directories.
- case "$temp_rpath " in
- *" $dir "*) ;;
- *) temp_rpath="$temp_rpath $dir" ;;
- esac
- fi
-
- # We need an absolute path.
- case "$dir" in
- [\\/] | [A-Za-z]:[\\/]*) absdir="$dir" ;;
- *)
- absdir=`cd "$dir" && pwd`
- if test -z "$absdir"; then
- $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2
- $echo "$modename: passing it literally to the linker, although it might fail" 1>&2
- absdir="$dir"
- fi
- ;;
- esac
-
- # This is the magic to use -rpath.
- # Skip directories that are in the system default run-time
- # search path, unless they have been requested with -R.
- case " $sys_lib_dlsearch_path " in
- *" $absdir "*) ;;
- *)
- case "$compile_rpath " in
- *" $absdir "*) ;;
- *) compile_rpath="$compile_rpath $absdir"
- esac
- ;;
- esac
-
- case " $sys_lib_dlsearch_path " in
- *" $libdir "*) ;;
- *)
- case "$finalize_rpath " in
- *" $libdir "*) ;;
- *) finalize_rpath="$finalize_rpath $libdir"
- esac
- ;;
- esac
-
- lib_linked=yes
- case "$hardcode_action" in
- immediate | unsupported)
- if test "$hardcode_direct" = no; then
- compile_command="$compile_command $dir/$linklib"
- deplibs="$deplibs $dir/$linklib"
- case "$host" in
- *-*-cygwin* | *-*-mingw* | *-*-os2*)
- dllsearchdir=`cd "$dir" && pwd || echo "$dir"`
- if test -n "$dllsearchpath"; then
- dllsearchpath="$dllsearchpath:$dllsearchdir"
- else
- dllsearchpath="$dllsearchdir"
- fi
- ;;
- esac
- elif test "$hardcode_minus_L" = no; then
- case "$host" in
- *-*-sunos*)
- compile_shlibpath="$compile_shlibpath$dir:"
- ;;
- esac
- case "$compile_command " in
- *" -L$dir "*) ;;
- *) compile_command="$compile_command -L$dir";;
- esac
- compile_command="$compile_command -l$name"
- deplibs="$deplibs -L$dir -l$name"
- elif test "$hardcode_shlibpath_var" = no; then
- case ":$compile_shlibpath:" in
- *":$dir:"*) ;;
- *) compile_shlibpath="$compile_shlibpath$dir:";;
- esac
- compile_command="$compile_command -l$name"
- deplibs="$deplibs -l$name"
- else
- lib_linked=no
- fi
- ;;
-
- relink)
- if test "$hardcode_direct" = yes; then
- compile_command="$compile_command $absdir/$linklib"
- deplibs="$deplibs $absdir/$linklib"
- elif test "$hardcode_minus_L" = yes; then
- case "$compile_command " in
- *" -L$absdir "*) ;;
- *) compile_command="$compile_command -L$absdir";;
- esac
- compile_command="$compile_command -l$name"
- deplibs="$deplibs -L$absdir -l$name"
- elif test "$hardcode_shlibpath_var" = yes; then
- case ":$compile_shlibpath:" in
- *":$absdir:"*) ;;
- *) compile_shlibpath="$compile_shlibpath$absdir:";;
- esac
- compile_command="$compile_command -l$name"
- deplibs="$deplibs -l$name"
- else
- lib_linked=no
- fi
- ;;
-
- *)
- lib_linked=no
- ;;
- esac
-
- if test "$lib_linked" != yes; then
- $echo "$modename: configuration error: unsupported hardcode properties"
- exit 1
- fi
-
- # Finalize command for both is simple: just hardcode it.
- if test "$hardcode_direct" = yes; then
- finalize_command="$finalize_command $libdir/$linklib"
- elif test "$hardcode_minus_L" = yes; then
- case "$finalize_command " in
- *" -L$libdir "*) ;;
- *) finalize_command="$finalize_command -L$libdir";;
- esac
- finalize_command="$finalize_command -l$name"
- elif test "$hardcode_shlibpath_var" = yes; then
- case ":$finalize_shlibpath:" in
- *":$libdir:"*) ;;
- *) finalize_shlibpath="$finalize_shlibpath$libdir:";;
- esac
- finalize_command="$finalize_command -l$name"
- else
- # We cannot seem to hardcode it, guess we'll fake it.
- case "$finalize_command " in
- *" -L$dir "*) ;;
- *) finalize_command="$finalize_command -L$libdir";;
- esac
- finalize_command="$finalize_command -l$name"
- fi
- else
- # Transform directly to old archives if we don't build new libraries.
- if test -n "$pic_flag" && test -z "$old_library"; then
- $echo "$modename: cannot find static library for \`$arg'" 1>&2
- exit 1
- fi
-
- # Here we assume that one of hardcode_direct or hardcode_minus_L
- # is not unsupported. This is valid on all known static and
- # shared platforms.
- if test "$hardcode_direct" != unsupported; then
- test -n "$old_library" && linklib="$old_library"
- compile_command="$compile_command $dir/$linklib"
- finalize_command="$finalize_command $dir/$linklib"
- else
- case "$compile_command " in
- *" -L$dir "*) ;;
- *) compile_command="$compile_command -L$dir";;
- esac
- compile_command="$compile_command -l$name"
- case "$finalize_command " in
- *" -L$dir "*) ;;
- *) finalize_command="$finalize_command -L$dir";;
- esac
- finalize_command="$finalize_command -l$name"
- fi
- fi
-
- # Add in any libraries that this one depends upon.
- compile_command="$compile_command$dependency_libs"
- finalize_command="$finalize_command$dependency_libs"
- continue
- ;;
-
- # Some other compiler argument.
- *)
- # Unknown arguments in both finalize_command and compile_command need
- # to be aesthetically quoted because they are evaled later.
- arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
- case "$arg" in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
- arg="\"$arg\""
- ;;
- esac
- ;;
- esac
-
- # Now actually substitute the argument into the commands.
- if test -n "$arg"; then
- compile_command="$compile_command $arg"
- finalize_command="$finalize_command $arg"
- fi
- done
-
- if test -n "$prev"; then
- $echo "$modename: the \`$prevarg' option requires an argument" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
- eval arg=\"$export_dynamic_flag_spec\"
- compile_command="$compile_command $arg"
- finalize_command="$finalize_command $arg"
- fi
-
- oldlibs=
- # calculate the name of the file, without its directory
- outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'`
- libobjs_save="$libobjs"
-
- case "$output" in
- "")
- $echo "$modename: you must specify an output file" 1>&2
- $echo "$help" 1>&2
- exit 1
- ;;
-
- *.a | *.lib)
- if test -n "$link_against_libtool_libs"; then
- $echo "$modename: error: cannot link libtool libraries into archives" 1>&2
- exit 1
- fi
-
- if test -n "$deplibs"; then
- $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2
- fi
-
- if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
- $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2
- fi
-
- if test -n "$rpath"; then
- $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2
- fi
-
- if test -n "$xrpath"; then
- $echo "$modename: warning: \`-R' is ignored for archives" 1>&2
- fi
-
- if test -n "$vinfo"; then
- $echo "$modename: warning: \`-version-info' is ignored for archives" 1>&2
- fi
-
- if test -n "$release"; then
- $echo "$modename: warning: \`-release' is ignored for archives" 1>&2
- fi
-
- if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
- $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2
- fi
-
- # Now set the variables for building old libraries.
- build_libtool_libs=no
- oldlibs="$output"
- ;;
-
- *.la)
- # Make sure we only generate libraries of the form `libNAME.la'.
- case "$outputname" in
- lib*)
- name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
- eval libname=\"$libname_spec\"
- ;;
- *)
- if test "$module" = no; then
- $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
- if test "$need_lib_prefix" != no; then
- # Add the "lib" prefix for modules if required
- name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
- eval libname=\"$libname_spec\"
- else
- libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
- fi
- ;;
- esac
-
- output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$output_objdir" = "X$output"; then
- output_objdir="$objdir"
- else
- output_objdir="$output_objdir/$objdir"
- fi
-
- if test -n "$objs"; then
- $echo "$modename: cannot build libtool library \`$output' from non-libtool objects:$objs" 2>&1
- exit 1
- fi
-
- # How the heck are we supposed to write a wrapper for a shared library?
- if test -n "$link_against_libtool_libs"; then
- $echo "$modename: error: cannot link shared libraries into libtool libraries" 1>&2
- exit 1
- fi
-
- if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
- $echo "$modename: warning: \`-dlopen' is ignored for libtool libraries" 1>&2
- fi
-
- set dummy $rpath
- if test $# -gt 2; then
- $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2
- fi
- install_libdir="$2"
-
- oldlibs=
- if test -z "$rpath"; then
- if test "$build_libtool_libs" = yes; then
- # Building a libtool convenience library.
- libext=al
- oldlibs="$output_objdir/$libname.$libext $oldlibs"
- build_libtool_libs=convenience
- build_old_libs=yes
- fi
- dependency_libs="$deplibs"
-
- if test -n "$vinfo"; then
- $echo "$modename: warning: \`-version-info' is ignored for convenience libraries" 1>&2
- fi
-
- if test -n "$release"; then
- $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2
- fi
- else
-
- # Parse the version information argument.
- IFS="${IFS= }"; save_ifs="$IFS"; IFS=':'
- set dummy $vinfo 0 0 0
- IFS="$save_ifs"
-
- if test -n "$8"; then
- $echo "$modename: too many parameters to \`-version-info'" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- current="$2"
- revision="$3"
- age="$4"
-
- # Check that each of the things are valid numbers.
- case "$current" in
- 0 | [1-9] | [1-9][0-9]*) ;;
- *)
- $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2
- $echo "$modename: \`$vinfo' is not valid version information" 1>&2
- exit 1
- ;;
- esac
-
- case "$revision" in
- 0 | [1-9] | [1-9][0-9]*) ;;
- *)
- $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2
- $echo "$modename: \`$vinfo' is not valid version information" 1>&2
- exit 1
- ;;
- esac
-
- case "$age" in
- 0 | [1-9] | [1-9][0-9]*) ;;
- *)
- $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2
- $echo "$modename: \`$vinfo' is not valid version information" 1>&2
- exit 1
- ;;
- esac
-
- if test $age -gt $current; then
- $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2
- $echo "$modename: \`$vinfo' is not valid version information" 1>&2
- exit 1
- fi
-
- # Calculate the version variables.
- major=
- versuffix=
- verstring=
- case "$version_type" in
- none) ;;
-
- irix)
- major=`expr $current - $age + 1`
- versuffix="$major.$revision"
- verstring="sgi$major.$revision"
-
- # Add in all the interfaces that we are compatible with.
- loop=$revision
- while test $loop != 0; do
- iface=`expr $revision - $loop`
- loop=`expr $loop - 1`
- verstring="sgi$major.$iface:$verstring"
- done
- ;;
-
- linux)
- major=.`expr $current - $age`
- versuffix="$major.$age.$revision"
- ;;
-
- osf)
- major=`expr $current - $age`
- versuffix=".$current.$age.$revision"
- verstring="$current.$age.$revision"
-
- # Add in all the interfaces that we are compatible with.
- loop=$age
- while test $loop != 0; do
- iface=`expr $current - $loop`
- loop=`expr $loop - 1`
- verstring="$verstring:${iface}.0"
- done
-
- # Make executables depend on our current version.
- verstring="$verstring:${current}.0"
- ;;
-
- sunos)
- major=".$current"
- versuffix=".$current.$revision"
- ;;
-
- freebsd-aout)
- major=".$current"
- versuffix=".$current.$revision";
- ;;
-
- freebsd-elf)
- major=".$current"
- versuffix=".$current";
- ;;
-
- windows)
- # Like Linux, but with '-' rather than '.', since we only
- # want one extension on Windows 95.
- major=`expr $current - $age`
- versuffix="-$major-$age-$revision"
- ;;
-
- *)
- $echo "$modename: unknown library version type \`$version_type'" 1>&2
- echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
- exit 1
- ;;
- esac
-
- # Clear the version info if we defaulted, and they specified a release.
- if test -z "$vinfo" && test -n "$release"; then
- major=
- verstring="0.0"
- if test "$need_version" = no; then
- versuffix=
- else
- versuffix=".0.0"
- fi
- fi
-
- # Remove version info from name if versioning should be avoided
- if test "$avoid_version" = yes && test "$need_version" = no; then
- major=
- versuffix=
- verstring=""
- fi
-
- # Check to see if the archive will have undefined symbols.
- if test "$allow_undefined" = yes; then
- if test "$allow_undefined_flag" = unsupported; then
- $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2
- build_libtool_libs=no
- build_old_libs=yes
- fi
- else
- # Don't allow undefined symbols.
- allow_undefined_flag="$no_undefined_flag"
- fi
-
- dependency_libs="$deplibs"
- case "$host" in
- *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos*)
- # these systems don't actually have a c library (as such)!
- ;;
- *)
- # Add libc to deplibs on all other systems.
- deplibs="$deplibs -lc"
- ;;
- esac
- fi
-
- # Create the output directory, or remove our outputs if we need to.
- if test -d $output_objdir; then
- $show "${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*"
- $run ${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*
- else
- $show "$mkdir $output_objdir"
- $run $mkdir $output_objdir
- status=$?
- if test $status -ne 0 && test ! -d $output_objdir; then
- exit $status
- fi
- fi
-
- # Now set the variables for building old libraries.
- if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
- oldlibs="$oldlibs $output_objdir/$libname.$libext"
-
- # Transform .lo files to .o files.
- oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP`
- fi
-
- if test "$build_libtool_libs" = yes; then
- # Transform deplibs into only deplibs that can be linked in shared.
- name_save=$name
- libname_save=$libname
- release_save=$release
- versuffix_save=$versuffix
- major_save=$major
- # I'm not sure if I'm treating the release correctly. I think
- # release should show up in the -l (ie -lgmp5) so we don't want to
- # add it in twice. Is that correct?
- release=""
- versuffix=""
- major=""
- newdeplibs=
- droppeddeps=no
- case "$deplibs_check_method" in
- pass_all)
- # Don't check for shared/static. Everything works.
- # This might be a little naive. We might want to check
- # whether the library exists or not. But this is on
- # osf3 & osf4 and I'm not really sure... Just
- # implementing what was already the behaviour.
- newdeplibs=$deplibs
- ;;
- test_compile)
- # This code stresses the "libraries are programs" paradigm to its
- # limits. Maybe even breaks it. We compile a program, linking it
- # against the deplibs as a proxy for the library. Then we can check
- # whether they linked in statically or dynamically with ldd.
- $rm conftest.c
- cat > conftest.c <<EOF
- int main() { return 0; }
-EOF
- $rm conftest
- $C_compiler -o conftest conftest.c $deplibs
- if test $? -eq 0 ; then
- ldd_output=`ldd conftest`
- for i in $deplibs; do
- name="`expr $i : '-l\(.*\)'`"
- # If $name is empty we are operating on a -L argument.
- if test "$name" != "" ; then
- libname=`eval \\$echo \"$libname_spec\"`
- deplib_matches=`eval \\$echo \"$library_names_spec\"`
- set dummy $deplib_matches
- deplib_match=$2
- if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
- newdeplibs="$newdeplibs $i"
- else
- droppeddeps=yes
- echo
- echo "*** Warning: This library needs some functionality provided by $i."
- echo "*** I have the capability to make that library automatically link in when"
- echo "*** you link to this library. But I can only do this if you have a"
- echo "*** shared version of the library, which you do not appear to have."
- fi
- else
- newdeplibs="$newdeplibs $i"
- fi
- done
- else
- # Error occured in the first compile. Let's try to salvage the situation:
- # Compile a seperate program for each library.
- for i in $deplibs; do
- name="`expr $i : '-l\(.*\)'`"
- # If $name is empty we are operating on a -L argument.
- if test "$name" != "" ; then
- $rm conftest
- $C_compiler -o conftest conftest.c $i
- # Did it work?
- if test $? -eq 0 ; then
- ldd_output=`ldd conftest`
- libname=`eval \\$echo \"$libname_spec\"`
- deplib_matches=`eval \\$echo \"$library_names_spec\"`
- set dummy $deplib_matches
- deplib_match=$2
- if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
- newdeplibs="$newdeplibs $i"
- else
- droppeddeps=yes
- echo
- echo "*** Warning: This library needs some functionality provided by $i."
- echo "*** I have the capability to make that library automatically link in when"
- echo "*** you link to this library. But I can only do this if you have a"
- echo "*** shared version of the library, which you do not appear to have."
- fi
- else
- droppeddeps=yes
- echo
- echo "*** Warning! Library $i is needed by this library but I was not able to"
- echo "*** make it link in! You will probably need to install it or some"
- echo "*** library that it depends on before this library will be fully"
- echo "*** functional. Installing it before continuing would be even better."
- fi
- else
- newdeplibs="$newdeplibs $i"
- fi
- done
- fi
- ;;
- file_magic*)
- set dummy $deplibs_check_method
- file_magic_regex="`expr \"$deplibs_check_method\" : \"$2 \(.*\)\"`"
- for a_deplib in $deplibs; do
- name="`expr $a_deplib : '-l\(.*\)'`"
- # If $name is empty we are operating on a -L argument.
- if test "$name" != "" ; then
- libname=`eval \\$echo \"$libname_spec\"`
- for i in $lib_search_path; do
- potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
- for potent_lib in $potential_libs; do
- # Follow soft links.
- if ls -lLd "$potent_lib" 2>/dev/null \
- | grep " -> " >/dev/null; then
- continue
- fi
- # The statement above tries to avoid entering an
- # endless loop below, in case of cyclic links.
- # We might still enter an endless loop, since a link
- # loop can be closed while we follow links,
- # but so what?
- potlib="$potent_lib"
- while test -h "$potlib" 2>/dev/null; do
- potliblink=`ls -ld $potlib | sed 's/.* -> //'`
- case "$potliblink" in
- [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
- *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";;
- esac
- done
- if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \
- | sed 10q \
- | egrep "$file_magic_regex" > /dev/null; then
- newdeplibs="$newdeplibs $a_deplib"
- a_deplib=""
- break 2
- fi
- done
- done
- if test -n "$a_deplib" ; then
- droppeddeps=yes
- echo
- echo "*** Warning: This library needs some functionality provided by $a_deplib."
- echo "*** I have the capability to make that library automatically link in when"
- echo "*** you link to this library. But I can only do this if you have a"
- echo "*** shared version of the library, which you do not appear to have."
- fi
- else
- # Add a -L argument.
- newdeplibs="$newdeplibs $a_deplib"
- fi
- done # Gone through all deplibs.
- ;;
- none | unknown | *)
- newdeplibs=""
- if $echo "X $deplibs" | $Xsed -e 's/ -lc$//' \
- -e 's/ -[LR][^ ]*//g' -e 's/[ ]//g' |
- grep . >/dev/null; then
- echo
- if test "X$deplibs_check_method" = "Xnone"; then
- echo "*** Warning: inter-library dependencies are not supported in this platform."
- else
- echo "*** Warning: inter-library dependencies are not known to be supported."
- fi
- echo "*** All declared inter-library dependencies are being dropped."
- droppeddeps=yes
- fi
- ;;
- esac
- versuffix=$versuffix_save
- major=$major_save
- release=$release_save
- libname=$libname_save
- name=$name_save
-
- if test "$droppeddeps" = yes; then
- if test "$module" = yes; then
- echo
- echo "*** Warning: libtool could not satisfy all declared inter-library"
- echo "*** dependencies of module $libname. Therefore, libtool will create"
- echo "*** a static module, that should work as long as the dlopening"
- echo "*** application is linked with the -dlopen flag."
- if test -z "$global_symbol_pipe"; then
- echo
- echo "*** However, this would only work if libtool was able to extract symbol"
- echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
- echo "*** not find such a program. So, this module is probably useless."
- echo "*** \`nm' from GNU binutils and a full rebuild may help."
- fi
- if test "$build_old_libs" = no; then
- oldlibs="$output_objdir/$libname.$libext"
- build_libtool_libs=module
- build_old_libs=yes
- else
- build_libtool_libs=no
- fi
- else
- echo "*** The inter-library dependencies that have been dropped here will be"
- echo "*** automatically added whenever a program is linked with this library"
- echo "*** or is declared to -dlopen it."
- fi
- fi
- # Done checking deplibs!
- deplibs=$newdeplibs
- fi
-
- # All the library-specific variables (install_libdir is set above).
- library_names=
- old_library=
- dlname=
-
- # Test again, we may have decided not to build it any more
- if test "$build_libtool_libs" = yes; then
- # Get the real and link names of the library.
- eval library_names=\"$library_names_spec\"
- set dummy $library_names
- realname="$2"
- shift; shift
-
- if test -n "$soname_spec"; then
- eval soname=\"$soname_spec\"
- else
- soname="$realname"
- fi
-
- lib="$output_objdir/$realname"
- for link
- do
- linknames="$linknames $link"
- done
-
- # Ensure that we have .o objects for linkers which dislike .lo
- # (e.g. aix) incase we are running --disable-static
- for obj in $libobjs; do
- oldobj=`$echo "X$obj" | $Xsed -e "$lo2o"`
- if test ! -f $oldobj; then
- $show "${LN_S} $obj $oldobj"
- $run ${LN_S} $obj $oldobj || exit $?
- fi
- done
-
- # Use standard objects if they are pic
- test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
-
- # Prepare the list of exported symbols
- if test -z "$export_symbols"; then
- if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
- $show "generating symbol list for \`$libname.la'"
- export_symbols="$output_objdir/$libname.exp"
- $run $rm $export_symbols
- eval cmds=\"$export_symbols_cmds\"
- IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- if test -n "$export_symbols_regex"; then
- $show "egrep -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\""
- $run eval 'egrep -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
- $show "$mv \"${export_symbols}T\" \"$export_symbols\""
- $run eval '$mv "${export_symbols}T" "$export_symbols"'
- fi
- fi
- fi
-
- if test -n "$export_symbols" && test -n "$include_expsyms"; then
- $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"'
- fi
-
- if test -n "$convenience"; then
- if test -n "$whole_archive_flag_spec"; then
- eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
- else
- gentop="$output_objdir/${outputname}x"
- $show "${rm}r $gentop"
- $run ${rm}r "$gentop"
- $show "mkdir $gentop"
- $run mkdir "$gentop"
- status=$?
- if test $status -ne 0 && test ! -d "$gentop"; then
- exit $status
- fi
- generated="$generated $gentop"
-
- for xlib in $convenience; do
- # Extract the objects.
- case "$xlib" in
- [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
- *) xabs=`pwd`"/$xlib" ;;
- esac
- xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
- xdir="$gentop/$xlib"
-
- $show "${rm}r $xdir"
- $run ${rm}r "$xdir"
- $show "mkdir $xdir"
- $run mkdir "$xdir"
- status=$?
- if test $status -ne 0 && test ! -d "$xdir"; then
- exit $status
- fi
- $show "(cd $xdir && $AR x $xabs)"
- $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
-
- libobjs="$libobjs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP`
- done
- fi
- fi
-
- if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
- eval flag=\"$thread_safe_flag_spec\"
- linkopts="$linkopts $flag"
- fi
-
- # Do each of the archive commands.
- if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
- eval cmds=\"$archive_expsym_cmds\"
- else
- eval cmds=\"$archive_cmds\"
- fi
- IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
-
- # Create links to the real library.
- for linkname in $linknames; do
- if test "$realname" != "$linkname"; then
- $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)"
- $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $?
- fi
- done
-
- # If -module or -export-dynamic was specified, set the dlname.
- if test "$module" = yes || test "$export_dynamic" = yes; then
- # On all known operating systems, these are identical.
- dlname="$soname"
- fi
- fi
- ;;
-
- *.lo | *.o | *.obj)
- if test -n "$link_against_libtool_libs"; then
- $echo "$modename: error: cannot link libtool libraries into objects" 1>&2
- exit 1
- fi
-
- if test -n "$deplibs"; then
- $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2
- fi
-
- if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
- $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2
- fi
-
- if test -n "$rpath"; then
- $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2
- fi
-
- if test -n "$xrpath"; then
- $echo "$modename: warning: \`-R' is ignored for objects" 1>&2
- fi
-
- if test -n "$vinfo"; then
- $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2
- fi
-
- if test -n "$release"; then
- $echo "$modename: warning: \`-release' is ignored for objects" 1>&2
- fi
-
- case "$output" in
- *.lo)
- if test -n "$objs"; then
- $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2
- exit 1
- fi
- libobj="$output"
- obj=`$echo "X$output" | $Xsed -e "$lo2o"`
- ;;
- *)
- libobj=
- obj="$output"
- ;;
- esac
-
- # Delete the old objects.
- $run $rm $obj $libobj
-
- # Objects from convenience libraries. This assumes
- # single-version convenience libraries. Whenever we create
- # different ones for PIC/non-PIC, this we'll have to duplicate
- # the extraction.
- reload_conv_objs=
- gentop=
- # reload_cmds runs $LD directly, so let us get rid of
- # -Wl from whole_archive_flag_spec
- wl=
-
- if test -n "$convenience"; then
- if test -n "$whole_archive_flag_spec"; then
- eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\"
- else
- gentop="$output_objdir/${obj}x"
- $show "${rm}r $gentop"
- $run ${rm}r "$gentop"
- $show "mkdir $gentop"
- $run mkdir "$gentop"
- status=$?
- if test $status -ne 0 && test ! -d "$gentop"; then
- exit $status
- fi
- generated="$generated $gentop"
-
- for xlib in $convenience; do
- # Extract the objects.
- case "$xlib" in
- [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
- *) xabs=`pwd`"/$xlib" ;;
- esac
- xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
- xdir="$gentop/$xlib"
-
- $show "${rm}r $xdir"
- $run ${rm}r "$xdir"
- $show "mkdir $xdir"
- $run mkdir "$xdir"
- status=$?
- if test $status -ne 0 && test ! -d "$xdir"; then
- exit $status
- fi
- $show "(cd $xdir && $AR x $xabs)"
- $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
-
- reload_conv_objs="$reload_objs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP`
- done
- fi
- fi
-
- # Create the old-style object.
- reload_objs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs"
-
- output="$obj"
- eval cmds=\"$reload_cmds\"
- IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
-
- # Exit if we aren't doing a library object file.
- if test -z "$libobj"; then
- if test -n "$gentop"; then
- $show "${rm}r $gentop"
- $run ${rm}r $gentop
- fi
-
- exit 0
- fi
-
- if test "$build_libtool_libs" != yes; then
- if test -n "$gentop"; then
- $show "${rm}r $gentop"
- $run ${rm}r $gentop
- fi
-
- # Create an invalid libtool object if no PIC, so that we don't
- # accidentally link it into a program.
- $show "echo timestamp > $libobj"
- $run eval "echo timestamp > $libobj" || exit $?
- exit 0
- fi
-
- if test -n "$pic_flag"; then
- # Only do commands if we really have different PIC objects.
- reload_objs="$libobjs $reload_conv_objs"
- output="$libobj"
- eval cmds=\"$reload_cmds\"
- IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- else
- # Just create a symlink.
- $show $rm $libobj
- $run $rm $libobj
- $show "$LN_S $obj $libobj"
- $run $LN_S $obj $libobj || exit $?
- fi
-
- if test -n "$gentop"; then
- $show "${rm}r $gentop"
- $run ${rm}r $gentop
- fi
-
- exit 0
- ;;
-
- # Anything else should be a program.
- *)
- if test -n "$vinfo"; then
- $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2
- fi
-
- if test -n "$release"; then
- $echo "$modename: warning: \`-release' is ignored for programs" 1>&2
- fi
-
- if test "$preload" = yes; then
- if test "$dlopen" = unknown && test "$dlopen_self" = unknown &&
- test "$dlopen_self_static" = unknown; then
- $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support."
- fi
- fi
-
- if test -n "$rpath$xrpath"; then
- # If the user specified any rpath flags, then add them.
- for libdir in $rpath $xrpath; do
- # This is the magic to use -rpath.
- case "$compile_rpath " in
- *" $libdir "*) ;;
- *) compile_rpath="$compile_rpath $libdir" ;;
- esac
- case "$finalize_rpath " in
- *" $libdir "*) ;;
- *) finalize_rpath="$finalize_rpath $libdir" ;;
- esac
- done
- fi
-
- # Now hardcode the library paths
- rpath=
- hardcode_libdirs=
- for libdir in $compile_rpath $finalize_rpath; do
- if test -n "$hardcode_libdir_flag_spec"; then
- if test -n "$hardcode_libdir_separator"; then
- if test -z "$hardcode_libdirs"; then
- hardcode_libdirs="$libdir"
- else
- # Just accumulate the unique libdirs.
- case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in
- *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
- ;;
- *)
- hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
- ;;
- esac
- fi
- else
- eval flag=\"$hardcode_libdir_flag_spec\"
- rpath="$rpath $flag"
- fi
- elif test -n "$runpath_var"; then
- case "$perm_rpath " in
- *" $libdir "*) ;;
- *) perm_rpath="$perm_rpath $libdir" ;;
- esac
- fi
- done
- # Substitute the hardcoded libdirs into the rpath.
- if test -n "$hardcode_libdir_separator" &&
- test -n "$hardcode_libdirs"; then
- libdir="$hardcode_libdirs"
- eval rpath=\" $hardcode_libdir_flag_spec\"
- fi
- compile_rpath="$rpath"
-
- rpath=
- hardcode_libdirs=
- for libdir in $finalize_rpath; do
- if test -n "$hardcode_libdir_flag_spec"; then
- if test -n "$hardcode_libdir_separator"; then
- if test -z "$hardcode_libdirs"; then
- hardcode_libdirs="$libdir"
- else
- # Just accumulate the unique libdirs.
- case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in
- *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
- ;;
- *)
- hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
- ;;
- esac
- fi
- else
- eval flag=\"$hardcode_libdir_flag_spec\"
- rpath="$rpath $flag"
- fi
- elif test -n "$runpath_var"; then
- case "$finalize_perm_rpath " in
- *" $libdir "*) ;;
- *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
- esac
- fi
- done
- # Substitute the hardcoded libdirs into the rpath.
- if test -n "$hardcode_libdir_separator" &&
- test -n "$hardcode_libdirs"; then
- libdir="$hardcode_libdirs"
- eval rpath=\" $hardcode_libdir_flag_spec\"
- fi
- finalize_rpath="$rpath"
-
- output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$output_objdir" = "X$output"; then
- output_objdir="$objdir"
- else
- output_objdir="$output_objdir/$objdir"
- fi
-
- # Create the binary in the object directory, then wrap it.
- if test ! -d $output_objdir; then
- $show "$mkdir $output_objdir"
- $run $mkdir $output_objdir
- status=$?
- if test $status -ne 0 && test ! -d $output_objdir; then
- exit $status
- fi
- fi
-
- if test -n "$libobjs" && test "$build_old_libs" = yes; then
- # Transform all the library objects into standard objects.
- compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
- finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
- fi
-
- dlsyms=
- if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
- if test -n "$NM" && test -n "$global_symbol_pipe"; then
- dlsyms="${outputname}S.c"
- else
- $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2
- fi
- fi
-
- if test -n "$dlsyms"; then
- case "$dlsyms" in
- "") ;;
- *.c)
- # Discover the nlist of each of the dlfiles.
- nlist="$output_objdir/${outputname}.nm"
-
- $show "$rm $nlist ${nlist}S ${nlist}T"
- $run $rm "$nlist" "${nlist}S" "${nlist}T"
-
- # Parse the name list into a source file.
- $show "creating $output_objdir/$dlsyms"
-
- test -z "$run" && $echo > "$output_objdir/$dlsyms" "\
-/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */
-/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */
-
-#ifdef __cplusplus
-extern \"C\" {
-#endif
-
-/* Prevent the only kind of declaration conflicts we can make. */
-#define lt_preloaded_symbols some_other_symbol
-
-/* External symbol declarations for the compiler. */\
-"
-
- if test "$dlself" = yes; then
- $show "generating symbol list for \`$output'"
-
- test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist"
-
- # Add our own program objects to the symbol list.
- progfiles=`$echo "X$objs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
- for arg in $progfiles; do
- $show "extracting global C symbols from \`$arg'"
- $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
- done
-
- if test -n "$exclude_expsyms"; then
- $run eval 'egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
- $run eval '$mv "$nlist"T "$nlist"'
- fi
-
- if test -n "$export_symbols_regex"; then
- $run eval 'egrep -e "$export_symbols_regex" "$nlist" > "$nlist"T'
- $run eval '$mv "$nlist"T "$nlist"'
- fi
-
- # Prepare the list of exported symbols
- if test -z "$export_symbols"; then
- export_symbols="$output_objdir/$output.exp"
- $run $rm $export_symbols
- $run eval "sed -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
- else
- $run eval "sed -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"'
- $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T'
- $run eval 'mv "$nlist"T "$nlist"'
- fi
- fi
-
- for arg in $dlprefiles; do
- $show "extracting global C symbols from \`$arg'"
- name=`echo "$arg" | sed -e 's%^.*/%%'`
- $run eval 'echo ": $name " >> "$nlist"'
- $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
- done
-
- if test -z "$run"; then
- # Make sure we have at least an empty file.
- test -f "$nlist" || : > "$nlist"
-
- if test -n "$exclude_expsyms"; then
- egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
- $mv "$nlist"T "$nlist"
- fi
-
- # Try sorting and uniquifying the output.
- if grep -v "^: " < "$nlist" | sort +2 | uniq > "$nlist"S; then
- :
- else
- grep -v "^: " < "$nlist" > "$nlist"S
- fi
-
- if test -f "$nlist"S; then
- eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"'
- else
- echo '/* NONE */' >> "$output_objdir/$dlsyms"
- fi
-
- $echo >> "$output_objdir/$dlsyms" "\
-
-#undef lt_preloaded_symbols
-
-#if defined (__STDC__) && __STDC__
-# define lt_ptr_t void *
-#else
-# define lt_ptr_t char *
-# define const
-#endif
-
-/* The mapping between symbol names and symbols. */
-const struct {
- const char *name;
- lt_ptr_t address;
-}
-lt_preloaded_symbols[] =
-{\
-"
-
- sed -n -e 's/^: \([^ ]*\) $/ {\"\1\", (lt_ptr_t) 0},/p' \
- -e 's/^. \([^ ]*\) \([^ ]*\)$/ {"\2", (lt_ptr_t) \&\2},/p' \
- < "$nlist" >> "$output_objdir/$dlsyms"
-
- $echo >> "$output_objdir/$dlsyms" "\
- {0, (lt_ptr_t) 0}
-};
-
-/* This works around a problem in FreeBSD linker */
-#ifdef FREEBSD_WORKAROUND
-static const void *lt_preloaded_setup() {
- return lt_preloaded_symbols;
-}
-#endif
-
-#ifdef __cplusplus
-}
-#endif\
-"
- fi
-
- pic_flag_for_symtable=
- case "$host" in
- # compiling the symbol table file with pic_flag works around
- # a FreeBSD bug that causes programs to crash when -lm is
- # linked before any other PIC object. But we must not use
- # pic_flag when linking with -static. The problem exists in
- # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
- *-*-freebsd2*|*-*-freebsd3.0*)
- case "$compile_command " in
- *" -static "*) ;;
- *) pic_flag_for_symtable=" $pic_flag -DPIC -DFREEBSD_WORKAROUND";;
- esac
- esac
-
- # Now compile the dynamic symbol file.
- $show "(cd $output_objdir && $C_compiler -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")"
- $run eval '(cd $output_objdir && $C_compiler -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $?
-
- # Clean up the generated files.
- $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T"
- $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T"
-
- # Transform the symbol file into the correct name.
- compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
- finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
- ;;
- *)
- $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2
- exit 1
- ;;
- esac
- else
- # We keep going just in case the user didn't refer to
- # lt_preloaded_symbols. The linker will fail if global_symbol_pipe
- # really was required.
-
- # Nullify the symbol file.
- compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"`
- finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"`
- fi
-
- if test -z "$link_against_libtool_libs" || test "$build_libtool_libs" != yes; then
- # Replace the output file specification.
- compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
- link_command="$compile_command$compile_rpath"
-
- # We have no uninstalled library dependencies, so finalize right now.
- $show "$link_command"
- $run eval "$link_command"
- status=$?
-
- # Delete the generated files.
- if test -n "$dlsyms"; then
- $show "$rm $output_objdir/${outputname}S.${objext}"
- $run $rm "$output_objdir/${outputname}S.${objext}"
- fi
-
- exit $status
- fi
-
- if test -n "$shlibpath_var"; then
- # We should set the shlibpath_var
- rpath=
- for dir in $temp_rpath; do
- case "$dir" in
- [\\/]* | [A-Za-z]:[\\/]*)
- # Absolute path.
- rpath="$rpath$dir:"
- ;;
- *)
- # Relative path: add a thisdir entry.
- rpath="$rpath\$thisdir/$dir:"
- ;;
- esac
- done
- temp_rpath="$rpath"
- fi
-
- if test -n "$compile_shlibpath$finalize_shlibpath"; then
- compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
- fi
- if test -n "$finalize_shlibpath"; then
- finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
- fi
-
- compile_var=
- finalize_var=
- if test -n "$runpath_var"; then
- if test -n "$perm_rpath"; then
- # We should set the runpath_var.
- rpath=
- for dir in $perm_rpath; do
- rpath="$rpath$dir:"
- done
- compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
- fi
- if test -n "$finalize_perm_rpath"; then
- # We should set the runpath_var.
- rpath=
- for dir in $finalize_perm_rpath; do
- rpath="$rpath$dir:"
- done
- finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
- fi
- fi
-
- if test "$hardcode_action" = relink; then
- # Fast installation is not supported
- link_command="$compile_var$compile_command$compile_rpath"
- relink_command="$finalize_var$finalize_command$finalize_rpath"
-
- $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2
- $echo "$modename: \`$output' will be relinked during installation" 1>&2
- else
- if test "$fast_install" != no; then
- link_command="$finalize_var$compile_command$finalize_rpath"
- if test "$fast_install" = yes; then
- relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'`
- else
- # fast_install is set to needless
- relink_command=
- fi
- else
- link_command="$compile_var$compile_command$compile_rpath"
- relink_command="$finalize_var$finalize_command$finalize_rpath"
- fi
- fi
-
- # Replace the output file specification.
- link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
-
- # Delete the old output files.
- $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname
-
- $show "$link_command"
- $run eval "$link_command" || exit $?
-
- # Now create the wrapper script.
- $show "creating $output"
-
- # Quote the relink command for shipping.
- if test -n "$relink_command"; then
- relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
- fi
-
- # Quote $echo for shipping.
- if test "X$echo" = "X$SHELL $0 --fallback-echo"; then
- case "$0" in
- [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $0 --fallback-echo";;
- *) qecho="$SHELL `pwd`/$0 --fallback-echo";;
- esac
- qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"`
- else
- qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"`
- fi
-
- # Only actually do things if our run command is non-null.
- if test -z "$run"; then
- # win32 will think the script is a binary if it has
- # a .exe suffix, so we strip it off here.
- case $output in
- *.exe) output=`echo $output|sed 's,.exe$,,'` ;;
- esac
- $rm $output
- trap "$rm $output; exit 1" 1 2 15
-
- $echo > $output "\
-#! $SHELL
-
-# $output - temporary wrapper script for $objdir/$outputname
-# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
-#
-# The $output program cannot be directly executed until all the libtool
-# libraries that it depends on are installed.
-#
-# This wrapper script should never be moved out of the build directory.
-# If it is, it will not operate correctly.
-
-# Sed substitution that helps us do robust quoting. It backslashifies
-# metacharacters that are still active within double-quoted strings.
-Xsed='sed -e 1s/^X//'
-sed_quote_subst='$sed_quote_subst'
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-if test \"\${CDPATH+set}\" = set; then CDPATH=; export CDPATH; fi
-
-relink_command=\"$relink_command\"
-
-# This environment variable determines our operation mode.
-if test \"\$libtool_install_magic\" = \"$magic\"; then
- # install mode needs the following variable:
- link_against_libtool_libs='$link_against_libtool_libs'
-else
- # When we are sourced in execute mode, \$file and \$echo are already set.
- if test \"\$libtool_execute_magic\" != \"$magic\"; then
- echo=\"$qecho\"
- file=\"\$0\"
- # Make sure echo works.
- if test \"X\$1\" = X--no-reexec; then
- # Discard the --no-reexec flag, and continue.
- shift
- elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then
- # Yippee, \$echo works!
- :
- else
- # Restart under the correct shell, and then maybe \$echo will work.
- exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"}
- fi
- fi\
-"
- $echo >> $output "\
-
- # Find the directory that this script lives in.
- thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\`
- test \"x\$thisdir\" = \"x\$file\" && thisdir=.
-
- # Follow symbolic links until we get to the real thisdir.
- file=\`ls -ld \"\$file\" | sed -n 's/.*-> //p'\`
- while test -n \"\$file\"; do
- destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\`
-
- # If there was a directory component, then change thisdir.
- if test \"x\$destdir\" != \"x\$file\"; then
- case \"\$destdir\" in
- [\\/]* | [A-Za-z]:[\\/]*) thisdir=\"\$destdir\" ;;
- *) thisdir=\"\$thisdir/\$destdir\" ;;
- esac
- fi
-
- file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\`
- file=\`ls -ld \"\$thisdir/\$file\" | sed -n 's/.*-> //p'\`
- done
-
- # Try to get the absolute directory name.
- absdir=\`cd \"\$thisdir\" && pwd\`
- test -n \"\$absdir\" && thisdir=\"\$absdir\"
-"
-
- if test "$fast_install" = yes; then
- echo >> $output "\
- program=lt-'$outputname'
- progdir=\"\$thisdir/$objdir\"
-
- if test ! -f \"\$progdir/\$program\" || \\
- { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | sed 1q\`; \\
- test \"X\$file\" != \"X\$progdir/\$program\"; }; then
-
- file=\"\$\$-\$program\"
-
- if test ! -d \"\$progdir\"; then
- $mkdir \"\$progdir\"
- else
- $rm \"\$progdir/\$file\"
- fi"
-
- echo >> $output "\
-
- # relink executable if necessary
- if test -n \"\$relink_command\"; then
- if (cd \"\$thisdir\" && eval \$relink_command); then :
- else
- $rm \"\$progdir/\$file\"
- exit 1
- fi
- fi
-
- $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
- { $rm \"\$progdir/\$program\";
- $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; }
- $rm \"\$progdir/\$file\"
- fi"
- else
- echo >> $output "\
- program='$outputname$exeext'
- progdir=\"\$thisdir/$objdir\"
-"
- fi
-
- echo >> $output "\
-
- if test -f \"\$progdir/\$program\"; then"
-
- # Export our shlibpath_var if we have one.
- if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
- $echo >> $output "\
- # Add our own library path to $shlibpath_var
- $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
-
- # Some systems cannot cope with colon-terminated $shlibpath_var
- # The second colon is a workaround for a bug in BeOS R4 sed
- $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\`
-
- export $shlibpath_var
-"
- fi
-
- # fixup the dll searchpath if we need to.
- if test -n "$dllsearchpath"; then
- $echo >> $output "\
- # Add the dll search path components to the executable PATH
- PATH=$dllsearchpath:\$PATH
-"
- fi
-
- $echo >> $output "\
- if test \"\$libtool_execute_magic\" != \"$magic\"; then
- # Run the actual program with our arguments.
-"
- case $host in
- *-*-cygwin* | *-*-mingw | *-*-os2*)
- # win32 systems need to use the prog path for dll
- # lookup to work
- $echo >> $output "\
- exec \$progdir\\\\\$program \${1+\"\$@\"}
-"
- ;;
- *)
- $echo >> $output "\
- # Export the path to the program.
- PATH=\"\$progdir:\$PATH\"
- export PATH
-
- exec \$program \${1+\"\$@\"}
-"
- ;;
- esac
- $echo >> $output "\
- \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\"
- exit 1
- fi
- else
- # The program doesn't exist.
- \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2
- \$echo \"This script is just a wrapper for \$program.\" 1>&2
- echo \"See the $PACKAGE documentation for more information.\" 1>&2
- exit 1
- fi
-fi\
-"
- chmod +x $output
- fi
- exit 0
- ;;
- esac
-
- # See if we need to build an old-fashioned archive.
- for oldlib in $oldlibs; do
-
- if test "$build_libtool_libs" = convenience; then
- oldobjs="$libobjs_save"
- addlibs="$convenience"
- build_libtool_libs=no
- else
- if test "$build_libtool_libs" = module; then
- oldobjs="$libobjs_save"
- build_libtool_libs=no
- else
- oldobjs="$objs "`$echo "X$libobjs_save" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`
- fi
- addlibs="$old_convenience"
- fi
-
- if test -n "$addlibs"; then
- gentop="$output_objdir/${outputname}x"
- $show "${rm}r $gentop"
- $run ${rm}r "$gentop"
- $show "mkdir $gentop"
- $run mkdir "$gentop"
- status=$?
- if test $status -ne 0 && test ! -d "$gentop"; then
- exit $status
- fi
- generated="$generated $gentop"
-
- # Add in members from convenience archives.
- for xlib in $addlibs; do
- # Extract the objects.
- case "$xlib" in
- [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
- *) xabs=`pwd`"/$xlib" ;;
- esac
- xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
- xdir="$gentop/$xlib"
-
- $show "${rm}r $xdir"
- $run ${rm}r "$xdir"
- $show "mkdir $xdir"
- $run mkdir "$xdir"
- status=$?
- if test $status -ne 0 && test ! -d "$xdir"; then
- exit $status
- fi
- $show "(cd $xdir && $AR x $xabs)"
- $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
-
- oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP`
- done
- fi
-
- # Do each command in the archive commands.
- if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
- eval cmds=\"$old_archive_from_new_cmds\"
- else
- # Ensure that we have .o objects in place incase we decided
- # not to build a shared library, and have fallen back to building
- # static libs even though --disable-static was passed!
- for oldobj in $oldobjs; do
- if test ! -f $oldobj; then
- obj=`$echo "X$oldobj" | $Xsed -e "$o2lo"`
- $show "${LN_S} $obj $oldobj"
- $run ${LN_S} $obj $oldobj || exit $?
- fi
- done
-
- eval cmds=\"$old_archive_cmds\"
- fi
- IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- done
-
- if test -n "$generated"; then
- $show "${rm}r$generated"
- $run ${rm}r$generated
- fi
-
- # Now create the libtool archive.
- case "$output" in
- *.la)
- old_library=
- test "$build_old_libs" = yes && old_library="$libname.$libext"
- $show "creating $output"
-
- if test -n "$xrpath"; then
- temp_xrpath=
- for libdir in $xrpath; do
- temp_xrpath="$temp_xrpath -R$libdir"
- done
- dependency_libs="$temp_xrpath $dependency_libs"
- fi
-
- # Only create the output if not a dry run.
- if test -z "$run"; then
- for installed in no yes; do
- if test "$installed" = yes; then
- if test -z "$install_libdir"; then
- break
- fi
- output="$output_objdir/$outputname"i
- fi
- $rm $output
- $echo > $output "\
-# $outputname - a libtool library file
-# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
-#
-# Please DO NOT delete this file!
-# It is necessary for linking the library.
-
-# The name that we can dlopen(3).
-dlname='$dlname'
-
-# Names of this library.
-library_names='$library_names'
-
-# The name of the static archive.
-old_library='$old_library'
-
-# Libraries that this one depends upon.
-dependency_libs='$dependency_libs'
-
-# Version information for $libname.
-current=$current
-age=$age
-revision=$revision
-
-# Is this an already installed library?
-installed=$installed
-
-# Directory that this library needs to be installed in:
-libdir='$install_libdir'\
-"
- done
- fi
-
- # Do a symbolic link so that the libtool archive can be found in
- # LD_LIBRARY_PATH before the program is installed.
- $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)"
- $run eval "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" || exit $?
- ;;
- esac
- exit 0
- ;;
-
- # libtool install mode
- install)
- modename="$modename: install"
-
- # There may be an optional sh(1) argument at the beginning of
- # install_prog (especially on Windows NT).
- if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh; then
- # Aesthetically quote it.
- arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"`
- case "$arg" in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
- arg="\"$arg\""
- ;;
- esac
- install_prog="$arg "
- arg="$1"
- shift
- else
- install_prog=
- arg="$nonopt"
- fi
-
- # The real first argument should be the name of the installation program.
- # Aesthetically quote it.
- arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
- case "$arg" in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
- arg="\"$arg\""
- ;;
- esac
- install_prog="$install_prog$arg"
-
- # We need to accept at least all the BSD install flags.
- dest=
- files=
- opts=
- prev=
- install_type=
- isdir=no
- stripme=
- for arg
- do
- if test -n "$dest"; then
- files="$files $dest"
- dest="$arg"
- continue
- fi
-
- case "$arg" in
- -d) isdir=yes ;;
- -f) prev="-f" ;;
- -g) prev="-g" ;;
- -m) prev="-m" ;;
- -o) prev="-o" ;;
- -s)
- stripme=" -s"
- continue
- ;;
- -*) ;;
-
- *)
- # If the previous option needed an argument, then skip it.
- if test -n "$prev"; then
- prev=
- else
- dest="$arg"
- continue
- fi
- ;;
- esac
-
- # Aesthetically quote the argument.
- arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
- case "$arg" in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
- arg="\"$arg\""
- ;;
- esac
- install_prog="$install_prog $arg"
- done
-
- if test -z "$install_prog"; then
- $echo "$modename: you must specify an install program" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- if test -n "$prev"; then
- $echo "$modename: the \`$prev' option requires an argument" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- if test -z "$files"; then
- if test -z "$dest"; then
- $echo "$modename: no file or destination specified" 1>&2
- else
- $echo "$modename: you must specify a destination" 1>&2
- fi
- $echo "$help" 1>&2
- exit 1
- fi
-
- # Strip any trailing slash from the destination.
- dest=`$echo "X$dest" | $Xsed -e 's%/$%%'`
-
- # Check to see that the destination is a directory.
- test -d "$dest" && isdir=yes
- if test "$isdir" = yes; then
- destdir="$dest"
- destname=
- else
- destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'`
- test "X$destdir" = "X$dest" && destdir=.
- destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'`
-
- # Not a directory, so check to see that there is only one file specified.
- set dummy $files
- if test $# -gt 2; then
- $echo "$modename: \`$dest' is not a directory" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
- fi
- case "$destdir" in
- [\\/]* | [A-Za-z]:[\\/]*) ;;
- *)
- for file in $files; do
- case "$file" in
- *.lo) ;;
- *)
- $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2
- $echo "$help" 1>&2
- exit 1
- ;;
- esac
- done
- ;;
- esac
-
- # This variable tells wrapper scripts just to set variables rather
- # than running their programs.
- libtool_install_magic="$magic"
-
- staticlibs=
- future_libdirs=
- current_libdirs=
- for file in $files; do
-
- # Do each installation.
- case "$file" in
- *.a | *.lib)
- # Do the static libraries later.
- staticlibs="$staticlibs $file"
- ;;
-
- *.la)
- # Check to see that this really is a libtool archive.
- if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
- else
- $echo "$modename: \`$file' is not a valid libtool archive" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- library_names=
- old_library=
- # If there is no directory component, then add one.
- case "$file" in
- */* | *\\*) . $file ;;
- *) . ./$file ;;
- esac
-
- # Add the libdir to current_libdirs if it is the destination.
- if test "X$destdir" = "X$libdir"; then
- case "$current_libdirs " in
- *" $libdir "*) ;;
- *) current_libdirs="$current_libdirs $libdir" ;;
- esac
- else
- # Note the libdir as a future libdir.
- case "$future_libdirs " in
- *" $libdir "*) ;;
- *) future_libdirs="$future_libdirs $libdir" ;;
- esac
- fi
-
- dir="`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/"
- test "X$dir" = "X$file/" && dir=
- dir="$dir$objdir"
-
- # See the names of the shared library.
- set dummy $library_names
- if test -n "$2"; then
- realname="$2"
- shift
- shift
-
- # Install the shared library and build the symlinks.
- $show "$install_prog $dir/$realname $destdir/$realname"
- $run eval "$install_prog $dir/$realname $destdir/$realname" || exit $?
-
- if test $# -gt 0; then
- # Delete the old symlinks, and create new ones.
- for linkname
- do
- if test "$linkname" != "$realname"; then
- $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
- $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
- fi
- done
- fi
-
- # Do each command in the postinstall commands.
- lib="$destdir/$realname"
- eval cmds=\"$postinstall_cmds\"
- IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- fi
-
- # Install the pseudo-library for information purposes.
- name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
- instname="$dir/$name"i
- $show "$install_prog $instname $destdir/$name"
- $run eval "$install_prog $instname $destdir/$name" || exit $?
-
- # Maybe install the static library, too.
- test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
- ;;
-
- *.lo)
- # Install (i.e. copy) a libtool object.
-
- # Figure out destination file name, if it wasn't already specified.
- if test -n "$destname"; then
- destfile="$destdir/$destname"
- else
- destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
- destfile="$destdir/$destfile"
- fi
-
- # Deduce the name of the destination old-style object file.
- case "$destfile" in
- *.lo)
- staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"`
- ;;
- *.o | *.obj)
- staticdest="$destfile"
- destfile=
- ;;
- *)
- $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2
- $echo "$help" 1>&2
- exit 1
- ;;
- esac
-
- # Install the libtool object if requested.
- if test -n "$destfile"; then
- $show "$install_prog $file $destfile"
- $run eval "$install_prog $file $destfile" || exit $?
- fi
-
- # Install the old object if enabled.
- if test "$build_old_libs" = yes; then
- # Deduce the name of the old-style object file.
- staticobj=`$echo "X$file" | $Xsed -e "$lo2o"`
-
- $show "$install_prog $staticobj $staticdest"
- $run eval "$install_prog \$staticobj \$staticdest" || exit $?
- fi
- exit 0
- ;;
-
- *)
- # Figure out destination file name, if it wasn't already specified.
- if test -n "$destname"; then
- destfile="$destdir/$destname"
- else
- destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
- destfile="$destdir/$destfile"
- fi
-
- # Do a test to see if this is really a libtool program.
- if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
- link_against_libtool_libs=
- relink_command=
-
- # If there is no directory component, then add one.
- case "$file" in
- */* | *\\*) . $file ;;
- *) . ./$file ;;
- esac
-
- # Check the variables that should have been set.
- if test -z "$link_against_libtool_libs"; then
- $echo "$modename: invalid libtool wrapper script \`$file'" 1>&2
- exit 1
- fi
-
- finalize=yes
- for lib in $link_against_libtool_libs; do
- # Check to see that each library is installed.
- libdir=
- if test -f "$lib"; then
- # If there is no directory component, then add one.
- case "$lib" in
- */* | *\\*) . $lib ;;
- *) . ./$lib ;;
- esac
- fi
- libfile="$libdir/`$echo "X$lib" | $Xsed -e 's%^.*/%%g'`"
- if test -n "$libdir" && test ! -f "$libfile"; then
- $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2
- finalize=no
- fi
- done
-
- outputname=
- if test "$fast_install" = no && test -n "$relink_command"; then
- if test "$finalize" = yes && test -z "$run"; then
- tmpdir="/tmp"
- test -n "$TMPDIR" && tmpdir="$TMPDIR"
- tmpdir="$tmpdir/libtool-$$"
- if $mkdir -p "$tmpdir" && chmod 700 "$tmpdir"; then :
- else
- $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2
- continue
- fi
- outputname="$tmpdir/$file"
- # Replace the output file specification.
- relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'`
-
- $show "$relink_command"
- if $run eval "$relink_command"; then :
- else
- $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
- ${rm}r "$tmpdir"
- continue
- fi
- file="$outputname"
- else
- $echo "$modename: warning: cannot relink \`$file'" 1>&2
- fi
- else
- # Install the binary that we compiled earlier.
- file=`$echo "X$file" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"`
- fi
- fi
-
- $show "$install_prog$stripme $file $destfile"
- $run eval "$install_prog\$stripme \$file \$destfile" || exit $?
- test -n "$outputname" && ${rm}r "$tmpdir"
- ;;
- esac
- done
-
- for file in $staticlibs; do
- name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
-
- # Set up the ranlib parameters.
- oldlib="$destdir/$name"
-
- $show "$install_prog $file $oldlib"
- $run eval "$install_prog \$file \$oldlib" || exit $?
-
- # Do each command in the postinstall commands.
- eval cmds=\"$old_postinstall_cmds\"
- IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- done
-
- if test -n "$future_libdirs"; then
- $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2
- fi
-
- if test -n "$current_libdirs"; then
- # Maybe just do a dry run.
- test -n "$run" && current_libdirs=" -n$current_libdirs"
- exec $SHELL $0 --finish$current_libdirs
- exit 1
- fi
-
- exit 0
- ;;
-
- # libtool finish mode
- finish)
- modename="$modename: finish"
- libdirs="$nonopt"
- admincmds=
-
- if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
- for dir
- do
- libdirs="$libdirs $dir"
- done
-
- for libdir in $libdirs; do
- if test -n "$finish_cmds"; then
- # Do each command in the finish commands.
- eval cmds=\"$finish_cmds\"
- IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || admincmds="$admincmds
- $cmd"
- done
- IFS="$save_ifs"
- fi
- if test -n "$finish_eval"; then
- # Do the single finish_eval.
- eval cmds=\"$finish_eval\"
- $run eval "$cmds" || admincmds="$admincmds
- $cmds"
- fi
- done
- fi
-
- # Exit here if they wanted silent mode.
- test "$show" = : && exit 0
-
- echo "----------------------------------------------------------------------"
- echo "Libraries have been installed in:"
- for libdir in $libdirs; do
- echo " $libdir"
- done
- echo
- echo "If you ever happen to want to link against installed libraries"
- echo "in a given directory, LIBDIR, you must either use libtool, and"
- echo "specify the full pathname of the library, or use \`-LLIBDIR'"
- echo "flag during linking and do at least one of the following:"
- if test -n "$shlibpath_var"; then
- echo " - add LIBDIR to the \`$shlibpath_var' environment variable"
- echo " during execution"
- fi
- if test -n "$runpath_var"; then
- echo " - add LIBDIR to the \`$runpath_var' environment variable"
- echo " during linking"
- fi
- if test -n "$hardcode_libdir_flag_spec"; then
- libdir=LIBDIR
- eval flag=\"$hardcode_libdir_flag_spec\"
-
- echo " - use the \`$flag' linker flag"
- fi
- if test -n "$admincmds"; then
- echo " - have your system administrator run these commands:$admincmds"
- fi
- if test -f /etc/ld.so.conf; then
- echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
- fi
- echo
- echo "See any operating system documentation about shared libraries for"
- echo "more information, such as the ld(1) and ld.so(8) manual pages."
- echo "----------------------------------------------------------------------"
- exit 0
- ;;
-
- # libtool execute mode
- execute)
- modename="$modename: execute"
-
- # The first argument is the command name.
- cmd="$nonopt"
- if test -z "$cmd"; then
- $echo "$modename: you must specify a COMMAND" 1>&2
- $echo "$help"
- exit 1
- fi
-
- # Handle -dlopen flags immediately.
- for file in $execute_dlfiles; do
- if test ! -f "$file"; then
- $echo "$modename: \`$file' is not a file" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- dir=
- case "$file" in
- *.la)
- # Check to see that this really is a libtool archive.
- if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
- else
- $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- # Read the libtool library.
- dlname=
- library_names=
-
- # If there is no directory component, then add one.
- case "$file" in
- */* | *\\*) . $file ;;
- *) . ./$file ;;
- esac
-
- # Skip this library if it cannot be dlopened.
- if test -z "$dlname"; then
- # Warn if it was a shared library.
- test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'"
- continue
- fi
-
- dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
- test "X$dir" = "X$file" && dir=.
-
- if test -f "$dir/$objdir/$dlname"; then
- dir="$dir/$objdir"
- else
- $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2
- exit 1
- fi
- ;;
-
- *.lo)
- # Just add the directory containing the .lo file.
- dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
- test "X$dir" = "X$file" && dir=.
- ;;
-
- *)
- $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2
- continue
- ;;
- esac
-
- # Get the absolute pathname.
- absdir=`cd "$dir" && pwd`
- test -n "$absdir" && dir="$absdir"
-
- # Now add the directory to shlibpath_var.
- if eval "test -z \"\$$shlibpath_var\""; then
- eval "$shlibpath_var=\"\$dir\""
- else
- eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
- fi
- done
-
- # This variable tells wrapper scripts just to set shlibpath_var
- # rather than running their programs.
- libtool_execute_magic="$magic"
-
- # Check if any of the arguments is a wrapper script.
- args=
- for file
- do
- case "$file" in
- -*) ;;
- *)
- # Do a test to see if this is really a libtool program.
- if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
- # If there is no directory component, then add one.
- case "$file" in
- */* | *\\*) . $file ;;
- *) . ./$file ;;
- esac
-
- # Transform arg to wrapped name.
- file="$progdir/$program"
- fi
- ;;
- esac
- # Quote arguments (to preserve shell metacharacters).
- file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"`
- args="$args \"$file\""
- done
-
- if test -z "$run"; then
- # Export the shlibpath_var.
- eval "export $shlibpath_var"
-
- # Restore saved enviroment variables
- if test "${save_LC_ALL+set}" = set; then
- LC_ALL="$save_LC_ALL"; export LC_ALL
- fi
- if test "${save_LANG+set}" = set; then
- LANG="$save_LANG"; export LANG
- fi
-
- # Now actually exec the command.
- eval "exec \$cmd$args"
-
- $echo "$modename: cannot exec \$cmd$args"
- exit 1
- else
- # Display what would be done.
- eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\""
- $echo "export $shlibpath_var"
- $echo "$cmd$args"
- exit 0
- fi
- ;;
-
- # libtool uninstall mode
- uninstall)
- modename="$modename: uninstall"
- rm="$nonopt"
- files=
-
- for arg
- do
- case "$arg" in
- -*) rm="$rm $arg" ;;
- *) files="$files $arg" ;;
- esac
- done
-
- if test -z "$rm"; then
- $echo "$modename: you must specify an RM program" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- for file in $files; do
- dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
- test "X$dir" = "X$file" && dir=.
- name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
-
- rmfiles="$file"
-
- case "$name" in
- *.la)
- # Possibly a libtool archive, so verify it.
- if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
- . $dir/$name
-
- # Delete the libtool libraries and symlinks.
- for n in $library_names; do
- rmfiles="$rmfiles $dir/$n"
- done
- test -n "$old_library" && rmfiles="$rmfiles $dir/$old_library"
-
- $show "$rm $rmfiles"
- $run $rm $rmfiles
-
- if test -n "$library_names"; then
- # Do each command in the postuninstall commands.
- eval cmds=\"$postuninstall_cmds\"
- IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd"
- done
- IFS="$save_ifs"
- fi
-
- if test -n "$old_library"; then
- # Do each command in the old_postuninstall commands.
- eval cmds=\"$old_postuninstall_cmds\"
- IFS="${IFS= }"; save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd"
- done
- IFS="$save_ifs"
- fi
-
- # FIXME: should reinstall the best remaining shared library.
- fi
- ;;
-
- *.lo)
- if test "$build_old_libs" = yes; then
- oldobj=`$echo "X$name" | $Xsed -e "$lo2o"`
- rmfiles="$rmfiles $dir/$oldobj"
- fi
- $show "$rm $rmfiles"
- $run $rm $rmfiles
- ;;
-
- *)
- $show "$rm $rmfiles"
- $run $rm $rmfiles
- ;;
- esac
- done
- exit 0
- ;;
-
- "")
- $echo "$modename: you must specify a MODE" 1>&2
- $echo "$generic_help" 1>&2
- exit 1
- ;;
- esac
-
- $echo "$modename: invalid operation mode \`$mode'" 1>&2
- $echo "$generic_help" 1>&2
- exit 1
-fi # test -z "$show_help"
-
-# We need to display help for each of the modes.
-case "$mode" in
-"") $echo \
-"Usage: $modename [OPTION]... [MODE-ARG]...
-
-Provide generalized library-building support services.
-
- --config show all configuration variables
- --debug enable verbose shell tracing
--n, --dry-run display commands without modifying any files
- --features display basic configuration information and exit
- --finish same as \`--mode=finish'
- --help display this help message and exit
- --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS]
- --quiet same as \`--silent'
- --silent don't print informational messages
- --version print version information
-
-MODE must be one of the following:
-
- compile compile a source file into a libtool object
- execute automatically set library path, then run a program
- finish complete the installation of libtool libraries
- install install libraries or executables
- link create a library or an executable
- uninstall remove libraries from an installed directory
-
-MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for
-a more detailed description of MODE."
- exit 0
- ;;
-
-compile)
- $echo \
-"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
-
-Compile a source file into a libtool library object.
-
-This mode accepts the following additional options:
-
- -o OUTPUT-FILE set the output file name to OUTPUT-FILE
- -static always build a \`.o' file suitable for static linking
-
-COMPILE-COMMAND is a command to be used in creating a \`standard' object file
-from the given SOURCEFILE.
-
-The output file name is determined by removing the directory component from
-SOURCEFILE, then substituting the C source code suffix \`.c' with the
-library object suffix, \`.lo'."
- ;;
-
-execute)
- $echo \
-"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]...
-
-Automatically set library path, then run a program.
-
-This mode accepts the following additional options:
-
- -dlopen FILE add the directory containing FILE to the library path
-
-This mode sets the library path environment variable according to \`-dlopen'
-flags.
-
-If any of the ARGS are libtool executable wrappers, then they are translated
-into their corresponding uninstalled binary, and any of their required library
-directories are added to the library path.
-
-Then, COMMAND is executed, with ARGS as arguments."
- ;;
-
-finish)
- $echo \
-"Usage: $modename [OPTION]... --mode=finish [LIBDIR]...
-
-Complete the installation of libtool libraries.
-
-Each LIBDIR is a directory that contains libtool libraries.
-
-The commands that this mode executes may require superuser privileges. Use
-the \`--dry-run' option if you just want to see what would be executed."
- ;;
-
-install)
- $echo \
-"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND...
-
-Install executables or libraries.
-
-INSTALL-COMMAND is the installation command. The first component should be
-either the \`install' or \`cp' program.
-
-The rest of the components are interpreted as arguments to that command (only
-BSD-compatible install options are recognized)."
- ;;
-
-link)
- $echo \
-"Usage: $modename [OPTION]... --mode=link LINK-COMMAND...
-
-Link object files or libraries together to form another library, or to
-create an executable program.
-
-LINK-COMMAND is a command using the C compiler that you would use to create
-a program from several object files.
-
-The following components of LINK-COMMAND are treated specially:
-
- -all-static do not do any dynamic linking at all
- -avoid-version do not add a version suffix if possible
- -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime
- -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols
- -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
- -export-symbols SYMFILE
- try to export only the symbols listed in SYMFILE
- -export-symbols-regex REGEX
- try to export only the symbols matching REGEX
- -LLIBDIR search LIBDIR for required installed libraries
- -lNAME OUTPUT-FILE requires the installed library libNAME
- -module build a library that can dlopened
- -no-undefined declare that a library does not refer to external symbols
- -o OUTPUT-FILE create OUTPUT-FILE from the specified objects
- -release RELEASE specify package release information
- -rpath LIBDIR the created library will eventually be installed in LIBDIR
- -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries
- -static do not do any dynamic linking of libtool libraries
- -version-info CURRENT[:REVISION[:AGE]]
- specify library version info [each variable defaults to 0]
-
-All other options (arguments beginning with \`-') are ignored.
-
-Every other argument is treated as a filename. Files ending in \`.la' are
-treated as uninstalled libtool libraries, other files are standard or library
-object files.
-
-If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
-only library objects (\`.lo' files) may be specified, and \`-rpath' is
-required, except when creating a convenience library.
-
-If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
-using \`ar' and \`ranlib', or on Windows using \`lib'.
-
-If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
-is created, otherwise an executable program is created."
- ;;
-
-uninstall)
- $echo \
-"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
-
-Remove libraries from an installation directory.
-
-RM is the name of the program to use to delete files associated with each FILE
-(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
-to RM.
-
-If FILE is a libtool library, all the files associated with it are deleted.
-Otherwise, only FILE itself is deleted using RM."
- ;;
-
-*)
- $echo "$modename: invalid operation mode \`$mode'" 1>&2
- $echo "$help" 1>&2
- exit 1
- ;;
-esac
-
-echo
-$echo "Try \`$modename --help' for more information about other modes."
-
-exit 0
-
-# Local Variables:
-# mode:shell-script
-# sh-indentation:2
-# End:
+++ /dev/null
-#! /bin/sh
-# Common stub for a few missing GNU programs while installing.
-# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
-# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-# 02111-1307, USA.
-
-if test $# -eq 0; then
- echo 1>&2 "Try \`$0 --help' for more information"
- exit 1
-fi
-
-case "$1" in
-
- -h|--h|--he|--hel|--help)
- echo "\
-$0 [OPTION]... PROGRAM [ARGUMENT]...
-
-Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
-error status if there is no known handling for PROGRAM.
-
-Options:
- -h, --help display this help and exit
- -v, --version output version information and exit
-
-Supported PROGRAM values:
- aclocal touch file \`aclocal.m4'
- autoconf touch file \`configure'
- autoheader touch file \`config.h.in'
- automake touch all \`Makefile.in' files
- bison create \`y.tab.[ch]', if possible, from existing .[ch]
- flex create \`lex.yy.c', if possible, from existing .c
- lex create \`lex.yy.c', if possible, from existing .c
- makeinfo touch the output file
- yacc create \`y.tab.[ch]', if possible, from existing .[ch]"
- ;;
-
- -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
- echo "missing - GNU libit 0.0"
- ;;
-
- -*)
- echo 1>&2 "$0: Unknown \`$1' option"
- echo 1>&2 "Try \`$0 --help' for more information"
- exit 1
- ;;
-
- aclocal)
- echo 1>&2 "\
-WARNING: \`$1' is missing on your system. You should only need it if
- you modified \`acinclude.m4' or \`configure.in'. You might want
- to install the \`Automake' and \`Perl' packages. Grab them from
- any GNU archive site."
- touch aclocal.m4
- ;;
-
- autoconf)
- echo 1>&2 "\
-WARNING: \`$1' is missing on your system. You should only need it if
- you modified \`configure.in'. You might want to install the
- \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
- archive site."
- touch configure
- ;;
-
- autoheader)
- echo 1>&2 "\
-WARNING: \`$1' is missing on your system. You should only need it if
- you modified \`acconfig.h' or \`configure.in'. You might want
- to install the \`Autoconf' and \`GNU m4' packages. Grab them
- from any GNU archive site."
- files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' configure.in`
- test -z "$files" && files="config.h"
- touch_files=
- for f in $files; do
- case "$f" in
- *:*) touch_files="$touch_files "`echo "$f" |
- sed -e 's/^[^:]*://' -e 's/:.*//'`;;
- *) touch_files="$touch_files $f.in";;
- esac
- done
- touch $touch_files
- ;;
-
- automake)
- echo 1>&2 "\
-WARNING: \`$1' is missing on your system. You should only need it if
- you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'.
- You might want to install the \`Automake' and \`Perl' packages.
- Grab them from any GNU archive site."
- find . -type f -name Makefile.am -print |
- sed 's/\.am$/.in/' |
- while read f; do touch "$f"; done
- ;;
-
- bison|yacc)
- echo 1>&2 "\
-WARNING: \`$1' is missing on your system. You should only need it if
- you modified a \`.y' file. You may need the \`Bison' package
- in order for those modifications to take effect. You can get
- \`Bison' from any GNU archive site."
- rm -f y.tab.c y.tab.h
- if [ $# -ne 1 ]; then
- eval LASTARG="\${$#}"
- case "$LASTARG" in
- *.y)
- SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
- if [ -f "$SRCFILE" ]; then
- cp "$SRCFILE" y.tab.c
- fi
- SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
- if [ -f "$SRCFILE" ]; then
- cp "$SRCFILE" y.tab.h
- fi
- ;;
- esac
- fi
- if [ ! -f y.tab.h ]; then
- echo >y.tab.h
- fi
- if [ ! -f y.tab.c ]; then
- echo 'main() { return 0; }' >y.tab.c
- fi
- ;;
-
- lex|flex)
- echo 1>&2 "\
-WARNING: \`$1' is missing on your system. You should only need it if
- you modified a \`.l' file. You may need the \`Flex' package
- in order for those modifications to take effect. You can get
- \`Flex' from any GNU archive site."
- rm -f lex.yy.c
- if [ $# -ne 1 ]; then
- eval LASTARG="\${$#}"
- case "$LASTARG" in
- *.l)
- SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
- if [ -f "$SRCFILE" ]; then
- cp "$SRCFILE" lex.yy.c
- fi
- ;;
- esac
- fi
- if [ ! -f lex.yy.c ]; then
- echo 'main() { return 0; }' >lex.yy.c
- fi
- ;;
-
- makeinfo)
- echo 1>&2 "\
-WARNING: \`$1' is missing on your system. You should only need it if
- you modified a \`.texi' or \`.texinfo' file, or any other file
- indirectly affecting the aspect of the manual. The spurious
- call might also be the consequence of using a buggy \`make' (AIX,
- DU, IRIX). You might want to install the \`Texinfo' package or
- the \`GNU make' package. Grab either from any GNU archive site."
- file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
- if test -z "$file"; then
- file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
- file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
- fi
- touch $file
- ;;
-
- *)
- echo 1>&2 "\
-WARNING: \`$1' is needed, and you do not seem to have it handy on your
- system. You might have modified some files without having the
- proper tools for further handling them. Check the \`README' file,
- it often tells you about the needed prerequirements for installing
- this package. You may also peek at any GNU archive site, in case
- some other package would contain this missing \`$1' program."
- exit 1
- ;;
-esac
-
-exit 0
+++ /dev/null
-#! /bin/sh
-# mkinstalldirs --- make directory hierarchy
-# Author: Noah Friedman <friedman@prep.ai.mit.edu>
-# Created: 1993-05-16
-# Public domain
-
-# $Id$
-
-errstatus=0
-
-for file
-do
- set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
- shift
-
- pathcomp=
- for d
- do
- pathcomp="$pathcomp$d"
- case "$pathcomp" in
- -* ) pathcomp=./$pathcomp ;;
- esac
-
- if test ! -d "$pathcomp"; then
- echo "mkdir $pathcomp"
-
- mkdir "$pathcomp" || lasterr=$?
-
- if test ! -d "$pathcomp"; then
- errstatus=$lasterr
- fi
- fi
-
- pathcomp="$pathcomp/"
- done
-done
-
-exit $errstatus
-
-# mkinstalldirs ends here
--- /dev/null
+dnl RRDtool AutoConf script ...
+dnl ---------------------------
+dnl
+dnl Created by Jeff Allen, Tobi Oetiker, Blair Zajac
+dnl
+dnl
+
+dnl tell automake the this script is for rrdtool
+AC_INIT(src/rrd_tool.c)
+AC_CONFIG_AUX_DIR(config)
+AC_CANONICAL_TARGET([])
+AM_INIT_AUTOMAKE(rrdtool, 1.1.0)
+AM_CONFIG_HEADER(config/config.h)
+
+dnl all our local stuff like install scripts and include files
+dnl is in there
+
+
+dnl determine the type of system we are running on
+
+
+AC_SUBST(VERSION)
+
+dnl where we install our stuff ...
+AC_PREFIX_DEFAULT( /usr/local/rrdtool-1.1.0 )
+
+dnl Minimum Autoconf version required.
+AC_PREREQ(2.52)
+
+dnl At the TOP of the HEADER
+
+AH_TOP([
+
+#ifndef CONFIG_H
+#define CONFIG_H
+/* IEEE can be prevented from raising signals with fpsetmask(0) */
+#undef MUST_DISABLE_FPMASK
+
+/* IEEE math only works if SIGFPE gets actively set to IGNORE */
+
+#undef MUST_DISABLE_SIGFPE
+
+/* realloc does not support NULL as argument */
+#undef NO_NULL_REALLOC
+ ])
+
+AH_BOTTOM([
+
+/* define strrchr, strchr and memcpy, memmove in terms of bsd funcs
+ make sure you are NOT using bcopy, index or rindex in the code */
+
+#if STDC_HEADERS
+# include <string.h>
+#else
+# ifndef HAVE_STRCHR
+# define strchr index
+# define strrchr rindex
+# endif
+char *strchr (), *strrchr ();
+# ifndef HAVE_MEMMOVE
+# define memcpy(d, s, n) bcopy ((s), (d), (n))
+# define memmove(d, s, n) bcopy ((s), (d), (n))
+# endif
+#endif
+
+
+#if NO_NULL_REALLOC
+# define rrd_realloc(a,b) ( (a) == NULL ? malloc( (b) ) : realloc( (a) , (b) ))
+#else
+# define rrd_realloc(a,b) realloc((a), (b))
+#endif
+
+#if HAVE_MATH_H
+# include <math.h>
+#endif
+
+#if HAVE_FLOAT_H
+# include <float.h>
+#endif
+
+#if HAVE_IEEEFP_H
+# include <ieeefp.h>
+#endif
+
+#if HAVE_FP_CLASS_H
+# include <fp_class.h>
+#endif
+
+/* for Solaris */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASS))
+# define HAVE_ISINF 1
+# define isinf(a) (fpclass(a) == FP_NINF || fpclass(a) == FP_PINF)
+#endif
+
+/* for OSF1 Digital Unix */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FP_CLASS) && defined(HAVE_FP_CLASS_H))
+# define HAVE_ISINF 1
+# define isinf(a) (fp_class(a) == FP_NEG_INF || fp_class(a) == FP_POS_INF)
+#endif
+
+#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY) && defined(FP_PLUS_INF) && defined(FP_MINUS_INF))
+# define HAVE_ISINF 1
+# define isinf(a) (fpclassify(a) == FP_MINUS_INF || fpclassify(a) == FP_PLUS_INF)
+#endif
+
+#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY) && defined(FP_INFINITE))
+# define HAVE_ISINF 1
+# define isinf(a) (fpclassify(a) == FP_INFINITE)
+#endif
+
+/* for AIX */
+#if (! defined(HAVE_ISINF) && defined(HAVE_CLASS))
+# define HAVE_ISINF 1
+# define isinf(a) (class(a) == FP_MINUS_INF || class(a) == FP_PLUS_INF)
+#endif
+
+#if (! defined (HAVE_FINITE) && defined (HAVE_ISFINITE))
+# define HAVE_FINITE 1
+# define finite(a) isfinite(a)
+#endif
+
+#if (! defined(HAVE_FINITE) && defined(HAVE_ISNAN) && defined(HAVE_ISINF))
+# define HAVE_FINITE 1
+# define finite(a) (! isnan(a) && ! isinf(a))
+#endif
+
+#ifndef HAVE_FINITE
+#error "Can't compile without finite function"
+#endif
+
+#ifndef HAVE_ISINF
+#error "Can't compile without isinf function"
+#endif
+
+#endif /* CONFIG_H */
+])
+
+
+dnl Define library subdirectory names here.
+CGI_LIB_DIR=libraries/cgilib-0.4
+FREETYPE_LIB_DIR=libraries/freetype-2.0.5
+ART_LIB_DIR=libraries/libart_lgpl-2.3.7
+PNG_LIB_DIR=libraries/libpng-1.2.0
+ZLIB_LIB_DIR=libraries/zlib-1.1.3
+
+dnl substitute them in all the files listed in AC_OUTPUT
+AC_SUBST(CGI_LIB_DIR)
+AC_SUBST(ART_LIB_DIR)
+AC_SUBST(PNG_LIB_DIR)
+AC_SUBST(FREETYPE_LIB_DIR)
+AC_SUBST(ZLIB_LIB_DIR)
+AC_SUBST(PERLFLAGS)
+
+dnl Check for Perl.
+AC_PATH_PROG(PERL, perl, no)
+if test "x$PERL" = "xno"; then
+ COMP_PERL=
+else
+ COMP_PERL="perl_piped perl_shared"
+ AC_MSG_CHECKING(for shared library extension)
+ SO_EXT=`$PERL -e 'use Config; if (defined $Config{so} and $Config{so} ne 'a') {print "$Config{so}\n"} else {print "so\n"};'`
+ AC_MSG_RESULT($SO_EXT)
+ AC_MSG_CHECKING(for the C compiler perl wants to use to build its modules)
+ PROBLEMCC=`$PERL -e 'use Config; map {if (-x "$_/$Config{cc}"){exit 0}} split /:/, $ENV{PATH};print $Config{cc}'`
+ if test x$PROBLEMCC != x; then
+ AC_MSG_RESULT(no)
+ echo Could not find the Compiler: '"'$PROBLEMCC'"'
+ echo which has been used to build perl. You may have to compile
+ echo your own copy of perl to make this work. Binary perls often
+ echo exhibit this problem
+ exit 1
+ else
+ AC_MSG_RESULT(found)
+ fi
+fi
+AC_SUBST(COMP_PERL)
+AC_SUBST(SO_EXT)
+
+dnl Check for Tcl.
+withval=""
+AC_ARG_WITH(tcllib,[ --with-tcllib=DIR location of the tclConfig.sh])
+found=0
+AC_MSG_CHECKING(for tclConfig.sh in $withval)
+if test -f "$withval/tclConfig.sh" ; then
+ tcl_config=$withval/tclConfig.sh
+ found=1
+ AC_MSG_RESULT(yes)
+ break
+else
+ AC_MSG_RESULT(no)
+fi
+
+if test $found -eq 0 ; then
+ AC_MSG_WARN([tclConfig.sh not found - Tcl interface won't be built])
+else
+ . $tcl_config
+fi
+
+dnl Pass additional perl options when generating Makefile from Makefile.PL
+# Options to pass when configuring perl module
+AC_ARG_WITH(perl-options,
+[ --with-perl-options=[OPTIONS] options to pass on command-line when
+ generating Makefile from Makefile.PL],
+[PERL_MAKE_OPTIONS=$withval])
+AC_SUBST(PERL_MAKE_OPTIONS)
+
+AM_CONDITIONAL(COMP_TCL, test x$found = x1 )
+
+AC_SUBST(TCL_PREFIX)
+AC_SUBST(TCL_SHLIB_CFLAGS)
+AC_SUBST(TCL_SHLIB_LD)
+AC_SUBST(TCL_SHLIB_SUFFIX)
+AC_SUBST(TCL_PACKAGE_PATH)
+AC_SUBST(TCL_LD_SEARCH_FLAGS)
+
+dnl Check for the compiler and static/shared library creation.
+AC_PROG_CC
+AC_PROG_CPP
+
+dnl don't build a shared library ...
+dnl this can be changed when running configure
+AC_DISABLE_SHARED
+AC_PROG_LIBTOOL
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h fp_class.h malloc.h unistd.h ieeefp.h math.h sys/time.h sys/times.h sys/param.h sys/resource.h float.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_HEADER_TIME
+AC_STRUCT_TM
+
+dnl Checks for libraries.
+AC_CHECK_FUNC(acos, , AC_CHECK_LIB(m, acos))
+
+dnl Check for nroff
+AC_PATH_PROGS(NROFF, gnroff nroff)
+AC_PATH_PROGS(TROFF, groff troff)
+
+dnl Does the compiler like -Wall and -pedantic?
+if test "x$GCC" = "xyes"; then
+ oCFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS -Wall -pedantic -Wshadow -Wpointer-arith -Wcast-align -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline"
+ AC_CACHE_CHECK(if we can use GCC-specific compiler options, rd_cv_gcc_opt,
+ [AC_TRY_COMPILE( , return 0 ,
+ rd_cv_gcc_opt=yes,
+ rd_cv_gcc_opt=no )
+ ]
+ )
+ if test $rd_cv_gcc_opt = no; then
+ CFLAGS=$oCFLAGS
+ fi
+fi
+
+dnl add pic flag in any case this makes sure all our code is relocatable
+CFLAGS="$CFLAGS "`grep pic_flag= libtool | sed -e 's/.*pic_flag=//' -e 's/"//g'`
+
+ZLIB_CFLAGS=$CFLAGS
+dnl it seems that hpux chockes on -fPIC for some reason
+case $target_os in
+*hpux*)
+ ZLIB_CFLAGS=`echo $CFLAGS|sed -e 's/-fPIC/-fpic/g'`
+;;
+esac
+AC_SUBST(ZLIB_CFLAGS)
+
+dnl Checks for library functions.
+AC_FUNC_STRFTIME
+AC_FUNC_VPRINTF
+
+dnl for each function found we get a definition in config.h
+dnl of the form HAVE_FUNCTION
+
+AC_CHECK_FUNCS(strerror snprintf vsnprintf fpclass class fp_class isnan memmove strchr mktime getrusage gettimeofday)
+
+dnl HP-UX 11.00 does not have finite but does have isfinite as a macro
+AC_CHECK_FUNCS(fpclassify, ,
+ [AC_MSG_CHECKING(for fpclassify with <math.h>)
+ AC_TRY_LINK([#include <math.h>], [float f = 0.0; fpclassify(f)],
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_FPCLASSIFY), AC_MSG_RESULT(no))])
+AC_CHECK_FUNCS(finite, ,
+ [AC_CHECK_FUNCS(isfinite, ,
+ [AC_MSG_CHECKING(for isfinite with <math.h>)
+ AC_TRY_LINK([#include <math.h>], [float f = 0.0; isfinite(f)],
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_ISFINITE), AC_MSG_RESULT(no))])])
+AC_CHECK_FUNCS(isinf, ,
+ [AC_MSG_CHECKING(for isinf with <math.h>)
+ AC_TRY_LINK([#include <math.h>], [float f = 0.0; isinf(f)],
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_ISINF), AC_MSG_RESULT(no))])
+
+dnl what does realloc do if it gets called with a NULL pointer
+
+AC_CACHE_CHECK([if realloc can deal with NULL], rd_cv_null_realloc,
+[AC_TRY_RUN([#include <stdlib.h>
+ int main(void){
+ char *x = NULL;
+ x = realloc (x,10);
+ if (x==NULL) return 1;
+ return 0;
+ }],
+ [rd_cv_null_realloc=yes],[rd_cv_null_realloc=nope],:)])
+
+if test x"$rd_cv_null_realloc" = xnope; then
+AC_DEFINE(NO_NULL_REALLOC)
+fi
+
+dnl determine how to get IEEE math working
+dnl AC_IEEE(MESSAGE, set rd_cv_ieee_[var] variable, INCLUDES,
+dnl FUNCTION-BODY, [ACTION-IF-FOUND [,ACTION-IF-NOT-FOUND]])
+
+AC_C_BIGENDIAN
+
+AC_DEFUN(AC_IEEE,
+AC_MSG_CHECKING([if IEEE math works $1])
+AC_CACHE_VAL([rd_cv_ieee_$2],
+[AC_TRY_RUN([$3
+
+#if HAVE_MATH_H
+# include <math.h>
+#endif
+
+#if HAVE_FLOAT_H
+# include <float.h>
+#endif
+
+#if HAVE_IEEEFP_H
+# include <ieeefp.h>
+#endif
+
+#if HAVE_FP_CLASS_H
+# include <fp_class.h>
+#endif
+
+/* Solaris */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASS))
+# define HAVE_ISINF 1
+# define isinf(a) (fpclass(a) == FP_NINF || fpclass(a) == FP_PINF)
+#endif
+
+/* Digital UNIX */
+#if (! defined(HAVE_ISINF) && defined(HAVE_FP_CLASS) && defined(HAVE_FP_CLASS_H))
+# define HAVE_ISINF 1
+# define isinf(a) (fp_class(a) == FP_NEG_INF || fp_class(a) == FP_POS_INF)
+#endif
+
+/* AIX */
+#if (! defined(HAVE_ISINF) && defined(HAVE_CLASS))
+# define HAVE_ISINF 1
+# define isinf(a) (class(a) == FP_MINUS_INF || class(a) == FP_PLUS_INF)
+#endif
+
+#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY) && defined(FP_PLUS_INF) && defined(FP_MINUS_INF))
+# define HAVE_ISINF 1
+# define isinf(a) (fpclassify(a) == FP_MINUS_INF || fpclassify(a) == FP_PLUS_INF)
+#endif
+
+#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY) && defined(FP_INFINITE))
+# define HAVE_ISINF 1
+# define isinf(a) (fpclassify(a) == FP_INFINITE)
+#endif
+
+#include <stdio.h>
+int main(void){
+ double nan,inf,c,zero;
+ $4;
+ /* some math to see if we get a floating point exception */
+ zero=sin(0.0); /* don't let the compiler optimize us away */
+ nan=0.0/zero; /* especially here */
+ inf=1.0/zero; /* and here. I want to know if it can do the magic */
+ /* at run time without sig fpe */
+ c = inf + nan;
+ c = inf / nan;
+ if (! isnan(nan)) {printf ("not isnan(NaN) ... "); return 1;}
+ if (nan == nan) {printf ("nan == nan ... "); return 1;}
+ if (! isinf(inf)) {printf ("not isinf(oo) ... "); return 1;}
+ if (! isinf(-inf)) {printf ("not isinf(-oo) ... "); return 1;}
+ if (! inf > 0) {printf ("not inf > 0 ... "); return 1;}
+ if (! -inf < 0) {printf ("not -inf < 0 ... "); return 1;}
+ return 0;
+ }],
+
+rd_cv_ieee_$2=yes,
+rd_cv_ieee_$2=no,
+:)])
+dnl these we run regardles is cached or not
+if test x${rd_cv_ieee_$2} = "xyes"; then
+ AC_MSG_RESULT(yes)
+ $5
+else
+ AC_MSG_RESULT(no)
+ $6
+fi
+
+)
+
+_cflags=${CFLAGS}
+AC_IEEE([out of the box], works, , , ,
+ [CFLAGS="$_cflags -ieee"
+ AC_IEEE([with the -ieee switch], switch, , , ,
+ [CFLAGS="$_cflags -qfloat=nofold"
+ AC_IEEE([with the -qfloat=nofold switch], nofold, , , ,
+ [CFLAGS="$_cflags -w -qflttrap=enable:zerodivide"
+ AC_IEEE([with the -w -qflttrap=enable:zerodivide], flttrap, , , ,
+ [CFLAGS="$_cflags -mieee"
+ AC_IEEE([with the -mieee switch], mswitch, , , ,
+ [CFLAGS="$_cflags -q float=rndsngl"
+ AC_IEEE([with the -q float=rndsngl switch], qswitch, , , ,
+ [CFLAGS="$_cflags -OPT:IEEE_comparisons=ON"
+ AC_IEEE([with the -OPT:IEEE_comparisons=ON switch], ieeecmpswitch, , , ,
+ [CFLAGS=$_cflags
+ AC_IEEE([with fpsetmask(0)], mask,
+ [#include <floatingpoint.h>], [fpsetmask(0)],
+ [AC_DEFINE(MUST_DISABLE_FPMASK)
+ PERLFLAGS="CCFLAGS=-DMUST_DISABLE_FPMASK"],
+ [AC_IEEE([with signal(SIGFPE,SIG_IGN)], sigfpe,
+ [#include <signal.h>], [signal(SIGFPE,SIG_IGN)],
+ [AC_DEFINE(MUST_DISABLE_SIGFPE)
+ PERLFLAGS="CCFLAGS=-DMUST_DISABLE_SIGFPE"],
+ AC_MSG_ERROR([
+Your Compiler does not do propper IEEE math ... Please find out how to
+make IEEE math work with your compiler and let me know (oetiker@ee.ethz.ch).
+Check config.log to see what went wrong ...
+]))])])])])])])])])
+
+
+AC_CONFIG_FILES([examples/shared-demo.pl \
+ examples/piped-demo.pl \
+ examples/stripes.pl \
+ examples/bigtops.pl \
+ examples/minmax.pl \
+ examples/cgi-demo.cgi \
+ examples/Makefile \
+ doc/Makefile \
+ libraries/Makefile \
+ libraries/cgilib-0.4/Makefile \
+ libraries/libart_lgpl-2.3.7/Makefile \
+ libraries/libpng-1.2.0/Makefile \
+ libraries/zlib-1.1.3/Makefile \
+ libraries/freetype-2.0.5/Makefile \
+ src/Makefile \
+ bindings/Makefile \
+ bindings/tcl/Makefile \
+ Makefile])
+AC_CONFIG_COMMANDS([default],[[\
+ chmod +x examples/*.cgi examples/*.pl]],[[]])
+AC_OUTPUT
+
+AC_MSG_CHECKING(in)
+AC_MSG_RESULT(and out again)
+
+echo $ECHO_N "ordering CD from http://ee-staff.ethz.ch/~oetiker/wish $ECHO_C" 1>&6
+sleep 1
+echo $ECHO_N ".$ECHO_C" 1>&6
+sleep 1
+echo $ECHO_N ".$ECHO_C" 1>&6
+sleep 1
+echo $ECHO_N ".$ECHO_C" 1>&6
+sleep 1
+echo $ECHO_N ".$ECHO_C" 1>&6
+sleep 1
+AC_MSG_RESULT([ just kidding ;-)])
+echo
+echo "----------------------------------------------------------------"
+echo "Config is DONE!"
+echo
+echo "Type 'make' to compile the software and use 'make install' to "
+echo "install everything to: $prefix."
+echo
+echo "If you want to install the perl"
+echo "modules in site-perl, try 'make site-perl-install'."
+echo
+echo " ... that wishlist is NO JOKE. If you find RRDtool useful"
+echo "make me happy. Go to http://ee-staff.ethz.ch/~oetiker/wish and"
+echo "place an order."
+echo
+echo " -- Tobi Oetiker <tobi@oetiker.ch>"
+echo "----------------------------------------------------------------"
+++ /dev/null
-dnl RRDtool AutoConf script ...
-dnl ---------------------------
-dnl
-dnl Created by Jeff Allen, Tobi Oetiker, Blair Zajac
-dnl
-dnl
-
-dnl make sure we are being executed in the right place
-AC_INIT(src/rrd_tool.c)
-
-dnl all our local stuff like install scripts and include files
-dnl is in there
-AC_CONFIG_AUX_DIR(config)
-
-dnl determine the type of system we are running on
-AC_CANONICAL_SYSTEM
-
-dnl tell automake the this script is for rrdtool
-AM_INIT_AUTOMAKE(rrdtool, 1.0.33)
-AC_SUBST(VERSION)
-
-dnl where we install our stuff ...
-AC_PREFIX_DEFAULT( /usr/local/rrdtool-1.0.33 )
-
-dnl tell automake which file to use as config header
-AM_CONFIG_HEADER(config/config.h)
-
-dnl Minimum Autoconf version required.
-AC_PREREQ(2.13)
-
-dnl Define library subdirectory names here.
-CGI_LIB_DIR=libraries/cgilib-0.4
-GD_LIB_DIR=libraries/gd1.3
-PNG_LIB_DIR=libraries/libpng-1.0.9
-ZLIB_LIB_DIR=libraries/zlib-1.1.3
-
-dnl substitute them in all the files listed in AC_OUTPUT
-AC_SUBST(CGI_LIB_DIR)
-AC_SUBST(GD_LIB_DIR)
-AC_SUBST(PNG_LIB_DIR)
-AC_SUBST(ZLIB_LIB_DIR)
-AC_SUBST(PERLFLAGS)
-
-dnl Check for Perl.
-AC_PATH_PROG(PERL, perl, no)
-if test "x$PERL" = "xno"; then
- COMP_PERL=
-else
- COMP_PERL="perl_piped perl_shared"
- AC_MSG_CHECKING(for shared library extension)
- SO_EXT=`$PERL -e 'use Config; if (defined $Config{so} and $Config{so} ne 'a') {print "$Config{so}\n"} else {print "so\n"};'`
- AC_MSG_RESULT($SO_EXT)
- AC_MSG_CHECKING(for the C compiler perl wants to use to build its modules)
- PROBLEMCC=`$PERL -e 'use Config; map {if (-x "$_/$Config{cc}"){exit 0}} split /:/, $ENV{PATH};print $Config{cc}'`
- if test x$PROBLEMCC != x; then
- AC_MSG_RESULT(no)
- echo Could not find the Compiler: '"'$PROBLEMCC'"'
- echo which has been used to build perl. You may have to compile
- echo your own copy of perl to make this work. Binary perls often
- echo exhibit this problem
- exit 1
- else
- AC_MSG_RESULT(found)
- fi
-fi
-AC_SUBST(COMP_PERL)
-AC_SUBST(SO_EXT)
-
-dnl Check for Tcl.
-withval=""
-AC_ARG_WITH(tcllib,[ --with-tcllib=DIR location of the tclConfig.sh])
-found=0
-AC_MSG_CHECKING(for tclConfig.sh in $withval)
-if test -f "$withval/tclConfig.sh" ; then
- tcl_config=$withval/tclConfig.sh
- found=1
- AC_MSG_RESULT(yes)
- break
-else
- AC_MSG_RESULT(no)
-fi
-
-if test $found -eq 0 ; then
- AC_MSG_WARN([tclConfig.sh not found - Tcl interface won't be built])
-else
- . $tcl_config
-fi
-
-dnl Pass additional perl options when generating Makefile from Makefile.PL
-# Options to pass when configuring perl module
-AC_ARG_WITH(perl-options,
-[ --with-perl-options=[OPTIONS] options to pass on command-line when
- generating Makefile from Makefile.PL],
-[PERL_MAKE_OPTIONS=$withval])
-AC_SUBST(PERL_MAKE_OPTIONS)
-
-AM_CONDITIONAL(COMP_TCL, test x$found = x1 )
-
-AC_SUBST(TCL_PREFIX)
-AC_SUBST(TCL_SHLIB_CFLAGS)
-AC_SUBST(TCL_SHLIB_LD)
-AC_SUBST(TCL_SHLIB_SUFFIX)
-AC_SUBST(TCL_PACKAGE_PATH)
-AC_SUBST(TCL_LD_SEARCH_FLAGS)
-
-dnl Check for the compiler and static/shared library creation.
-AC_PROG_CC
-AC_PROG_CPP
-dnl RRD_ACLOCAL_FIND_LIBTOOL
-
-dnl don't build a shared library ...
-dnl this can be changed when running configure
-AC_DISABLE_SHARED
-
-AM_PROG_LIBTOOL
-
-dnl Checks for header files.
-AC_HEADER_STDC
-AC_CHECK_HEADERS(fcntl.h fp_class.h malloc.h unistd.h ieeefp.h math.h sys/time.h sys/times.h sys/param.h sys/resource.h float.h)
-
-dnl Checks for typedefs, structures, and compiler characteristics.
-AC_C_CONST
-AC_HEADER_TIME
-AC_STRUCT_TM
-
-dnl Checks for libraries.
-AC_CHECK_FUNC(acos, , AC_CHECK_LIB(m, acos))
-
-dnl Check for nroff
-AC_PATH_PROGS(NROFF, gnroff nroff)
-AC_PATH_PROGS(TROFF, groff troff)
-
-dnl Does the compiler like -Wall and -pedantic?
-if test "x$GCC" = "xyes"; then
- oCFLAGS=$CFLAGS
- CFLAGS="$CFLAGS -Wall -pedantic -Wshadow -Wpointer-arith -Wcast-align -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline"
- AC_CACHE_CHECK(if we can use GCC-specific compiler options, rd_cv_gcc_opt,
- [AC_TRY_COMPILE( , return 0 ,
- rd_cv_gcc_opt=yes,
- rd_cv_gcc_opt=no )
- ]
- )
- if test $rd_cv_gcc_opt = no; then
- CFLAGS=$oCFLAGS
- fi
-fi
-
-dnl add pic flag in any case this makes sure all our code is relocatable
-CFLAGS="$CFLAGS "`grep pic_flag= libtool | sed -e 's/.*pic_flag=//' -e 's/"//g'`
-
-ZLIB_CFLAGS=$CFLAGS
-dnl it seems that hpux chockes on -fPIC for some reason
-case $target_os in
-*hpux*)
- ZLIB_CFLAGS=`echo $CFLAGS|sed -e 's/-fPIC/-fpic/g'`
-;;
-esac
-AC_SUBST(ZLIB_CFLAGS)
-
-dnl Checks for library functions.
-AC_FUNC_STRFTIME
-AC_FUNC_VPRINTF
-
-dnl for each function found we get a definition in config.h
-dnl of the form HAVE_FUNCTION
-
-AC_CHECK_FUNCS(strerror snprintf vsnprintf fpclass class fp_class isnan memmove strchr mktime getrusage gettimeofday)
-
-dnl HP-UX 11.00 does not have finite but does have isfinite as a macro
-AC_CHECK_FUNCS(fpclassify, ,
- [AC_MSG_CHECKING(for fpclassify with <math.h>)
- AC_TRY_LINK([#include <math.h>], [float f = 0.0; fpclassify(f)],
- AC_MSG_RESULT(yes)
- AC_DEFINE(HAVE_FPCLASSIFY), AC_MSG_RESULT(no))])
-AC_CHECK_FUNCS(finite, ,
- [AC_CHECK_FUNCS(isfinite, ,
- [AC_MSG_CHECKING(for isfinite with <math.h>)
- AC_TRY_LINK([#include <math.h>], [float f = 0.0; isfinite(f)],
- AC_MSG_RESULT(yes)
- AC_DEFINE(HAVE_ISFINITE), AC_MSG_RESULT(no))])])
-AC_CHECK_FUNCS(isinf, ,
- [AC_MSG_CHECKING(for isinf with <math.h>)
- AC_TRY_LINK([#include <math.h>], [float f = 0.0; isinf(f)],
- AC_MSG_RESULT(yes)
- AC_DEFINE(HAVE_ISINF), AC_MSG_RESULT(no))])
-
-dnl what does realloc do if it gets called with a NULL pointer
-
-AC_CACHE_CHECK([if realloc can deal with NULL], rd_cv_null_realloc,
-[AC_TRY_RUN([#include <stdlib.h>
- int main(void){
- char *x = NULL;
- x = realloc (x,10);
- if (x==NULL) return 1;
- return 0;
- }],
- [rd_cv_null_realloc=yes],[rd_cv_null_realloc=nope],:)])
-
-if test x"$rd_cv_null_realloc" = xnope; then
-AC_DEFINE(NO_NULL_REALLOC)
-fi
-
-dnl determine how to get IEEE math working
-dnl AC_IEEE(MESSAGE, set rd_cv_ieee_[var] variable, INCLUDES,
-dnl FUNCTION-BODY, [ACTION-IF-FOUND [,ACTION-IF-NOT-FOUND]])
-
-AC_DEFUN(AC_IEEE,
-AC_MSG_CHECKING([if IEEE math works $1])
-AC_CACHE_VAL([rd_cv_ieee_$2],
-[AC_TRY_RUN([$3
-
-#if HAVE_MATH_H
-# include <math.h>
-#endif
-
-#if HAVE_FLOAT_H
-# include <float.h>
-#endif
-
-#if HAVE_IEEEFP_H
-# include <ieeefp.h>
-#endif
-
-#if HAVE_FP_CLASS_H
-# include <fp_class.h>
-#endif
-
-/* Solaris */
-#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASS))
-# define HAVE_ISINF 1
-# define isinf(a) (fpclass(a) == FP_NINF || fpclass(a) == FP_PINF)
-#endif
-
-/* Digital UNIX */
-#if (! defined(HAVE_ISINF) && defined(HAVE_FP_CLASS) && defined(HAVE_FP_CLASS_H))
-# define HAVE_ISINF 1
-# define isinf(a) (fp_class(a) == FP_NEG_INF || fp_class(a) == FP_POS_INF)
-#endif
-
-/* AIX */
-#if (! defined(HAVE_ISINF) && defined(HAVE_CLASS))
-# define HAVE_ISINF 1
-# define isinf(a) (class(a) == FP_MINUS_INF || class(a) == FP_PLUS_INF)
-#endif
-
-#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY) && defined(FP_PLUS_INF) && defined(FP_MINUS_INF))
-# define HAVE_ISINF 1
-# define isinf(a) (fpclassify(a) == FP_MINUS_INF || fpclassify(a) == FP_PLUS_INF)
-#endif
-
-#if (! defined(HAVE_ISINF) && defined(HAVE_FPCLASSIFY) && defined(FP_INFINITE))
-# define HAVE_ISINF 1
-# define isinf(a) (fpclassify(a) == FP_INFINITE)
-#endif
-
-#include <stdio.h>
-int main(void){
- double nan,inf,c,zero;
- $4;
- /* some math to see if we get a floating point exception */
- zero=sin(0.0); /* don't let the compiler optimize us away */
- nan=0.0/zero; /* especially here */
- inf=1.0/zero; /* and here. I want to know if it can do the magic */
- /* at run time without sig fpe */
- c = inf + nan;
- c = inf / nan;
- if (! isnan(nan)) {printf ("not isnan(NaN) ... "); return 1;}
- if (nan == nan) {printf ("nan == nan ... "); return 1;}
- if (! isinf(inf)) {printf ("not isinf(oo) ... "); return 1;}
- if (! isinf(-inf)) {printf ("not isinf(-oo) ... "); return 1;}
- if (! inf > 0) {printf ("not inf > 0 ... "); return 1;}
- if (! -inf < 0) {printf ("not -inf < 0 ... "); return 1;}
- return 0;
- }],
-
-rd_cv_ieee_$2=yes,
-rd_cv_ieee_$2=no,
-:)])
-dnl these we run regardles is cached or not
-if test x${rd_cv_ieee_$2} = "xyes"; then
- AC_MSG_RESULT(yes)
- $5
-else
- AC_MSG_RESULT(no)
- $6
-fi
-
-)
-
-_cflags=${CFLAGS}
-AC_IEEE([out of the box], works, , , ,
- [CFLAGS="$_cflags -ieee"
- AC_IEEE([with the -ieee switch], switch, , , ,
- [CFLAGS="$_cflags -qfloat=nofold"
- AC_IEEE([with the -qfloat=nofold switch], nofold, , , ,
- [CFLAGS="$_cflags -w -qflttrap=enable:zerodivide"
- AC_IEEE([with the -w -qflttrap=enable:zerodivide], flttrap, , , ,
- [CFLAGS="$_cflags -mieee"
- AC_IEEE([with the -mieee switch], mswitch, , , ,
- [CFLAGS="$_cflags -q float=rndsngl"
- AC_IEEE([with the -q float=rndsngl switch], qswitch, , , ,
- [CFLAGS="$_cflags -OPT:IEEE_comparisons=ON"
- AC_IEEE([with the -OPT:IEEE_comparisons=ON switch], ieeecmpswitch, , , ,
- [CFLAGS=$_cflags
- AC_IEEE([with fpsetmask(0)], mask,
- [#include <floatingpoint.h>], [fpsetmask(0)],
- [AC_DEFINE(MUST_DISABLE_FPMASK)
- PERLFLAGS="CCFLAGS=-DMUST_DISABLE_FPMASK"],
- [AC_IEEE([with signal(SIGFPE,SIG_IGN)], sigfpe,
- [#include <signal.h>], [signal(SIGFPE,SIG_IGN)],
- [AC_DEFINE(MUST_DISABLE_SIGFPE)
- PERLFLAGS="CCFLAGS=-DMUST_DISABLE_SIGFPE"],
- AC_MSG_ERROR([
-Your Compiler does not do propper IEEE math ... Please find out how to
-make IEEE math work with your compiler and let me know (oetiker@ee.ethz.ch).
-Check config.log to see what went wrong ...
-]))])])])])])])])])
-
-
-AC_OUTPUT(examples/shared-demo.pl \
- examples/piped-demo.pl \
- examples/stripes.pl \
- examples/bigtops.pl \
- examples/minmax.pl \
- examples/cgi-demo.cgi \
- examples/Makefile \
- doc/Makefile \
- libraries/Makefile \
- libraries/cgilib-0.4/Makefile \
- libraries/gd1.3/Makefile \
- libraries/libpng-1.0.9/Makefile \
- libraries/zlib-1.1.3/Makefile \
- src/Makefile \
- bindings/Makefile \
- bindings/tcl/Makefile \
- Makefile, \
- [chmod +x examples/*.cgi examples/*.pl])
-
-AC_MSG_CHECKING(in)
-AC_MSG_RESULT(and out again)
-
-echo $ac_n "ordering CD from http://ee-staff.ethz.ch/~oetiker/wish $ac_c" 1>&6
-sleep 1
-echo $ac_n ".$ac_c" 1>&6
-sleep 1
-echo $ac_n ".$ac_c" 1>&6
-sleep 1
-echo $ac_n ".$ac_c" 1>&6
-sleep 1
-echo $ac_n ".$ac_c" 1>&6
-sleep 1
-AC_MSG_RESULT([ just kidding ;-)])
-echo
-echo "----------------------------------------------------------------"
-echo "Config is DONE!"
-echo
-echo "Type 'make' to compile the software and use 'make install' to "
-echo "install everything to: $prefix."
-echo
-echo "If you want to install the perl"
-echo "modules in site-perl, try 'make site-perl-install'."
-echo
-echo " ... that wishlist is NO JOKE. If you find RRDtool useful"
-echo "make me happy. Go to http://ee-staff.ethz.ch/~oetiker/wish and"
-echo "place an order."
-echo
-echo " -- Tobi Oetiker <tobi@oetiker.ch>"
-echo "----------------------------------------------------------------"
--imginfo '<IMG SRC="/img/%s" WIDTH="%lu" HEIGHT="%lu" ALT="Demo">'
-B<[-c|--color I<COLORTAG#rrggbb>]>
+B<[-c|--color I<COLORTAGBB<#>I<rrggbb>B<[>I<aa>B<<]>
Override the default colors for the standard elements of the graph.
The I<COLORTAG> is one of C<BACK> ground, C<CANVAS>, C<SHADEA> for the
A green arrow is made by: C<--color ARROW:00FF00>
-B<[-a|--imgformat C<GIF>|C<PNG>]>
+B<--zoom> I<factor>
+
+Zoom the graphics by the given amount ... The factor must be > 0
+
+B<[-n|--font I<FONTTAG>B<:>I<size>B<:>I<font>
+
+Lets you customize which font to use for the various text elements on the
+rrd graphs. C<DEFAULT> sets the default value for all elements C<TITLE>,
+C<AXIS> for the axis labels, C<UNIT> for the vertical unit label, C<LEGEND>
+for the graph legend.
+
+Use Times for the title: C<--font TITLE:13:/usr/lib/fonts/times.ttf>
+
+B<[-a|--imgformat C<PNG>]>
+
+At present only PNG is supported, but C<EPS>, C<SVG> or even C<FLASH> should
+not be all that difficult to add.
+
B<[-i|--interlaced]>
The default is to generate a non-interlaced GIF image. It is recommended
[B<PRINT:>I<vname>B<:>I<CF>B<:>I<format>]
[B<GPRINT:>I<vname>B<:>I<CF>B<:>I<format>]
-[B<HRULE:>I<value>B<#>I<rrggbb>[B<:>I<legend>]]
-[B<STACK:>I<vname>[B<#>I<rrggbb>[B<:>I<legend>]]]
+[B<HRULE:>I<value>B<#>I<rrggbbaa>[B<:>I<legend>]]
+[B<STACK:>I<vname>[B<#>I<rrggbbaa>[B<:>I<legend>]]]
I<(soon) available commands>
[B<PRINT:>I<vname>B<:>I<format>]
[B<GPRINT:>I<vname>B<:>I<format>]
[B<COMMENT:>I<text>]
-[B<VRULE:>I<vname>B<#>I<rrggbb>[B<:>I<legend>]]
-[B<LINE>{B<1>|B<2>|B<3>}B<:>I<vname>[B<#>I<rrggbb>[B<:>I<legend>]]][B<:STACK>]
-[B<AREA:>I<vname>[B<#>I<rrggbb>[B<:>I<legend>]]][B<:STACK>]
+[B<VRULE:>I<vname>B<#>I<rrggbbaa>[B<:>I<legend>]]
+[B<LINE>{I<width>}B<:>I<vname>[B<#>I<rrggbbaa>[B<:>I<legend>]]][B<:STACK>]
+[B<AREA:>I<vname>[B<#>I<rrggbbaa>[B<:>I<legend>]]][B<:STACK>]
I<to be implemented commands>
[B<SHIFT:>I<vname>]
-[B<PART:>I<vname>B<#>I<rrggbb>[B<:>I<legend>]]
+[B<PART:>I<vname>B<#>I<rrggbbaa>[B<:>I<legend>]]
=head1 DESCRIPTION
Text is printed literally in the legend section of the graph
-B<HRULE:>I<value>B<#>I<rrggbb>[B<:>I<legend>]
+B<HRULE:>I<value>B<#>I<rrggbbaa>[B<:>I<legend>]
Draw an horizontal line at I<value>. Its color is composed from three
hexadecimal numbers specifying the color components (00 is off, FF is
printed in the legend section. I<value> can be a variable from a B<VDEF>.
It is an error to use I<vname>s from B<DEF> or B<CDEF> here.
-B<VRULE:>I<time>B<#>I<rrggbb>[B<:>I<legend>]
+B<VRULE:>I<time>B<#>I<rrggbbaa>[B<:>I<legend>]
Draw a vertical line at I<time>. Its color is composed from three
hexadecimal numbers specifying the color components (00 is off, FF is
printed in the legend section. I<time> may be a number or a variable
from a B<VDEF>. It is an error to use I<vname>s from B<DEF> or B<CDEF> here.
-B<LINE>{B<1>|B<2>|B<3>}B<:>I<vname>[B<#>I<rrggbb>[B<:>I<legend>]][B<:STACK>]
+B<LINE>{I<width>}B<:>I<vname>[B<#>I<rrggbbaa>[B<:>I<legend>]][B<:STACK>]
Draw a line of the specified width into the graph. If the color
is not specified, the drawing is done 'blind'. This is useful when
stacked on top of the previous element which can be a B<LINEx> or
an B<AREA>
-B<AREA:>I<vname>[B<#>I<rrggbb>[B<:>I<legend>]][B<:STACK>]
+B<AREA:>I<vname>[B<#>I<rrggbbaa>[B<:>I<legend>]][B<:STACK>]
See B<LINEx>, however the area between the x-axis and the line will
also be filled.
-B<STACK:>I<vname>[B<#>I<rrggbb>[B<:>I<legend>]]
+B<STACK:>I<vname>[B<#>I<rrggbbaa>[B<:>I<legend>]]
I<Depriciated. Use the B<STACK> modifiers on the other commands.>
I<Note: the comments on stacking are still valid...>
used for the pie chart). The size of the canvas is determined by
the lesser of L<width and height|rrdgraph/item_Size>.
-B<PART:>I<vname>B<#>I<rrggbb>[B<:>I<legend>]
+B<PART:>I<vname>B<#>I<rrggbbaa>[B<:>I<legend>]
Draw a part of pie. Pie parts will be concatenated, the first one
will start at the top and parts will be created clockwise.
#! @PERL@
#makes things work when run without install
-use lib qw( ../libraries/perl-shared/blib/lib ../libraries/perl-shared/blib/arch );
+use lib qw( ../bindings/perl-shared/blib/lib ../bindings/perl-shared/blib/arch );
# this is for after install
use lib qw( @prefix@/lib/perl ../lib/perl );
use RRDs;
-#! /usr/sepp/bin/perl
+#! /usr/bin/perl
#makes things work when run without install
-use lib qw( ../libraries/perl-shared/blib/lib ../libraries/perl-shared/blib/arch );
+use lib qw( ../bindings/perl-shared/blib/lib ../bindings/perl-shared/blib/arch );
# this is for after install
-use lib qw( /usr/local/rrdtool-1.0.33/lib/perl ../lib/perl );
+use lib qw( /usr/local/rrdtool-1.1.0/lib/perl ../lib/perl );
use RRDs;
my $start=time;
#! @PERL@
#makes things work when run without install
-use lib qw( ../libraries/perl-shared/blib/lib ../libraries/perl-shared/blib/arch );
+use lib qw( ../bindings/perl-shared/blib/lib ../bindings/perl-shared/blib/arch );
# this is for after install
use lib qw( @prefix@/lib/perl ../lib/perl );
-#! /usr/local/rrdtool-1.0.33/bin/rrdcgi
+#! /usr/local/rrdtool-1.1.0/bin/rrdcgi
<HTML>
<HEAD>
-#! /usr/sepp/bin/perl
+#! /usr/bin/perl
#makes things work when run without install
-use lib qw( ../libraries/perl-shared/blib/lib ../libraries/perl-shared/blib/arch );
+use lib qw( ../bindings/perl-shared/blib/lib ../bindings/perl-shared/blib/arch );
# this is for after install
-use lib qw( /usr/local/rrdtool-1.0.33/lib/perl ../lib/perl );
+use lib qw( /usr/local/rrdtool-1.1.0/lib/perl ../lib/perl );
use RRDs;
my $start=time;
"--end", "start+1d",
"--lower-limit=0",
"--interlace",
+ "--zoom=2.5",
"--imgformat","PNG",
"--width=450",
"DEF:a=$rrd:a:AVERAGE",
#! @PERL@
#makes things work when run without install
-use lib qw( ../libraries/perl-shared/blib/lib ../libraries/perl-shared/blib/arch );
+use lib qw( ../bindings/perl-shared/blib/lib ../bindings/perl-shared/blib/arch );
# this is for after install
use lib qw( @prefix@/lib/perl ../lib/perl );
-#! /usr/sepp/bin/perl
+#! /usr/bin/perl
#makes things work when run without install
-use lib qw( ../libraries/perl-piped/blib/lib ../lib/perl );
+use lib qw( ../bindings/perl-piped/blib/lib ../lib/perl );
#makes programm work AFTER install
-use lib qw( /usr/local/rrdtool-1.0.33/lib/perl );
+use lib qw( /usr/local/rrdtool-1.1.0/lib/perl );
use RRDp;
$PNG = "piped-demo.png";
# some magic to find the correct rrdtol executable
-if ( -x "/usr/local/rrdtool-1.0.33/bin/rrdtool") {
- RRDp::start "/usr/local/rrdtool-1.0.33/bin/rrdtool";
+if ( -x "/usr/local/rrdtool-1.1.0/bin/rrdtool") {
+ RRDp::start "/usr/local/rrdtool-1.1.0/bin/rrdtool";
} elsif ( -x "../bin/rrdtool") {
RRDp::start "../bin/rrdtool";
} else {
#! @PERL@
#makes things work when run without install
-use lib qw( ../libraries/perl-piped/blib/lib ../lib/perl );
+use lib qw( ../bindings/perl-piped/blib/lib ../lib/perl );
#makes programm work AFTER install
use lib qw( @prefix@/lib/perl );
-#! /usr/sepp/bin/perl
+#! /usr/bin/perl
END {
}
#makes things work when run without install
-use lib qw( ../libraries/perl-shared/blib/lib ../libraries/perl-shared/blib/arch );
+use lib qw( ../bindings/perl-shared/blib/lib ../bindings/perl-shared/blib/arch );
#makes programm work AFTER install
-use lib qw( /usr/local/rrdtool-1.0.33/lib/perl ../lib/perl );
+use lib qw( /usr/local/rrdtool-1.1.0/lib/perl ../lib/perl );
use strict;
use vars qw(@ISA $loaded);
}
#makes things work when run without install
-use lib qw( ../libraries/perl-shared/blib/lib ../libraries/perl-shared/blib/arch );
+use lib qw( ../bindings/perl-shared/blib/lib ../bindings/perl-shared/blib/arch );
#makes programm work AFTER install
use lib qw( @prefix@/lib/perl ../lib/perl );
-#! /usr/sepp/bin/perl
+#! /usr/bin/perl
#makes things work when run without install
-use lib qw( ../libraries/perl-shared/blib/lib ../libraries/perl-shared/blib/arch );
+use lib qw( ../bindings/perl-shared/blib/lib ../bindings/perl-shared/blib/arch );
#makes programm work AFTER install
-use lib qw( /usr/local/rrdtool-1.0.33/lib/perl ../lib/perl );
+use lib qw( /usr/local/rrdtool-1.1.0/lib/perl ../lib/perl );
use strict;
use vars qw(@ISA $loaded);
#! @PERL@
#makes things work when run without install
-use lib qw( ../libraries/perl-shared/blib/lib ../libraries/perl-shared/blib/arch );
+use lib qw( ../bindings/perl-shared/blib/lib ../bindings/perl-shared/blib/arch );
#makes programm work AFTER install
use lib qw( @prefix@/lib/perl ../lib/perl );
-SUBDIRS = cgilib-0.4 gd1.3 libpng-1.0.9 zlib-1.1.3
-
+SUBDIRS = cgilib-0.4 zlib-1.1.3 libpng-1.2.0 libart_lgpl-2.3.7 freetype-2.0.5
-noinst_LTLIBRARIES = librrd_cgi.la
+noinst_LTLIBRARIES = librrd_cgi.la
librrd_cgi_la_SOURCES = cgi.c cgi.h
-EXTRA_DIST= *.[1-9] *.dsp *.dsw readme cgitest.c jumpto.c
-
+EXTRA_DIST= *.[1-9] *.dsp *.dsw readme cgitest.c jumpto.c
--- /dev/null
+wget http://prdownloads.sourceforge.net/freetype/freetype-2.0.5.tar.gz
+gtar zxvf freetype-2.0.5.tar.gz
+mv freetype-2.0.5 f
+mkdir freetype-2.0.5
+cp f/src/*/*.c freetype-2.0.5
+cp -r f/include freetype-2.0.5
+cp f/src/*/*.h freetype-2.0.5/include
--- /dev/null
+## Process this file with automake to produce Makefile.in
+# preparation
+# cp src/*/*.c .
+# cp src/*/*.h include
+
+noinst_LTLIBRARIES = librrd_freetype.la
+
+
+librrd_freetype_la_SOURCES = \
+ ahangles.c ahglyph.c ahglobal.c ahhint.c ahmodule.c\
+ cff.c ftglyph.c winfnt.c\
+ ftcalc.c fttrigon.c ftobjs.c ftstream.c ftlist.c\
+ ftoutln.c ftnames.c ftextend.c ftlru.c ftcmanag.c\
+ ftcglyph.c ftcchunk.c ftcimage.c ftcsbits.c pcfutil.c\
+ pcfread.c pcfdriver.c psobjs.c psauxmod.c t1decode.c\
+ psmodule.c ftraster.c ftrend1.c ttload.c ttcmap.c\
+ sfobjs.c sfdriver.c ttsbit.c ttpost.c ftgrays.c\
+ ftsmooth.c ttdriver.c ttpload.c ttgload.c ttobjs.c\
+ ttinterp.c t1parse.c t1load.c t1objs.c t1driver.c\
+ t1gload.c t1afm.c cidparse.c cidload.c cidobjs.c\
+ cidriver.c cidgload.c ftinit.c ftsystem.c
+
+EXTRA_DIST= README ChangeLog cffdrivr.c cffparse.c cffload.c cffobjs.c cffgload.c
+
+INCLUDES = -Iinclude
--- /dev/null
+* this is a mutilated copy of free type ... please get the original from
+
+ ftp://ftp.freetype.org/pub/freetype2/ftdocs-2.0.5.tar.bz2
+ ftp://ftp.freetype.org/pub/freetype2/ftdocs-2.0.5.tar.gz
+ ftp://ftp.freetype.org/pub/freetype2/ftdoc205.zip
+
--- /dev/null
+/***************************************************************************/
+/* */
+/* ahangles.h */
+/* */
+/* A routine used to compute vector angles with limited accuracy */
+/* and very high speed (body). */
+/* */
+/* Copyright 2000-2001 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "ahangles.h"
+
+
+ /* the following table has been automatically generated with */
+ /* the `mather.py' Python script */
+
+ const AH_Angle ah_arctan[1L << AH_ATAN_BITS] =
+ {
+ 0, 0, 1, 1, 1, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 5,
+ 5, 5, 6, 6, 6, 7, 7, 7,
+ 8, 8, 8, 9, 9, 9, 10, 10,
+ 10, 10, 11, 11, 11, 12, 12, 12,
+ 13, 13, 13, 14, 14, 14, 14, 15,
+ 15, 15, 16, 16, 16, 17, 17, 17,
+ 18, 18, 18, 18, 19, 19, 19, 20,
+ 20, 20, 21, 21, 21, 21, 22, 22,
+ 22, 23, 23, 23, 24, 24, 24, 24,
+ 25, 25, 25, 26, 26, 26, 26, 27,
+ 27, 27, 28, 28, 28, 28, 29, 29,
+ 29, 30, 30, 30, 30, 31, 31, 31,
+ 31, 32, 32, 32, 33, 33, 33, 33,
+ 34, 34, 34, 34, 35, 35, 35, 35,
+ 36, 36, 36, 36, 37, 37, 37, 38,
+ 38, 38, 38, 39, 39, 39, 39, 40,
+ 40, 40, 40, 41, 41, 41, 41, 42,
+ 42, 42, 42, 42, 43, 43, 43, 43,
+ 44, 44, 44, 44, 45, 45, 45, 45,
+ 46, 46, 46, 46, 46, 47, 47, 47,
+ 47, 48, 48, 48, 48, 48, 49, 49,
+ 49, 49, 50, 50, 50, 50, 50, 51,
+ 51, 51, 51, 51, 52, 52, 52, 52,
+ 52, 53, 53, 53, 53, 53, 54, 54,
+ 54, 54, 54, 55, 55, 55, 55, 55,
+ 56, 56, 56, 56, 56, 57, 57, 57,
+ 57, 57, 57, 58, 58, 58, 58, 58,
+ 59, 59, 59, 59, 59, 59, 60, 60,
+ 60, 60, 60, 61, 61, 61, 61, 61,
+ 61, 62, 62, 62, 62, 62, 62, 63,
+ 63, 63, 63, 63, 63, 64, 64, 64
+ };
+
+
+ FT_LOCAL_DEF AH_Angle
+ ah_angle( FT_Vector* v )
+ {
+ FT_Pos dx, dy;
+ AH_Angle angle;
+
+
+ dx = v->x;
+ dy = v->y;
+
+ /* check trivial cases */
+ if ( dy == 0 )
+ {
+ angle = 0;
+ if ( dx < 0 )
+ angle = AH_PI;
+ return angle;
+ }
+ else if ( dx == 0 )
+ {
+ angle = AH_HALF_PI;
+ if ( dy < 0 )
+ angle = -AH_HALF_PI;
+ return angle;
+ }
+
+ angle = 0;
+ if ( dx < 0 )
+ {
+ dx = -v->x;
+ dy = -v->y;
+ angle = AH_PI;
+ }
+
+ if ( dy < 0 )
+ {
+ FT_Pos tmp;
+
+
+ tmp = dx;
+ dx = -dy;
+ dy = tmp;
+ angle -= AH_HALF_PI;
+ }
+
+ if ( dx == 0 && dy == 0 )
+ return 0;
+
+ if ( dx == dy )
+ angle += AH_PI / 4;
+ else if ( dx > dy )
+ angle += ah_arctan[FT_DivFix( dy, dx ) >> ( 16 - AH_ATAN_BITS )];
+ else
+ angle += AH_HALF_PI -
+ ah_arctan[FT_DivFix( dx, dy ) >> ( 16 - AH_ATAN_BITS )];
+
+ if ( angle > AH_PI )
+ angle -= AH_2PI;
+
+ return angle;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ahglobal.c */
+/* */
+/* Routines used to compute global metrics automatically (body). */
+/* */
+/* Copyright 2000-2001 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include "ahglobal.h"
+#include "ahglyph.h"
+
+
+#define MAX_TEST_CHARACTERS 12
+
+ static
+ const char* blue_chars[ah_blue_max] =
+ {
+ "THEZOCQS",
+ "HEZLOCUS",
+ "xzroesc",
+ "xzroesc",
+ "pqgjy"
+ };
+
+
+ /* simple insertion sort */
+ static void
+ sort_values( FT_Int count,
+ FT_Pos* table )
+ {
+ FT_Int i, j, swap;
+
+
+ for ( i = 1; i < count; i++ )
+ {
+ for ( j = i; j > 0; j-- )
+ {
+ if ( table[j] > table[j - 1] )
+ break;
+
+ swap = table[j];
+ table[j] = table[j - 1];
+ table[j - 1] = swap;
+ }
+ }
+ }
+
+
+ static FT_Error
+ ah_hinter_compute_blues( AH_Hinter* hinter )
+ {
+ AH_Blue blue;
+ AH_Globals* globals = &hinter->globals->design;
+ FT_Pos flats [MAX_TEST_CHARACTERS];
+ FT_Pos rounds[MAX_TEST_CHARACTERS];
+ FT_Int num_flats;
+ FT_Int num_rounds;
+
+ FT_Face face;
+ FT_GlyphSlot glyph;
+ FT_Error error;
+ FT_CharMap charmap;
+
+
+ face = hinter->face;
+ glyph = face->glyph;
+
+ /* save current charmap */
+ charmap = face->charmap;
+
+ /* do we have a Unicode charmap in there? */
+ error = FT_Select_Charmap( face, ft_encoding_unicode );
+ if ( error )
+ goto Exit;
+
+ /* we compute the blues simply by loading each character from the */
+ /* 'blue_chars[blues]' string, then compute its top-most and */
+ /* bottom-most points */
+
+ AH_LOG(( "blue zones computation\n" ));
+ AH_LOG(( "------------------------------------------------\n" ));
+
+ for ( blue = ah_blue_capital_top; blue < ah_blue_max; blue++ )
+ {
+ const char* p = blue_chars[blue];
+ const char* limit = p + MAX_TEST_CHARACTERS;
+ FT_Pos *blue_ref, *blue_shoot;
+
+
+ AH_LOG(( "blue %3d: ", blue ));
+
+ num_flats = 0;
+ num_rounds = 0;
+
+ for ( ; p < limit; p++ )
+ {
+ FT_UInt glyph_index;
+ FT_Vector* extremum;
+ FT_Vector* points;
+ FT_Vector* point_limit;
+ FT_Vector* point;
+ FT_Bool round;
+
+
+ /* exit if we reach the end of the string */
+ if ( !*p )
+ break;
+
+ AH_LOG(( "`%c'", *p ));
+
+ /* load the character in the face -- skip unknown or empty ones */
+ glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p );
+ if ( glyph_index == 0 )
+ continue;
+
+ error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
+ if ( error || glyph->outline.n_points <= 0 )
+ continue;
+
+ /* now compute min or max point indices and coordinates */
+ points = glyph->outline.points;
+ point_limit = points + glyph->outline.n_points;
+ point = points;
+ extremum = point;
+ point++;
+
+ if ( AH_IS_TOP_BLUE( blue ) )
+ {
+ for ( ; point < point_limit; point++ )
+ if ( point->y > extremum->y )
+ extremum = point;
+ }
+ else
+ {
+ for ( ; point < point_limit; point++ )
+ if ( point->y < extremum->y )
+ extremum = point;
+ }
+
+ AH_LOG(( "%5d", (int)extremum->y ));
+
+ /* now, check whether the point belongs to a straight or round */
+ /* segment; we first need to find in which contour the extremum */
+ /* lies, then see its previous and next points */
+ {
+ FT_Int index = (FT_Int)( extremum - points );
+ FT_Int n;
+ FT_Int first, last, prev, next, end;
+ FT_Pos dist;
+
+
+ last = -1;
+ first = 0;
+
+ for ( n = 0; n < glyph->outline.n_contours; n++ )
+ {
+ end = glyph->outline.contours[n];
+ if ( end >= index )
+ {
+ last = end;
+ break;
+ }
+ first = end + 1;
+ }
+
+ /* XXX: should never happen! */
+ if ( last < 0 )
+ continue;
+
+ /* now look for the previous and next points that are not on the */
+ /* same Y coordinate. Threshold the `closeness'... */
+
+ prev = index;
+ next = prev;
+
+ do
+ {
+ if ( prev > first )
+ prev--;
+ else
+ prev = last;
+
+ dist = points[prev].y - extremum->y;
+ if ( dist < -5 || dist > 5 )
+ break;
+
+ } while ( prev != index );
+
+ do
+ {
+ if ( next < last )
+ next++;
+ else
+ next = first;
+
+ dist = points[next].y - extremum->y;
+ if ( dist < -5 || dist > 5 )
+ break;
+
+ } while ( next != index );
+
+ /* now, set the `round' flag depending on the segment's kind */
+ round = FT_BOOL(
+ FT_CURVE_TAG( glyph->outline.tags[prev] ) != FT_Curve_Tag_On ||
+ FT_CURVE_TAG( glyph->outline.tags[next] ) != FT_Curve_Tag_On );
+
+ AH_LOG(( "%c ", round ? 'r' : 'f' ));
+ }
+
+ if ( round )
+ rounds[num_rounds++] = extremum->y;
+ else
+ flats[num_flats++] = extremum->y;
+ }
+
+ AH_LOG(( "\n" ));
+
+ /* we have computed the contents of the `rounds' and `flats' tables, */
+ /* now determine the reference and overshoot position of the blue; */
+ /* we simply take the median value after a simple short */
+ sort_values( num_rounds, rounds );
+ sort_values( num_flats, flats );
+
+ blue_ref = globals->blue_refs + blue;
+ blue_shoot = globals->blue_shoots + blue;
+ if ( num_flats == 0 && num_rounds == 0 )
+ {
+ *blue_ref = -10000;
+ *blue_shoot = -10000;
+ }
+ else if ( num_flats == 0 )
+ {
+ *blue_ref =
+ *blue_shoot = rounds[num_rounds / 2];
+ }
+ else if ( num_rounds == 0 )
+ {
+ *blue_ref =
+ *blue_shoot = flats[num_flats / 2];
+ }
+ else
+ {
+ *blue_ref = flats[num_flats / 2];
+ *blue_shoot = rounds[num_rounds / 2];
+ }
+
+ /* there are sometimes problems: if the overshoot position of top */
+ /* zones is under its reference position, or the opposite for bottom */
+ /* zones. We must thus check everything there and correct the errors */
+ if ( *blue_shoot != *blue_ref )
+ {
+ FT_Pos ref = *blue_ref;
+ FT_Pos shoot = *blue_shoot;
+ FT_Bool over_ref = FT_BOOL( shoot > ref );
+
+
+ if ( AH_IS_TOP_BLUE( blue ) ^ over_ref )
+ *blue_shoot = *blue_ref = ( shoot + ref ) / 2;
+ }
+
+ AH_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot ));
+ }
+
+ /* reset original face charmap */
+ FT_Set_Charmap( face, charmap );
+ error = 0;
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ ah_hinter_compute_widths( AH_Hinter* hinter )
+ {
+ /* scan the array of segments in each direction */
+ AH_Outline* outline = hinter->glyph;
+ AH_Segment* segments;
+ AH_Segment* limit;
+ AH_Globals* globals = &hinter->globals->design;
+ FT_Pos* widths;
+ FT_Int dimension;
+ FT_Int* p_num_widths;
+ FT_Error error = 0;
+ FT_Pos edge_distance_threshold = 32000;
+
+
+ globals->num_widths = 0;
+ globals->num_heights = 0;
+
+ /* For now, compute the standard width and height from the `o' */
+ /* character. I started computing the stem width of the `i' and the */
+ /* stem height of the "-", but it wasn't too good. Moreover, we now */
+ /* have a single character that gives us standard width and height. */
+ {
+ FT_UInt glyph_index;
+
+
+ glyph_index = FT_Get_Char_Index( hinter->face, 'o' );
+ if ( glyph_index == 0 )
+ return 0;
+
+ error = FT_Load_Glyph( hinter->face, glyph_index, FT_LOAD_NO_SCALE );
+ if ( error )
+ goto Exit;
+
+ error = ah_outline_load( hinter->glyph, hinter->face );
+ if ( error )
+ goto Exit;
+
+ ah_outline_compute_segments( hinter->glyph );
+ ah_outline_link_segments( hinter->glyph );
+ }
+
+ segments = outline->horz_segments;
+ limit = segments + outline->num_hsegments;
+ widths = globals->heights;
+ p_num_widths = &globals->num_heights;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Segment* seg = segments;
+ AH_Segment* link;
+ FT_Int num_widths = 0;
+
+
+ for ( ; seg < limit; seg++ )
+ {
+ link = seg->link;
+ /* we only consider stem segments there! */
+ if ( link && link->link == seg && link > seg )
+ {
+ FT_Int dist;
+
+
+ dist = seg->pos - link->pos;
+ if ( dist < 0 )
+ dist = -dist;
+
+ if ( num_widths < 12 )
+ widths[num_widths++] = dist;
+ }
+ }
+
+ sort_values( num_widths, widths );
+ *p_num_widths = num_widths;
+
+ /* we will now try to find the smallest width */
+ if ( num_widths > 0 && widths[0] < edge_distance_threshold )
+ edge_distance_threshold = widths[0];
+
+ segments = outline->vert_segments;
+ limit = segments + outline->num_vsegments;
+ widths = globals->widths;
+ p_num_widths = &globals->num_widths;
+
+ }
+
+ /* Now, compute the edge distance threshold as a fraction of the */
+ /* smallest width in the font. Set it in `hinter.glyph' too! */
+ if ( edge_distance_threshold == 32000 )
+ edge_distance_threshold = 50;
+
+ /* let's try 20% */
+ hinter->glyph->edge_distance_threshold = edge_distance_threshold / 5;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF FT_Error
+ ah_hinter_compute_globals( AH_Hinter* hinter )
+ {
+ return ah_hinter_compute_widths( hinter ) ||
+ ah_hinter_compute_blues ( hinter );
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ahglyph.c */
+/* */
+/* Routines used to load and analyze a given glyph before hinting */
+/* (body). */
+/* */
+/* Copyright 2000-2001 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "ahglyph.h"
+#include "ahangles.h"
+#include "ahglobal.h"
+#include "aherrors.h"
+
+#include <stdio.h>
+
+
+
+#ifdef AH_DEBUG
+
+ void
+ ah_dump_edges( AH_Outline* outline )
+ {
+ AH_Edge* edges;
+ AH_Edge* edge_limit;
+ AH_Segment* segments;
+ FT_Int dimension;
+
+
+ edges = outline->horz_edges;
+ edge_limit = edges + outline->num_hedges;
+ segments = outline->horz_segments;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Edge* edge;
+
+
+ printf ( "Table of %s edges:\n",
+ !dimension ? "vertical" : "horizontal" );
+ printf ( " [ index | pos | dir | link |"
+ " serif | blue | opos | pos ]\n" );
+
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ printf ( " [ %5d | %4d | %5s | %4d | %5d | %c | %5.2f | %5.2f ]\n",
+ edge - edges,
+ (int)edge->fpos,
+ edge->dir == ah_dir_up
+ ? "up"
+ : ( edge->dir == ah_dir_down
+ ? "down"
+ : ( edge->dir == ah_dir_left
+ ? "left"
+ : ( edge->dir == ah_dir_right
+ ? "right"
+ : "none" ) ) ),
+ edge->link ? ( edge->link - edges ) : -1,
+ edge->serif ? ( edge->serif - edges ) : -1,
+ edge->blue_edge ? 'y' : 'n',
+ edge->opos / 64.0,
+ edge->pos / 64.0 );
+ }
+
+ edges = outline->vert_edges;
+ edge_limit = edges + outline->num_vedges;
+ segments = outline->vert_segments;
+ }
+ }
+
+
+ /* A function used to dump the array of linked segments */
+ void
+ ah_dump_segments( AH_Outline* outline )
+ {
+ AH_Segment* segments;
+ AH_Segment* segment_limit;
+ AH_Point* points;
+ FT_Int dimension;
+
+
+ points = outline->points;
+ segments = outline->horz_segments;
+ segment_limit = segments + outline->num_hsegments;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Segment* seg;
+
+
+ printf ( "Table of %s segments:\n",
+ !dimension ? "vertical" : "horizontal" );
+ printf ( " [ index | pos | dir | link | serif |"
+ " numl | first | start ]\n" );
+
+ for ( seg = segments; seg < segment_limit; seg++ )
+ {
+ printf ( " [ %5d | %4d | %5s | %4d | %5d | %4d | %5d | %5d ]\n",
+ seg - segments,
+ (int)seg->pos,
+ seg->dir == ah_dir_up
+ ? "up"
+ : ( seg->dir == ah_dir_down
+ ? "down"
+ : ( seg->dir == ah_dir_left
+ ? "left"
+ : ( seg->dir == ah_dir_right
+ ? "right"
+ : "none" ) ) ),
+ seg->link ? (seg->link-segments) : -1,
+ seg->serif ? (seg->serif-segments) : -1,
+ (int)seg->num_linked,
+ seg->first - points,
+ seg->last - points );
+ }
+
+ segments = outline->vert_segments;
+ segment_limit = segments + outline->num_vsegments;
+ }
+ }
+
+#endif /* AH_DEBUG */
+
+
+ /* compute the direction value of a given vector.. */
+ static AH_Direction
+ ah_compute_direction( FT_Pos dx,
+ FT_Pos dy )
+ {
+ AH_Direction dir;
+ FT_Pos ax = ABS( dx );
+ FT_Pos ay = ABS( dy );
+
+
+ dir = ah_dir_none;
+
+ /* test for vertical direction */
+ if ( ax * 12 < ay )
+ {
+ dir = dy > 0 ? ah_dir_up : ah_dir_down;
+ }
+ /* test for horizontal direction */
+ else if ( ay * 12 < ax )
+ {
+ dir = dx > 0 ? ah_dir_right : ah_dir_left;
+ }
+
+ return dir;
+ }
+
+
+ /* this function is used by ah_get_orientation (see below) to test */
+ /* the fill direction of a given bbox extrema */
+ static int
+ ah_test_extrema( FT_Outline* outline,
+ int n )
+ {
+ FT_Vector *prev, *cur, *next;
+ FT_Pos product;
+ FT_Int first, last, c;
+
+
+ /* we need to compute the `previous' and `next' point */
+ /* for these extrema */
+ cur = outline->points + n;
+ prev = cur - 1;
+ next = cur + 1;
+
+ first = 0;
+ for ( c = 0; c < outline->n_contours; c++ )
+ {
+ last = outline->contours[c];
+
+ if ( n == first )
+ prev = outline->points + last;
+
+ if ( n == last )
+ next = outline->points + first;
+
+ first = last + 1;
+ }
+
+ product = FT_MulDiv( cur->x - prev->x, /* in.x */
+ next->y - cur->y, /* out.y */
+ 0x40 )
+ -
+ FT_MulDiv( cur->y - prev->y, /* in.y */
+ next->x - cur->x, /* out.x */
+ 0x40 );
+
+ if ( product )
+ product = product > 0 ? 2 : 1;
+
+ return product;
+ }
+
+
+ /* Compute the orientation of path filling. It differs between TrueType */
+ /* and Type1 formats. We could use the `ft_outline_reverse_fill' flag, */
+ /* but it is better to re-compute it directly (it seems that this flag */
+ /* isn't correctly set for some weird composite glyphs currently). */
+ /* */
+ /* We do this by computing bounding box points, and computing their */
+ /* curvature. */
+ /* */
+ /* The function returns either 1 or -1. */
+ /* */
+ static int
+ ah_get_orientation( FT_Outline* outline )
+ {
+ FT_BBox box;
+ FT_BBox indices;
+ int n, last;
+
+
+ indices.xMin = -1;
+ indices.yMin = -1;
+ indices.xMax = -1;
+ indices.yMax = -1;
+
+ box.xMin = box.yMin = 32767L;
+ box.xMax = box.yMax = -32768L;
+
+ /* is it empty? */
+ if ( outline->n_contours < 1 )
+ return 1;
+
+ last = outline->contours[outline->n_contours - 1];
+
+ for ( n = 0; n <= last; n++ )
+ {
+ FT_Pos x, y;
+
+
+ x = outline->points[n].x;
+ if ( x < box.xMin )
+ {
+ box.xMin = x;
+ indices.xMin = n;
+ }
+ if ( x > box.xMax )
+ {
+ box.xMax = x;
+ indices.xMax = n;
+ }
+
+ y = outline->points[n].y;
+ if ( y < box.yMin )
+ {
+ box.yMin = y;
+ indices.yMin = n;
+ }
+ if ( y > box.yMax )
+ {
+ box.yMax = y;
+ indices.yMax = n;
+ }
+ }
+
+ /* test orientation of the xmin */
+ n = ah_test_extrema( outline, indices.xMin );
+ if ( n )
+ goto Exit;
+
+ n = ah_test_extrema( outline, indices.yMin );
+ if ( n )
+ goto Exit;
+
+ n = ah_test_extrema( outline, indices.xMax );
+ if ( n )
+ goto Exit;
+
+ n = ah_test_extrema( outline, indices.yMax );
+ if ( !n )
+ n = 1;
+
+ Exit:
+ return n;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ah_outline_new */
+ /* */
+ /* <Description> */
+ /* Creates a new and empty AH_Outline object. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ ah_outline_new( FT_Memory memory,
+ AH_Outline** aoutline )
+ {
+ FT_Error error;
+ AH_Outline* outline;
+
+
+ if ( !ALLOC( outline, sizeof ( *outline ) ) )
+ {
+ outline->memory = memory;
+ *aoutline = outline;
+ }
+
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ah_outline_done */
+ /* */
+ /* <Description> */
+ /* Destroys a given AH_Outline object. */
+ /* */
+ FT_LOCAL_DEF void
+ ah_outline_done( AH_Outline* outline )
+ {
+ FT_Memory memory = outline->memory;
+
+
+ FREE( outline->horz_edges );
+ FREE( outline->horz_segments );
+ FREE( outline->contours );
+ FREE( outline->points );
+
+ FREE( outline );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ah_outline_save */
+ /* */
+ /* <Description> */
+ /* Saves the content of a given AH_Outline object into a face's glyph */
+ /* slot. */
+ /* */
+ FT_LOCAL_DEF void
+ ah_outline_save( AH_Outline* outline,
+ AH_Loader* gloader )
+ {
+ AH_Point* point = outline->points;
+ AH_Point* point_limit = point + outline->num_points;
+ FT_Vector* vec = gloader->current.outline.points;
+ char* tag = gloader->current.outline.tags;
+
+
+ /* we assume that the glyph loader has already been checked for storage */
+ for ( ; point < point_limit; point++, vec++, tag++ )
+ {
+ vec->x = point->x;
+ vec->y = point->y;
+
+ if ( point->flags & ah_flah_conic )
+ tag[0] = FT_Curve_Tag_Conic;
+ else if ( point->flags & ah_flah_cubic )
+ tag[0] = FT_Curve_Tag_Cubic;
+ else
+ tag[0] = FT_Curve_Tag_On;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ah_outline_load */
+ /* */
+ /* <Description> */
+ /* Loads an unscaled outline from a glyph slot into an AH_Outline */
+ /* object. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ ah_outline_load( AH_Outline* outline,
+ FT_Face face )
+ {
+ FT_Memory memory = outline->memory;
+ FT_Error error = AH_Err_Ok;
+ FT_Outline* source = &face->glyph->outline;
+ FT_Int num_points = source->n_points;
+ FT_Int num_contours = source->n_contours;
+ AH_Point* points;
+
+
+ /* check arguments */
+ if ( !face ||
+ !face->size ||
+ face->glyph->format != ft_glyph_format_outline )
+ return AH_Err_Invalid_Argument;
+
+ /* first of all, reallocate the contours array if necessary */
+ if ( num_contours > outline->max_contours )
+ {
+ FT_Int new_contours = ( num_contours + 3 ) & -4;
+
+
+ if ( REALLOC_ARRAY( outline->contours, outline->max_contours,
+ new_contours, AH_Point* ) )
+ goto Exit;
+
+ outline->max_contours = new_contours;
+ }
+
+ /* then, reallocate the points, segments & edges arrays if needed -- */
+ /* note that we reserved two additional point positions, used to */
+ /* hint metrics appropriately */
+ /* */
+ if ( num_points + 2 > outline->max_points )
+ {
+ FT_Int news = ( num_points + 2 + 7 ) & -8;
+ FT_Int max = outline->max_points;
+
+
+ if ( REALLOC_ARRAY( outline->points,
+ max, news, AH_Point ) ||
+ REALLOC_ARRAY( outline->horz_edges,
+ max * 2, news * 2, AH_Edge ) ||
+ REALLOC_ARRAY( outline->horz_segments,
+ max * 2, news * 2, AH_Segment ) )
+ goto Exit;
+
+ /* readjust some pointers */
+ outline->vert_edges = outline->horz_edges + news;
+ outline->vert_segments = outline->horz_segments + news;
+ outline->max_points = news;
+ }
+
+ outline->num_points = num_points;
+ outline->num_contours = num_contours;
+
+ outline->num_hedges = 0;
+ outline->num_vedges = 0;
+ outline->num_hsegments = 0;
+ outline->num_vsegments = 0;
+
+ /* We can't rely on the value of `FT_Outline.flags' to know the fill */
+ /* direction used for a glyph, given that some fonts are broken (e.g. */
+ /* the Arphic ones). We thus recompute it each time we need to. */
+ /* */
+ outline->vert_major_dir = ah_dir_up;
+ outline->horz_major_dir = ah_dir_left;
+
+ if ( ah_get_orientation( source ) > 1 )
+ {
+ outline->vert_major_dir = ah_dir_down;
+ outline->horz_major_dir = ah_dir_right;
+ }
+
+ outline->x_scale = face->size->metrics.x_scale;
+ outline->y_scale = face->size->metrics.y_scale;
+
+ points = outline->points;
+ if ( outline->num_points == 0 )
+ goto Exit;
+
+ {
+ /* do one thing at a time -- it is easier to understand, and */
+ /* the code is clearer */
+ AH_Point* point;
+ AH_Point* point_limit = points + outline->num_points;
+
+
+ /* compute coordinates */
+ {
+ FT_Vector* vec = source->points;
+ FT_Fixed x_scale = outline->x_scale;
+ FT_Fixed y_scale = outline->y_scale;
+
+
+ for ( point = points; point < point_limit; vec++, point++ )
+ {
+ point->fx = vec->x;
+ point->fy = vec->y;
+ point->ox = point->x = FT_MulFix( vec->x, x_scale );
+ point->oy = point->y = FT_MulFix( vec->y, y_scale );
+
+ point->flags = 0;
+ }
+ }
+
+ /* compute Bezier flags */
+ {
+ char* tag = source->tags;
+
+
+ for ( point = points; point < point_limit; point++, tag++ )
+ {
+ switch ( FT_CURVE_TAG( *tag ) )
+ {
+ case FT_Curve_Tag_Conic:
+ point->flags = ah_flah_conic; break;
+ case FT_Curve_Tag_Cubic:
+ point->flags = ah_flah_cubic; break;
+ default:
+ ;
+ }
+ }
+ }
+
+ /* compute `next' and `prev' */
+ {
+ FT_Int contour_index;
+ AH_Point* prev;
+ AH_Point* first;
+ AH_Point* end;
+
+
+ contour_index = 0;
+
+ first = points;
+ end = points + source->contours[0];
+ prev = end;
+
+ for ( point = points; point < point_limit; point++ )
+ {
+ point->prev = prev;
+ if ( point < end )
+ {
+ point->next = point + 1;
+ prev = point;
+ }
+ else
+ {
+ point->next = first;
+ contour_index++;
+ if ( point + 1 < point_limit )
+ {
+ end = points + source->contours[contour_index];
+ first = point + 1;
+ prev = end;
+ }
+ }
+ }
+ }
+
+ /* set-up the contours array */
+ {
+ AH_Point** contour = outline->contours;
+ AH_Point** contour_limit = contour + outline->num_contours;
+ short* end = source->contours;
+ short index = 0;
+
+
+ for ( ; contour < contour_limit; contour++, end++ )
+ {
+ contour[0] = points + index;
+ index = (short)( end[0] + 1 );
+ }
+ }
+
+ /* compute directions of in & out vectors */
+ {
+ for ( point = points; point < point_limit; point++ )
+ {
+ AH_Point* prev;
+ AH_Point* next;
+ FT_Vector vec;
+
+
+ prev = point->prev;
+ vec.x = point->fx - prev->fx;
+ vec.y = point->fy - prev->fy;
+
+ point->in_dir = ah_compute_direction( vec.x, vec.y );
+
+#ifndef AH_OPTION_NO_WEAK_INTERPOLATION
+ point->in_angle = ah_angle( &vec );
+#endif
+
+ next = point->next;
+ vec.x = next->fx - point->fx;
+ vec.y = next->fy - point->fy;
+
+ point->out_dir = ah_compute_direction( vec.x, vec.y );
+
+#ifndef AH_OPTION_NO_WEAK_INTERPOLATION
+ point->out_angle = ah_angle( &vec );
+
+ {
+ AH_Angle delta = point->in_angle - point->out_angle;
+
+
+ if ( delta < 0 )
+ delta = -delta;
+ if ( delta < 2 )
+ point->flags |= ah_flah_weak_interpolation;
+ }
+
+#if 0
+ if ( point->flags & ( ah_flah_conic | ah_flah_cubic ) )
+ point->flags |= ah_flah_weak_interpolation;
+#endif
+
+#endif /* !AH_OPTION_NO_WEAK_INTERPOLATION */
+
+#ifdef AH_OPTION_NO_STRONG_INTERPOLATION
+ point->flags |= ah_flah_weak_interpolation;
+#endif
+ }
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF void
+ ah_setup_uv( AH_Outline* outline,
+ AH_UV source )
+ {
+ AH_Point* point = outline->points;
+ AH_Point* point_limit = point + outline->num_points;
+
+
+ for ( ; point < point_limit; point++ )
+ {
+ FT_Pos u, v;
+
+
+ switch ( source )
+ {
+ case ah_uv_fxy:
+ u = point->fx;
+ v = point->fy;
+ break;
+ case ah_uv_fyx:
+ u = point->fy;
+ v = point->fx;
+ break;
+ case ah_uv_oxy:
+ u = point->ox;
+ v = point->oy;
+ break;
+ case ah_uv_oyx:
+ u = point->oy;
+ v = point->ox;
+ break;
+ case ah_uv_yx:
+ u = point->y;
+ v = point->x;
+ break;
+ case ah_uv_ox:
+ u = point->x;
+ v = point->ox;
+ break;
+ case ah_uv_oy:
+ u = point->y;
+ v = point->oy;
+ break;
+ default:
+ u = point->x;
+ v = point->y;
+ break;
+ }
+ point->u = u;
+ point->v = v;
+ }
+ }
+
+
+ FT_LOCAL_DEF void
+ ah_outline_compute_segments( AH_Outline* outline )
+ {
+ int dimension;
+ AH_Segment* segments;
+ FT_Int* p_num_segments;
+ AH_Direction segment_dir;
+ AH_Direction major_dir;
+
+
+ segments = outline->horz_segments;
+ p_num_segments = &outline->num_hsegments;
+ major_dir = ah_dir_right; /* This value must be positive! */
+ segment_dir = major_dir;
+
+ /* set up (u,v) in each point */
+ ah_setup_uv( outline, ah_uv_fyx );
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Point** contour = outline->contours;
+ AH_Point** contour_limit = contour + outline->num_contours;
+ AH_Segment* segment = segments;
+ FT_Int num_segments = 0;
+
+#ifdef AH_HINT_METRICS
+ AH_Point* min_point = 0;
+ AH_Point* max_point = 0;
+ FT_Pos min_coord = 32000;
+ FT_Pos max_coord = -32000;
+#endif
+
+
+ /* do each contour separately */
+ for ( ; contour < contour_limit; contour++ )
+ {
+ AH_Point* point = contour[0];
+ AH_Point* last = point->prev;
+ int on_edge = 0;
+ FT_Pos min_pos = +32000; /* minimum segment pos != min_coord */
+ FT_Pos max_pos = -32000; /* maximum segment pos != max_coord */
+ FT_Bool passed;
+
+
+#ifdef AH_HINT_METRICS
+ if ( point->u < min_coord )
+ {
+ min_coord = point->u;
+ min_point = point;
+ }
+ if ( point->u > max_coord )
+ {
+ max_coord = point->u;
+ max_point = point;
+ }
+#endif
+
+ if ( point == last ) /* skip singletons -- just in case? */
+ continue;
+
+ if ( ABS( last->out_dir ) == major_dir &&
+ ABS( point->out_dir ) == major_dir )
+ {
+ /* we are already on an edge, try to locate its start */
+ last = point;
+
+ for (;;)
+ {
+ point = point->prev;
+ if ( ABS( point->out_dir ) != major_dir )
+ {
+ point = point->next;
+ break;
+ }
+ if ( point == last )
+ break;
+ }
+
+ }
+
+ last = point;
+ passed = 0;
+
+ for (;;)
+ {
+ FT_Pos u, v;
+
+
+ if ( on_edge )
+ {
+ u = point->u;
+ if ( u < min_pos )
+ min_pos = u;
+ if ( u > max_pos )
+ max_pos = u;
+
+ if ( point->out_dir != segment_dir || point == last )
+ {
+ /* we are just leaving an edge; record a new segment! */
+ segment->last = point;
+ segment->pos = ( min_pos + max_pos ) >> 1;
+
+ /* a segment is round if either its first or last point */
+ /* is a control point */
+ if ( ( segment->first->flags | point->flags ) &
+ ah_flah_control )
+ segment->flags |= ah_edge_round;
+
+ /* compute segment size */
+ min_pos = max_pos = point->v;
+
+ v = segment->first->v;
+ if ( v < min_pos )
+ min_pos = v;
+ if ( v > max_pos )
+ max_pos = v;
+
+ segment->min_coord = min_pos;
+ segment->max_coord = max_pos;
+
+ on_edge = 0;
+ num_segments++;
+ segment++;
+ /* fallthrough */
+ }
+ }
+
+ /* now exit if we are at the start/end point */
+ if ( point == last )
+ {
+ if ( passed )
+ break;
+ passed = 1;
+ }
+
+ if ( !on_edge && ABS( point->out_dir ) == major_dir )
+ {
+ /* this is the start of a new segment! */
+ segment_dir = point->out_dir;
+
+ /* clear all segment fields */
+ memset( segment, 0, sizeof ( *segment ) );
+
+ segment->dir = segment_dir;
+ segment->flags = ah_edge_normal;
+ min_pos = max_pos = point->u;
+ segment->first = point;
+ segment->last = point;
+ segment->contour = contour;
+ on_edge = 1;
+
+#ifdef AH_HINT_METRICS
+ if ( point == max_point )
+ max_point = 0;
+
+ if ( point == min_point )
+ min_point = 0;
+#endif
+ }
+
+ point = point->next;
+ }
+
+ } /* contours */
+
+#ifdef AH_HINT_METRICS
+ /* we need to ensure that there are edges on the left-most and */
+ /* right-most points of the glyph in order to hint the metrics; */
+ /* we do this by inserting fake segments when needed */
+ if ( dimension == 0 )
+ {
+ AH_Point* point = outline->points;
+ AH_Point* point_limit = point + outline->num_points;
+
+ FT_Pos min_pos = 32000;
+ FT_Pos max_pos = -32000;
+
+
+ min_point = 0;
+ max_point = 0;
+
+ /* compute minimum and maximum points */
+ for ( ; point < point_limit; point++ )
+ {
+ FT_Pos x = point->fx;
+
+
+ if ( x < min_pos )
+ {
+ min_pos = x;
+ min_point = point;
+ }
+ if ( x > max_pos )
+ {
+ max_pos = x;
+ max_point = point;
+ }
+ }
+
+ /* insert minimum segment */
+ if ( min_point )
+ {
+ /* clear all segment fields */
+ memset( segment, 0, sizeof ( *segment ) );
+
+ segment->dir = segment_dir;
+ segment->flags = ah_edge_normal;
+ segment->first = min_point;
+ segment->last = min_point;
+ segment->pos = min_pos;
+
+ num_segments++;
+ segment++;
+ }
+
+ /* insert maximum segment */
+ if ( max_point )
+ {
+ /* clear all segment fields */
+ memset( segment, 0, sizeof ( *segment ) );
+
+ segment->dir = segment_dir;
+ segment->flags = ah_edge_normal;
+ segment->first = max_point;
+ segment->last = max_point;
+ segment->pos = max_pos;
+
+ num_segments++;
+ segment++;
+ }
+ }
+#endif /* AH_HINT_METRICS */
+
+ *p_num_segments = num_segments;
+
+ segments = outline->vert_segments;
+ major_dir = ah_dir_up;
+ p_num_segments = &outline->num_vsegments;
+ ah_setup_uv( outline, ah_uv_fxy );
+ }
+ }
+
+
+ FT_LOCAL_DEF void
+ ah_outline_link_segments( AH_Outline* outline )
+ {
+ AH_Segment* segments;
+ AH_Segment* segment_limit;
+ int dimension;
+
+
+ ah_setup_uv( outline, ah_uv_fyx );
+
+ segments = outline->horz_segments;
+ segment_limit = segments + outline->num_hsegments;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Segment* seg1;
+ AH_Segment* seg2;
+
+
+ /* now compare each segment to the others */
+ for ( seg1 = segments; seg1 < segment_limit; seg1++ )
+ {
+ FT_Pos best_score = 32000;
+ AH_Segment* best_segment = 0;
+
+
+ /* the fake segments are introduced to hint the metrics -- */
+ /* we must never link them to anything */
+ if ( seg1->first == seg1->last )
+ continue;
+
+ for ( seg2 = segments; seg2 < segment_limit; seg2++ )
+ if ( seg1 != seg2 && seg1->dir + seg2->dir == 0 )
+ {
+ FT_Pos pos1 = seg1->pos;
+ FT_Pos pos2 = seg2->pos;
+ FT_Bool is_dir;
+ FT_Bool is_pos;
+
+
+ /* check that the segments are correctly oriented and */
+ /* positioned to form a black distance */
+
+ is_dir = (FT_Bool)( seg1->dir == outline->horz_major_dir ||
+ seg1->dir == outline->vert_major_dir );
+ is_pos = (FT_Bool)( pos1 > pos2 );
+
+ if ( pos1 == pos2 || !(is_dir ^ is_pos) )
+ continue;
+
+ /* Check the two segments. We now have a better algorithm */
+ /* that doesn't rely on the segment points themselves but */
+ /* on their relative position. This gets rids of many */
+ /* unpleasant artefacts and incorrect stem/serifs */
+ /* computations. */
+
+ /* first of all, compute the size of the `common' height */
+ {
+ FT_Pos min = seg1->min_coord;
+ FT_Pos max = seg1->max_coord;
+ FT_Pos len, score;
+ FT_Pos size1, size2;
+
+
+ size1 = max - min;
+ size2 = seg2->max_coord - seg2->min_coord;
+
+ if ( min < seg2->min_coord )
+ min = seg2->min_coord;
+
+ if ( max < seg2->max_coord )
+ max = seg2->max_coord;
+
+ len = max - min;
+ score = seg2->pos - seg1->pos;
+ if ( score < 0 )
+ score = -score;
+
+ /* before comparing the scores, take care that the segments */
+ /* are really facing each other (often not for italics..) */
+ if ( 4 * len >= size1 && 4 * len >= size2 )
+ if ( score < best_score )
+ {
+ best_score = score;
+ best_segment = seg2;
+ }
+ }
+ }
+
+ if ( best_segment )
+ {
+ seg1->link = best_segment;
+ seg1->score = best_score;
+
+ best_segment->num_linked++;
+ }
+
+
+ } /* edges 1 */
+
+ /* now, compute the `serif' segments */
+ for ( seg1 = segments; seg1 < segment_limit; seg1++ )
+ {
+ seg2 = seg1->link;
+
+ if ( seg2 && seg2->link != seg1 )
+ {
+ seg1->link = 0;
+ seg1->serif = seg2->link;
+ }
+ }
+
+ ah_setup_uv( outline, ah_uv_fxy );
+
+ segments = outline->vert_segments;
+ segment_limit = segments + outline->num_vsegments;
+ }
+ }
+
+
+ static void
+ ah_outline_compute_edges( AH_Outline* outline )
+ {
+ AH_Edge* edges;
+ AH_Segment* segments;
+ AH_Segment* segment_limit;
+ AH_Direction up_dir;
+ FT_Int* p_num_edges;
+ FT_Int dimension;
+ FT_Fixed scale;
+ FT_Pos edge_distance_threshold;
+
+
+ edges = outline->horz_edges;
+ segments = outline->horz_segments;
+ segment_limit = segments + outline->num_hsegments;
+ p_num_edges = &outline->num_hedges;
+ up_dir = ah_dir_right;
+ scale = outline->y_scale;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Edge* edge;
+ AH_Edge* edge_limit; /* really == edge + num_edges */
+ AH_Segment* seg;
+
+
+ /*********************************************************************/
+ /* */
+ /* We will begin by generating a sorted table of edges for the */
+ /* current direction. To do so, we simply scan each segment and try */
+ /* to find an edge in our table that corresponds to its position. */
+ /* */
+ /* If no edge is found, we create and insert a new edge in the */
+ /* sorted table. Otherwise, we simply add the segment to the edge's */
+ /* list which will be processed in the second step to compute the */
+ /* edge's properties. */
+ /* */
+ /* Note that the edges table is sorted along the segment/edge */
+ /* position. */
+ /* */
+ /*********************************************************************/
+
+ edge_distance_threshold = FT_MulFix( outline->edge_distance_threshold,
+ scale );
+ if ( edge_distance_threshold > 64 / 4 )
+ edge_distance_threshold = 64 / 4;
+
+ edge_limit = edges;
+ for ( seg = segments; seg < segment_limit; seg++ )
+ {
+ AH_Edge* found = 0;
+
+
+ /* look for an edge corresponding to the segment */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ FT_Pos dist;
+
+
+ dist = seg->pos - edge->fpos;
+ if ( dist < 0 )
+ dist = -dist;
+
+ dist = FT_MulFix( dist, scale );
+ if ( dist < edge_distance_threshold )
+ {
+ found = edge;
+ break;
+ }
+ }
+
+ if ( !found )
+ {
+ /* insert a new edge in the list and */
+ /* sort according to the position */
+ while ( edge > edges && edge[-1].fpos > seg->pos )
+ {
+ edge[0] = edge[-1];
+ edge--;
+ }
+ edge_limit++;
+
+ /* clear all edge fields */
+ memset( edge, 0, sizeof ( *edge ) );
+
+ /* add the segment to the new edge's list */
+ edge->first = seg;
+ edge->last = seg;
+ edge->fpos = seg->pos;
+ edge->opos = edge->pos = FT_MulFix( seg->pos, scale );
+ seg->edge_next = seg;
+ }
+ else
+ {
+ /* if an edge was found, simply add the segment to the edge's */
+ /* list */
+ seg->edge_next = edge->first;
+ edge->last->edge_next = seg;
+ edge->last = seg;
+ }
+ }
+
+ *p_num_edges = (FT_Int)( edge_limit - edges );
+
+
+ /*********************************************************************/
+ /* */
+ /* Good, we will now compute each edge's properties according to */
+ /* segments found on its position. Basically, these are: */
+ /* */
+ /* - edge's main direction */
+ /* - stem edge, serif edge or both (which defaults to stem then) */
+ /* - rounded edge, straigth or both (which defaults to straight) */
+ /* - link for edge */
+ /* */
+ /*********************************************************************/
+
+ /* first of all, set the `edge' field in each segment -- this is */
+ /* required in order to compute edge links */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ seg = edge->first;
+ if ( seg )
+ do
+ {
+ seg->edge = edge;
+ seg = seg->edge_next;
+ }
+ while ( seg != edge->first );
+ }
+
+ /* now, compute each edge properties */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ int is_round = 0; /* does it contain round segments? */
+ int is_straight = 0; /* does it contain straight segments? */
+ int ups = 0; /* number of upwards segments */
+ int downs = 0; /* number of downwards segments */
+
+
+ seg = edge->first;
+
+ do
+ {
+ FT_Bool is_serif;
+
+
+ /* check for roundness of segment */
+ if ( seg->flags & ah_edge_round )
+ is_round++;
+ else
+ is_straight++;
+
+ /* check for segment direction */
+ if ( seg->dir == up_dir )
+ ups += seg->max_coord-seg->min_coord;
+ else
+ downs += seg->max_coord-seg->min_coord;
+
+ /* check for links -- if seg->serif is set, then seg->link must */
+ /* be ignored */
+ is_serif = (FT_Bool)( seg->serif && seg->serif->edge != edge );
+
+ if ( seg->link || is_serif )
+ {
+ AH_Edge* edge2;
+ AH_Segment* seg2;
+
+
+ edge2 = edge->link;
+ seg2 = seg->link;
+
+ if ( is_serif )
+ {
+ seg2 = seg->serif;
+ edge2 = edge->serif;
+ }
+
+ if ( edge2 )
+ {
+ FT_Pos edge_delta;
+ FT_Pos seg_delta;
+
+
+ edge_delta = edge->fpos - edge2->fpos;
+ if ( edge_delta < 0 )
+ edge_delta = -edge_delta;
+
+ seg_delta = seg->pos - seg2->pos;
+ if ( seg_delta < 0 )
+ seg_delta = -seg_delta;
+
+ if ( seg_delta < edge_delta )
+ edge2 = seg2->edge;
+ }
+ else
+ edge2 = seg2->edge;
+
+ if ( is_serif )
+ edge->serif = edge2;
+ else
+ edge->link = edge2;
+ }
+
+ seg = seg->edge_next;
+
+ } while ( seg != edge->first );
+
+ /* set the round/straight flags */
+ edge->flags = ah_edge_normal;
+
+ if ( is_round > 0 && is_round >= is_straight )
+ edge->flags |= ah_edge_round;
+
+ /* set the edge's main direction */
+ edge->dir = ah_dir_none;
+
+ if ( ups > downs )
+ edge->dir = up_dir;
+
+ else if ( ups < downs )
+ edge->dir = - up_dir;
+
+ else if ( ups == downs )
+ edge->dir = 0; /* both up and down !! */
+
+ /* gets rid of serifs if link is set */
+ /* XXX: This gets rid of many unpleasant artefacts! */
+ /* Example: the `c' in cour.pfa at size 13 */
+
+ if ( edge->serif && edge->link )
+ edge->serif = 0;
+ }
+
+ edges = outline->vert_edges;
+ segments = outline->vert_segments;
+ segment_limit = segments + outline->num_vsegments;
+ p_num_edges = &outline->num_vedges;
+ up_dir = ah_dir_up;
+ scale = outline->x_scale;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ah_outline_detect_features */
+ /* */
+ /* <Description> */
+ /* Performs feature detection on a given AH_Outline object. */
+ /* */
+ FT_LOCAL_DEF void
+ ah_outline_detect_features( AH_Outline* outline )
+ {
+ ah_outline_compute_segments( outline );
+ ah_outline_link_segments ( outline );
+ ah_outline_compute_edges ( outline );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ah_outline_compute_blue_edges */
+ /* */
+ /* <Description> */
+ /* Computes the `blue edges' in a given outline (i.e. those that must */
+ /* be snapped to a blue zone edge (top or bottom). */
+ /* */
+ FT_LOCAL_DEF void
+ ah_outline_compute_blue_edges( AH_Outline* outline,
+ AH_Face_Globals* face_globals )
+ {
+ AH_Edge* edge = outline->horz_edges;
+ AH_Edge* edge_limit = edge + outline->num_hedges;
+ AH_Globals* globals = &face_globals->design;
+ FT_Fixed y_scale = outline->y_scale;
+
+ FT_Bool blue_active[ah_blue_max];
+
+
+ /* compute which blue zones are active, i.e. have their scaled */
+ /* size < 3/4 pixels */
+ {
+ AH_Blue blue;
+ FT_Bool check = 0;
+
+
+ for ( blue = ah_blue_capital_top; blue < ah_blue_max; blue++ )
+ {
+ FT_Pos ref, shoot, dist;
+
+
+ ref = globals->blue_refs[blue];
+ shoot = globals->blue_shoots[blue];
+ dist = ref-shoot;
+ if ( dist < 0 )
+ dist = -dist;
+
+ blue_active[blue] = 0;
+
+ if ( FT_MulFix( dist, y_scale ) < 48 )
+ {
+ blue_active[blue] = 1;
+ check = 1;
+ }
+ }
+
+ /* return immediately if no blue zone is active */
+ if ( !check )
+ return;
+ }
+
+ /* compute for each horizontal edge, which blue zone is closer */
+ for ( ; edge < edge_limit; edge++ )
+ {
+ AH_Blue blue;
+ FT_Pos* best_blue = 0;
+ FT_Pos best_dist; /* initial threshold */
+
+
+ /* compute the initial threshold as a fraction of the EM size */
+ best_dist = FT_MulFix( face_globals->face->units_per_EM / 40, y_scale );
+ if ( best_dist > 64 / 4 )
+ best_dist = 64 / 4;
+
+ for ( blue = ah_blue_capital_top; blue < ah_blue_max; blue++ )
+ {
+ /* if it is a top zone, check for right edges -- if it is a bottom */
+ /* zone, check for left edges */
+ /* */
+ /* of course, that's for TrueType XXX */
+ FT_Bool is_top_blue =
+ FT_BOOL( AH_IS_TOP_BLUE( blue ) );
+ FT_Bool is_major_dir =
+ FT_BOOL( edge->dir == outline->horz_major_dir );
+
+ if ( !blue_active[blue] )
+ continue;
+
+ /* if it is a top zone, the edge must be against the major */
+ /* direction; if it is a bottom zone, it must be in the major */
+ /* direction */
+ if ( is_top_blue ^ is_major_dir )
+ {
+ FT_Pos dist;
+ FT_Pos* blue_pos = globals->blue_refs + blue;
+
+
+ /* first of all, compare it to the reference position */
+ dist = edge->fpos - *blue_pos;
+ if ( dist < 0 )
+ dist = -dist;
+
+ dist = FT_MulFix( dist, y_scale );
+ if ( dist < best_dist )
+ {
+ best_dist = dist;
+ best_blue = blue_pos;
+ }
+
+ /* now, compare it to the overshoot position if the edge is */
+ /* rounded, and if the edge is over the reference position of a */
+ /* top zone, or under the reference position of a bottom zone */
+ if ( edge->flags & ah_edge_round && dist != 0 )
+ {
+ FT_Bool is_under_ref = FT_BOOL( edge->fpos < *blue_pos );
+
+
+ if ( is_top_blue ^ is_under_ref )
+ {
+ blue_pos = globals->blue_shoots + blue;
+ dist = edge->fpos - *blue_pos;
+ if ( dist < 0 )
+ dist = -dist;
+
+ dist = FT_MulFix( dist, y_scale );
+ if ( dist < best_dist )
+ {
+ best_dist = dist;
+ best_blue = blue_pos;
+ }
+ }
+ }
+ }
+ }
+
+ if ( best_blue )
+ edge->blue_edge = best_blue;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ah_outline_scale_blue_edges */
+ /* */
+ /* <Description> */
+ /* This functions must be called before hinting in order to re-adjust */
+ /* the contents of the detected edges (basically change the `blue */
+ /* edge' pointer from `design units' to `scaled ones'). */
+ /* */
+ FT_LOCAL_DEF void
+ ah_outline_scale_blue_edges( AH_Outline* outline,
+ AH_Face_Globals* globals )
+ {
+ AH_Edge* edge = outline->horz_edges;
+ AH_Edge* edge_limit = edge + outline->num_hedges;
+ FT_Int delta;
+
+
+ delta = globals->scaled.blue_refs - globals->design.blue_refs;
+
+ for ( ; edge < edge_limit; edge++ )
+ {
+ if ( edge->blue_edge )
+ edge->blue_edge += delta;
+ }
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ahhint.c */
+/* */
+/* Glyph hinter (body). */
+/* */
+/* Copyright 2000-2001 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "ahhint.h"
+#include "ahglyph.h"
+#include "ahangles.h"
+#include "aherrors.h"
+#include FT_OUTLINE_H
+
+
+#define FACE_GLOBALS( face ) ((AH_Face_Globals*)(face)->autohint.data)
+
+#define AH_USE_IUP
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** Hinting routines ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* snap a given width in scaled coordinates to one of the */
+ /* current standard widths */
+ static FT_Pos
+ ah_snap_width( FT_Pos* widths,
+ FT_Int count,
+ FT_Pos width )
+ {
+ int n;
+ FT_Pos best = 64 + 32 + 2;
+ FT_Pos reference = width;
+
+
+ for ( n = 0; n < count; n++ )
+ {
+ FT_Pos w;
+ FT_Pos dist;
+
+
+ w = widths[n];
+ dist = width - w;
+ if ( dist < 0 )
+ dist = -dist;
+ if ( dist < best )
+ {
+ best = dist;
+ reference = w;
+ }
+ }
+
+ if ( width >= reference )
+ {
+ width -= 0x21;
+ if ( width < reference )
+ width = reference;
+ }
+ else
+ {
+ width += 0x21;
+ if ( width > reference )
+ width = reference;
+ }
+
+ return width;
+ }
+
+
+ /* align one stem edge relative to the previous stem edge */
+ static void
+ ah_align_linked_edge( AH_Hinter* hinter,
+ AH_Edge* base_edge,
+ AH_Edge* stem_edge,
+ int vertical )
+ {
+ FT_Pos dist = stem_edge->opos - base_edge->opos;
+ AH_Globals* globals = &hinter->globals->scaled;
+ FT_Pos sign = 1;
+
+
+ if ( dist < 0 )
+ {
+ dist = -dist;
+ sign = -1;
+ }
+
+ if ( vertical )
+ {
+ dist = ah_snap_width( globals->heights, globals->num_heights, dist );
+
+ /* in the case of vertical hinting, always round */
+ /* the stem heights to integer pixels */
+ if ( dist >= 64 )
+ dist = ( dist + 16 ) & -64;
+ else
+ dist = 64;
+ }
+ else
+ {
+ dist = ah_snap_width( globals->widths, globals->num_widths, dist );
+
+ if ( hinter->flags & ah_hinter_monochrome )
+ {
+ /* monochrome horizontal hinting: snap widths to integer pixels */
+ /* with a different threshold */
+ if ( dist < 64 )
+ dist = 64;
+ else
+ dist = ( dist + 32 ) & -64;
+ }
+ else
+ {
+ /* for horizontal anti-aliased hinting, we adopt a more subtle */
+ /* approach: we strengthen small stems, round stems whose size */
+ /* is between 1 and 2 pixels to an integer, otherwise nothing */
+ if ( dist < 48 )
+ dist = ( dist + 64 ) >> 1;
+
+ else if ( dist < 128 )
+ dist = ( dist + 42 ) & -64;
+ }
+ }
+
+ stem_edge->pos = base_edge->pos + sign * dist;
+ }
+
+
+ static void
+ ah_align_serif_edge( AH_Hinter* hinter,
+ AH_Edge* base,
+ AH_Edge* serif )
+ {
+ FT_Pos dist;
+ FT_Pos sign = 1;
+
+ UNUSED( hinter );
+
+
+ dist = serif->opos - base->opos;
+ if ( dist < 0 )
+ {
+ dist = -dist;
+ sign = -1;
+ }
+
+ /* do not strengthen serifs */
+ if ( base->flags & ah_edge_done )
+ {
+ if ( dist > 64 )
+ dist = ( dist + 16 ) & -64;
+
+ else if ( dist <= 32 )
+ dist = ( dist + 33 ) >> 1;
+ }
+
+ serif->pos = base->pos + sign * dist;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** E D G E H I N T I N G ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* Another alternative edge hinting algorithm */
+ static void
+ ah_hint_edges_3( AH_Hinter* hinter )
+ {
+ AH_Edge* edges;
+ AH_Edge* edge_limit;
+ AH_Outline* outline = hinter->glyph;
+ FT_Int dimension;
+
+
+ edges = outline->horz_edges;
+ edge_limit = edges + outline->num_hedges;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Edge* edge;
+ AH_Edge* anchor = 0;
+ int has_serifs = 0;
+
+
+ if ( hinter->disable_vert_edges && !dimension )
+ goto Next_Dimension;
+
+ if ( hinter->disable_horz_edges && dimension )
+ goto Next_Dimension;
+
+ /* we begin by aligning all stems relative to the blue zone */
+ /* if needed -- that's only for horizontal edges */
+ if ( dimension )
+ {
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ FT_Pos* blue;
+ AH_Edge *edge1, *edge2;
+
+
+ if ( edge->flags & ah_edge_done )
+ continue;
+
+ blue = edge->blue_edge;
+ edge1 = 0;
+ edge2 = edge->link;
+
+ if ( blue )
+ {
+ edge1 = edge;
+ }
+ else if (edge2 && edge2->blue_edge)
+ {
+ blue = edge2->blue_edge;
+ edge1 = edge2;
+ edge2 = edge;
+ }
+
+ if ( !edge1 )
+ continue;
+
+ edge1->pos = blue[0];
+ edge1->flags |= ah_edge_done;
+
+ if ( edge2 && !edge2->blue_edge )
+ {
+ ah_align_linked_edge( hinter, edge1, edge2, dimension );
+ edge2->flags |= ah_edge_done;
+ }
+
+ if ( !anchor )
+ anchor = edge;
+ }
+ }
+
+ /* now, we will align all stem edges, trying to maintain the */
+ /* relative order of stems in the glyph.. */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ AH_Edge *edge2;
+
+
+ if ( edge->flags & ah_edge_done )
+ continue;
+
+ /* skip all non-stem edges */
+ edge2 = edge->link;
+ if ( !edge2 )
+ {
+ has_serifs++;
+ continue;
+ }
+
+ /* now, align the stem */
+
+ /* this should not happen, but it's better to be safe.. */
+ if ( edge2->blue_edge || edge2 < edge )
+ {
+
+#if 0
+ printf( "strange blue alignement, edge %d to %d\n",
+ edge - edges, edge2 - edges );
+#endif
+
+ ah_align_linked_edge( hinter, edge2, edge, dimension );
+ edge->flags |= ah_edge_done;
+ continue;
+ }
+
+ {
+ FT_Bool min = 0;
+ FT_Pos delta;
+
+ if ( !anchor )
+ {
+ edge->pos = ( edge->opos + 32 ) & -64;
+ anchor = edge;
+ }
+ else
+ edge->pos = anchor->pos +
+ ( ( edge->opos - anchor->opos + 32 ) & -64 );
+
+ edge->flags |= ah_edge_done;
+
+ if ( edge > edges && edge->pos < edge[-1].pos )
+ {
+ edge->pos = edge[-1].pos;
+ min = 1;
+ }
+
+ ah_align_linked_edge( hinter, edge, edge2, dimension );
+ delta = 0;
+ if ( edge2 + 1 < edge_limit &&
+ edge2[1].flags & ah_edge_done )
+ delta = edge2[1].pos - edge2->pos;
+
+ if ( delta < 0 )
+ {
+ edge2->pos += delta;
+ if ( !min )
+ edge->pos += delta;
+ }
+ edge2->flags |= ah_edge_done;
+ }
+ }
+
+ if ( !has_serifs )
+ goto Next_Dimension;
+
+ /* now, hint the remaining edges (serifs and single) in order */
+ /* to complete our processing */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ if ( edge->flags & ah_edge_done )
+ continue;
+
+ if ( edge->serif )
+ {
+ ah_align_serif_edge( hinter, edge->serif, edge );
+ }
+ else if ( !anchor )
+ {
+ edge->pos = ( edge->opos + 32 ) & -64;
+ anchor = edge;
+ }
+ else
+ edge->pos = anchor->pos +
+ ( ( edge->opos-anchor->opos + 32 ) & -64 );
+
+ edge->flags |= ah_edge_done;
+
+ if ( edge > edges && edge->pos < edge[-1].pos )
+ edge->pos = edge[-1].pos;
+
+ if ( edge + 1 < edge_limit &&
+ edge[1].flags & ah_edge_done &&
+ edge->pos > edge[1].pos )
+ edge->pos = edge[1].pos;
+ }
+
+ Next_Dimension:
+ edges = outline->vert_edges;
+ edge_limit = edges + outline->num_vedges;
+ }
+ }
+
+
+ FT_LOCAL_DEF void
+ ah_hinter_hint_edges( AH_Hinter* hinter,
+ FT_Bool no_horz_edges,
+ FT_Bool no_vert_edges )
+ {
+ hinter->disable_horz_edges = no_horz_edges;
+ hinter->disable_vert_edges = no_vert_edges;
+
+ /* AH_Interpolate_Blue_Edges( hinter ); -- doesn't seem to help */
+ /* reduce the problem of the disappearing eye in the `e' of Times... */
+ /* also, creates some artifacts near the blue zones? */
+ {
+ ah_hint_edges_3( hinter );
+
+#if 0
+ /* outline optimizer removed temporarily */
+ if ( hinter->flags & ah_hinter_optimize )
+ {
+ AH_Optimizer opt;
+
+
+ if ( !AH_Optimizer_Init( &opt, hinter->glyph, hinter->memory ) )
+ {
+ AH_Optimizer_Compute( &opt );
+ AH_Optimizer_Done( &opt );
+ }
+ }
+#endif
+
+ }
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** P O I N T H I N T I N G ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static void
+ ah_hinter_align_edge_points( AH_Hinter* hinter )
+ {
+ AH_Outline* outline = hinter->glyph;
+ AH_Edge* edges;
+ AH_Edge* edge_limit;
+ FT_Int dimension;
+
+
+ edges = outline->horz_edges;
+ edge_limit = edges + outline->num_hedges;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Edge* edge;
+
+
+ edge = edges;
+ for ( ; edge < edge_limit; edge++ )
+ {
+ /* move the points of each segment */
+ /* in each edge to the edge's position */
+ AH_Segment* seg = edge->first;
+
+
+ do
+ {
+ AH_Point* point = seg->first;
+
+
+ for (;;)
+ {
+ if ( dimension )
+ {
+ point->y = edge->pos;
+ point->flags |= ah_flah_touch_y;
+ }
+ else
+ {
+ point->x = edge->pos;
+ point->flags |= ah_flah_touch_x;
+ }
+
+ if ( point == seg->last )
+ break;
+
+ point = point->next;
+ }
+
+ seg = seg->edge_next;
+
+ } while ( seg != edge->first );
+ }
+
+ edges = outline->vert_edges;
+ edge_limit = edges + outline->num_vedges;
+ }
+ }
+
+
+ /* hint the strong points -- this is equivalent to the TrueType `IP' */
+ static void
+ ah_hinter_align_strong_points( AH_Hinter* hinter )
+ {
+ AH_Outline* outline = hinter->glyph;
+ FT_Int dimension;
+ AH_Edge* edges;
+ AH_Edge* edge_limit;
+ AH_Point* points;
+ AH_Point* point_limit;
+ AH_Flags touch_flag;
+
+
+ points = outline->points;
+ point_limit = points + outline->num_points;
+
+ edges = outline->horz_edges;
+ edge_limit = edges + outline->num_hedges;
+ touch_flag = ah_flah_touch_y;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Point* point;
+ AH_Edge* edge;
+
+
+ if ( edges < edge_limit )
+ for ( point = points; point < point_limit; point++ )
+ {
+ FT_Pos u, ou, fu; /* point position */
+ FT_Pos delta;
+
+
+ if ( point->flags & touch_flag )
+ continue;
+
+#ifndef AH_OPTION_NO_WEAK_INTERPOLATION
+ /* if this point is candidate to weak interpolation, we will */
+ /* interpolate it after all strong points have been processed */
+ if ( point->flags & ah_flah_weak_interpolation )
+ continue;
+#endif
+
+ if ( dimension )
+ {
+ u = point->fy;
+ ou = point->oy;
+ }
+ else
+ {
+ u = point->fx;
+ ou = point->ox;
+ }
+
+ fu = u;
+
+ /* is the point before the first edge? */
+ edge = edges;
+ delta = edge->fpos - u;
+ if ( delta >= 0 )
+ {
+ u = edge->pos - ( edge->opos - ou );
+ goto Store_Point;
+ }
+
+ /* is the point after the last edge ? */
+ edge = edge_limit - 1;
+ delta = u - edge->fpos;
+ if ( delta >= 0 )
+ {
+ u = edge->pos + ( ou - edge->opos );
+ goto Store_Point;
+ }
+
+ /* otherwise, interpolate the point in between */
+ {
+ AH_Edge* before = 0;
+ AH_Edge* after = 0;
+
+
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ if ( u == edge->fpos )
+ {
+ u = edge->pos;
+ goto Store_Point;
+ }
+ if ( u < edge->fpos )
+ break;
+ before = edge;
+ }
+
+ for ( edge = edge_limit - 1; edge >= edges; edge-- )
+ {
+ if ( u == edge->fpos )
+ {
+ u = edge->pos;
+ goto Store_Point;
+ }
+ if ( u > edge->fpos )
+ break;
+ after = edge;
+ }
+
+ /* assert( before && after && before != after ) */
+ u = before->pos + FT_MulDiv( fu - before->fpos,
+ after->pos - before->pos,
+ after->fpos - before->fpos );
+ }
+
+ Store_Point:
+
+ /* save the point position */
+ if ( dimension )
+ point->y = u;
+ else
+ point->x = u;
+
+ point->flags |= touch_flag;
+ }
+
+ edges = outline->vert_edges;
+ edge_limit = edges + outline->num_vedges;
+ touch_flag = ah_flah_touch_x;
+ }
+ }
+
+
+#ifndef AH_OPTION_NO_WEAK_INTERPOLATION
+
+ static void
+ ah_iup_shift( AH_Point* p1,
+ AH_Point* p2,
+ AH_Point* ref )
+ {
+ AH_Point* p;
+ FT_Pos delta = ref->u - ref->v;
+
+
+ for ( p = p1; p < ref; p++ )
+ p->u = p->v + delta;
+
+ for ( p = ref + 1; p <= p2; p++ )
+ p->u = p->v + delta;
+ }
+
+
+ static void
+ ah_iup_interp( AH_Point* p1,
+ AH_Point* p2,
+ AH_Point* ref1,
+ AH_Point* ref2 )
+ {
+ AH_Point* p;
+ FT_Pos u;
+ FT_Pos v1 = ref1->v;
+ FT_Pos v2 = ref2->v;
+ FT_Pos d1 = ref1->u - v1;
+ FT_Pos d2 = ref2->u - v2;
+
+
+ if ( p1 > p2 )
+ return;
+
+ if ( v1 == v2 )
+ {
+ for ( p = p1; p <= p2; p++ )
+ {
+ u = p->v;
+
+ if ( u <= v1 )
+ u += d1;
+ else
+ u += d2;
+
+ p->u = u;
+ }
+ return;
+ }
+
+ if ( v1 < v2 )
+ {
+ for ( p = p1; p <= p2; p++ )
+ {
+ u = p->v;
+
+ if ( u <= v1 )
+ u += d1;
+ else if ( u >= v2 )
+ u += d2;
+ else
+ u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
+
+ p->u = u;
+ }
+ }
+ else
+ {
+ for ( p = p1; p <= p2; p++ )
+ {
+ u = p->v;
+
+ if ( u <= v2 )
+ u += d2;
+ else if ( u >= v1 )
+ u += d1;
+ else
+ u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
+
+ p->u = u;
+ }
+ }
+ }
+
+
+ /* interpolate weak points -- this is equivalent to the TrueType `IUP' */
+ static void
+ ah_hinter_align_weak_points( AH_Hinter* hinter )
+ {
+ AH_Outline* outline = hinter->glyph;
+ FT_Int dimension;
+ AH_Point* points;
+ AH_Point* point_limit;
+ AH_Point** contour_limit;
+ AH_Flags touch_flag;
+
+
+ points = outline->points;
+ point_limit = points + outline->num_points;
+
+ /* PASS 1: Move segment points to edge positions */
+
+ touch_flag = ah_flah_touch_y;
+
+ contour_limit = outline->contours + outline->num_contours;
+
+ ah_setup_uv( outline, ah_uv_oy );
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Point* point;
+ AH_Point* end_point;
+ AH_Point* first_point;
+ AH_Point** contour;
+
+
+ point = points;
+ contour = outline->contours;
+
+ for ( ; contour < contour_limit; contour++ )
+ {
+ point = *contour;
+ end_point = point->prev;
+ first_point = point;
+
+ while ( point <= end_point && !( point->flags & touch_flag ) )
+ point++;
+
+ if ( point <= end_point )
+ {
+ AH_Point* first_touched = point;
+ AH_Point* cur_touched = point;
+
+
+ point++;
+ while ( point <= end_point )
+ {
+ if ( point->flags & touch_flag )
+ {
+ /* we found two successive touched points; we interpolate */
+ /* all contour points between them */
+ ah_iup_interp( cur_touched + 1, point - 1,
+ cur_touched, point );
+ cur_touched = point;
+ }
+ point++;
+ }
+
+ if ( cur_touched == first_touched )
+ {
+ /* this is a special case: only one point was touched in the */
+ /* contour; we thus simply shift the whole contour */
+ ah_iup_shift( first_point, end_point, cur_touched );
+ }
+ else
+ {
+ /* now interpolate after the last touched point to the end */
+ /* of the contour */
+ ah_iup_interp( cur_touched + 1, end_point,
+ cur_touched, first_touched );
+
+ /* if the first contour point isn't touched, interpolate */
+ /* from the contour start to the first touched point */
+ if ( first_touched > points )
+ ah_iup_interp( first_point, first_touched - 1,
+ cur_touched, first_touched );
+ }
+ }
+ }
+
+ /* now save the interpolated values back to x/y */
+ if ( dimension )
+ {
+ for ( point = points; point < point_limit; point++ )
+ point->y = point->u;
+
+ touch_flag = ah_flah_touch_x;
+ ah_setup_uv( outline, ah_uv_ox );
+ }
+ else
+ {
+ for ( point = points; point < point_limit; point++ )
+ point->x = point->u;
+
+ break; /* exit loop */
+ }
+ }
+ }
+
+#endif /* !AH_OPTION_NO_WEAK_INTERPOLATION */
+
+
+ FT_LOCAL_DEF void
+ ah_hinter_align_points( AH_Hinter* hinter )
+ {
+ ah_hinter_align_edge_points( hinter );
+
+#ifndef AH_OPTION_NO_STRONG_INTERPOLATION
+ ah_hinter_align_strong_points( hinter );
+#endif
+
+#ifndef AH_OPTION_NO_WEAK_INTERPOLATION
+ ah_hinter_align_weak_points( hinter );
+#endif
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** H I N T E R O B J E C T M E T H O D S ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* scale and fit the global metrics */
+ static void
+ ah_hinter_scale_globals( AH_Hinter* hinter,
+ FT_Fixed x_scale,
+ FT_Fixed y_scale )
+ {
+ FT_Int n;
+ AH_Face_Globals* globals = hinter->globals;
+ AH_Globals* design = &globals->design;
+ AH_Globals* scaled = &globals->scaled;
+
+
+ /* copy content */
+ *scaled = *design;
+
+ /* scale the standard widths & heights */
+ for ( n = 0; n < design->num_widths; n++ )
+ scaled->widths[n] = FT_MulFix( design->widths[n], x_scale );
+
+ for ( n = 0; n < design->num_heights; n++ )
+ scaled->heights[n] = FT_MulFix( design->heights[n], y_scale );
+
+ /* scale the blue zones */
+ for ( n = 0; n < ah_blue_max; n++ )
+ {
+ FT_Pos delta, delta2;
+
+
+ delta = design->blue_shoots[n] - design->blue_refs[n];
+ delta2 = delta;
+ if ( delta < 0 )
+ delta2 = -delta2;
+ delta2 = FT_MulFix( delta2, y_scale );
+
+ if ( delta2 < 32 )
+ delta2 = 0;
+ else if ( delta2 < 64 )
+ delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & -32 );
+ else
+ delta2 = ( delta2 + 32 ) & -64;
+
+ if ( delta < 0 )
+ delta2 = -delta2;
+
+ scaled->blue_refs[n] =
+ ( FT_MulFix( design->blue_refs[n], y_scale ) + 32 ) & -64;
+ scaled->blue_shoots[n] = scaled->blue_refs[n] + delta2;
+ }
+
+ globals->x_scale = x_scale;
+ globals->y_scale = y_scale;
+ }
+
+
+ static void
+ ah_hinter_align( AH_Hinter* hinter )
+ {
+ ah_hinter_align_edge_points( hinter );
+ ah_hinter_align_points( hinter );
+ }
+
+
+ /* finalize a hinter object */
+ FT_LOCAL_DEF void
+ ah_hinter_done( AH_Hinter* hinter )
+ {
+ if ( hinter )
+ {
+ FT_Memory memory = hinter->memory;
+
+
+ ah_loader_done( hinter->loader );
+ ah_outline_done( hinter->glyph );
+
+ /* note: the `globals' pointer is _not_ owned by the hinter */
+ /* but by the current face object, we don't need to */
+ /* release it */
+ hinter->globals = 0;
+ hinter->face = 0;
+
+ FREE( hinter );
+ }
+ }
+
+
+ /* create a new empty hinter object */
+ FT_LOCAL_DEF FT_Error
+ ah_hinter_new( FT_Library library,
+ AH_Hinter** ahinter )
+ {
+ AH_Hinter* hinter = 0;
+ FT_Memory memory = library->memory;
+ FT_Error error;
+
+
+ *ahinter = 0;
+
+ /* allocate object */
+ if ( ALLOC( hinter, sizeof ( *hinter ) ) )
+ goto Exit;
+
+ hinter->memory = memory;
+ hinter->flags = 0;
+
+ /* allocate outline and loader */
+ error = ah_outline_new( memory, &hinter->glyph ) ||
+ ah_loader_new ( memory, &hinter->loader ) ||
+ ah_loader_create_extra( hinter->loader );
+ if ( error )
+ goto Exit;
+
+ *ahinter = hinter;
+
+ Exit:
+ if ( error )
+ ah_hinter_done( hinter );
+
+ return error;
+ }
+
+
+ /* create a face's autohint globals */
+ FT_LOCAL_DEF FT_Error
+ ah_hinter_new_face_globals( AH_Hinter* hinter,
+ FT_Face face,
+ AH_Globals* globals )
+ {
+ FT_Error error;
+ FT_Memory memory = hinter->memory;
+ AH_Face_Globals* face_globals;
+
+
+ if ( ALLOC( face_globals, sizeof ( *face_globals ) ) )
+ goto Exit;
+
+ hinter->face = face;
+ hinter->globals = face_globals;
+
+ if ( globals )
+ face_globals->design = *globals;
+ else
+ ah_hinter_compute_globals( hinter );
+
+ face->autohint.data = face_globals;
+ face->autohint.finalizer = (FT_Generic_Finalizer)
+ ah_hinter_done_face_globals;
+ face_globals->face = face;
+
+ Exit:
+ return error;
+ }
+
+
+ /* discard a face's autohint globals */
+ FT_LOCAL_DEF void
+ ah_hinter_done_face_globals( AH_Face_Globals* globals )
+ {
+ FT_Face face = globals->face;
+ FT_Memory memory = face->memory;
+
+
+ FREE( globals );
+ }
+
+
+ static FT_Error
+ ah_hinter_load( AH_Hinter* hinter,
+ FT_UInt glyph_index,
+ FT_UInt load_flags,
+ FT_UInt depth )
+ {
+ FT_Face face = hinter->face;
+ FT_GlyphSlot slot = face->glyph;
+ FT_Slot_Internal internal = slot->internal;
+ FT_Fixed x_scale = face->size->metrics.x_scale;
+ FT_Fixed y_scale = face->size->metrics.y_scale;
+ FT_Error error;
+ AH_Outline* outline = hinter->glyph;
+ AH_Loader* gloader = hinter->loader;
+ FT_Bool no_horz_hints = FT_BOOL(
+ ( load_flags & AH_HINT_NO_HORZ_EDGES ) != 0 );
+ FT_Bool no_vert_hints = FT_BOOL(
+ ( load_flags & AH_HINT_NO_VERT_EDGES ) != 0 );
+
+
+ /* load the glyph */
+ error = FT_Load_Glyph( face, glyph_index, load_flags );
+ if ( error )
+ goto Exit;
+
+ /* Set `hinter->transformed' after loading with FT_LOAD_NO_RECURSE. */
+ hinter->transformed = internal->glyph_transformed;
+
+ if ( hinter->transformed )
+ {
+ FT_Matrix imatrix;
+
+ imatrix = internal->glyph_matrix;
+ hinter->trans_delta = internal->glyph_delta;
+ hinter->trans_matrix = imatrix;
+
+ FT_Matrix_Invert( &imatrix );
+ FT_Vector_Transform( &hinter->trans_delta, &imatrix );
+ }
+
+ /* set linear horizontal metrics */
+ slot->linearHoriAdvance = slot->metrics.horiAdvance;
+ slot->linearVertAdvance = slot->metrics.vertAdvance;
+
+ switch ( slot->format )
+ {
+ case ft_glyph_format_outline:
+
+ /* translate glyph outline if we need to */
+ if ( hinter->transformed )
+ {
+ FT_UInt n = slot->outline.n_points;
+ FT_Vector* point = slot->outline.points;
+
+
+ for ( ; n > 0; point++, n-- )
+ {
+ point->x += hinter->trans_delta.x;
+ point->y += hinter->trans_delta.y;
+ }
+ }
+
+ /* copy the outline points in the loader's current */
+ /* extra points, which is used to keep original glyph coordinates */
+ error = ah_loader_check_points( gloader, slot->outline.n_points + 2,
+ slot->outline.n_contours );
+ if ( error )
+ goto Exit;
+
+ MEM_Copy( gloader->current.extra_points, slot->outline.points,
+ slot->outline.n_points * sizeof ( FT_Vector ) );
+
+ MEM_Copy( gloader->current.outline.contours, slot->outline.contours,
+ slot->outline.n_contours * sizeof ( short ) );
+
+ MEM_Copy( gloader->current.outline.tags, slot->outline.tags,
+ slot->outline.n_points * sizeof ( char ) );
+
+ gloader->current.outline.n_points = slot->outline.n_points;
+ gloader->current.outline.n_contours = slot->outline.n_contours;
+
+ /* compute original phantom points */
+ hinter->pp1.x = 0;
+ hinter->pp1.y = 0;
+ hinter->pp2.x = FT_MulFix( slot->metrics.horiAdvance, x_scale );
+ hinter->pp2.y = 0;
+
+ /* be sure to check for spacing glyphs */
+ if ( slot->outline.n_points == 0 )
+ goto Hint_Metrics;
+
+ /* now, load the slot image into the auto-outline, and run the */
+ /* automatic hinting process */
+ error = ah_outline_load( outline, face ); /* XXX: change to slot */
+ if ( error )
+ goto Exit;
+
+ /* perform feature detection */
+ ah_outline_detect_features( outline );
+
+ if ( !no_horz_hints )
+ {
+ ah_outline_compute_blue_edges( outline, hinter->globals );
+ ah_outline_scale_blue_edges( outline, hinter->globals );
+ }
+
+ /* perform alignment control */
+ ah_hinter_hint_edges( hinter, no_horz_hints, no_vert_hints );
+ ah_hinter_align( hinter );
+
+ /* now save the current outline into the loader's current table */
+ ah_outline_save( outline, gloader );
+
+ /* we now need to hint the metrics according to the change in */
+ /* width/positioning that occured during the hinting process */
+ {
+ FT_Pos old_advance;
+ FT_Pos old_lsb, new_lsb;
+ AH_Edge* edge1 = outline->vert_edges; /* leftmost edge */
+ AH_Edge* edge2 = edge1 +
+ outline->num_vedges - 1; /* rightmost edge */
+
+
+ old_advance = hinter->pp2.x;
+ old_lsb = edge1->opos;
+ new_lsb = edge1->pos;
+
+ hinter->pp1.x = ( ( new_lsb - old_lsb ) + 32 ) & -64;
+ hinter->pp2.x = ( ( edge2->pos +
+ ( old_advance - edge2->opos ) ) + 32 ) & -64;
+ }
+
+ /* good, we simply add the glyph to our loader's base */
+ ah_loader_add( gloader );
+ break;
+
+ case ft_glyph_format_composite:
+ {
+ FT_UInt nn, num_subglyphs = slot->num_subglyphs;
+ FT_UInt num_base_subgs, start_point;
+ FT_SubGlyph* subglyph;
+
+
+ start_point = gloader->base.outline.n_points;
+
+ /* first of all, copy the subglyph descriptors in the glyph loader */
+ error = ah_loader_check_subglyphs( gloader, num_subglyphs );
+ if ( error )
+ goto Exit;
+
+ MEM_Copy( gloader->current.subglyphs, slot->subglyphs,
+ num_subglyphs * sizeof ( FT_SubGlyph ) );
+
+ gloader->current.num_subglyphs = num_subglyphs;
+ num_base_subgs = gloader->base.num_subglyphs;
+
+ /* now, read each subglyph independently */
+ for ( nn = 0; nn < num_subglyphs; nn++ )
+ {
+ FT_Vector pp1, pp2;
+ FT_Pos x, y;
+ FT_UInt num_points, num_new_points, num_base_points;
+
+
+ /* gloader.current.subglyphs can change during glyph loading due */
+ /* to re-allocation -- we must recompute the current subglyph on */
+ /* each iteration */
+ subglyph = gloader->base.subglyphs + num_base_subgs + nn;
+
+ pp1 = hinter->pp1;
+ pp2 = hinter->pp2;
+
+ num_base_points = gloader->base.outline.n_points;
+
+ error = ah_hinter_load( hinter, subglyph->index,
+ load_flags, depth + 1 );
+ if ( error )
+ goto Exit;
+
+ /* recompute subglyph pointer */
+ subglyph = gloader->base.subglyphs + num_base_subgs + nn;
+
+ if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS )
+ {
+ pp1 = hinter->pp1;
+ pp2 = hinter->pp2;
+ }
+ else
+ {
+ hinter->pp1 = pp1;
+ hinter->pp2 = pp2;
+ }
+
+ num_points = gloader->base.outline.n_points;
+ num_new_points = num_points - num_base_points;
+
+ /* now perform the transform required for this subglyph */
+
+ if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE |
+ FT_SUBGLYPH_FLAG_XY_SCALE |
+ FT_SUBGLYPH_FLAG_2X2 ) )
+ {
+ FT_Vector* cur = gloader->base.outline.points +
+ num_base_points;
+ FT_Vector* org = gloader->base.extra_points +
+ num_base_points;
+ FT_Vector* limit = cur + num_new_points;
+
+
+ for ( ; cur < limit; cur++, org++ )
+ {
+ FT_Vector_Transform( cur, &subglyph->transform );
+ FT_Vector_Transform( org, &subglyph->transform );
+ }
+ }
+
+ /* apply offset */
+
+ if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) )
+ {
+ FT_Int k = subglyph->arg1;
+ FT_UInt l = subglyph->arg2;
+ FT_Vector* p1;
+ FT_Vector* p2;
+
+
+ if ( start_point + k >= num_base_points ||
+ l >= (FT_UInt)num_new_points )
+ {
+ error = AH_Err_Invalid_Composite;
+ goto Exit;
+ }
+
+ l += num_base_points;
+
+ /* for now, only use the current point coordinates */
+ /* we may consider another approach in the near future */
+ p1 = gloader->base.outline.points + start_point + k;
+ p2 = gloader->base.outline.points + start_point + l;
+
+ x = p1->x - p2->x;
+ y = p1->y - p2->y;
+ }
+ else
+ {
+ x = FT_MulFix( subglyph->arg1, x_scale );
+ y = FT_MulFix( subglyph->arg2, y_scale );
+
+ x = ( x + 32 ) & -64;
+ y = ( y + 32 ) & -64;
+ }
+
+ {
+ FT_Outline dummy = gloader->base.outline;
+
+
+ dummy.points += num_base_points;
+ dummy.n_points = (short)num_new_points;
+
+ FT_Outline_Translate( &dummy, x, y );
+ }
+ }
+ }
+ break;
+
+ default:
+ /* we don't support other formats (yet?) */
+ error = AH_Err_Unimplemented_Feature;
+ }
+
+ Hint_Metrics:
+ if ( depth == 0 )
+ {
+ FT_BBox bbox;
+
+
+ /* transform the hinted outline if needed */
+ if ( hinter->transformed )
+ FT_Outline_Transform( &gloader->base.outline, &hinter->trans_matrix );
+
+ /* we must translate our final outline by -pp1.x, and compute */
+ /* the new metrics */
+ if ( hinter->pp1.x )
+ FT_Outline_Translate( &gloader->base.outline, -hinter->pp1.x, 0 );
+
+ FT_Outline_Get_CBox( &gloader->base.outline, &bbox );
+ bbox.xMin &= -64;
+ bbox.yMin &= -64;
+ bbox.xMax = ( bbox.xMax + 63 ) & -64;
+ bbox.yMax = ( bbox.yMax + 63 ) & -64;
+
+ slot->metrics.width = bbox.xMax - bbox.xMin;
+ slot->metrics.height = bbox.yMax - bbox.yMin;
+ slot->metrics.horiBearingX = bbox.xMin;
+ slot->metrics.horiBearingY = bbox.yMax;
+ slot->metrics.horiAdvance = hinter->pp2.x - hinter->pp1.x;
+ /* XXX: TO DO - slot->linearHoriAdvance */
+
+ /* now copy outline into glyph slot */
+ ah_loader_rewind( slot->internal->loader );
+ error = ah_loader_copy_points( slot->internal->loader, gloader );
+ if ( error )
+ goto Exit;
+
+ slot->outline = slot->internal->loader->base.outline;
+ slot->format = ft_glyph_format_outline;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /* load and hint a given glyph */
+ FT_LOCAL_DEF FT_Error
+ ah_hinter_load_glyph( AH_Hinter* hinter,
+ FT_GlyphSlot slot,
+ FT_Size size,
+ FT_UInt glyph_index,
+ FT_Int load_flags )
+ {
+ FT_Face face = slot->face;
+ FT_Error error;
+ FT_Fixed x_scale = size->metrics.x_scale;
+ FT_Fixed y_scale = size->metrics.y_scale;
+ AH_Face_Globals* face_globals = FACE_GLOBALS( face );
+
+
+ /* first of all, we need to check that we're using the correct face and */
+ /* global hints to load the glyph */
+ if ( hinter->face != face || hinter->globals != face_globals )
+ {
+ hinter->face = face;
+ if ( !face_globals )
+ {
+ error = ah_hinter_new_face_globals( hinter, face, 0 );
+ if ( error )
+ goto Exit;
+
+ }
+ hinter->globals = FACE_GLOBALS( face );
+ face_globals = FACE_GLOBALS( face );
+
+ }
+
+ /* now, we must check the current character pixel size to see if we */
+ /* need to rescale the global metrics */
+ if ( face_globals->x_scale != x_scale ||
+ face_globals->y_scale != y_scale )
+ ah_hinter_scale_globals( hinter, x_scale, y_scale );
+
+ ah_loader_rewind( hinter->loader );
+
+#if 1
+ load_flags = FT_LOAD_NO_SCALE
+ | FT_LOAD_IGNORE_TRANSFORM ;
+#else
+ load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_RECURSE;
+#endif
+
+ error = ah_hinter_load( hinter, glyph_index, load_flags, 0 );
+
+ Exit:
+ return error;
+ }
+
+
+ /* retrieve a face's autohint globals for client applications */
+ FT_LOCAL_DEF void
+ ah_hinter_get_global_hints( AH_Hinter* hinter,
+ FT_Face face,
+ void** global_hints,
+ long* global_len )
+ {
+ AH_Globals* globals = 0;
+ FT_Memory memory = hinter->memory;
+ FT_Error error;
+
+
+ /* allocate new master globals */
+ if ( ALLOC( globals, sizeof ( *globals ) ) )
+ goto Fail;
+
+ /* compute face globals if needed */
+ if ( !FACE_GLOBALS( face ) )
+ {
+ error = ah_hinter_new_face_globals( hinter, face, 0 );
+ if ( error )
+ goto Fail;
+ }
+
+ *globals = FACE_GLOBALS( face )->design;
+ *global_hints = globals;
+ *global_len = sizeof( *globals );
+
+ return;
+
+ Fail:
+ FREE( globals );
+
+ *global_hints = 0;
+ *global_len = 0;
+ }
+
+
+ FT_LOCAL_DEF void
+ ah_hinter_done_global_hints( AH_Hinter* hinter,
+ void* global_hints )
+ {
+ FT_Memory memory = hinter->memory;
+
+
+ FREE( global_hints );
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ahmodule.c */
+/* */
+/* Auto-hinting module implementation (declaration). */
+/* */
+/* Copyright 2000-2001 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_MODULE_H
+#include "ahhint.h"
+
+
+ typedef struct FT_AutoHinterRec_
+ {
+ FT_ModuleRec root;
+ AH_Hinter* hinter;
+
+ } FT_AutoHinterRec;
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ft_autohinter_init( FT_AutoHinter module )
+ {
+ return ah_hinter_new( module->root.library, &module->hinter );
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ ft_autohinter_done( FT_AutoHinter module )
+ {
+ ah_hinter_done( module->hinter );
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ft_autohinter_load( FT_AutoHinter module,
+ FT_GlyphSlot slot,
+ FT_Size size,
+ FT_UInt glyph_index,
+ FT_ULong load_flags )
+ {
+ return ah_hinter_load_glyph( module->hinter,
+ slot, size, glyph_index, load_flags );
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ ft_autohinter_reset( FT_AutoHinter module,
+ FT_Face face )
+ {
+ UNUSED( module );
+
+ if ( face->autohint.data )
+ ah_hinter_done_face_globals( (AH_Face_Globals*)(face->autohint.data) );
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ ft_autohinter_get_globals( FT_AutoHinter module,
+ FT_Face face,
+ void** global_hints,
+ long* global_len )
+ {
+ ah_hinter_get_global_hints( module->hinter, face,
+ global_hints, global_len );
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ ft_autohinter_done_globals( FT_AutoHinter module,
+ void* global_hints )
+ {
+ ah_hinter_done_global_hints( module->hinter, global_hints );
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_AutoHinter_Interface autohinter_interface =
+ {
+ ft_autohinter_reset,
+ ft_autohinter_load,
+ ft_autohinter_get_globals,
+ ft_autohinter_done_globals
+ };
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Module_Class autohint_module_class =
+ {
+ ft_module_hinter,
+ sizeof ( FT_AutoHinterRec ),
+
+ "autohinter",
+ 0x10000L, /* version 1.0 of the autohinter */
+ 0x20000L, /* requires FreeType 2.0 or above */
+
+ (const void*)&autohinter_interface,
+
+ (FT_Module_Constructor)ft_autohinter_init,
+ (FT_Module_Destructor) ft_autohinter_done,
+ (FT_Module_Requester) 0
+ };
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ahoptim.c */
+/* */
+/* FreeType auto hinting outline optimization (body). */
+/* */
+/* Copyright 2000-2001 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This module is in charge of optimising the outlines produced by the */
+ /* auto-hinter in direct mode. This is required at small pixel sizes in */
+ /* order to ensure coherent spacing, among other things.. */
+ /* */
+ /* The technique used in this module is a simplified simulated */
+ /* annealing. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H /* for ALLOC_ARRAY() and FREE() */
+#include "ahoptim.h"
+
+
+ /* define this macro to use brute force optimisation -- this is slow, */
+ /* but a good way to perfect the distortion function `by hand' through */
+ /* tweaking */
+#define AH_BRUTE_FORCE
+
+
+#define xxxAH_DEBUG_OPTIM
+
+
+#undef LOG
+#ifdef AH_DEBUG_OPTIM
+
+#define LOG( x ) optim_log ## x
+
+#else
+
+#define LOG( x )
+
+#endif /* AH_DEBUG_OPTIM */
+
+
+#ifdef AH_DEBUG_OPTIM
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define FLOAT( x ) ( (float)( (x) / 64.0 ) )
+
+ static void
+ optim_log( const char* fmt, ... )
+ {
+ va_list ap;
+
+
+ va_start( ap, fmt );
+ vprintf( fmt, ap );
+ va_end( ap );
+ }
+
+
+ static void
+ AH_Dump_Stems( AH_Optimizer* optimizer )
+ {
+ int n;
+ AH_Stem* stem;
+
+
+ stem = optimizer->stems;
+ for ( n = 0; n < optimizer->num_stems; n++, stem++ )
+ {
+ LOG(( " %c%2d [%.1f:%.1f]={%.1f:%.1f}="
+ "<%1.f..%1.f> force=%.1f speed=%.1f\n",
+ optimizer->vertical ? 'V' : 'H', n,
+ FLOAT( stem->edge1->opos ), FLOAT( stem->edge2->opos ),
+ FLOAT( stem->edge1->pos ), FLOAT( stem->edge2->pos ),
+ FLOAT( stem->min_pos ), FLOAT( stem->max_pos ),
+ FLOAT( stem->force ), FLOAT( stem->velocity ) ));
+ }
+ }
+
+
+ static void
+ AH_Dump_Stems2( AH_Optimizer* optimizer )
+ {
+ int n;
+ AH_Stem* stem;
+
+
+ stem = optimizer->stems;
+ for ( n = 0; n < optimizer->num_stems; n++, stem++ )
+ {
+ LOG(( " %c%2d [%.1f]=<%1.f..%1.f> force=%.1f speed=%.1f\n",
+ optimizer->vertical ? 'V' : 'H', n,
+ FLOAT( stem->pos ),
+ FLOAT( stem->min_pos ), FLOAT( stem->max_pos ),
+ FLOAT( stem->force ), FLOAT( stem->velocity ) ));
+ }
+ }
+
+
+ static void
+ AH_Dump_Springs( AH_Optimizer* optimizer )
+ {
+ int n;
+ AH_Spring* spring;
+ AH_Stem* stems;
+
+
+ spring = optimizer->springs;
+ stems = optimizer->stems;
+ LOG(( "%cSprings ", optimizer->vertical ? 'V' : 'H' ));
+
+ for ( n = 0; n < optimizer->num_springs; n++, spring++ )
+ {
+ LOG(( " [%d-%d:%.1f:%1.f:%.1f]",
+ spring->stem1 - stems, spring->stem2 - stems,
+ FLOAT( spring->owidth ),
+ FLOAT( spring->stem2->pos -
+ ( spring->stem1->pos + spring->stem1->width ) ),
+ FLOAT( spring->tension ) ));
+ }
+
+ LOG(( "\n" ));
+ }
+
+#endif /* AH_DEBUG_OPTIM */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** COMPUTE STEMS AND SPRINGS IN AN OUTLINE ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ static int
+ valid_stem_segments( AH_Segment* seg1,
+ AH_Segment* seg2 )
+ {
+ return seg1->serif == 0 &&
+ seg2 &&
+ seg2->link == seg1 &&
+ seg1->pos < seg2->pos &&
+ seg1->min_coord <= seg2->max_coord &&
+ seg2->min_coord <= seg1->max_coord;
+ }
+
+
+ /* compute all stems in an outline */
+ static int
+ optim_compute_stems( AH_Optimizer* optimizer )
+ {
+ AH_Outline* outline = optimizer->outline;
+ FT_Fixed scale;
+ FT_Memory memory = optimizer->memory;
+ FT_Error error = 0;
+ FT_Int dimension;
+ AH_Edge* edges;
+ AH_Edge* edge_limit;
+ AH_Stem** p_stems;
+ FT_Int* p_num_stems;
+
+
+ edges = outline->horz_edges;
+ edge_limit = edges + outline->num_hedges;
+ scale = outline->y_scale;
+
+ p_stems = &optimizer->horz_stems;
+ p_num_stems = &optimizer->num_hstems;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AH_Stem* stems = 0;
+ FT_Int num_stems = 0;
+ AH_Edge* edge;
+
+
+ /* first of all, count the number of stems in this direction */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ AH_Segment* seg = edge->first;
+
+
+ do
+ {
+ if (valid_stem_segments( seg, seg->link ) )
+ num_stems++;
+
+ seg = seg->edge_next;
+
+ } while ( seg != edge->first );
+ }
+
+ /* now allocate the stems and build their table */
+ if ( num_stems > 0 )
+ {
+ AH_Stem* stem;
+
+
+ if ( ALLOC_ARRAY( stems, num_stems, AH_Stem ) )
+ goto Exit;
+
+ stem = stems;
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ AH_Segment* seg = edge->first;
+ AH_Segment* seg2;
+
+
+ do
+ {
+ seg2 = seg->link;
+ if ( valid_stem_segments( seg, seg2 ) )
+ {
+ AH_Edge* edge1 = seg->edge;
+ AH_Edge* edge2 = seg2->edge;
+
+
+ stem->edge1 = edge1;
+ stem->edge2 = edge2;
+ stem->opos = edge1->opos;
+ stem->pos = edge1->pos;
+ stem->owidth = edge2->opos - edge1->opos;
+ stem->width = edge2->pos - edge1->pos;
+
+ /* compute min_coord and max_coord */
+ {
+ FT_Pos min_coord = seg->min_coord;
+ FT_Pos max_coord = seg->max_coord;
+
+
+ if ( seg2->min_coord > min_coord )
+ min_coord = seg2->min_coord;
+
+ if ( seg2->max_coord < max_coord )
+ max_coord = seg2->max_coord;
+
+ stem->min_coord = min_coord;
+ stem->max_coord = max_coord;
+ }
+
+ /* compute minimum and maximum positions for stem -- */
+ /* note that the left-most/bottom-most stem has always */
+ /* a fixed position */
+ if ( stem == stems || edge1->blue_edge || edge2->blue_edge )
+ {
+ /* this stem cannot move; it is snapped to a blue edge */
+ stem->min_pos = stem->pos;
+ stem->max_pos = stem->pos;
+ }
+ else
+ {
+ /* this edge can move; compute its min and max positions */
+ FT_Pos pos1 = stem->opos;
+ FT_Pos pos2 = pos1 + stem->owidth - stem->width;
+ FT_Pos min1 = pos1 & -64;
+ FT_Pos min2 = pos2 & -64;
+
+
+ stem->min_pos = min1;
+ stem->max_pos = min1 + 64;
+ if ( min2 < min1 )
+ stem->min_pos = min2;
+ else
+ stem->max_pos = min2 + 64;
+
+ /* XXX: just to see what it does */
+ stem->max_pos += 64;
+
+ /* just for the case where direct hinting did some */
+ /* incredible things (e.g. blue edge shifts) */
+ if ( stem->min_pos > stem->pos )
+ stem->min_pos = stem->pos;
+
+ if ( stem->max_pos < stem->pos )
+ stem->max_pos = stem->pos;
+ }
+
+ stem->velocity = 0;
+ stem->force = 0;
+
+ stem++;
+ }
+ seg = seg->edge_next;
+
+ } while ( seg != edge->first );
+ }
+ }
+
+ *p_stems = stems;
+ *p_num_stems = num_stems;
+
+ edges = outline->vert_edges;
+ edge_limit = edges + outline->num_vedges;
+ scale = outline->x_scale;
+
+ p_stems = &optimizer->vert_stems;
+ p_num_stems = &optimizer->num_vstems;
+ }
+
+ Exit:
+
+#ifdef AH_DEBUG_OPTIM
+ AH_Dump_Stems( optimizer );
+#endif
+
+ return error;
+ }
+
+
+ /* returns the spring area between two stems, 0 if none */
+ static FT_Pos
+ stem_spring_area( AH_Stem* stem1,
+ AH_Stem* stem2 )
+ {
+ FT_Pos area1 = stem1->max_coord - stem1->min_coord;
+ FT_Pos area2 = stem2->max_coord - stem2->min_coord;
+ FT_Pos min = stem1->min_coord;
+ FT_Pos max = stem1->max_coord;
+ FT_Pos area;
+
+
+ /* order stems */
+ if ( stem2->opos <= stem1->opos + stem1->owidth )
+ return 0;
+
+ if ( min < stem2->min_coord )
+ min = stem2->min_coord;
+
+ if ( max < stem2->max_coord )
+ max = stem2->max_coord;
+
+ area = ( max-min );
+ if ( 2 * area < area1 && 2 * area < area2 )
+ area = 0;
+
+ return area;
+ }
+
+
+ /* compute all springs in an outline */
+ static int
+ optim_compute_springs( AH_Optimizer* optimizer )
+ {
+ /* basically, a spring exists between two stems if most of their */
+ /* surface is aligned */
+ FT_Memory memory = optimizer->memory;
+
+ AH_Stem* stems;
+ AH_Stem* stem_limit;
+ AH_Stem* stem;
+ int dimension;
+ int error = 0;
+
+ FT_Int* p_num_springs;
+ AH_Spring** p_springs;
+
+
+ stems = optimizer->horz_stems;
+ stem_limit = stems + optimizer->num_hstems;
+
+ p_springs = &optimizer->horz_springs;
+ p_num_springs = &optimizer->num_hsprings;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ FT_Int num_springs = 0;
+ AH_Spring* springs = 0;
+
+
+ /* first of all, count stem springs */
+ for ( stem = stems; stem + 1 < stem_limit; stem++ )
+ {
+ AH_Stem* stem2;
+
+
+ for ( stem2 = stem+1; stem2 < stem_limit; stem2++ )
+ if ( stem_spring_area( stem, stem2 ) )
+ num_springs++;
+ }
+
+ /* then allocate and build the springs table */
+ if ( num_springs > 0 )
+ {
+ AH_Spring* spring;
+
+
+ /* allocate table of springs */
+ if ( ALLOC_ARRAY( springs, num_springs, AH_Spring ) )
+ goto Exit;
+
+ /* fill the springs table */
+ spring = springs;
+ for ( stem = stems; stem+1 < stem_limit; stem++ )
+ {
+ AH_Stem* stem2;
+ FT_Pos area;
+
+
+ for ( stem2 = stem + 1; stem2 < stem_limit; stem2++ )
+ {
+ area = stem_spring_area( stem, stem2 );
+ if ( area )
+ {
+ /* add a new spring here */
+ spring->stem1 = stem;
+ spring->stem2 = stem2;
+ spring->owidth = stem2->opos - ( stem->opos + stem->owidth );
+ spring->tension = 0;
+
+ spring++;
+ }
+ }
+ }
+ }
+ *p_num_springs = num_springs;
+ *p_springs = springs;
+
+ stems = optimizer->vert_stems;
+ stem_limit = stems + optimizer->num_vstems;
+
+ p_springs = &optimizer->vert_springs;
+ p_num_springs = &optimizer->num_vsprings;
+ }
+
+ Exit:
+
+#ifdef AH_DEBUG_OPTIM
+ AH_Dump_Springs( optimizer );
+#endif
+
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** OPTIMIZE THROUGH MY STRANGE SIMULATED ANNEALING ALGO ;-) ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+#ifndef AH_BRUTE_FORCE
+
+ /* compute all spring tensions */
+ static void
+ optim_compute_tensions( AH_Optimizer* optimizer )
+ {
+ AH_Spring* spring = optimizer->springs;
+ AH_Spring* limit = spring + optimizer->num_springs;
+
+
+ for ( ; spring < limit; spring++ )
+ {
+ AH_Stem* stem1 = spring->stem1;
+ AH_Stem* stem2 = spring->stem2;
+ FT_Int status;
+
+ FT_Pos width;
+ FT_Pos tension;
+ FT_Pos sign;
+
+
+ /* compute the tension; it simply is -K*(new_width-old_width) */
+ width = stem2->pos - ( stem1->pos + stem1->width );
+ tension = width - spring->owidth;
+
+ sign = 1;
+ if ( tension < 0 )
+ {
+ sign = -1;
+ tension = -tension;
+ }
+
+ if ( width <= 0 )
+ tension = 32000;
+ else
+ tension = ( tension << 10 ) / width;
+
+ tension = -sign * FT_MulFix( tension, optimizer->tension_scale );
+ spring->tension = tension;
+
+ /* now, distribute tension among the englobing stems, if they */
+ /* are able to move */
+ status = 0;
+ if ( stem1->pos <= stem1->min_pos )
+ status |= 1;
+ if ( stem2->pos >= stem2->max_pos )
+ status |= 2;
+
+ if ( !status )
+ tension /= 2;
+
+ if ( ( status & 1 ) == 0 )
+ stem1->force -= tension;
+
+ if ( ( status & 2 ) == 0 )
+ stem2->force += tension;
+ }
+ }
+
+
+ /* compute all stem movements -- returns 0 if nothing moved */
+ static int
+ optim_compute_stem_movements( AH_Optimizer* optimizer )
+ {
+ AH_Stem* stems = optimizer->stems;
+ AH_Stem* limit = stems + optimizer->num_stems;
+ AH_Stem* stem = stems;
+ int moved = 0;
+
+
+ /* set initial forces to velocity */
+ for ( stem = stems; stem < limit; stem++ )
+ {
+ stem->force = stem->velocity;
+ stem->velocity /= 2; /* XXX: Heuristics */
+ }
+
+ /* compute the sum of forces applied on each stem */
+ optim_compute_tensions( optimizer );
+
+#ifdef AH_DEBUG_OPTIM
+ AH_Dump_Springs( optimizer );
+ AH_Dump_Stems2( optimizer );
+#endif
+
+ /* now, see whether something can move */
+ for ( stem = stems; stem < limit; stem++ )
+ {
+ if ( stem->force > optimizer->tension_threshold )
+ {
+ /* there is enough tension to move the stem to the right */
+ if ( stem->pos < stem->max_pos )
+ {
+ stem->pos += 64;
+ stem->velocity = stem->force / 2;
+ moved = 1;
+ }
+ else
+ stem->velocity = 0;
+ }
+ else if ( stem->force < optimizer->tension_threshold )
+ {
+ /* there is enough tension to move the stem to the left */
+ if ( stem->pos > stem->min_pos )
+ {
+ stem->pos -= 64;
+ stem->velocity = stem->force / 2;
+ moved = 1;
+ }
+ else
+ stem->velocity = 0;
+ }
+ }
+
+ /* return 0 if nothing moved */
+ return moved;
+ }
+
+#endif /* AH_BRUTE_FORCE */
+
+
+ /* compute current global distortion from springs */
+ static FT_Pos
+ optim_compute_distortion( AH_Optimizer* optimizer )
+ {
+ AH_Spring* spring = optimizer->springs;
+ AH_Spring* limit = spring + optimizer->num_springs;
+ FT_Pos distortion = 0;
+
+
+ for ( ; spring < limit; spring++ )
+ {
+ AH_Stem* stem1 = spring->stem1;
+ AH_Stem* stem2 = spring->stem2;
+ FT_Pos width;
+
+ width = stem2->pos - ( stem1->pos + stem1->width );
+ width -= spring->owidth;
+ if ( width < 0 )
+ width = -width;
+
+ distortion += width;
+ }
+
+ return distortion;
+ }
+
+
+ /* record stems configuration in `best of' history */
+ static void
+ optim_record_configuration( AH_Optimizer* optimizer )
+ {
+ FT_Pos distortion;
+ AH_Configuration* configs = optimizer->configs;
+ AH_Configuration* limit = configs + optimizer->num_configs;
+ AH_Configuration* config;
+
+
+ distortion = optim_compute_distortion( optimizer );
+ LOG(( "config distortion = %.1f ", FLOAT( distortion * 64 ) ));
+
+ /* check that we really need to add this configuration to our */
+ /* sorted history */
+ if ( limit > configs && limit[-1].distortion < distortion )
+ {
+ LOG(( "ejected\n" ));
+ return;
+ }
+
+ /* add new configuration at the end of the table */
+ {
+ int n;
+
+
+ config = limit;
+ if ( optimizer->num_configs < AH_MAX_CONFIGS )
+ optimizer->num_configs++;
+ else
+ config--;
+
+ config->distortion = distortion;
+
+ for ( n = 0; n < optimizer->num_stems; n++ )
+ config->positions[n] = optimizer->stems[n].pos;
+ }
+
+ /* move the current configuration towards the front of the list */
+ /* when necessary -- yes this is slow bubble sort ;-) */
+ while ( config > configs && config[0].distortion < config[-1].distortion )
+ {
+ AH_Configuration temp;
+
+
+ config--;
+ temp = config[0];
+ config[0] = config[1];
+ config[1] = temp;
+ }
+ LOG(( "recorded!\n" ));
+ }
+
+
+#ifdef AH_BRUTE_FORCE
+
+ /* optimize outline in a single direction */
+ static void
+ optim_compute( AH_Optimizer* optimizer )
+ {
+ int n;
+ FT_Bool moved;
+
+ AH_Stem* stem = optimizer->stems;
+ AH_Stem* limit = stem + optimizer->num_stems;
+
+
+ /* empty, exit */
+ if ( stem >= limit )
+ return;
+
+ optimizer->num_configs = 0;
+
+ stem = optimizer->stems;
+ for ( ; stem < limit; stem++ )
+ stem->pos = stem->min_pos;
+
+ do
+ {
+ /* record current configuration */
+ optim_record_configuration( optimizer );
+
+ /* now change configuration */
+ moved = 0;
+ for ( stem = optimizer->stems; stem < limit; stem++ )
+ {
+ if ( stem->pos < stem->max_pos )
+ {
+ stem->pos += 64;
+ moved = 1;
+ break;
+ }
+
+ stem->pos = stem->min_pos;
+ }
+ } while ( moved );
+
+ /* now, set the best stem positions */
+ for ( n = 0; n < optimizer->num_stems; n++ )
+ {
+ AH_Stem* stem = optimizer->stems + n;
+ FT_Pos pos = optimizer->configs[0].positions[n];
+
+
+ stem->edge1->pos = pos;
+ stem->edge2->pos = pos + stem->width;
+
+ stem->edge1->flags |= ah_edge_done;
+ stem->edge2->flags |= ah_edge_done;
+ }
+ }
+
+#else /* AH_BRUTE_FORCE */
+
+ /* optimize outline in a single direction */
+ static void
+ optim_compute( AH_Optimizer* optimizer )
+ {
+ int n, counter, counter2;
+
+
+ optimizer->num_configs = 0;
+ optimizer->tension_scale = 0x80000L;
+ optimizer->tension_threshold = 64;
+
+ /* record initial configuration threshold */
+ optim_record_configuration( optimizer );
+
+ counter = 0;
+ for ( counter2 = optimizer->num_stems*8; counter2 >= 0; counter2-- )
+ {
+ if ( counter == 0 )
+ counter = 2 * optimizer->num_stems;
+
+ if ( !optim_compute_stem_movements( optimizer ) )
+ break;
+
+ optim_record_configuration( optimizer );
+
+ counter--;
+ if ( counter == 0 )
+ optimizer->tension_scale /= 2;
+ }
+
+ /* now, set the best stem positions */
+ for ( n = 0; n < optimizer->num_stems; n++ )
+ {
+ AH_Stem* stem = optimizer->stems + n;
+ FT_Pos pos = optimizer->configs[0].positions[n];
+
+
+ stem->edge1->pos = pos;
+ stem->edge2->pos = pos + stem->width;
+
+ stem->edge1->flags |= ah_edge_done;
+ stem->edge2->flags |= ah_edge_done;
+ }
+ }
+
+#endif /* AH_BRUTE_FORCE */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** HIGH-LEVEL OPTIMIZER API ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* releases the optimization data */
+ void
+ AH_Optimizer_Done( AH_Optimizer* optimizer )
+ {
+ if ( optimizer )
+ {
+ FT_Memory memory = optimizer->memory;
+
+
+ FREE( optimizer->horz_stems );
+ FREE( optimizer->vert_stems );
+ FREE( optimizer->horz_springs );
+ FREE( optimizer->vert_springs );
+ FREE( optimizer->positions );
+ }
+ }
+
+
+ /* loads the outline into the optimizer */
+ int
+ AH_Optimizer_Init( AH_Optimizer* optimizer,
+ AH_Outline* outline,
+ FT_Memory memory )
+ {
+ FT_Error error;
+
+
+ MEM_Set( optimizer, 0, sizeof ( *optimizer ) );
+ optimizer->outline = outline;
+ optimizer->memory = memory;
+
+ LOG(( "initializing new optimizer\n" ));
+ /* compute stems and springs */
+ error = optim_compute_stems ( optimizer ) ||
+ optim_compute_springs( optimizer );
+ if ( error )
+ goto Fail;
+
+ /* allocate stem positions history and configurations */
+ {
+ int n, max_stems;
+
+
+ max_stems = optimizer->num_hstems;
+ if ( max_stems < optimizer->num_vstems )
+ max_stems = optimizer->num_vstems;
+
+ if ( ALLOC_ARRAY( optimizer->positions,
+ max_stems * AH_MAX_CONFIGS, FT_Pos ) )
+ goto Fail;
+
+ optimizer->num_configs = 0;
+ for ( n = 0; n < AH_MAX_CONFIGS; n++ )
+ optimizer->configs[n].positions = optimizer->positions +
+ n * max_stems;
+ }
+
+ return error;
+
+ Fail:
+ AH_Optimizer_Done( optimizer );
+ return error;
+ }
+
+
+ /* compute optimal outline */
+ void
+ AH_Optimizer_Compute( AH_Optimizer* optimizer )
+ {
+ optimizer->num_stems = optimizer->num_hstems;
+ optimizer->stems = optimizer->horz_stems;
+ optimizer->num_springs = optimizer->num_hsprings;
+ optimizer->springs = optimizer->horz_springs;
+
+ if ( optimizer->num_springs > 0 )
+ {
+ LOG(( "horizontal optimization ------------------------\n" ));
+ optim_compute( optimizer );
+ }
+
+ optimizer->num_stems = optimizer->num_vstems;
+ optimizer->stems = optimizer->vert_stems;
+ optimizer->num_springs = optimizer->num_vsprings;
+ optimizer->springs = optimizer->vert_springs;
+
+ if ( optimizer->num_springs )
+ {
+ LOG(( "vertical optimization --------------------------\n" ));
+ optim_compute( optimizer );
+ }
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* autohint.c */
+/* */
+/* Automatic Hinting wrapper (body only). */
+/* */
+/* Copyright 2000-2001 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "ahangles.c"
+#include "ahglyph.c"
+#include "ahglobal.c"
+#include "ahhint.c"
+#include "ahmodule.c"
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cff.c */
+/* */
+/* FreeType OpenType driver component (body only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "cffdrivr.c"
+#include "cffparse.c"
+#include "cffload.c"
+#include "cffobjs.c"
+#include "cffgload.c"
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cffdrivr.c */
+/* */
+/* OpenType font driver implementation (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_SFNT_H
+#include FT_TRUETYPE_IDS_H
+
+#include "cffdrivr.h"
+#include "cffgload.h"
+#include "cffload.h"
+
+#include "cfferrs.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cffdriver
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** F A C E S ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#undef PAIR_TAG
+#define PAIR_TAG( left, right ) ( ( (FT_ULong)left << 16 ) | \
+ (FT_ULong)right )
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Get_Kerning */
+ /* */
+ /* <Description> */
+ /* A driver method used to return the kerning vector between two */
+ /* glyphs of the same face. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* left_glyph :: The index of the left glyph in the kern pair. */
+ /* */
+ /* right_glyph :: The index of the right glyph in the kern pair. */
+ /* */
+ /* <Output> */
+ /* kerning :: The kerning vector. This is in font units for */
+ /* scalable formats, and in pixels for fixed-sizes */
+ /* formats. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Only horizontal layouts (left-to-right & right-to-left) are */
+ /* supported by this function. Other layouts, or more sophisticated */
+ /* kernings, are out of scope of this method (the basic driver */
+ /* interface is meant to be simple). */
+ /* */
+ /* They can be implemented by format-specific interfaces. */
+ /* */
+ static FT_Error
+ Get_Kerning( TT_Face face,
+ FT_UInt left_glyph,
+ FT_UInt right_glyph,
+ FT_Vector* kerning )
+ {
+ TT_Kern_0_Pair* pair;
+
+
+ if ( !face )
+ return CFF_Err_Invalid_Face_Handle;
+
+ kerning->x = 0;
+ kerning->y = 0;
+
+ if ( face->kern_pairs )
+ {
+ /* there are some kerning pairs in this font file! */
+ FT_ULong search_tag = PAIR_TAG( left_glyph, right_glyph );
+ FT_Long left, right;
+
+
+ left = 0;
+ right = face->num_kern_pairs - 1;
+
+ while ( left <= right )
+ {
+ FT_Int middle = left + ( ( right - left ) >> 1 );
+ FT_ULong cur_pair;
+
+
+ pair = face->kern_pairs + middle;
+ cur_pair = PAIR_TAG( pair->left, pair->right );
+
+ if ( cur_pair == search_tag )
+ goto Found;
+
+ if ( cur_pair < search_tag )
+ left = middle + 1;
+ else
+ right = middle - 1;
+ }
+ }
+
+ Exit:
+ return CFF_Err_Ok;
+
+ Found:
+ kerning->x = pair->value;
+ goto Exit;
+ }
+
+
+#undef PAIR_TAG
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Load_Glyph */
+ /* */
+ /* <Description> */
+ /* A driver method used to load a glyph within a given glyph slot. */
+ /* */
+ /* <Input> */
+ /* slot :: A handle to the target slot object where the glyph */
+ /* will be loaded. */
+ /* */
+ /* size :: A handle to the source face size at which the glyph */
+ /* must be scaled, loaded, etc. */
+ /* */
+ /* glyph_index :: The index of the glyph in the font file. */
+ /* */
+ /* load_flags :: A flag indicating what to load for this glyph. The */
+ /* FTLOAD_??? constants can be used to control the */
+ /* glyph loading process (e.g., whether the outline */
+ /* should be scaled, whether to load bitmaps or not, */
+ /* whether to hint the outline, etc). */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ Load_Glyph( CFF_GlyphSlot slot,
+ CFF_Size size,
+ FT_UShort glyph_index,
+ FT_UInt load_flags )
+ {
+ FT_Error error;
+
+
+ if ( !slot )
+ return CFF_Err_Invalid_Slot_Handle;
+
+ /* check whether we want a scaled outline or bitmap */
+ if ( !size )
+ load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+
+ if ( load_flags & FT_LOAD_NO_SCALE )
+ size = NULL;
+
+ /* reset the size object if necessary */
+ if ( size )
+ {
+ /* these two object must have the same parent */
+ if ( size->face != slot->root.face )
+ return CFF_Err_Invalid_Face_Handle;
+ }
+
+ /* now load the glyph outline if necessary */
+ error = CFF_Load_Glyph( slot, size, glyph_index, load_flags );
+
+ /* force drop-out mode to 2 - irrelevant now */
+ /* slot->outline.dropout_mode = 2; */
+
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** C H A R A C T E R M A P P I N G S ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static FT_Error
+ cff_get_glyph_name( CFF_Face face,
+ FT_UInt glyph_index,
+ FT_Pointer buffer,
+ FT_UInt buffer_max )
+ {
+ CFF_Font* font = (CFF_Font*)face->extra.data;
+ FT_Memory memory = FT_FACE_MEMORY(face);
+ FT_String* gname;
+ FT_UShort sid;
+ PSNames_Interface* psnames;
+ FT_Error error;
+
+ psnames = (PSNames_Interface*)FT_Get_Module_Interface(
+ face->root.driver->root.library, "psnames" );
+
+ if ( !psnames )
+ {
+ FT_ERROR(( "CFF_Init_Face:" ));
+ FT_ERROR(( " cannot open CFF & CEF fonts\n" ));
+ FT_ERROR(( " " ));
+ FT_ERROR(( " without the `PSNames' module\n" ));
+ error = CFF_Err_Unknown_File_Format;
+ goto Exit;
+ }
+
+ /* first, locate the sid in the charset table */
+ sid = font->charset.sids[glyph_index];
+
+ /* now, lookup the name itself */
+ gname = CFF_Get_String( &font->string_index, sid, psnames );
+
+ if ( buffer_max > 0 )
+ {
+ FT_UInt len = strlen( gname );
+
+
+ if ( len >= buffer_max )
+ len = buffer_max - 1;
+
+ MEM_Copy( buffer, gname, len );
+ ((FT_Byte*)buffer)[len] = 0;
+ }
+
+ FREE ( gname );
+ error = CFF_Err_Ok;
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* cff_get_char_index */
+ /* */
+ /* <Description> */
+ /* Uses a charmap to return a given character code's glyph index. */
+ /* */
+ /* <Input> */
+ /* charmap :: A handle to the source charmap object. */
+ /* charcode :: The character code. */
+ /* */
+ /* <Return> */
+ /* Glyph index. 0 means `undefined character code'. */
+ /* */
+ static FT_UInt
+ cff_get_char_index( TT_CharMap charmap,
+ FT_Long charcode )
+ {
+ FT_Error error;
+ CFF_Face face;
+ TT_CMapTable* cmap;
+
+
+ cmap = &charmap->cmap;
+ face = (CFF_Face)charmap->root.face;
+
+ /* Load table if needed */
+ if ( !cmap->loaded )
+ {
+ SFNT_Interface* sfnt = (SFNT_Interface*)face->sfnt;
+
+
+ error = sfnt->load_charmap( face, cmap, face->root.stream );
+ if ( error )
+ return 0;
+
+ cmap->loaded = TRUE;
+ }
+
+ return ( cmap->get_index ? cmap->get_index( cmap, charcode ) : 0 );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* cff_get_name_index */
+ /* */
+ /* <Description> */
+ /* Uses the psnames module and the CFF font's charset to to return a */
+ /* a given glyph name's glyph index. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* glyph_name :: The glyph name. */
+ /* */
+ /* <Return> */
+ /* Glyph index. 0 means `undefined character code'. */
+ /* */
+ static FT_UInt
+ cff_get_name_index( CFF_Face face,
+ FT_String* glyph_name )
+ {
+ CFF_Font* cff;
+ CFF_Charset* charset;
+ PSNames_Interface* psnames;
+ FT_String* name;
+ FT_UShort sid;
+ FT_UInt i;
+
+
+ cff = face->extra.data;
+ charset = &cff->charset;
+
+ psnames = (PSNames_Interface*)FT_Get_Module_Interface(
+ face->root.driver->root.library, "psnames" );
+
+ for ( i = 0; i < cff->num_glyphs; i++ )
+ {
+ sid = charset->sids[i];
+
+ if ( sid > 390 )
+ name = CFF_Get_Name( &cff->string_index, sid - 391 );
+ else
+ name = (FT_String *)psnames->adobe_std_strings( sid );
+
+ if ( !strcmp( glyph_name, name ) )
+ return i;
+ }
+
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** D R I V E R I N T E R F A C E ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static FT_Module_Interface
+ cff_get_interface( CFF_Driver driver,
+ const char* interface )
+ {
+ FT_Module sfnt;
+
+#ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES
+
+ if ( strcmp( (const char*)interface, "glyph_name" ) == 0 )
+ return (FT_Module_Interface)cff_get_glyph_name;
+
+ if ( strcmp( (const char*)interface, "name_index" ) == 0 )
+ return (FT_Module_Interface)cff_get_name_index;
+
+#endif
+
+ /* we simply pass our request to the `sfnt' module */
+ sfnt = FT_Get_Module( driver->root.root.library, "sfnt" );
+
+ return sfnt ? sfnt->clazz->get_interface( sfnt, interface ) : 0;
+ }
+
+
+ /* The FT_DriverInterface structure is defined in ftdriver.h. */
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Driver_Class cff_driver_class =
+ {
+ /* begin with the FT_Module_Class fields */
+ {
+ ft_module_font_driver | ft_module_driver_scalable,
+ sizeof( CFF_DriverRec ),
+ "cff",
+ 0x10000L,
+ 0x20000L,
+
+ 0, /* module-specific interface */
+
+ (FT_Module_Constructor)CFF_Init_Driver,
+ (FT_Module_Destructor) CFF_Done_Driver,
+ (FT_Module_Requester) cff_get_interface,
+ },
+
+ /* now the specific driver fields */
+ sizeof( TT_FaceRec ),
+ sizeof( FT_SizeRec ),
+ sizeof( CFF_GlyphSlotRec ),
+
+ (FTDriver_initFace) CFF_Init_Face,
+ (FTDriver_doneFace) CFF_Done_Face,
+ (FTDriver_initSize) 0,
+ (FTDriver_doneSize) 0,
+ (FTDriver_initGlyphSlot)0,
+ (FTDriver_doneGlyphSlot)0,
+
+ (FTDriver_setCharSizes) 0,
+ (FTDriver_setPixelSizes)0,
+
+ (FTDriver_loadGlyph) Load_Glyph,
+ (FTDriver_getCharIndex) cff_get_char_index,
+
+ (FTDriver_getKerning) Get_Kerning,
+ (FTDriver_attachFile) 0,
+ (FTDriver_getAdvances) 0
+ };
+
+
+#ifdef FT_CONFIG_OPTION_DYNAMIC_DRIVERS
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* getDriverClass */
+ /* */
+ /* <Description> */
+ /* This function is used when compiling the TrueType driver as a */
+ /* shared library (`.DLL' or `.so'). It will be used by the */
+ /* high-level library of FreeType to retrieve the address of the */
+ /* driver's generic interface. */
+ /* */
+ /* It shouldn't be implemented in a static build, as each driver must */
+ /* have the same function as an exported entry point. */
+ /* */
+ /* <Return> */
+ /* The address of the TrueType's driver generic interface. The */
+ /* format-specific interface can then be retrieved through the method */
+ /* interface->get_format_interface. */
+ /* */
+ FT_EXPORT_DEF( const FT_Driver_Class* )
+ getDriverClass( void )
+ {
+ return &cff_driver_class;
+ }
+
+
+#endif /* CONFIG_OPTION_DYNAMIC_DRIVERS */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cffgload.c */
+/* */
+/* OpenType Glyph Loader (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_SFNT_H
+#include FT_OUTLINE_H
+#include FT_TRUETYPE_TAGS_H
+
+#include "cffload.h"
+#include "cffgload.h"
+
+#include "cfferrs.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cffgload
+
+
+ typedef enum CFF_Operator_
+ {
+ cff_op_unknown = 0,
+
+ cff_op_rmoveto,
+ cff_op_hmoveto,
+ cff_op_vmoveto,
+
+ cff_op_rlineto,
+ cff_op_hlineto,
+ cff_op_vlineto,
+
+ cff_op_rrcurveto,
+ cff_op_hhcurveto,
+ cff_op_hvcurveto,
+ cff_op_rcurveline,
+ cff_op_rlinecurve,
+ cff_op_vhcurveto,
+ cff_op_vvcurveto,
+
+ cff_op_flex,
+ cff_op_hflex,
+ cff_op_hflex1,
+ cff_op_flex1,
+
+ cff_op_endchar,
+
+ cff_op_hstem,
+ cff_op_vstem,
+ cff_op_hstemhm,
+ cff_op_vstemhm,
+
+ cff_op_hintmask,
+ cff_op_cntrmask,
+ cff_op_dotsection, /* deprecated, acts as no-op */
+
+ cff_op_abs,
+ cff_op_add,
+ cff_op_sub,
+ cff_op_div,
+ cff_op_neg,
+ cff_op_random,
+ cff_op_mul,
+ cff_op_sqrt,
+
+ cff_op_blend,
+
+ cff_op_drop,
+ cff_op_exch,
+ cff_op_index,
+ cff_op_roll,
+ cff_op_dup,
+
+ cff_op_put,
+ cff_op_get,
+ cff_op_store,
+ cff_op_load,
+
+ cff_op_and,
+ cff_op_or,
+ cff_op_not,
+ cff_op_eq,
+ cff_op_ifelse,
+
+ cff_op_callsubr,
+ cff_op_callgsubr,
+ cff_op_return,
+
+ /* do not remove */
+ cff_op_max
+
+ } CFF_Operator;
+
+
+#define CFF_COUNT_CHECK_WIDTH 0x80
+#define CFF_COUNT_EXACT 0x40
+#define CFF_COUNT_CLEAR_STACK 0x20
+
+
+ static const FT_Byte cff_argument_counts[] =
+ {
+ 0, /* unknown */
+
+ 2 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT, /* rmoveto */
+ 1 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT,
+ 1 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT,
+
+ 0 | CFF_COUNT_CLEAR_STACK, /* rlineto */
+ 0 | CFF_COUNT_CLEAR_STACK,
+ 0 | CFF_COUNT_CLEAR_STACK,
+
+ 0 | CFF_COUNT_CLEAR_STACK, /* rrcurveto */
+ 0 | CFF_COUNT_CLEAR_STACK,
+ 0 | CFF_COUNT_CLEAR_STACK,
+ 0 | CFF_COUNT_CLEAR_STACK,
+ 0 | CFF_COUNT_CLEAR_STACK,
+ 0 | CFF_COUNT_CLEAR_STACK,
+ 0 | CFF_COUNT_CLEAR_STACK,
+
+ 13, /* flex */
+ 7,
+ 9,
+ 11,
+
+ 0 | CFF_COUNT_CHECK_WIDTH, /* endchar */
+
+ 2 | CFF_COUNT_CHECK_WIDTH, /* hstem */
+ 2 | CFF_COUNT_CHECK_WIDTH,
+ 2 | CFF_COUNT_CHECK_WIDTH,
+ 2 | CFF_COUNT_CHECK_WIDTH,
+
+ 0, /* hintmask */
+ 0, /* cntrmask */
+ 0, /* dotsection */
+
+ 1, /* abs */
+ 2,
+ 2,
+ 2,
+ 1,
+ 0,
+ 2,
+ 1,
+
+ 1, /* blend */
+
+ 1, /* drop */
+ 2,
+ 1,
+ 2,
+ 1,
+
+ 2, /* put */
+ 1,
+ 4,
+ 3,
+
+ 2, /* and */
+ 2,
+ 1,
+ 2,
+ 4,
+
+ 1, /* callsubr */
+ 1,
+ 0
+ };
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********** *********/
+ /********** *********/
+ /********** GENERIC CHARSTRING PARSING *********/
+ /********** *********/
+ /********** *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* CFF_Init_Builder */
+ /* */
+ /* <Description> */
+ /* Initializes a given glyph builder. */
+ /* */
+ /* <InOut> */
+ /* builder :: A pointer to the glyph builder to initialize. */
+ /* */
+ /* <Input> */
+ /* face :: The current face object. */
+ /* */
+ /* size :: The current size object. */
+ /* */
+ /* glyph :: The current glyph object. */
+ /* */
+ static void
+ CFF_Init_Builder( CFF_Builder* builder,
+ TT_Face face,
+ CFF_Size size,
+ CFF_GlyphSlot glyph )
+ {
+ builder->path_begun = 0;
+ builder->load_points = 1;
+
+ builder->face = face;
+ builder->glyph = glyph;
+ builder->memory = face->root.memory;
+
+ if ( glyph )
+ {
+ FT_GlyphLoader* loader = glyph->root.internal->loader;
+
+
+ builder->loader = loader;
+ builder->base = &loader->base.outline;
+ builder->current = &loader->current.outline;
+ FT_GlyphLoader_Rewind( loader );
+ }
+
+ if ( size )
+ {
+ builder->scale_x = size->metrics.x_scale;
+ builder->scale_y = size->metrics.y_scale;
+ }
+
+ builder->pos_x = 0;
+ builder->pos_y = 0;
+
+ builder->left_bearing.x = 0;
+ builder->left_bearing.y = 0;
+ builder->advance.x = 0;
+ builder->advance.y = 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* CFF_Done_Builder */
+ /* */
+ /* <Description> */
+ /* Finalizes a given glyph builder. Its contents can still be used */
+ /* after the call, but the function saves important information */
+ /* within the corresponding glyph slot. */
+ /* */
+ /* <Input> */
+ /* builder :: A pointer to the glyph builder to finalize. */
+ /* */
+ static void
+ CFF_Done_Builder( CFF_Builder* builder )
+ {
+ CFF_GlyphSlot glyph = builder->glyph;
+
+
+ if ( glyph )
+ glyph->root.outline = *builder->base;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* cff_compute_bias */
+ /* */
+ /* <Description> */
+ /* Computes the bias value in dependence of the number of glyph */
+ /* subroutines. */
+ /* */
+ /* <Input> */
+ /* num_subrs :: The number of glyph subroutines. */
+ /* */
+ /* <Return> */
+ /* The bias value. */
+ static FT_Int
+ cff_compute_bias( FT_UInt num_subrs )
+ {
+ FT_Int result;
+
+
+ if ( num_subrs < 1240 )
+ result = 107;
+ else if ( num_subrs < 33900U )
+ result = 1131;
+ else
+ result = 32768U;
+
+ return result;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* CFF_Init_Decoder */
+ /* */
+ /* <Description> */
+ /* Initializes a given glyph decoder. */
+ /* */
+ /* <InOut> */
+ /* decoder :: A pointer to the glyph builder to initialize. */
+ /* */
+ /* <Input> */
+ /* face :: The current face object. */
+ /* */
+ /* size :: The current size object. */
+ /* */
+ /* slot :: The current glyph object. */
+ /* */
+ FT_LOCAL_DEF void
+ CFF_Init_Decoder( CFF_Decoder* decoder,
+ TT_Face face,
+ CFF_Size size,
+ CFF_GlyphSlot slot )
+ {
+ CFF_Font* cff = (CFF_Font*)face->extra.data;
+
+
+ /* clear everything */
+ MEM_Set( decoder, 0, sizeof ( *decoder ) );
+
+ /* initialize builder */
+ CFF_Init_Builder( &decoder->builder, face, size, slot );
+
+ /* initialize Type2 decoder */
+ decoder->num_globals = cff->num_global_subrs;
+ decoder->globals = cff->global_subrs;
+ decoder->globals_bias = cff_compute_bias( decoder->num_globals );
+ }
+
+
+ /* this function is used to select the locals subrs array */
+ FT_LOCAL_DEF void
+ CFF_Prepare_Decoder( CFF_Decoder* decoder,
+ FT_UInt glyph_index )
+ {
+ CFF_Font* cff = (CFF_Font*)decoder->builder.face->extra.data;
+ CFF_SubFont* sub = &cff->top_font;
+
+
+ /* manage CID fonts */
+ if ( cff->num_subfonts >= 1 )
+ {
+ FT_Byte fd_index = CFF_Get_FD( &cff->fd_select, glyph_index );
+
+
+ sub = cff->subfonts[fd_index];
+ }
+
+ decoder->num_locals = sub->num_local_subrs;
+ decoder->locals = sub->local_subrs;
+ decoder->locals_bias = cff_compute_bias( decoder->num_locals );
+
+ decoder->glyph_width = sub->private_dict.default_width;
+ decoder->nominal_width = sub->private_dict.nominal_width;
+ }
+
+
+ /* check that there is enough room for `count' more points */
+ static FT_Error
+ check_points( CFF_Builder* builder,
+ FT_Int count )
+ {
+ return FT_GlyphLoader_Check_Points( builder->loader, count, 0 );
+ }
+
+
+ /* add a new point, do not check space */
+ static void
+ add_point( CFF_Builder* builder,
+ FT_Pos x,
+ FT_Pos y,
+ FT_Byte flag )
+ {
+ FT_Outline* outline = builder->current;
+
+
+ if ( builder->load_points )
+ {
+ FT_Vector* point = outline->points + outline->n_points;
+ FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points;
+
+
+ point->x = x >> 16;
+ point->y = y >> 16;
+ *control = (FT_Byte)( flag ? FT_Curve_Tag_On : FT_Curve_Tag_Cubic );
+
+ builder->last = *point;
+ }
+ outline->n_points++;
+ }
+
+
+ /* check space for a new on-curve point, then add it */
+ static FT_Error
+ add_point1( CFF_Builder* builder,
+ FT_Pos x,
+ FT_Pos y )
+ {
+ FT_Error error;
+
+
+ error = check_points( builder, 1 );
+ if ( !error )
+ add_point( builder, x, y, 1 );
+
+ return error;
+ }
+
+
+ /* check room for a new contour, then add it */
+ static FT_Error
+ add_contour( CFF_Builder* builder )
+ {
+ FT_Outline* outline = builder->current;
+ FT_Error error;
+
+
+ if ( !builder->load_points )
+ {
+ outline->n_contours++;
+ return CFF_Err_Ok;
+ }
+
+ error = FT_GlyphLoader_Check_Points( builder->loader, 0, 1 );
+ if ( !error )
+ {
+ if ( outline->n_contours > 0 )
+ outline->contours[outline->n_contours - 1] =
+ (short)( outline->n_points - 1 );
+
+ outline->n_contours++;
+ }
+
+ return error;
+ }
+
+
+ /* if a path was begun, add its first on-curve point */
+ static FT_Error
+ start_point( CFF_Builder* builder,
+ FT_Pos x,
+ FT_Pos y )
+ {
+ FT_Error error = 0;
+
+
+ /* test whether we are building a new contour */
+ if ( !builder->path_begun )
+ {
+ builder->path_begun = 1;
+ error = add_contour( builder );
+ if ( !error )
+ error = add_point1( builder, x, y );
+ }
+ return error;
+ }
+
+
+ /* close the current contour */
+ static void
+ close_contour( CFF_Builder* builder )
+ {
+ FT_Outline* outline = builder->current;
+
+ /* XXXX: We must not include the last point in the path if it */
+ /* is located on the first point. */
+ if ( outline->n_points > 1 )
+ {
+ FT_Int first = 0;
+ FT_Vector* p1 = outline->points + first;
+ FT_Vector* p2 = outline->points + outline->n_points - 1;
+ FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1;
+
+
+ if ( outline->n_contours > 1 )
+ {
+ first = outline->contours[outline->n_contours - 2] + 1;
+ p1 = outline->points + first;
+ }
+
+ /* `delete' last point only if it coincides with the first */
+ /* point and it is not a control point (which can happen). */
+ if ( p1->x == p2->x && p1->y == p2->y )
+ if ( *control == FT_Curve_Tag_On )
+ outline->n_points--;
+ }
+
+ if ( outline->n_contours > 0 )
+ outline->contours[outline->n_contours - 1] =
+ (short)( outline->n_points - 1 );
+ }
+
+
+ static FT_Int
+ cff_lookup_glyph_by_stdcharcode( CFF_Font* cff,
+ FT_Int charcode )
+ {
+ FT_UInt n;
+ FT_UShort glyph_sid;
+
+
+ /* check range of standard char code */
+ if ( charcode < 0 || charcode > 255 )
+ return -1;
+
+
+ /* Get code to SID mapping from `cff_standard_encoding'. */
+ glyph_sid = cff_standard_encoding[charcode];
+
+ for ( n = 0; n < cff->num_glyphs; n++ )
+ {
+ if ( cff->charset.sids[n] == glyph_sid )
+ return n;
+ }
+
+ return -1;
+ }
+
+
+ static FT_Error
+ cff_operator_seac( CFF_Decoder* decoder,
+ FT_Pos adx,
+ FT_Pos ady,
+ FT_Int bchar,
+ FT_Int achar )
+ {
+ FT_Error error;
+ FT_Int bchar_index, achar_index, n_base_points;
+ FT_Outline* base = decoder->builder.base;
+ TT_Face face = decoder->builder.face;
+ CFF_Font* cff = (CFF_Font*)(face->extra.data);
+ FT_Vector left_bearing, advance;
+ FT_Byte* charstring;
+ FT_ULong charstring_len;
+
+
+ bchar_index = cff_lookup_glyph_by_stdcharcode( cff, bchar );
+ achar_index = cff_lookup_glyph_by_stdcharcode( cff, achar );
+
+ if ( bchar_index < 0 || achar_index < 0 )
+ {
+ FT_ERROR(( "cff_operator_seac:" ));
+ FT_ERROR(( " invalid seac character code arguments\n" ));
+ return CFF_Err_Syntax_Error;
+ }
+
+ /* If we are trying to load a composite glyph, do not load the */
+ /* accent character and return the array of subglyphs. */
+ if ( decoder->builder.no_recurse )
+ {
+ FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph;
+ FT_GlyphLoader* loader = glyph->internal->loader;
+ FT_SubGlyph* subg;
+
+
+ /* reallocate subglyph array if necessary */
+ error = FT_GlyphLoader_Check_Subglyphs( loader, 2 );
+ if ( error )
+ goto Exit;
+
+ subg = loader->current.subglyphs;
+
+ /* subglyph 0 = base character */
+ subg->index = bchar_index;
+ subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES |
+ FT_SUBGLYPH_FLAG_USE_MY_METRICS;
+ subg->arg1 = 0;
+ subg->arg2 = 0;
+ subg++;
+
+ /* subglyph 1 = accent character */
+ subg->index = achar_index;
+ subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES;
+ subg->arg1 = adx;
+ subg->arg2 = ady;
+
+ /* set up remaining glyph fields */
+ glyph->num_subglyphs = 2;
+ glyph->subglyphs = loader->base.subglyphs;
+ glyph->format = ft_glyph_format_composite;
+
+ loader->current.num_subglyphs = 2;
+ }
+
+ /* First load `bchar' in builder */
+ error = CFF_Access_Element( &cff->charstrings_index, bchar_index,
+ &charstring, &charstring_len );
+ if ( !error )
+ {
+ error = CFF_Parse_CharStrings( decoder, charstring, charstring_len );
+
+ if ( error )
+ goto Exit;
+
+ CFF_Forget_Element( &cff->charstrings_index, &charstring );
+ }
+
+ n_base_points = base->n_points;
+
+ /* Save the left bearing and width of the base character */
+ /* as they will be erased by the next load. */
+
+ left_bearing = decoder->builder.left_bearing;
+ advance = decoder->builder.advance;
+
+ decoder->builder.left_bearing.x = 0;
+ decoder->builder.left_bearing.y = 0;
+
+ /* Now load `achar' on top of the base outline. */
+ error = CFF_Access_Element( &cff->charstrings_index, achar_index,
+ &charstring, &charstring_len );
+ if ( !error )
+ {
+ error = CFF_Parse_CharStrings( decoder, charstring, charstring_len );
+
+ if ( error )
+ goto Exit;
+
+ CFF_Forget_Element( &cff->charstrings_index, &charstring );
+ }
+
+ /* Restore the left side bearing and advance width */
+ /* of the base character. */
+ decoder->builder.left_bearing = left_bearing;
+ decoder->builder.advance = advance;
+
+ /* Finally, move the accent. */
+ if ( decoder->builder.load_points )
+ {
+ FT_Outline dummy;
+
+
+ dummy.n_points = (short)( base->n_points - n_base_points );
+ dummy.points = base->points + n_base_points;
+
+ FT_Outline_Translate( &dummy, adx, ady );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* CFF_Parse_CharStrings */
+ /* */
+ /* <Description> */
+ /* Parses a given Type 2 charstrings program. */
+ /* */
+ /* <InOut> */
+ /* decoder :: The current Type 1 decoder. */
+ /* */
+ /* <Input> */
+ /* charstring_base :: The base of the charstring stream. */
+ /* */
+ /* charstring_len :: The length in bytes of the charstring stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ CFF_Parse_CharStrings( CFF_Decoder* decoder,
+ FT_Byte* charstring_base,
+ FT_Int charstring_len )
+ {
+ FT_Error error;
+ CFF_Decoder_Zone* zone;
+ FT_Byte* ip;
+ FT_Byte* limit;
+ CFF_Builder* builder = &decoder->builder;
+ FT_Pos x, y;
+ FT_Fixed seed;
+ FT_Fixed* stack;
+
+
+ /* set default width */
+ decoder->num_hints = 0;
+ decoder->read_width = 1;
+
+ /* compute random seed from stack address of parameter */
+ seed = (FT_Fixed)(char*)&seed ^
+ (FT_Fixed)(char*)&decoder ^
+ (FT_Fixed)(char*)&charstring_base;
+ seed = ( seed ^ ( seed >> 10 ) ^ ( seed >> 20 ) ) & 0xFFFF;
+ if ( seed == 0 )
+ seed = 0x7384;
+
+ /* initialize the decoder */
+ decoder->top = decoder->stack;
+ decoder->zone = decoder->zones;
+ zone = decoder->zones;
+ stack = decoder->top;
+
+ builder->path_begun = 0;
+
+ zone->base = charstring_base;
+ limit = zone->limit = charstring_base + charstring_len;
+ ip = zone->cursor = zone->base;
+
+ error = CFF_Err_Ok;
+
+ x = builder->pos_x;
+ y = builder->pos_y;
+
+ /* now, execute loop */
+ while ( ip < limit )
+ {
+ CFF_Operator op;
+ FT_Byte v;
+
+
+ /********************************************************************/
+ /* */
+ /* Decode operator or operand */
+ /* */
+ v = *ip++;
+ if ( v >= 32 || v == 28 )
+ {
+ FT_Int shift = 16;
+ FT_Int32 val;
+
+
+ /* this is an operand, push it on the stack */
+ if ( v == 28 )
+ {
+ if ( ip + 1 >= limit )
+ goto Syntax_Error;
+ val = (FT_Short)( ( (FT_Short)ip[0] << 8 ) | ip[1] );
+ ip += 2;
+ }
+ else if ( v < 247 )
+ val = (FT_Long)v - 139;
+ else if ( v < 251 )
+ {
+ if ( ip >= limit )
+ goto Syntax_Error;
+ val = ( (FT_Long)v - 247 ) * 256 + *ip++ + 108;
+ }
+ else if ( v < 255 )
+ {
+ if ( ip >= limit )
+ goto Syntax_Error;
+ val = -( (FT_Long)v - 251 ) * 256 - *ip++ - 108;
+ }
+ else
+ {
+ if ( ip + 3 >= limit )
+ goto Syntax_Error;
+ val = ( (FT_Int32)ip[0] << 24 ) |
+ ( (FT_Int32)ip[1] << 16 ) |
+ ( (FT_Int32)ip[2] << 8 ) |
+ ip[3];
+ ip += 4;
+ shift = 0;
+ }
+ if ( decoder->top - stack >= CFF_MAX_OPERANDS )
+ goto Stack_Overflow;
+
+ val <<= shift;
+ *decoder->top++ = val;
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ if ( !( val & 0xFFFF ) )
+ FT_TRACE4(( " %d", (FT_Int32)( val >> 16 ) ));
+ else
+ FT_TRACE4(( " %.2f", val / 65536.0 ));
+#endif
+
+ }
+ else
+ {
+ FT_Fixed* args = decoder->top;
+ FT_Int num_args = args - decoder->stack;
+ FT_Int req_args;
+
+
+ /* find operator */
+ op = cff_op_unknown;
+
+ switch ( v )
+ {
+ case 1:
+ op = cff_op_hstem;
+ break;
+ case 3:
+ op = cff_op_vstem;
+ break;
+ case 4:
+ op = cff_op_vmoveto;
+ break;
+ case 5:
+ op = cff_op_rlineto;
+ break;
+ case 6:
+ op = cff_op_hlineto;
+ break;
+ case 7:
+ op = cff_op_vlineto;
+ break;
+ case 8:
+ op = cff_op_rrcurveto;
+ break;
+ case 10:
+ op = cff_op_callsubr;
+ break;
+ case 11:
+ op = cff_op_return;
+ break;
+ case 12:
+ {
+ if ( ip >= limit )
+ goto Syntax_Error;
+ v = *ip++;
+
+ switch ( v )
+ {
+ case 0:
+ op = cff_op_dotsection;
+ break;
+ case 3:
+ op = cff_op_and;
+ break;
+ case 4:
+ op = cff_op_or;
+ break;
+ case 5:
+ op = cff_op_not;
+ break;
+ case 8:
+ op = cff_op_store;
+ break;
+ case 9:
+ op = cff_op_abs;
+ break;
+ case 10:
+ op = cff_op_add;
+ break;
+ case 11:
+ op = cff_op_sub;
+ break;
+ case 12:
+ op = cff_op_div;
+ break;
+ case 13:
+ op = cff_op_load;
+ break;
+ case 14:
+ op = cff_op_neg;
+ break;
+ case 15:
+ op = cff_op_eq;
+ break;
+ case 18:
+ op = cff_op_drop;
+ break;
+ case 20:
+ op = cff_op_put;
+ break;
+ case 21:
+ op = cff_op_get;
+ break;
+ case 22:
+ op = cff_op_ifelse;
+ break;
+ case 23:
+ op = cff_op_random;
+ break;
+ case 24:
+ op = cff_op_mul;
+ break;
+ case 26:
+ op = cff_op_sqrt;
+ break;
+ case 27:
+ op = cff_op_dup;
+ break;
+ case 28:
+ op = cff_op_exch;
+ break;
+ case 29:
+ op = cff_op_index;
+ break;
+ case 30:
+ op = cff_op_roll;
+ break;
+ case 34:
+ op = cff_op_hflex;
+ break;
+ case 35:
+ op = cff_op_flex;
+ break;
+ case 36:
+ op = cff_op_hflex1;
+ break;
+ case 37:
+ op = cff_op_flex1;
+ break;
+ default:
+ /* decrement ip for syntax error message */
+ ip--;
+ }
+ }
+ break;
+ case 14:
+ op = cff_op_endchar;
+ break;
+ case 16:
+ op = cff_op_blend;
+ break;
+ case 18:
+ op = cff_op_hstemhm;
+ break;
+ case 19:
+ op = cff_op_hintmask;
+ break;
+ case 20:
+ op = cff_op_cntrmask;
+ break;
+ case 21:
+ op = cff_op_rmoveto;
+ break;
+ case 22:
+ op = cff_op_hmoveto;
+ break;
+ case 23:
+ op = cff_op_vstemhm;
+ break;
+ case 24:
+ op = cff_op_rcurveline;
+ break;
+ case 25:
+ op = cff_op_rlinecurve;
+ break;
+ case 26:
+ op = cff_op_vvcurveto;
+ break;
+ case 27:
+ op = cff_op_hhcurveto;
+ break;
+ case 29:
+ op = cff_op_callgsubr;
+ break;
+ case 30:
+ op = cff_op_vhcurveto;
+ break;
+ case 31:
+ op = cff_op_hvcurveto;
+ break;
+ default:
+ ;
+ }
+ if ( op == cff_op_unknown )
+ goto Syntax_Error;
+
+ /* check arguments */
+ req_args = cff_argument_counts[op];
+ if ( req_args & CFF_COUNT_CHECK_WIDTH )
+ {
+ args = stack;
+
+ if ( num_args > 0 && decoder->read_width )
+ {
+ /* If `nominal_width' is non-zero, the number is really a */
+ /* difference against `nominal_width'. Else, the number here */
+ /* is truly a width, not a difference against `nominal_width'. */
+ /* If the font does not set `nominal_width', then */
+ /* `nominal_width' defaults to zero, and so we can set */
+ /* `glyph_width' to `nominal_width' plus number on the stack */
+ /* -- for either case. */
+
+ FT_Int set_width_ok;
+
+
+ switch ( op )
+ {
+ case cff_op_hmoveto:
+ case cff_op_vmoveto:
+ set_width_ok = num_args & 2;
+ break;
+
+ case cff_op_hstem:
+ case cff_op_vstem:
+ case cff_op_hstemhm:
+ case cff_op_vstemhm:
+ case cff_op_rmoveto:
+ set_width_ok = num_args & 1;
+ break;
+
+ case cff_op_endchar:
+ /* If there is a width specified for endchar, we either have */
+ /* 1 argument or 5 arguments. We like to argue. */
+ set_width_ok = ( ( num_args == 5 ) || ( num_args == 1 ) );
+ break;
+
+ default:
+ set_width_ok = 0;
+ break;
+ }
+
+ if ( set_width_ok )
+ {
+ decoder->glyph_width = decoder->nominal_width +
+ ( stack[0] >> 16 );
+
+ /* Consumed an argument. */
+ num_args--;
+ args++;
+ }
+ }
+
+ decoder->read_width = 0;
+ req_args = 0;
+ }
+
+ req_args &= 15;
+ if ( num_args < req_args )
+ goto Stack_Underflow;
+ args -= req_args;
+ num_args -= req_args;
+
+ switch ( op )
+ {
+ case cff_op_hstem:
+ case cff_op_vstem:
+ case cff_op_hstemhm:
+ case cff_op_vstemhm:
+ /* if the number of arguments is not even, the first one */
+ /* is simply the glyph width, encoded as the difference */
+ /* to nominalWidthX */
+ FT_TRACE4(( op == cff_op_hstem ? " hstem" :
+ op == cff_op_vstem ? " vstem" :
+ op == cff_op_hstemhm ? " hstemhm" :
+ " vstemhm" ));
+ decoder->num_hints += num_args / 2;
+ args = stack;
+ break;
+
+ case cff_op_hintmask:
+ case cff_op_cntrmask:
+ FT_TRACE4(( op == cff_op_hintmask ? " hintmask"
+ : " cntrmask" ));
+
+ decoder->num_hints += num_args / 2;
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ {
+ FT_UInt maskbyte;
+
+ FT_TRACE4(( " " ));
+
+ for ( maskbyte = 0;
+ maskbyte < (FT_UInt)(( decoder->num_hints + 7 ) >> 3);
+ maskbyte++, ip++ )
+ {
+ FT_TRACE4(( "%02X", *ip ));
+ }
+
+ }
+#else
+ ip += ( decoder->num_hints + 7 ) >> 3;
+#endif
+ if ( ip >= limit )
+ goto Syntax_Error;
+ args = stack;
+ break;
+
+ case cff_op_rmoveto:
+ FT_TRACE4(( " rmoveto" ));
+
+ close_contour( builder );
+ builder->path_begun = 0;
+ x += args[0];
+ y += args[1];
+ args = stack;
+ break;
+
+ case cff_op_vmoveto:
+ FT_TRACE4(( " vmoveto" ));
+
+ close_contour( builder );
+ builder->path_begun = 0;
+ y += args[0];
+ args = stack;
+ break;
+
+ case cff_op_hmoveto:
+ FT_TRACE4(( " hmoveto" ));
+
+ close_contour( builder );
+ builder->path_begun = 0;
+ x += args[0];
+ args = stack;
+ break;
+
+ case cff_op_rlineto:
+ FT_TRACE4(( " rlineto" ));
+
+ if ( start_point ( builder, x, y ) ||
+ check_points( builder, num_args / 2 ) )
+ goto Memory_Error;
+
+ if ( num_args < 2 || num_args & 1 )
+ goto Stack_Underflow;
+
+ args = stack;
+ while ( args < decoder->top )
+ {
+ x += args[0];
+ y += args[1];
+ add_point( builder, x, y, 1 );
+ args += 2;
+ }
+ args = stack;
+ break;
+
+ case cff_op_hlineto:
+ case cff_op_vlineto:
+ {
+ FT_Int phase = ( op == cff_op_hlineto );
+
+
+ FT_TRACE4(( op == cff_op_hlineto ? " hlineto"
+ : " vlineto" ));
+
+ if ( start_point ( builder, x, y ) ||
+ check_points( builder, num_args ) )
+ goto Memory_Error;
+
+ args = stack;
+ while (args < decoder->top )
+ {
+ if ( phase )
+ x += args[0];
+ else
+ y += args[0];
+
+ if ( add_point1( builder, x, y ) )
+ goto Memory_Error;
+
+ args++;
+ phase ^= 1;
+ }
+ args = stack;
+ }
+ break;
+
+ case cff_op_rrcurveto:
+ FT_TRACE4(( " rrcurveto" ));
+
+ /* check number of arguments; must be a multiple of 6 */
+ if ( num_args % 6 != 0 )
+ goto Stack_Underflow;
+
+ if ( start_point ( builder, x, y ) ||
+ check_points( builder, num_args / 2 ) )
+ goto Memory_Error;
+
+ args = stack;
+ while ( args < decoder->top )
+ {
+ x += args[0];
+ y += args[1];
+ add_point( builder, x, y, 0 );
+ x += args[2];
+ y += args[3];
+ add_point( builder, x, y, 0 );
+ x += args[4];
+ y += args[5];
+ add_point( builder, x, y, 1 );
+ args += 6;
+ }
+ args = stack;
+ break;
+
+ case cff_op_vvcurveto:
+ FT_TRACE4(( " vvcurveto" ));
+
+ if ( start_point ( builder, x, y ) )
+ goto Memory_Error;
+
+ args = stack;
+ if ( num_args & 1 )
+ {
+ x += args[0];
+ args++;
+ num_args--;
+ }
+
+ if ( num_args % 4 != 0 )
+ goto Stack_Underflow;
+
+ if ( check_points( builder, 3 * ( num_args / 4 ) ) )
+ goto Memory_Error;
+
+ while ( args < decoder->top )
+ {
+ y += args[0];
+ add_point( builder, x, y, 0 );
+ x += args[1];
+ y += args[2];
+ add_point( builder, x, y, 0 );
+ y += args[3];
+ add_point( builder, x, y, 1 );
+ args += 4;
+ }
+ args = stack;
+ break;
+
+ case cff_op_hhcurveto:
+ FT_TRACE4(( " hhcurveto" ));
+
+ if ( start_point ( builder, x, y ) )
+ goto Memory_Error;
+
+ args = stack;
+ if ( num_args & 1 )
+ {
+ y += args[0];
+ args++;
+ num_args--;
+ }
+
+ if ( num_args % 4 != 0 )
+ goto Stack_Underflow;
+
+ if ( check_points( builder, 3 * ( num_args / 4 ) ) )
+ goto Memory_Error;
+
+ while ( args < decoder->top )
+ {
+ x += args[0];
+ add_point( builder, x, y, 0 );
+ x += args[1];
+ y += args[2];
+ add_point( builder, x, y, 0 );
+ x += args[3];
+ add_point( builder, x, y, 1 );
+ args += 4;
+ }
+ args = stack;
+ break;
+
+ case cff_op_vhcurveto:
+ case cff_op_hvcurveto:
+ {
+ FT_Int phase;
+
+
+ FT_TRACE4(( op == cff_op_vhcurveto ? " vhcurveto"
+ : " hvcurveto" ));
+
+ if ( start_point ( builder, x, y ) )
+ goto Memory_Error;
+
+ args = stack;
+ if (num_args < 4 || ( num_args % 4 ) > 1 )
+ goto Stack_Underflow;
+
+ if ( check_points( builder, ( num_args / 4 ) * 3 ) )
+ goto Stack_Underflow;
+
+ phase = ( op == cff_op_hvcurveto );
+
+ while ( num_args >= 4 )
+ {
+ num_args -= 4;
+ if ( phase )
+ {
+ x += args[0];
+ add_point( builder, x, y, 0 );
+ x += args[1];
+ y += args[2];
+ add_point( builder, x, y, 0 );
+ y += args[3];
+ if ( num_args == 1 )
+ x += args[4];
+ add_point( builder, x, y, 1 );
+ }
+ else
+ {
+ y += args[0];
+ add_point( builder, x, y, 0 );
+ x += args[1];
+ y += args[2];
+ add_point( builder, x, y, 0 );
+ x += args[3];
+ if ( num_args == 1 )
+ y += args[4];
+ add_point( builder, x, y, 1 );
+ }
+ args += 4;
+ phase ^= 1;
+ }
+ args = stack;
+ }
+ break;
+
+ case cff_op_rlinecurve:
+ {
+ FT_Int num_lines = ( num_args - 6 ) / 2;
+
+
+ FT_TRACE4(( " rlinecurve" ));
+
+ if ( num_args < 8 || ( num_args - 6 ) & 1 )
+ goto Stack_Underflow;
+
+ if ( start_point( builder, x, y ) ||
+ check_points( builder, num_lines + 3 ) )
+ goto Memory_Error;
+
+ args = stack;
+
+ /* first, add the line segments */
+ while ( num_lines > 0 )
+ {
+ x += args[0];
+ y += args[1];
+ add_point( builder, x, y, 1 );
+ args += 2;
+ num_lines--;
+ }
+
+ /* then the curve */
+ x += args[0];
+ y += args[1];
+ add_point( builder, x, y, 0 );
+ x += args[2];
+ y += args[3];
+ add_point( builder, x, y, 0 );
+ x += args[4];
+ y += args[5];
+ add_point( builder, x, y, 1 );
+ args = stack;
+ }
+ break;
+
+ case cff_op_rcurveline:
+ {
+ FT_Int num_curves = ( num_args - 2 ) / 6;
+
+
+ FT_TRACE4(( " rcurveline" ));
+
+ if ( num_args < 8 || ( num_args - 2 ) % 6 )
+ goto Stack_Underflow;
+
+ if ( start_point ( builder, x, y ) ||
+ check_points( builder, num_curves*3 + 2 ) )
+ goto Memory_Error;
+
+ args = stack;
+
+ /* first, add the curves */
+ while ( num_curves > 0 )
+ {
+ x += args[0];
+ y += args[1];
+ add_point( builder, x, y, 0 );
+ x += args[2];
+ y += args[3];
+ add_point( builder, x, y, 0 );
+ x += args[4];
+ y += args[5];
+ add_point( builder, x, y, 1 );
+ args += 6;
+ num_curves--;
+ }
+
+ /* then the final line */
+ x += args[0];
+ y += args[1];
+ add_point( builder, x, y, 1 );
+ args = stack;
+ }
+ break;
+
+ case cff_op_hflex1:
+ {
+ FT_Pos start_y;
+
+
+ FT_TRACE4(( " hflex1" ));
+
+ args = stack;
+
+ /* adding five more points; 4 control points, 1 on-curve point */
+ /* make sure we have enough space for the start point if it */
+ /* needs to be added.. */
+ if ( start_point( builder, x, y ) ||
+ check_points( builder, 6 ) )
+ goto Memory_Error;
+
+ /* Record the starting point's y postion for later use */
+ start_y = y;
+
+ /* first control point */
+ x += args[0];
+ y += args[1];
+ add_point( builder, x, y, 0 );
+
+ /* second control point */
+ x += args[2];
+ y += args[3];
+ add_point( builder, x, y, 0 );
+
+ /* join point; on curve, with y-value the same as the last */
+ /* control point's y-value */
+ x += args[4];
+ add_point( builder, x, y, 1 );
+
+ /* third control point, with y-value the same as the join */
+ /* point's y-value */
+ x += args[5];
+ add_point( builder, x, y, 0 );
+
+ /* fourth control point */
+ x += args[6];
+ y += args[7];
+ add_point( builder, x, y, 0 );
+
+ /* ending point, with y-value the same as the start */
+ x += args[8];
+ y = start_y;
+ add_point( builder, x, y, 1 );
+
+ args = stack;
+ break;
+ }
+
+ case cff_op_hflex:
+ {
+ FT_Pos start_y;
+
+
+ FT_TRACE4(( " hflex" ));
+
+ args = stack;
+
+ /* adding six more points; 4 control points, 2 on-curve points */
+ if ( start_point( builder, x, y ) ||
+ check_points ( builder, 6 ) )
+ goto Memory_Error;
+
+ /* record the starting point's y-position for later use */
+ start_y = y;
+
+ /* first control point */
+ x += args[0];
+ add_point( builder, x, y, 0 );
+
+ /* second control point */
+ x += args[1];
+ y += args[2];
+ add_point( builder, x, y, 0 );
+
+ /* join point; on curve, with y-value the same as the last */
+ /* control point's y-value */
+ x += args[3];
+ add_point( builder, x, y, 1 );
+
+ /* third control point, with y-value the same as the join */
+ /* point's y-value */
+ x += args[4];
+ add_point( builder, x, y, 0 );
+
+ /* fourth control point */
+ x += args[5];
+ y = start_y;
+ add_point( builder, x, y, 0 );
+
+ /* ending point, with y-value the same as the start point's */
+ /* y-value -- we don't add this point, though */
+ x += args[6];
+ add_point( builder, x, y, 1 );
+
+ args = stack;
+ break;
+ }
+
+ case cff_op_flex1:
+ {
+ FT_Pos start_x, start_y; /* record start x, y values for alter */
+ /* use */
+ FT_Int dx = 0, dy = 0; /* used in horizontal/vertical */
+ /* algorithm below */
+ FT_Int horizontal, count;
+
+
+ FT_TRACE4(( " flex1" ));
+
+ /* adding six more points; 4 control points, 2 on-curve points */
+ if ( start_point( builder, x, y ) ||
+ check_points( builder, 6 ) )
+ goto Memory_Error;
+
+ /* record the starting point's x, y postion for later use */
+ start_x = x;
+ start_y = y;
+
+ /* XXX: figure out whether this is supposed to be a horizontal */
+ /* or vertical flex; the Type 2 specification is vague... */
+
+ args = stack;
+
+ /* grab up to the last argument */
+ for ( count = 5; count > 0; count-- )
+ {
+ dx += args[0];
+ dy += args[1];
+ args += 2;
+ }
+
+ /* rewind */
+ args = stack;
+
+ if ( dx < 0 ) dx = -dx;
+ if ( dy < 0 ) dy = -dy;
+
+ /* strange test, but here it is... */
+ horizontal = ( dx > dy );
+
+ for ( count = 5; count > 0; count-- )
+ {
+ x += args[0];
+ y += args[1];
+ add_point( builder, x, y, (FT_Bool)( count == 3 ) );
+ args += 2;
+ }
+
+ /* is last operand an x- or y-delta? */
+ if ( horizontal )
+ {
+ x += args[0];
+ y = start_y;
+ }
+ else
+ {
+ x = start_x;
+ y += args[0];
+ }
+
+ add_point( builder, x, y, 1 );
+
+ args = stack;
+ break;
+ }
+
+ case cff_op_flex:
+ {
+ FT_UInt count;
+
+
+ FT_TRACE4(( " flex" ));
+
+ if ( start_point( builder, x, y ) ||
+ check_points( builder, 6 ) )
+ goto Memory_Error;
+
+ args = stack;
+ for ( count = 6; count > 0; count-- )
+ {
+ x += args[0];
+ y += args[1];
+ add_point( builder, x, y,
+ (FT_Bool)( count == 3 || count == 0 ) );
+ args += 2;
+ }
+
+ args = stack;
+ }
+ break;
+
+ case cff_op_endchar:
+ FT_TRACE4(( " endchar" ));
+
+ /* We are going to emulate the seac operator. */
+ if ( num_args == 4 )
+ {
+ error = cff_operator_seac( decoder,
+ args[0] >> 16, args[1] >> 16,
+ args[2] >> 16, args[3] >> 16 );
+ args += 4;
+ }
+
+ if ( !error )
+ error = CFF_Err_Ok;
+
+ close_contour( builder );
+
+ /* add current outline to the glyph slot */
+ FT_GlyphLoader_Add( builder->loader );
+
+ /* return now! */
+ FT_TRACE4(( "\n\n" ));
+ return error;
+
+ case cff_op_abs:
+ FT_TRACE4(( " abs" ));
+
+ if ( args[0] < 0 )
+ args[0] = -args[0];
+ args++;
+ break;
+
+ case cff_op_add:
+ FT_TRACE4(( " add" ));
+
+ args[0] += args[1];
+ args++;
+ break;
+
+ case cff_op_sub:
+ FT_TRACE4(( " sub" ));
+
+ args[0] -= args[1];
+ args++;
+ break;
+
+ case cff_op_div:
+ FT_TRACE4(( " div" ));
+
+ args[0] = FT_DivFix( args[0], args[1] );
+ args++;
+ break;
+
+ case cff_op_neg:
+ FT_TRACE4(( " neg" ));
+
+ args[0] = -args[0];
+ args++;
+ break;
+
+ case cff_op_random:
+ {
+ FT_Fixed rand;
+
+
+ FT_TRACE4(( " rand" ));
+
+ rand = seed;
+ if ( rand >= 0x8000 )
+ rand++;
+
+ args[0] = rand;
+ seed = FT_MulFix( seed, 0x10000L - seed );
+ if ( seed == 0 )
+ seed += 0x2873;
+ args++;
+ }
+ break;
+
+ case cff_op_mul:
+ FT_TRACE4(( " mul" ));
+
+ args[0] = FT_MulFix( args[0], args[1] );
+ args++;
+ break;
+
+ case cff_op_sqrt:
+ FT_TRACE4(( " sqrt" ));
+
+ if ( args[0] > 0 )
+ {
+ FT_Int count = 9;
+ FT_Fixed root = args[0];
+ FT_Fixed new_root;
+
+
+ for (;;)
+ {
+ new_root = ( root + FT_DivFix( args[0], root ) + 1 ) >> 1;
+ if ( new_root == root || count <= 0 )
+ break;
+ root = new_root;
+ }
+ args[0] = new_root;
+ }
+ else
+ args[0] = 0;
+ args++;
+ break;
+
+ case cff_op_drop:
+ /* nothing */
+ FT_TRACE4(( " drop" ));
+
+ break;
+
+ case cff_op_exch:
+ {
+ FT_Fixed tmp;
+
+
+ FT_TRACE4(( " exch" ));
+
+ tmp = args[0];
+ args[0] = args[1];
+ args[1] = tmp;
+ args += 2;
+ }
+ break;
+
+ case cff_op_index:
+ {
+ FT_Int index = args[0] >> 16;
+
+
+ FT_TRACE4(( " index" ));
+
+ if ( index < 0 )
+ index = 0;
+ else if ( index > num_args - 2 )
+ index = num_args - 2;
+ args[0] = args[-( index + 1 )];
+ args++;
+ }
+ break;
+
+ case cff_op_roll:
+ {
+ FT_Int count = (FT_Int)( args[0] >> 16 );
+ FT_Int index = (FT_Int)( args[1] >> 16 );
+
+
+ FT_TRACE4(( " roll" ));
+
+ if ( count <= 0 )
+ count = 1;
+
+ args -= count;
+ if ( args < stack )
+ goto Stack_Underflow;
+
+ if ( index >= 0 )
+ {
+ while ( index > 0 )
+ {
+ FT_Fixed tmp = args[count - 1];
+ FT_Int i;
+
+
+ for ( i = count - 2; i >= 0; i-- )
+ args[i + 1] = args[i];
+ args[0] = tmp;
+ index--;
+ }
+ }
+ else
+ {
+ while ( index < 0 )
+ {
+ FT_Fixed tmp = args[0];
+ FT_Int i;
+
+
+ for ( i = 0; i < count - 1; i++ )
+ args[i] = args[i + 1];
+ args[count - 1] = tmp;
+ index++;
+ }
+ }
+ args += count;
+ }
+ break;
+
+ case cff_op_dup:
+ FT_TRACE4(( " dup" ));
+
+ args[1] = args[0];
+ args++;
+ break;
+
+ case cff_op_put:
+ {
+ FT_Fixed val = args[0];
+ FT_Int index = (FT_Int)( args[1] >> 16 );
+
+
+ FT_TRACE4(( " put" ));
+
+ if ( index >= 0 && index < decoder->len_buildchar )
+ decoder->buildchar[index] = val;
+ }
+ break;
+
+ case cff_op_get:
+ {
+ FT_Int index = (FT_Int)( args[0] >> 16 );
+ FT_Fixed val = 0;
+
+
+ FT_TRACE4(( " get" ));
+
+ if ( index >= 0 && index < decoder->len_buildchar )
+ val = decoder->buildchar[index];
+
+ args[0] = val;
+ args++;
+ }
+ break;
+
+ case cff_op_store:
+ FT_TRACE4(( " store "));
+
+ goto Unimplemented;
+
+ case cff_op_load:
+ FT_TRACE4(( " load" ));
+
+ goto Unimplemented;
+
+ case cff_op_dotsection:
+ /* this operator is deprecated and ignored by the parser */
+ FT_TRACE4(( " dotsection" ));
+ break;
+
+ case cff_op_and:
+ {
+ FT_Fixed cond = args[0] && args[1];
+
+
+ FT_TRACE4(( " and" ));
+
+ args[0] = cond ? 0x10000L : 0;
+ args++;
+ }
+ break;
+
+ case cff_op_or:
+ {
+ FT_Fixed cond = args[0] || args[1];
+
+
+ FT_TRACE4(( " or" ));
+
+ args[0] = cond ? 0x10000L : 0;
+ args++;
+ }
+ break;
+
+ case cff_op_eq:
+ {
+ FT_Fixed cond = !args[0];
+
+
+ FT_TRACE4(( " eq" ));
+
+ args[0] = cond ? 0x10000L : 0;
+ args++;
+ }
+ break;
+
+ case cff_op_ifelse:
+ {
+ FT_Fixed cond = (args[2] <= args[3]);
+
+
+ FT_TRACE4(( " ifelse" ));
+
+ if ( !cond )
+ args[0] = args[1];
+ args++;
+ }
+ break;
+
+ case cff_op_callsubr:
+ {
+ FT_UInt index = (FT_UInt)( ( args[0] >> 16 ) +
+ decoder->locals_bias );
+
+
+ FT_TRACE4(( " callsubr(%d)", index ));
+
+ if ( index >= decoder->num_locals )
+ {
+ FT_ERROR(( "CFF_Parse_CharStrings:" ));
+ FT_ERROR(( " invalid local subr index\n" ));
+ goto Syntax_Error;
+ }
+
+ if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS )
+ {
+ FT_ERROR(( "CFF_Parse_CharStrings: too many nested subrs\n" ));
+ goto Syntax_Error;
+ }
+
+ zone->cursor = ip; /* save current instruction pointer */
+
+ zone++;
+ zone->base = decoder->locals[index];
+ zone->limit = decoder->locals[index + 1];
+ zone->cursor = zone->base;
+
+ if ( !zone->base )
+ {
+ FT_ERROR(( "CFF_Parse_CharStrings: invoking empty subrs!\n" ));
+ goto Syntax_Error;
+ }
+
+ decoder->zone = zone;
+ ip = zone->base;
+ limit = zone->limit;
+ }
+ break;
+
+ case cff_op_callgsubr:
+ {
+ FT_UInt index = (FT_UInt)( ( args[0] >> 16 ) +
+ decoder->globals_bias );
+
+
+ FT_TRACE4(( " callgsubr(%d)", index ));
+
+ if ( index >= decoder->num_globals )
+ {
+ FT_ERROR(( "CFF_Parse_CharStrings:" ));
+ FT_ERROR(( " invalid global subr index\n" ));
+ goto Syntax_Error;
+ }
+
+ if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS )
+ {
+ FT_ERROR(( "CFF_Parse_CharStrings: too many nested subrs\n" ));
+ goto Syntax_Error;
+ }
+
+ zone->cursor = ip; /* save current instruction pointer */
+
+ zone++;
+ zone->base = decoder->globals[index];
+ zone->limit = decoder->globals[index+1];
+ zone->cursor = zone->base;
+
+ if ( !zone->base )
+ {
+ FT_ERROR(( "CFF_Parse_CharStrings: invoking empty subrs!\n" ));
+ goto Syntax_Error;
+ }
+
+ decoder->zone = zone;
+ ip = zone->base;
+ limit = zone->limit;
+ }
+ break;
+
+ case cff_op_return:
+ FT_TRACE4(( " return" ));
+
+ if ( decoder->zone <= decoder->zones )
+ {
+ FT_ERROR(( "CFF_Parse_CharStrings: unexpected return\n" ));
+ goto Syntax_Error;
+ }
+
+ decoder->zone--;
+ zone = decoder->zone;
+ ip = zone->cursor;
+ limit = zone->limit;
+ break;
+
+ default:
+ Unimplemented:
+ FT_ERROR(( "Unimplemented opcode: %d", ip[-1] ));
+
+ if ( ip[-1] == 12 )
+ FT_ERROR(( " %d", ip[0] ));
+ FT_ERROR(( "\n" ));
+
+ return CFF_Err_Unimplemented_Feature;
+ }
+
+ decoder->top = args;
+
+ } /* general operator processing */
+
+ } /* while ip < limit */
+
+ FT_TRACE4(( "..end..\n\n" ));
+
+ return error;
+
+ Syntax_Error:
+ FT_TRACE4(( "CFF_Parse_CharStrings: syntax error!" ));
+ return CFF_Err_Invalid_File_Format;
+
+ Stack_Underflow:
+ FT_TRACE4(( "CFF_Parse_CharStrings: stack underflow!" ));
+ return CFF_Err_Too_Few_Arguments;
+
+ Stack_Overflow:
+ FT_TRACE4(( "CFF_Parse_CharStrings: stack overflow!" ));
+ return CFF_Err_Stack_Overflow;
+
+ Memory_Error:
+ return builder->error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********** *********/
+ /********** *********/
+ /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/
+ /********** *********/
+ /********** The following code is in charge of computing *********/
+ /********** the maximum advance width of the font. It *********/
+ /********** quickly processes each glyph charstring to *********/
+ /********** extract the value from either a `sbw' or `seac' *********/
+ /********** operator. *********/
+ /********** *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#if 0 /* unused until we support pure CFF fonts */
+
+
+ FT_LOCAL_DEF FT_Error
+ CFF_Compute_Max_Advance( TT_Face face,
+ FT_Int* max_advance )
+ {
+ FT_Error error = 0;
+ CFF_Decoder decoder;
+ FT_Int glyph_index;
+ CFF_Font* cff = (CFF_Font*)face->other;
+
+
+ *max_advance = 0;
+
+ /* Initialize load decoder */
+ CFF_Init_Decoder( &decoder, face, 0, 0 );
+
+ decoder.builder.metrics_only = 1;
+ decoder.builder.load_points = 0;
+
+ /* For each glyph, parse the glyph charstring and extract */
+ /* the advance width. */
+ for ( glyph_index = 0; glyph_index < face->root.num_glyphs;
+ glyph_index++ )
+ {
+ FT_Byte* charstring;
+ FT_ULong charstring_len;
+
+
+ /* now get load the unscaled outline */
+ error = CFF_Access_Element( &cff->charstrings_index, glyph_index,
+ &charstring, &charstring_len );
+ if ( !error )
+ {
+ CFF_Prepare_Decoder( &decoder, glyph_index );
+ error = CFF_Parse_CharStrings( &decoder, charstring, charstring_len );
+
+ CFF_Forget_Element( &cff->charstrings_index, &charstring );
+ }
+
+ /* ignore the error if one has occurred -- skip to next glyph */
+ error = 0;
+ }
+
+ *max_advance = decoder.builder.advance.x;
+
+ return CFF_Err_Ok;
+ }
+
+
+#endif /* 0 */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********** *********/
+ /********** *********/
+ /********** UNHINTED GLYPH LOADER *********/
+ /********** *********/
+ /********** The following code is in charge of loading a *********/
+ /********** single outline. It completely ignores hinting *********/
+ /********** and is used when FT_LOAD_NO_HINTING is set. *********/
+ /********** *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_LOCAL_DEF FT_Error
+ CFF_Load_Glyph( CFF_GlyphSlot glyph,
+ CFF_Size size,
+ FT_Int glyph_index,
+ FT_Int load_flags )
+ {
+ FT_Error error;
+ CFF_Decoder decoder;
+ TT_Face face = (TT_Face)glyph->root.face;
+ FT_Bool hinting;
+ CFF_Font* cff = (CFF_Font*)face->extra.data;
+
+ FT_Matrix font_matrix;
+ FT_Vector font_offset;
+
+
+ if ( load_flags & FT_LOAD_NO_RECURSE )
+ load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+
+ glyph->x_scale = 0x10000L;
+ glyph->y_scale = 0x10000L;
+ if ( size )
+ {
+ glyph->x_scale = size->metrics.x_scale;
+ glyph->y_scale = size->metrics.y_scale;
+ }
+
+ glyph->root.outline.n_points = 0;
+ glyph->root.outline.n_contours = 0;
+
+ hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 &&
+ ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
+
+ glyph->root.format = ft_glyph_format_outline; /* by default */
+
+ {
+ FT_Byte* charstring;
+ FT_ULong charstring_len;
+
+
+ CFF_Init_Decoder( &decoder, face, size, glyph );
+
+ decoder.builder.no_recurse =
+ (FT_Bool)( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 );
+
+ /* now load the unscaled outline */
+ error = CFF_Access_Element( &cff->charstrings_index, glyph_index,
+ &charstring, &charstring_len );
+ if ( !error )
+ {
+ CFF_Index csindex = cff->charstrings_index;
+
+
+ CFF_Prepare_Decoder( &decoder, glyph_index );
+ error = CFF_Parse_CharStrings( &decoder, charstring, charstring_len );
+
+ CFF_Forget_Element( &cff->charstrings_index, &charstring );
+
+ /* We set control_data and control_len if charstrings is loaded. */
+ /* See how charstring loads at CFF_Access_Element() in cffload.c. */
+
+ glyph->root.control_data =
+ csindex.bytes + csindex.offsets[glyph_index] - 1;
+ glyph->root.control_len =
+ charstring_len;
+ }
+
+ /* save new glyph tables */
+ CFF_Done_Builder( &decoder.builder );
+ }
+
+ font_matrix = cff->top_font.font_dict.font_matrix;
+ font_offset = cff->top_font.font_dict.font_offset;
+
+ /* Now, set the metrics -- this is rather simple, as */
+ /* the left side bearing is the xMin, and the top side */
+ /* bearing the yMax. */
+ if ( !error )
+ {
+ /* For composite glyphs, return only left side bearing and */
+ /* advance width. */
+ if ( load_flags & FT_LOAD_NO_RECURSE )
+ {
+ FT_Slot_Internal internal = glyph->root.internal;
+
+
+ glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x;
+ glyph->root.metrics.horiAdvance = decoder.glyph_width;
+ internal->glyph_matrix = font_matrix;
+ internal->glyph_delta = font_offset;
+ internal->glyph_transformed = 1;
+ }
+ else
+ {
+ FT_BBox cbox;
+ FT_Glyph_Metrics* metrics = &glyph->root.metrics;
+
+
+ /* copy the _unscaled_ advance width */
+ metrics->horiAdvance = decoder.glyph_width;
+ glyph->root.linearHoriAdvance = decoder.glyph_width;
+ glyph->root.internal->glyph_transformed = 0;
+
+ /* make up vertical metrics */
+ metrics->vertBearingX = 0;
+ metrics->vertBearingY = 0;
+ metrics->vertAdvance = 0;
+
+ glyph->root.linearVertAdvance = 0;
+
+ glyph->root.format = ft_glyph_format_outline;
+
+ glyph->root.outline.flags = 0;
+ if ( size && size->metrics.y_ppem < 24 )
+ glyph->root.outline.flags |= ft_outline_high_precision;
+
+ glyph->root.outline.flags |= ft_outline_reverse_fill;
+
+ /* apply the font matrix */
+ FT_Outline_Transform( &glyph->root.outline, &font_matrix );
+
+ FT_Outline_Translate( &glyph->root.outline,
+ font_offset.x,
+ font_offset.y );
+
+ if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 )
+ {
+ /* scale the outline and the metrics */
+ FT_Int n;
+ FT_Outline* cur = &glyph->root.outline;
+ FT_Vector* vec = cur->points;
+ FT_Fixed x_scale = glyph->x_scale;
+ FT_Fixed y_scale = glyph->y_scale;
+
+
+ /* First of all, scale the points */
+ for ( n = cur->n_points; n > 0; n--, vec++ )
+ {
+ vec->x = FT_MulFix( vec->x, x_scale );
+ vec->y = FT_MulFix( vec->y, y_scale );
+ }
+
+ FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
+
+ /* Then scale the metrics */
+ metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
+ metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
+
+ metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale );
+ metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale );
+ }
+
+ /* compute the other metrics */
+ FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
+
+ /* grid fit the bounding box if necessary */
+ if ( hinting )
+ {
+ cbox.xMin &= -64;
+ cbox.yMin &= -64;
+ cbox.xMax = ( cbox.xMax + 63 ) & -64;
+ cbox.yMax = ( cbox.yMax + 63 ) & -64;
+ }
+
+ metrics->width = cbox.xMax - cbox.xMin;
+ metrics->height = cbox.yMax - cbox.yMin;
+
+ metrics->horiBearingX = cbox.xMin;
+ metrics->horiBearingY = cbox.yMax;
+ }
+ }
+
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cffload.c */
+/* */
+/* OpenType and CFF data/program tables loader (body) */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_TRUETYPE_TAGS_H
+
+#include "cffload.h"
+#include "cffparse.h"
+
+#include "cfferrs.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cffload
+
+ /* read a CFF offset from memory */
+ static FT_ULong
+ cff_get_offset( FT_Byte* p,
+ FT_Byte off_size )
+ {
+ FT_ULong result;
+
+
+ for ( result = 0; off_size > 0; off_size-- )
+ {
+ result <<= 8;
+ result |= *p++;
+ }
+
+ return result;
+ }
+
+
+ static FT_Error
+ cff_new_index( CFF_Index* index,
+ FT_Stream stream,
+ FT_Bool load )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+ FT_UShort count;
+
+
+ MEM_Set( index, 0, sizeof ( *index ) );
+
+ index->stream = stream;
+ if ( !READ_UShort( count ) &&
+ count > 0 )
+ {
+ FT_Byte* p;
+ FT_Byte offsize;
+ FT_ULong data_size;
+ FT_ULong* poff;
+
+
+ /* there is at least one element; read the offset size, */
+ /* then access the offset table to compute the index's total size */
+ if ( READ_Byte( offsize ) )
+ goto Exit;
+
+ index->stream = stream;
+ index->count = count;
+ index->off_size = offsize;
+ data_size = (FT_ULong)( count + 1 ) * offsize;
+
+ if ( ALLOC_ARRAY( index->offsets, count + 1, FT_ULong ) ||
+ ACCESS_Frame( data_size ) )
+ goto Exit;
+
+ poff = index->offsets;
+ p = (FT_Byte*)stream->cursor;
+
+ for ( ; (FT_Short)count >= 0; count-- )
+ {
+ poff[0] = cff_get_offset( p, offsize );
+ poff++;
+ p += offsize;
+ }
+
+ FORGET_Frame();
+
+ index->data_offset = FILE_Pos();
+ data_size = poff[-1] - 1;
+
+ if ( load )
+ {
+ /* load the data */
+ if ( EXTRACT_Frame( data_size, index->bytes ) )
+ goto Exit;
+ }
+ else
+ {
+ /* skip the data */
+ if ( FILE_Skip( data_size ) )
+ goto Exit;
+ }
+ }
+
+ Exit:
+ if ( error )
+ FREE( index->offsets );
+
+ return error;
+ }
+
+
+ static void
+ cff_done_index( CFF_Index* index )
+ {
+ if ( index->stream )
+ {
+ FT_Stream stream = index->stream;
+ FT_Memory memory = stream->memory;
+
+
+ if ( index->bytes )
+ RELEASE_Frame( index->bytes );
+
+ FREE( index->offsets );
+ MEM_Set( index, 0, sizeof ( *index ) );
+ }
+ }
+
+
+ static FT_Error
+ cff_explicit_index( CFF_Index* index,
+ FT_Byte*** table )
+ {
+ FT_Error error = 0;
+ FT_Memory memory = index->stream->memory;
+ FT_UInt n, offset, old_offset;
+ FT_Byte** t;
+
+
+ *table = 0;
+
+ if ( index->count > 0 && !ALLOC_ARRAY( t, index->count + 1, FT_Byte* ) )
+ {
+ old_offset = 1;
+ for ( n = 0; n <= index->count; n++ )
+ {
+ offset = index->offsets[n];
+ if ( !offset )
+ offset = old_offset;
+
+ t[n] = index->bytes + offset - 1;
+
+ old_offset = offset;
+ }
+ *table = t;
+ }
+
+ return error;
+ }
+
+
+ FT_LOCAL_DEF FT_Error
+ CFF_Access_Element( CFF_Index* index,
+ FT_UInt element,
+ FT_Byte** pbytes,
+ FT_ULong* pbyte_len )
+ {
+ FT_Error error = 0;
+
+
+ if ( index && index->count > element )
+ {
+ /* compute start and end offsets */
+ FT_ULong off1, off2 = 0;
+
+
+ off1 = index->offsets[element];
+ if ( off1 )
+ {
+ do
+ {
+ element++;
+ off2 = index->offsets[element];
+
+ } while ( off2 == 0 && element < index->count );
+
+ if ( !off2 )
+ off1 = 0;
+ }
+
+ /* access element */
+ if ( off1 )
+ {
+ *pbyte_len = off2 - off1;
+
+ if ( index->bytes )
+ {
+ /* this index was completely loaded in memory, that's easy */
+ *pbytes = index->bytes + off1 - 1;
+ }
+ else
+ {
+ /* this index is still on disk/file, access it through a frame */
+ FT_Stream stream = index->stream;
+
+
+ if ( FILE_Seek( index->data_offset + off1 - 1 ) ||
+ EXTRACT_Frame( off2 - off1, *pbytes ) )
+ goto Exit;
+ }
+ }
+ else
+ {
+ /* empty index element */
+ *pbytes = 0;
+ *pbyte_len = 0;
+ }
+ }
+ else
+ error = CFF_Err_Invalid_Argument;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF void
+ CFF_Forget_Element( CFF_Index* index,
+ FT_Byte** pbytes )
+ {
+ if ( index->bytes == 0 )
+ {
+ FT_Stream stream = index->stream;
+
+
+ RELEASE_Frame( *pbytes );
+ }
+ }
+
+
+ FT_LOCAL_DEF FT_String*
+ CFF_Get_Name( CFF_Index* index,
+ FT_UInt element )
+ {
+ FT_Memory memory = index->stream->memory;
+ FT_Byte* bytes;
+ FT_ULong byte_len;
+ FT_Error error;
+ FT_String* name = 0;
+
+
+ error = CFF_Access_Element( index, element, &bytes, &byte_len );
+ if ( error )
+ goto Exit;
+
+ if ( !ALLOC( name, byte_len + 1 ) )
+ {
+ MEM_Copy( name, bytes, byte_len );
+ name[byte_len] = 0;
+ }
+ CFF_Forget_Element( index, &bytes );
+
+ Exit:
+ return name;
+ }
+
+
+ FT_LOCAL_DEF FT_String*
+ CFF_Get_String( CFF_Index* index,
+ FT_UInt sid,
+ PSNames_Interface* interface )
+ {
+ /* if it is not a standard string, return it */
+ if ( sid > 390 )
+ return CFF_Get_Name( index, sid - 391 );
+
+ /* that's a standard string, fetch a copy from the PSName module */
+ {
+ FT_String* name = 0;
+ const char* adobe_name = interface->adobe_std_strings( sid );
+ FT_UInt len;
+
+
+ if ( adobe_name )
+ {
+ FT_Memory memory = index->stream->memory;
+ FT_Error error;
+
+
+ len = (FT_UInt)strlen( adobe_name );
+ if ( !ALLOC( name, len + 1 ) )
+ {
+ MEM_Copy( name, adobe_name, len );
+ name[len] = 0;
+ }
+ }
+
+ return name;
+ }
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*** ***/
+ /*** FD Select table support ***/
+ /*** ***/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ static void
+ CFF_Done_FD_Select( CFF_FD_Select* select,
+ FT_Stream stream )
+ {
+ if ( select->data )
+ RELEASE_Frame( select->data );
+
+ select->data_size = 0;
+ select->format = 0;
+ select->range_count = 0;
+ }
+
+
+ static FT_Error
+ CFF_Load_FD_Select( CFF_FD_Select* select,
+ FT_UInt num_glyphs,
+ FT_Stream stream,
+ FT_ULong offset )
+ {
+ FT_Error error;
+ FT_Byte format;
+ FT_UInt num_ranges;
+
+
+ /* read format */
+ if ( FILE_Seek( offset ) || READ_Byte( format ) )
+ goto Exit;
+
+ select->format = format;
+ select->cache_count = 0; /* clear cache */
+
+ switch ( format )
+ {
+ case 0: /* format 0, that's simple */
+ select->data_size = num_glyphs;
+ goto Load_Data;
+
+ case 3: /* format 3, a tad more complex */
+ if ( READ_UShort( num_ranges ) )
+ goto Exit;
+
+ select->data_size = num_ranges * 3 + 2;
+
+ Load_Data:
+ if ( EXTRACT_Frame( select->data_size, select->data ) )
+ goto Exit;
+ break;
+
+ default: /* hmm... that's wrong */
+ error = CFF_Err_Invalid_File_Format;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF FT_Byte
+ CFF_Get_FD( CFF_FD_Select* select,
+ FT_UInt glyph_index )
+ {
+ FT_Byte fd = 0;
+
+
+ switch ( select->format )
+ {
+ case 0:
+ fd = select->data[glyph_index];
+ break;
+
+ case 3:
+ /* first, compare to cache */
+ if ( (FT_UInt)(glyph_index-select->cache_first) < select->cache_count )
+ {
+ fd = select->cache_fd;
+ break;
+ }
+
+ /* then, lookup the ranges array */
+ {
+ FT_Byte* p = select->data;
+ FT_Byte* p_limit = p + select->data_size;
+ FT_Byte fd2;
+ FT_UInt first, limit;
+
+
+ first = NEXT_UShort( p );
+ do
+ {
+ if ( glyph_index < first )
+ break;
+
+ fd2 = *p++;
+ limit = NEXT_UShort( p );
+
+ if ( glyph_index < limit )
+ {
+ fd = fd2;
+
+ /* update cache */
+ select->cache_first = first;
+ select->cache_count = limit-first;
+ select->cache_fd = fd2;
+ break;
+ }
+ first = limit;
+
+ } while ( p < p_limit );
+ }
+ break;
+
+ default:
+ ;
+ }
+
+ return fd;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*** ***/
+ /*** CFF font support ***/
+ /*** ***/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static void
+ CFF_Done_Encoding( CFF_Encoding* encoding,
+ FT_Stream stream )
+ {
+ FT_Memory memory = stream->memory;
+
+
+ FREE( encoding->codes );
+ FREE( encoding->sids );
+ encoding->format = 0;
+ encoding->offset = 0;
+ encoding->codes = 0;
+ encoding->sids = 0;
+ }
+
+
+ static void
+ CFF_Done_Charset( CFF_Charset* charset,
+ FT_Stream stream )
+ {
+ FT_Memory memory = stream->memory;
+
+
+ FREE( charset->sids );
+ charset->format = 0;
+ charset->offset = 0;
+ charset->sids = 0;
+ }
+
+
+ static FT_Error
+ CFF_Load_Charset( CFF_Charset* charset,
+ FT_UInt num_glyphs,
+ FT_Stream stream,
+ FT_ULong base_offset,
+ FT_ULong offset )
+ {
+ FT_Memory memory = stream->memory;
+ FT_Error error = 0;
+ FT_UShort glyph_sid;
+
+
+ charset->offset = base_offset + offset;
+
+ /* Get the format of the table. */
+ if ( FILE_Seek( charset->offset ) ||
+ READ_Byte( charset->format ) )
+ goto Exit;
+
+ /* If the the offset is greater than 2, we have to parse the */
+ /* charset table. */
+ if ( offset > 2 )
+ {
+ FT_UInt j;
+
+
+ /* Allocate memory for sids. */
+ if ( ALLOC( charset->sids, num_glyphs * sizeof ( FT_UShort ) ) )
+ goto Exit;
+
+ /* assign the .notdef glyph */
+ charset->sids[0] = 0;
+
+ switch ( charset->format )
+ {
+ case 0:
+ for ( j = 1; j < num_glyphs; j++ )
+ {
+ if ( READ_UShort( glyph_sid ) )
+ goto Exit;
+
+ charset->sids[j] = glyph_sid;
+ }
+ break;
+
+ case 1:
+ case 2:
+ {
+ FT_UInt nleft;
+ FT_UInt i;
+
+
+ j = 1;
+
+ while ( j < num_glyphs )
+ {
+
+ /* Read the first glyph sid of the range. */
+ if ( READ_UShort( glyph_sid ) )
+ goto Exit;
+
+ /* Read the number of glyphs in the range. */
+ if ( charset->format == 2 )
+ {
+ if ( READ_UShort( nleft ) )
+ goto Exit;
+ }
+ else
+ {
+ if ( READ_Byte( nleft ) )
+ goto Exit;
+ }
+
+ /* Fill in the range of sids -- `nleft + 1' glyphs. */
+ for ( i = 0; i <= nleft; i++, j++, glyph_sid++ )
+ charset->sids[j] = glyph_sid;
+ }
+ }
+ break;
+
+ default:
+ FT_ERROR(( "CFF_Load_Charset: invalid table format!\n" ));
+ error = CFF_Err_Invalid_File_Format;
+ goto Exit;
+ }
+ }
+ else
+ {
+ /* Parse default tables corresponding to offset == 0, 1, or 2. */
+ /* CFF specification intimates the following: */
+ /* */
+ /* In order to use a predefined charset, the following must be */
+ /* true: The charset constructed for the glyphs in the font's */
+ /* charstrings dictionary must match the predefined charset in */
+ /* the first num_glyphs, and hence must match the predefined */
+ /* charset *exactly*. */
+
+ switch ( offset )
+ {
+ case 0:
+ if ( num_glyphs != 229 )
+ {
+ FT_ERROR(("CFF_Load_Charset: implicit charset not equal to\n"
+ "predefined charset (Adobe ISO-Latin)!\n" ));
+ error = CFF_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* Allocate memory for sids. */
+ if ( ALLOC( charset->sids, num_glyphs * sizeof ( FT_UShort ) ) )
+ goto Exit;
+
+ /* Copy the predefined charset into the allocated memory. */
+ MEM_Copy( charset->sids, cff_isoadobe_charset,
+ num_glyphs * sizeof ( FT_UShort ) );
+
+ break;
+
+ case 1:
+ if ( num_glyphs != 166 )
+ {
+ FT_ERROR(( "CFF_Load_Charset: implicit charset not equal to\n"
+ "predefined charset (Adobe Expert)!\n" ));
+ error = CFF_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* Allocate memory for sids. */
+ if ( ALLOC( charset->sids, num_glyphs * sizeof ( FT_UShort ) ) )
+ goto Exit;
+
+ /* Copy the predefined charset into the allocated memory. */
+ MEM_Copy( charset->sids, cff_expert_charset,
+ num_glyphs * sizeof ( FT_UShort ) );
+
+ break;
+
+ case 2:
+ if ( num_glyphs != 87 )
+ {
+ FT_ERROR(( "CFF_Load_Charset: implicit charset not equal to\n"
+ "predefined charset (Adobe Expert Subset)!\n" ));
+ error = CFF_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* Allocate memory for sids. */
+ if ( ALLOC( charset->sids, num_glyphs * sizeof ( FT_UShort ) ) )
+ goto Exit;
+
+ /* Copy the predefined charset into the allocated memory. */
+ MEM_Copy( charset->sids, cff_expertsubset_charset,
+ num_glyphs * sizeof ( FT_UShort ) );
+
+ break;
+
+ default:
+ error = CFF_Err_Invalid_File_Format;
+ goto Exit;
+ }
+ }
+
+ Exit:
+
+ /* Clean up if there was an error. */
+ if ( error )
+ if ( charset->sids )
+ {
+ if ( charset->sids )
+ FREE( charset->sids );
+ charset->format = 0;
+ charset->offset = 0;
+ charset->sids = 0;
+ }
+
+ return error;
+ }
+
+
+ static FT_Error
+ CFF_Load_Encoding( CFF_Encoding* encoding,
+ CFF_Charset* charset,
+ FT_UInt num_glyphs,
+ FT_Stream stream,
+ FT_ULong base_offset,
+ FT_ULong offset )
+ {
+ FT_Memory memory = stream->memory;
+ FT_Error error = 0;
+ FT_UInt count;
+ FT_UInt j;
+ FT_UShort glyph_sid;
+ FT_Byte glyph_code;
+
+
+ /* Check for charset->sids. If we do not have this, we fail. */
+ if ( !charset->sids )
+ {
+ error = CFF_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* Allocate memory for sids/codes -- there are at most 256 sids/codes */
+ /* for an encoding. */
+ if ( ALLOC( encoding->sids, 256 * sizeof ( FT_UShort ) ) ||
+ ALLOC( encoding->codes, 256 * sizeof ( FT_UShort ) ) )
+ goto Exit;
+
+ /* Zero out the code to gid/sid mappings. */
+ for ( j = 0; j < 255; j++ )
+ {
+ encoding->sids [j] = 0;
+ encoding->codes[j] = 0;
+ }
+
+ /* Note: The encoding table in a CFF font is indexed by glyph index, */
+ /* where the first encoded glyph index is 1. Hence, we read the char */
+ /* code (`glyph_code') at index j and make the assignment: */
+ /* */
+ /* encoding->codes[glyph_code] = j + 1 */
+ /* */
+ /* We also make the assignment: */
+ /* */
+ /* encoding->sids[glyph_code] = charset->sids[j + 1] */
+ /* */
+ /* This gives us both a code to GID and a code to SID mapping. */
+
+ if ( offset > 1 )
+ {
+
+ encoding->offset = base_offset + offset;
+
+ /* we need to parse the table to determine its size */
+ if ( FILE_Seek( encoding->offset ) ||
+ READ_Byte( encoding->format ) ||
+ READ_Byte( count ) )
+ goto Exit;
+
+ switch ( encoding->format & 0x7F )
+ {
+ case 0:
+ for ( j = 1; j <= count; j++ )
+ {
+ if ( READ_Byte( glyph_code ) )
+ goto Exit;
+
+ /* Make sure j is not too big. */
+ if ( j > num_glyphs )
+ goto Exit;
+
+ /* Assign code to GID mapping. */
+ encoding->codes[glyph_code] = (FT_UShort)j;
+
+ /* Assign code to SID mapping. */
+ encoding->sids[glyph_code] = charset->sids[j];
+ }
+
+ break;
+
+ case 1:
+ {
+ FT_Byte nleft;
+ FT_UInt i = 1;
+ FT_UInt k;
+
+
+ /* Parse the Format1 ranges. */
+ for ( j = 0; j < count; j++, i += nleft )
+ {
+ /* Read the first glyph code of the range. */
+ if ( READ_Byte( glyph_code ) )
+ goto Exit;
+
+ /* Read the number of codes in the range. */
+ if ( READ_Byte( nleft ) )
+ goto Exit;
+
+ /* Increment nleft, so we read `nleft + 1' codes/sids. */
+ nleft++;
+
+ /* Fill in the range of codes/sids. */
+ for ( k = i; k < nleft + i; k++, glyph_code++ )
+ {
+ /* Make sure k is not too big. */
+ if ( k > num_glyphs )
+ goto Exit;
+
+ /* Assign code to GID mapping. */
+ encoding->codes[glyph_code] = (FT_UShort)k;
+
+ /* Assign code to SID mapping. */
+ encoding->sids[glyph_code] = charset->sids[k];
+ }
+ }
+ }
+ break;
+
+ default:
+ FT_ERROR(( "CFF_Load_Encoding: invalid table format!\n" ));
+ error = CFF_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* Parse supplemental encodings, if any. */
+ if ( encoding->format & 0x80 )
+ {
+ FT_UInt glyph_id;
+
+
+ /* count supplements */
+ if ( READ_Byte( count ) )
+ goto Exit;
+
+ for ( j = 0; j < count; j++ )
+ {
+ /* Read supplemental glyph code. */
+ if ( READ_Byte( glyph_code ) )
+ goto Exit;
+
+ /* Read the SID associated with this glyph code. */
+ if ( READ_UShort( glyph_sid ) )
+ goto Exit;
+
+ /* Assign code to SID mapping. */
+ encoding->sids[glyph_code] = glyph_sid;
+
+ /* First, lookup GID which has been assigned to */
+ /* SID glyph_sid. */
+ for ( glyph_id = 0; glyph_id < num_glyphs; glyph_id++ )
+ {
+ if ( charset->sids[glyph_id] == glyph_sid )
+ break;
+ }
+
+ /* Now, make the assignment. */
+ encoding->codes[glyph_code] = (FT_UShort)glyph_id;
+ }
+ }
+ }
+ else
+ {
+ FT_UInt i;
+
+
+ /* We take into account the fact a CFF font can use a predefined */
+ /* encoding without containing all of the glyphs encoded by this */
+ /* encoding (see the note at the end of section 12 in the CFF */
+ /* specification). */
+
+ switch ( offset )
+ {
+ case 0:
+ /* First, copy the code to SID mapping. */
+ MEM_Copy( encoding->sids, cff_standard_encoding,
+ 256 * sizeof ( FT_UShort ) );
+
+ /* Construct code to GID mapping from code */
+ /* to SID mapping and charset. */
+ for ( j = 0; j < 256; j++ )
+ {
+ /* If j is encoded, find the GID for it. */
+ if ( encoding->sids[j] )
+ {
+ for ( i = 1; i < num_glyphs; i++ )
+ /* We matched, so break. */
+ if ( charset->sids[i] == encoding->sids[j] )
+ break;
+
+ /* i will be equal to num_glyphs if we exited the above */
+ /* loop without a match. In this case, we also have to */
+ /* fix the code to SID mapping. */
+ if ( i == num_glyphs )
+ {
+ encoding->codes[j] = 0;
+ encoding->sids [j] = 0;
+ }
+ else
+ encoding->codes[j] = (FT_UShort)i;
+ }
+ }
+ break;
+
+ case 1:
+ /* First, copy the code to SID mapping. */
+ MEM_Copy( encoding->sids, cff_expert_encoding,
+ 256 * sizeof ( FT_UShort ) );
+
+ /* Construct code to GID mapping from code to SID mapping */
+ /* and charset. */
+ for ( j = 0; j < 256; j++ )
+ {
+ /* If j is encoded, find the GID for it. */
+ if ( encoding->sids[j] )
+ {
+ for ( i = 1; i < num_glyphs; i++ )
+ /* We matched, so break. */
+ if ( charset->sids[i] == encoding->sids[j] )
+ break;
+
+ /* i will be equal to num_glyphs if we exited the above */
+ /* loop without a match. In this case, we also have to */
+ /* fix the code to SID mapping. */
+ if ( i == num_glyphs )
+ {
+ encoding->codes[j] = 0;
+ encoding->sids [j] = 0;
+ }
+ else
+ encoding->codes[j] = (FT_UShort)i;
+ }
+ }
+ break;
+
+ default:
+ FT_ERROR(( "CFF_Load_Encoding: invalid table format!\n" ));
+ error = CFF_Err_Invalid_File_Format;
+ goto Exit;
+ }
+ }
+
+ Exit:
+
+ /* Clean up if there was an error. */
+ if ( error )
+ {
+ if ( encoding->sids || encoding->codes )
+ {
+ if ( encoding->sids )
+ FREE( encoding->sids );
+
+ if ( encoding->codes )
+ FREE( encoding->codes );
+
+ charset->format = 0;
+ charset->offset = 0;
+ charset->sids = 0;
+ }
+ }
+
+ return error;
+ }
+
+
+ static FT_Error
+ CFF_Load_SubFont( CFF_SubFont* font,
+ CFF_Index* index,
+ FT_UInt font_index,
+ FT_Stream stream,
+ FT_ULong base_offset )
+ {
+ FT_Error error;
+ CFF_Parser parser;
+ FT_Byte* dict;
+ FT_ULong dict_len;
+ CFF_Font_Dict* top = &font->font_dict;
+ CFF_Private* priv = &font->private_dict;
+
+
+ CFF_Parser_Init( &parser, CFF_CODE_TOPDICT, &font->font_dict );
+
+ /* set defaults */
+ MEM_Set( top, 0, sizeof ( *top ) );
+
+ top->underline_position = -100;
+ top->underline_thickness = 50;
+ top->charstring_type = 2;
+ top->font_matrix.xx = 0x10000L;
+ top->font_matrix.yy = 0x10000L;
+ top->cid_count = 8720;
+
+ error = CFF_Access_Element( index, font_index, &dict, &dict_len ) ||
+ CFF_Parser_Run( &parser, dict, dict + dict_len );
+
+ CFF_Forget_Element( index, &dict );
+
+ if ( error )
+ goto Exit;
+
+ /* if it is a CID font, we stop there */
+ if ( top->cid_registry )
+ goto Exit;
+
+ /* parse the private dictionary, if any */
+ if ( top->private_offset && top->private_size )
+ {
+ /* set defaults */
+ MEM_Set( priv, 0, sizeof ( *priv ) );
+
+ priv->blue_shift = 7;
+ priv->blue_fuzz = 1;
+ priv->lenIV = -1;
+ priv->expansion_factor = (FT_Fixed)0.06 * 0x10000L;
+ priv->blue_scale = (FT_Fixed)0.039625 * 0x10000L;
+
+ CFF_Parser_Init( &parser, CFF_CODE_PRIVATE, priv );
+
+ if ( FILE_Seek( base_offset + font->font_dict.private_offset ) ||
+ ACCESS_Frame( font->font_dict.private_size ) )
+ goto Exit;
+
+ error = CFF_Parser_Run( &parser,
+ (FT_Byte*)stream->cursor,
+ (FT_Byte*)stream->limit );
+ FORGET_Frame();
+ if ( error )
+ goto Exit;
+ }
+
+ /* read the local subrs, if any */
+ if ( priv->local_subrs_offset )
+ {
+ if ( FILE_Seek( base_offset + top->private_offset +
+ priv->local_subrs_offset ) )
+ goto Exit;
+
+ error = cff_new_index( &font->local_subrs_index, stream, 1 );
+ if ( error )
+ goto Exit;
+
+ font->num_local_subrs = font->local_subrs_index.count;
+ error = cff_explicit_index( &font->local_subrs_index,
+ &font->local_subrs );
+ if ( error )
+ goto Exit;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ static void
+ CFF_Done_SubFont( FT_Memory memory,
+ CFF_SubFont* subfont )
+ {
+ if ( subfont )
+ {
+ cff_done_index( &subfont->local_subrs_index );
+ FREE( subfont->local_subrs );
+ }
+ }
+
+
+ FT_LOCAL_DEF FT_Error
+ CFF_Load_Font( FT_Stream stream,
+ FT_Int face_index,
+ CFF_Font* font )
+ {
+ static const FT_Frame_Field cff_header_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE CFF_Font
+
+ FT_FRAME_START( 4 ),
+ FT_FRAME_BYTE( version_major ),
+ FT_FRAME_BYTE( version_minor ),
+ FT_FRAME_BYTE( header_size ),
+ FT_FRAME_BYTE( absolute_offsize ),
+ FT_FRAME_END
+ };
+
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+ FT_ULong base_offset;
+ CFF_Font_Dict* dict;
+
+
+ MEM_Set( font, 0, sizeof ( *font ) );
+
+ font->stream = stream;
+ font->memory = memory;
+ dict = &font->top_font.font_dict;
+ base_offset = FILE_Pos();
+
+ /* read CFF font header */
+ if ( READ_Fields( cff_header_fields, font ) )
+ goto Exit;
+
+ /* check format */
+ if ( font->version_major != 1 ||
+ font->header_size < 4 ||
+ font->absolute_offsize > 4 )
+ {
+ FT_TRACE2(( "[not a CFF font header!]\n" ));
+ error = CFF_Err_Unknown_File_Format;
+ goto Exit;
+ }
+
+ /* skip the rest of the header */
+ if ( FILE_Skip( font->header_size - 4 ) )
+ goto Exit;
+
+ /* read the name, top dict, string and global subrs index */
+ if ( FT_SET_ERROR( cff_new_index( &font->name_index, stream, 0 )) ||
+ FT_SET_ERROR( cff_new_index( &font->font_dict_index, stream, 0 )) ||
+ FT_SET_ERROR( cff_new_index( &font->string_index, stream, 0 )) ||
+ FT_SET_ERROR( cff_new_index( &font->global_subrs_index, stream, 1 )) )
+ goto Exit;
+
+ /* well, we don't really forget the `disabled' fonts... */
+ font->num_faces = font->name_index.count;
+ if ( face_index >= (FT_Int)font->num_faces )
+ {
+ FT_ERROR(( "CFF_Load_Font: incorrect face index = %d\n",
+ face_index ));
+ error = CFF_Err_Invalid_Argument;
+ }
+
+ /* in case of a font format check, simply exit now */
+ if ( face_index < 0 )
+ goto Exit;
+
+ /* now, parse the top-level font dictionary */
+ error = CFF_Load_SubFont( &font->top_font,
+ &font->font_dict_index,
+ face_index,
+ stream,
+ base_offset );
+ if ( error )
+ goto Exit;
+
+ /* now, check for a CID font */
+ if ( dict->cid_registry )
+ {
+ CFF_Index fd_index;
+ CFF_SubFont* sub;
+ FT_UInt index;
+
+
+ /* this is a CID-keyed font, we must now allocate a table of */
+ /* sub-fonts, then load each of them separately */
+ if ( FILE_Seek( base_offset + dict->cid_fd_array_offset ) )
+ goto Exit;
+
+ error = cff_new_index( &fd_index, stream, 0 );
+ if ( error )
+ goto Exit;
+
+ if ( fd_index.count > CFF_MAX_CID_FONTS )
+ {
+ FT_ERROR(( "CFF_Load_Font: FD array too large in CID font\n" ));
+ goto Fail_CID;
+ }
+
+ /* allocate & read each font dict independently */
+ font->num_subfonts = fd_index.count;
+ if ( ALLOC_ARRAY( sub, fd_index.count, CFF_SubFont ) )
+ goto Fail_CID;
+
+ /* setup pointer table */
+ for ( index = 0; index < fd_index.count; index++ )
+ font->subfonts[index] = sub + index;
+
+ /* now load each sub font independently */
+ for ( index = 0; index < fd_index.count; index++ )
+ {
+ sub = font->subfonts[index];
+ error = CFF_Load_SubFont( sub, &fd_index, index,
+ stream, base_offset );
+ if ( error )
+ goto Fail_CID;
+ }
+
+ /* now load the FD Select array */
+ error = CFF_Load_FD_Select( &font->fd_select,
+ dict->cid_count,
+ stream,
+ base_offset + dict->cid_fd_select_offset );
+
+ Fail_CID:
+ cff_done_index( &fd_index );
+
+ if ( error )
+ goto Exit;
+ }
+ else
+ font->num_subfonts = 0;
+
+ /* read the charstrings index now */
+ if ( dict->charstrings_offset == 0 )
+ {
+ FT_ERROR(( "CFF_Load_Font: no charstrings offset!\n" ));
+ error = CFF_Err_Unknown_File_Format;
+ goto Exit;
+ }
+
+ if ( FILE_Seek( base_offset + dict->charstrings_offset ) )
+ goto Exit;
+
+ error = cff_new_index( &font->charstrings_index, stream, 0 );
+ if ( error )
+ goto Exit;
+
+ /* explicit the global subrs */
+ font->num_global_subrs = font->global_subrs_index.count;
+ font->num_glyphs = font->charstrings_index.count;
+
+ error = cff_explicit_index( &font->global_subrs_index,
+ &font->global_subrs ) ;
+
+ if ( error )
+ goto Exit;
+
+ /* read the Charset and Encoding tables when available */
+ error = CFF_Load_Charset( &font->charset, font->num_glyphs, stream,
+ base_offset, dict->charset_offset );
+ if ( error )
+ goto Exit;
+
+ error = CFF_Load_Encoding( &font->encoding,
+ &font->charset,
+ font->num_glyphs,
+ stream,
+ base_offset,
+ dict->encoding_offset );
+ if ( error )
+ goto Exit;
+
+ /* get the font name */
+ font->font_name = CFF_Get_Name( &font->name_index, face_index );
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF void
+ CFF_Done_Font( CFF_Font* font )
+ {
+ FT_Memory memory = font->memory;
+ FT_UInt index;
+
+
+ cff_done_index( &font->global_subrs_index );
+ cff_done_index( &font->string_index );
+ cff_done_index( &font->font_dict_index );
+ cff_done_index( &font->name_index );
+ cff_done_index( &font->charstrings_index );
+
+ /* release font dictionaries */
+ for ( index = 0; index < font->num_subfonts; index++ )
+ CFF_Done_SubFont( memory, font->subfonts[index] );
+
+ CFF_Done_Encoding( &font->encoding, font->stream );
+ CFF_Done_Charset( &font->charset, font->stream );
+
+ CFF_Done_SubFont( memory, &font->top_font );
+
+ CFF_Done_FD_Select( &font->fd_select, font->stream );
+
+ FREE( font->global_subrs );
+ FREE( font->font_name );
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cffobjs.c */
+/* */
+/* OpenType objects manager (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_STREAM_H
+#include FT_ERRORS_H
+#include FT_TRUETYPE_IDS_H
+#include FT_TRUETYPE_TAGS_H
+#include FT_INTERNAL_SFNT_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include "cffobjs.h"
+#include "cffload.h"
+
+#include "cfferrs.h"
+
+#include <string.h> /* for strlen() */
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cffobjs
+
+
+ /*************************************************************************/
+ /* */
+ /* FACE FUNCTIONS */
+ /* */
+ /*************************************************************************/
+
+ static FT_String*
+ CFF_StrCopy( FT_Memory memory,
+ const FT_String* source )
+ {
+ FT_Error error;
+ FT_String* result = 0;
+ FT_Int len = (FT_Int)strlen( source );
+
+
+ if ( !ALLOC( result, len + 1 ) )
+ {
+ MEM_Copy( result, source, len );
+ result[len] = 0;
+ }
+ return result;
+ }
+
+
+#if 0
+
+ /* this function is used to build a Unicode charmap from the glyph names */
+ /* in a file */
+ static FT_Error
+ CFF_Build_Unicode_Charmap( CFF_Face face,
+ FT_ULong base_offset,
+ PSNames_Interface* psnames )
+ {
+ CFF_Font* font = (CFF_Font*)face->extra.data;
+ FT_Memory memory = FT_FACE_MEMORY(face);
+ FT_UInt n, num_glyphs = face->root.num_glyphs;
+ const char** glyph_names;
+ FT_Error error;
+ CFF_Font_Dict* dict = &font->top_font.font_dict;
+ FT_ULong charset_offset;
+ FT_Byte format;
+ FT_Stream stream = face->root.stream;
+
+
+ charset_offset = dict->charset_offset;
+ if ( !charset_offset )
+ {
+ FT_ERROR(( "CFF_Build_Unicode_Charmap: charset table is missing\n" ));
+ error = CFF_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* allocate the charmap */
+ if ( ALLOC( face->charmap, ...
+
+ /* seek to charset table and allocate glyph names table */
+ if ( FILE_Seek( base_offset + charset_offset ) ||
+ ALLOC_ARRAY( glyph_names, num_glyphs, const char* ) )
+ goto Exit;
+
+ /* now, read each glyph name and store it in the glyph name table */
+ if ( READ_Byte( format ) )
+ goto Fail;
+
+ switch ( format )
+ {
+ case 0: /* format 0 - one SID per glyph */
+ {
+ const char** gname = glyph_names;
+ const char** limit = gname + num_glyphs;
+
+
+ if ( ACCESS_Frame( num_glyphs * 2 ) )
+ goto Fail;
+
+ for ( ; gname < limit; gname++ )
+ gname[0] = CFF_Get_String( &font->string_index,
+ GET_UShort(),
+ psnames );
+ FORGET_Frame();
+ break;
+ }
+
+ case 1: /* format 1 - sequential ranges */
+ case 2: /* format 2 - sequential ranges with 16-bit counts */
+ {
+ const char** gname = glyph_names;
+ const char** limit = gname + num_glyphs;
+ FT_UInt len = 3;
+
+
+ if ( format == 2 )
+ len++;
+
+ while ( gname < limit )
+ {
+ FT_UInt first;
+ FT_UInt count;
+
+
+ if ( ACCESS_Frame( len ) )
+ goto Fail;
+
+ first = GET_UShort();
+ if ( format == 3 )
+ count = GET_UShort();
+ else
+ count = GET_Byte();
+
+ FORGET_Frame();
+
+ for ( ; count > 0; count-- )
+ {
+ gname[0] = CFF_Get_String( &font->string_index,
+ first,
+ psnames );
+ gname++;
+ first++;
+ }
+ }
+ break;
+ }
+
+ default: /* unknown charset format! */
+ FT_ERROR(( "CFF_Build_Unicode_Charmap: unknown charset format!\n" ));
+ error = CFF_Err_Invalid_File_Format;
+ goto Fail;
+ }
+
+ /* all right, the glyph names were loaded; we now need to create */
+ /* the corresponding unicode charmap */
+
+ Fail:
+ for ( n = 0; n < num_glyphs; n++ )
+ FREE( glyph_names[n] );
+
+ FREE( glyph_names );
+
+ Exit:
+ return error;
+ }
+
+#endif /* 0 */
+
+
+ static FT_Encoding
+ find_encoding( int platform_id,
+ int encoding_id )
+ {
+ typedef struct TEncoding
+ {
+ int platform_id;
+ int encoding_id;
+ FT_Encoding encoding;
+
+ } TEncoding;
+
+ static
+ const TEncoding tt_encodings[] =
+ {
+ { TT_PLATFORM_ISO, -1, ft_encoding_unicode },
+
+ { TT_PLATFORM_APPLE_UNICODE, -1, ft_encoding_unicode },
+
+ { TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, ft_encoding_apple_roman },
+
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, ft_encoding_unicode },
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, ft_encoding_sjis },
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_GB2312, ft_encoding_gb2312 },
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, ft_encoding_big5 },
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, ft_encoding_wansung },
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, ft_encoding_johab }
+ };
+
+ const TEncoding *cur, *limit;
+
+
+ cur = tt_encodings;
+ limit = cur + sizeof ( tt_encodings ) / sizeof ( tt_encodings[0] );
+
+ for ( ; cur < limit; cur++ )
+ {
+ if ( cur->platform_id == platform_id )
+ {
+ if ( cur->encoding_id == encoding_id ||
+ cur->encoding_id == -1 )
+ return cur->encoding;
+ }
+ }
+
+ return ft_encoding_none;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* CFF_Init_Face */
+ /* */
+ /* <Description> */
+ /* Initializes a given OpenType face object. */
+ /* */
+ /* <Input> */
+ /* stream :: The source font stream. */
+ /* */
+ /* face_index :: The index of the font face in the resource. */
+ /* */
+ /* num_params :: Number of additional generic parameters. Ignored. */
+ /* */
+ /* params :: Additional generic parameters. Ignored. */
+ /* */
+ /* <InOut> */
+ /* face :: The newly built face object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ CFF_Init_Face( FT_Stream stream,
+ CFF_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ FT_Error error;
+ SFNT_Interface* sfnt;
+ PSNames_Interface* psnames;
+ FT_Bool pure_cff = 1;
+ FT_Bool sfnt_format = 0;
+
+
+ sfnt = (SFNT_Interface*)FT_Get_Module_Interface(
+ face->root.driver->root.library, "sfnt" );
+ if ( !sfnt )
+ goto Bad_Format;
+
+ psnames = (PSNames_Interface*)FT_Get_Module_Interface(
+ face->root.driver->root.library, "psnames" );
+
+ /* create input stream from resource */
+ if ( FILE_Seek( 0 ) )
+ goto Exit;
+
+ /* check that we have a valid OpenType file */
+ error = sfnt->init_face( stream, face, face_index, num_params, params );
+ if ( !error )
+ {
+ if ( face->format_tag != 0x4F54544FL ) /* `OTTO'; OpenType/CFF font */
+ {
+ FT_TRACE2(( "[not a valid OpenType/CFF font]\n" ));
+ goto Bad_Format;
+ }
+
+ /* if we are performing a simple font format check, exit immediately */
+ if ( face_index < 0 )
+ return CFF_Err_Ok;
+
+ sfnt_format = 1;
+
+ /* now, the font can be either an OpenType/CFF font, or an SVG CEF */
+ /* font in the later case; it doesn't have a `head' table */
+ error = face->goto_table( face, TTAG_head, stream, 0 );
+ if ( !error )
+ {
+ pure_cff = 0;
+
+ /* load font directory */
+ error = sfnt->load_face( stream, face,
+ face_index, num_params, params );
+ if ( error )
+ goto Exit;
+ }
+ else
+ {
+ /* load the `cmap' table by hand */
+ error = sfnt->load_charmaps( face, stream );
+ if ( error )
+ goto Exit;
+
+ /* XXX: we don't load the GPOS table, as OpenType Layout */
+ /* support will be added later to a layout library on top of */
+ /* FreeType 2 */
+ }
+
+ /* now, load the CFF part of the file */
+ error = face->goto_table( face, TTAG_CFF, stream, 0 );
+ if ( error )
+ goto Exit;
+ }
+ else
+ {
+ /* rewind to start of file; we are going to load a pure-CFF font */
+ if ( FILE_Seek( 0 ) )
+ goto Exit;
+ error = CFF_Err_Ok;
+ }
+
+ /* now load and parse the CFF table in the file */
+ {
+ CFF_Font* cff;
+ FT_Memory memory = face->root.memory;
+ FT_Face root;
+ FT_UInt flags;
+
+
+ if ( ALLOC( cff, sizeof ( *cff ) ) )
+ goto Exit;
+
+ face->extra.data = cff;
+ error = CFF_Load_Font( stream, face_index, cff );
+ if ( error )
+ goto Exit;
+
+ /* Complement the root flags with some interesting information. */
+ /* Note that this is only necessary for pure CFF and CEF fonts. */
+
+ root = &face->root;
+ if ( pure_cff )
+ {
+ CFF_Font_Dict* dict = &cff->top_font.font_dict;
+
+
+ /* we need the `PSNames' module for pure-CFF and CEF formats */
+ if ( !psnames )
+ {
+ FT_ERROR(( "CFF_Init_Face:" ));
+ FT_ERROR(( " cannot open CFF & CEF fonts\n" ));
+ FT_ERROR(( " " ));
+ FT_ERROR(( " without the `PSNames' module\n" ));
+ goto Bad_Format;
+ }
+
+ /* Set up num_faces. */
+ root->num_faces = cff->num_faces;
+
+ /* compute number of glyphs */
+ if ( dict->cid_registry )
+ root->num_glyphs = dict->cid_count;
+ else
+ root->num_glyphs = cff->charstrings_index.count;
+
+ /* set global bbox, as well as EM size */
+ root->bbox = dict->font_bbox;
+ root->ascender = (FT_Short)( root->bbox.yMax >> 16 );
+ root->descender = (FT_Short)( root->bbox.yMin >> 16 );
+ root->height = (FT_Short)(
+ ( ( root->ascender - root->descender ) * 12 ) / 10 );
+
+ if ( dict->units_per_em )
+ root->units_per_EM = dict->units_per_em;
+ else
+ root->units_per_EM = 1000;
+
+ /* retrieve font family & style name */
+ root->family_name = CFF_Get_Name( &cff->name_index, face_index );
+ if ( dict->cid_registry )
+ root->style_name = CFF_StrCopy( memory, "Regular" ); /* XXXX */
+ else
+ root->style_name = CFF_Get_String( &cff->string_index,
+ dict->weight,
+ psnames );
+
+ /*******************************************************************/
+ /* */
+ /* Compute face flags. */
+ /* */
+ flags = FT_FACE_FLAG_SCALABLE | /* scalable outlines */
+ FT_FACE_FLAG_HORIZONTAL; /* horizontal data */
+
+ if ( sfnt_format )
+ flags |= FT_FACE_FLAG_SFNT;
+
+ /* fixed width font? */
+ if ( dict->is_fixed_pitch )
+ flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+ /* XXX: WE DO NOT SUPPORT KERNING METRICS IN THE GPOS TABLE FOR NOW */
+#if 0
+ /* kerning available? */
+ if ( face->kern_pairs )
+ flags |= FT_FACE_FLAG_KERNING;
+#endif
+
+#ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES
+ flags |= FT_FACE_FLAG_GLYPH_NAMES;
+#endif
+
+ root->face_flags = flags;
+
+ /*******************************************************************/
+ /* */
+ /* Compute style flags. */
+ /* */
+ flags = 0;
+
+ if ( dict->italic_angle )
+ flags |= FT_STYLE_FLAG_ITALIC;
+
+ /* XXX: may not be correct */
+ if ( cff->top_font.private_dict.force_bold )
+ flags |= FT_STYLE_FLAG_BOLD;
+
+ root->style_flags = flags;
+
+ /* set the charmaps if any */
+ if ( sfnt_format )
+ {
+ /*****************************************************************/
+ /* */
+ /* Polish the charmaps. */
+ /* */
+ /* Try to set the charmap encoding according to the platform & */
+ /* encoding ID of each charmap. */
+ /* */
+ TT_CharMap charmap;
+ FT_Int n;
+
+
+ charmap = face->charmaps;
+ root->num_charmaps = face->num_charmaps;
+
+ /* allocate table of pointers */
+ if ( ALLOC_ARRAY( root->charmaps, root->num_charmaps, FT_CharMap ) )
+ goto Exit;
+
+ for ( n = 0; n < root->num_charmaps; n++, charmap++ )
+ {
+ FT_Int platform = charmap->cmap.platformID;
+ FT_Int encoding = charmap->cmap.platformEncodingID;
+
+
+ charmap->root.face = (FT_Face)face;
+ charmap->root.platform_id = (FT_UShort)platform;
+ charmap->root.encoding_id = (FT_UShort)encoding;
+ charmap->root.encoding = find_encoding( platform, encoding );
+
+ /* now, set root->charmap with a unicode charmap */
+ /* wherever available */
+ if ( !root->charmap &&
+ charmap->root.encoding == ft_encoding_unicode )
+ root->charmap = (FT_CharMap)charmap;
+
+ root->charmaps[n] = (FT_CharMap)charmap;
+ }
+ }
+ }
+ }
+
+ Exit:
+ return error;
+
+ Bad_Format:
+ error = CFF_Err_Unknown_File_Format;
+ goto Exit;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* CFF_Done_Face */
+ /* */
+ /* <Description> */
+ /* Finalizes a given face object. */
+ /* */
+ /* <Input> */
+ /* face :: A pointer to the face object to destroy. */
+ /* */
+ FT_LOCAL_DEF void
+ CFF_Done_Face( CFF_Face face )
+ {
+ FT_Memory memory = face->root.memory;
+ SFNT_Interface* sfnt = (SFNT_Interface*)face->sfnt;
+
+
+ if ( sfnt )
+ sfnt->done_face( face );
+
+ {
+ CFF_Font* cff = (CFF_Font*)face->extra.data;
+
+
+ if ( cff )
+ {
+ CFF_Done_Font( cff );
+ FREE( face->extra.data );
+ }
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* CFF_Init_Driver */
+ /* */
+ /* <Description> */
+ /* Initializes a given OpenType driver object. */
+ /* */
+ /* <Input> */
+ /* driver :: A handle to the target driver object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ CFF_Init_Driver( CFF_Driver driver )
+ {
+ /* init extension registry if needed */
+
+#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
+
+ return TT_Init_Extensions( driver );
+
+#else
+
+ FT_UNUSED( driver );
+
+ return CFF_Err_Ok;
+
+#endif
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* CFF_Done_Driver */
+ /* */
+ /* <Description> */
+ /* Finalizes a given OpenType driver. */
+ /* */
+ /* <Input> */
+ /* driver :: A handle to the target OpenType driver. */
+ /* */
+ FT_LOCAL_DEF void
+ CFF_Done_Driver( CFF_Driver driver )
+ {
+ /* destroy extensions registry if needed */
+
+#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
+
+ TT_Done_Extensions( driver );
+
+#else
+
+ FT_UNUSED( driver );
+
+#endif
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cffparse.c */
+/* */
+/* CFF token stream parser (body) */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "cffparse.h"
+#include FT_INTERNAL_STREAM_H
+
+#include "cfferrs.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cffparse
+
+
+ enum
+ {
+ cff_kind_none = 0,
+ cff_kind_num,
+ cff_kind_fixed,
+ cff_kind_string,
+ cff_kind_bool,
+ cff_kind_delta,
+ cff_kind_callback,
+
+ cff_kind_max /* do not remove */
+ };
+
+
+ /* now generate handlers for the most simple fields */
+ typedef FT_Error (*CFF_Field_Reader)( CFF_Parser* parser );
+
+ typedef struct CFF_Field_Handler_
+ {
+ int kind;
+ int code;
+ FT_UInt offset;
+ FT_Byte size;
+ CFF_Field_Reader reader;
+ FT_UInt array_max;
+ FT_UInt count_offset;
+
+ } CFF_Field_Handler;
+
+
+ FT_LOCAL_DEF void
+ CFF_Parser_Init( CFF_Parser* parser,
+ FT_UInt code,
+ void* object )
+ {
+ MEM_Set( parser, 0, sizeof ( *parser ) );
+
+ parser->top = parser->stack;
+ parser->object_code = code;
+ parser->object = object;
+ }
+
+
+ /* read an integer */
+ static FT_Long
+ cff_parse_integer( FT_Byte* start,
+ FT_Byte* limit )
+ {
+ FT_Byte* p = start;
+ FT_Int v = *p++;
+ FT_Long val = 0;
+
+
+ if ( v == 28 )
+ {
+ if ( p + 2 > limit )
+ goto Bad;
+
+ val = (FT_Short)( ( (FT_Int)p[0] << 8 ) | p[1] );
+ p += 2;
+ }
+ else if ( v == 29 )
+ {
+ if ( p + 4 > limit )
+ goto Bad;
+
+ val = ( (FT_Long)p[0] << 24 ) |
+ ( (FT_Long)p[1] << 16 ) |
+ ( (FT_Long)p[2] << 8 ) |
+ p[3];
+ p += 4;
+ }
+ else if ( v < 247 )
+ {
+ val = v - 139;
+ }
+ else if ( v < 251 )
+ {
+ if ( p + 1 > limit )
+ goto Bad;
+
+ val = ( v - 247 ) * 256 + p[0] + 108;
+ p++;
+ }
+ else
+ {
+ if ( p + 1 > limit )
+ goto Bad;
+
+ val = -( v - 251 ) * 256 - p[0] - 108;
+ p++;
+ }
+
+ Exit:
+ return val;
+
+ Bad:
+ val = 0;
+ goto Exit;
+ }
+
+
+ /* read a real */
+ static FT_Fixed
+ cff_parse_real( FT_Byte* start,
+ FT_Byte* limit,
+ FT_Int power_ten )
+ {
+ FT_Byte* p = start;
+ FT_Long num, divider, result, exp;
+ FT_Int sign = 0, exp_sign = 0;
+ FT_UInt nib;
+ FT_UInt phase;
+
+
+ result = 0;
+ num = 0;
+ divider = 1;
+
+ /* first of all, read the integer part */
+ phase = 4;
+
+ for (;;)
+ {
+ /* If we entered this iteration with phase == 4, we need to */
+ /* read a new byte. This also skips past the intial 0x1E. */
+ if ( phase )
+ {
+ p++;
+
+ /* Make sure we don't read past the end. */
+ if ( p >= limit )
+ goto Bad;
+ }
+
+ /* Get the nibble. */
+ nib = ( p[0] >> phase ) & 0xF;
+ phase = 4 - phase;
+
+ if ( nib == 0xE )
+ sign = 1;
+ else if ( nib > 9 )
+ break;
+ else
+ result = result * 10 + nib;
+ }
+
+ /* read decimal part, if any */
+ if ( nib == 0xa )
+ for (;;)
+ {
+ /* If we entered this iteration with phase == 4, we need */
+ /* to read a new byte. */
+ if ( phase )
+ {
+ p++;
+
+ /* Make sure we don't read past the end. */
+ if ( p >= limit )
+ goto Bad;
+ }
+
+ /* Get the nibble. */
+ nib = ( p[0] >> phase ) & 0xF;
+ phase = 4 - phase;
+ if ( nib >= 10 )
+ break;
+
+ if ( divider < 10000000L )
+ {
+ num = num * 10 + nib;
+ divider *= 10;
+ }
+ }
+
+ /* read exponent, if any */
+ if ( nib == 12 )
+ {
+ exp_sign = 1;
+ nib = 11;
+ }
+
+ if ( nib == 11 )
+ {
+ exp = 0;
+
+ for (;;)
+ {
+ /* If we entered this iteration with phase == 4, we need */
+ /* to read a new byte. */
+ if ( phase )
+ {
+ p++;
+
+ /* Make sure we don't read past the end. */
+ if ( p >= limit )
+ goto Bad;
+ }
+
+ /* Get the nibble. */
+ nib = ( p[0] >> phase ) & 0xF;
+ phase = 4 - phase;
+ if ( nib >= 10 )
+ break;
+
+ exp = exp * 10 + nib;
+ }
+
+ if ( exp_sign )
+ exp = -exp;
+
+ power_ten += exp;
+ }
+
+ /* raise to power of ten if needed */
+ while ( power_ten > 0 )
+ {
+ result = result * 10;
+ num = num * 10;
+
+ power_ten--;
+ }
+
+ while ( power_ten < 0 )
+ {
+ result = result / 10;
+ divider = divider * 10;
+
+ power_ten++;
+ }
+
+ /* Move the integer part into the high 16 bits. */
+ result <<= 16;
+
+ /* Place the decimal part into the low 16 bits. */
+ if ( num )
+ result |= FT_DivFix( num, divider );
+
+ if ( sign )
+ result = -result;
+
+ Exit:
+ return result;
+
+ Bad:
+ result = 0;
+ goto Exit;
+ }
+
+
+ /* read a number, either integer or real */
+ static FT_Long
+ cff_parse_num( FT_Byte** d )
+ {
+ return ( **d == 30 ? ( cff_parse_real ( d[0], d[1], 0 ) >> 16 )
+ : cff_parse_integer( d[0], d[1] ) );
+ }
+
+
+ /* read a floating point number, either integer or real */
+ static FT_Fixed
+ cff_parse_fixed( FT_Byte** d )
+ {
+ return ( **d == 30 ? cff_parse_real ( d[0], d[1], 0 )
+ : cff_parse_integer( d[0], d[1] ) << 16 );
+ }
+
+ /* read a floating point number, either integer or real, */
+ /* but return 1000 times the number read in. */
+ static FT_Fixed
+ cff_parse_fixed_thousand( FT_Byte** d )
+ {
+ return **d ==
+ 30 ? cff_parse_real ( d[0], d[1], 3 )
+ : (FT_Fixed)FT_MulFix( cff_parse_integer( d[0], d[1] ) << 16, 1000 );
+ }
+
+ static FT_Error
+ cff_parse_font_matrix( CFF_Parser* parser )
+ {
+ CFF_Font_Dict* dict = (CFF_Font_Dict*)parser->object;
+ FT_Matrix* matrix = &dict->font_matrix;
+ FT_Vector* offset = &dict->font_offset;
+ FT_UShort* upm = &dict->units_per_em;
+ FT_Byte** data = parser->stack;
+ FT_Error error;
+ FT_Fixed temp;
+
+
+ error = CFF_Err_Stack_Underflow;
+
+ if ( parser->top >= parser->stack + 6 )
+ {
+ matrix->xx = cff_parse_fixed_thousand( data++ );
+ matrix->yx = cff_parse_fixed_thousand( data++ );
+ matrix->xy = cff_parse_fixed_thousand( data++ );
+ matrix->yy = cff_parse_fixed_thousand( data++ );
+ offset->x = cff_parse_fixed_thousand( data++ );
+ offset->y = cff_parse_fixed_thousand( data );
+
+ temp = ABS( matrix->yy );
+
+ *upm = (FT_UShort)FT_DivFix( 0x10000L, FT_DivFix( temp, 1000 ) );
+
+ if ( temp != 0x10000L )
+ {
+ matrix->xx = FT_DivFix( matrix->xx, temp );
+ matrix->yx = FT_DivFix( matrix->yx, temp );
+ matrix->xy = FT_DivFix( matrix->xy, temp );
+ matrix->yy = FT_DivFix( matrix->yy, temp );
+ offset->x = FT_DivFix( offset->x, temp );
+ offset->y = FT_DivFix( offset->y, temp );
+ }
+
+ /* note that the offsets must be expressed in integer font units */
+ offset->x >>= 16;
+ offset->y >>= 16;
+
+ error = CFF_Err_Ok;
+ }
+
+ return error;
+ }
+
+
+ static FT_Error
+ cff_parse_font_bbox( CFF_Parser* parser )
+ {
+ CFF_Font_Dict* dict = (CFF_Font_Dict*)parser->object;
+ FT_BBox* bbox = &dict->font_bbox;
+ FT_Byte** data = parser->stack;
+ FT_Error error;
+
+
+ error = CFF_Err_Stack_Underflow;
+
+ if ( parser->top >= parser->stack + 4 )
+ {
+ bbox->xMin = FT_RoundFix( cff_parse_fixed( data++ ) );
+ bbox->yMin = FT_RoundFix( cff_parse_fixed( data++ ) );
+ bbox->xMax = FT_RoundFix( cff_parse_fixed( data++ ) );
+ bbox->yMax = FT_RoundFix( cff_parse_fixed( data ) );
+ error = CFF_Err_Ok;
+ }
+
+ return error;
+ }
+
+
+ static FT_Error
+ cff_parse_private_dict( CFF_Parser* parser )
+ {
+ CFF_Font_Dict* dict = (CFF_Font_Dict*)parser->object;
+ FT_Byte** data = parser->stack;
+ FT_Error error;
+
+
+ error = CFF_Err_Stack_Underflow;
+
+ if ( parser->top >= parser->stack + 2 )
+ {
+ dict->private_size = cff_parse_num( data++ );
+ dict->private_offset = cff_parse_num( data );
+ error = CFF_Err_Ok;
+ }
+
+ return error;
+ }
+
+
+ static FT_Error
+ cff_parse_cid_ros( CFF_Parser* parser )
+ {
+ CFF_Font_Dict* dict = (CFF_Font_Dict*)parser->object;
+ FT_Byte** data = parser->stack;
+ FT_Error error;
+
+
+ error = CFF_Err_Stack_Underflow;
+
+ if ( parser->top >= parser->stack + 3 )
+ {
+ dict->cid_registry = (FT_UInt)cff_parse_num ( data++ );
+ dict->cid_ordering = (FT_UInt)cff_parse_num ( data++ );
+ dict->cid_supplement = (FT_ULong)cff_parse_num( data );
+ error = CFF_Err_Ok;
+ }
+
+ return error;
+ }
+
+
+#define CFF_FIELD_NUM( code, name ) \
+ CFF_FIELD( code, name, cff_kind_num )
+#define CFF_FIELD_FIXED( code, name ) \
+ CFF_FIELD( code, name, cff_kind_fixed )
+#define CFF_FIELD_STRING( code, name ) \
+ CFF_FIELD( code, name, cff_kind_string )
+#define CFF_FIELD_BOOL( code, name ) \
+ CFF_FIELD( code, name, cff_kind_bool )
+#define CFF_FIELD_DELTA( code, name, max ) \
+ CFF_FIELD( code, name, cff_kind_delta )
+
+#define CFF_FIELD_CALLBACK( code, name ) \
+ { \
+ cff_kind_callback, \
+ code | CFFCODE, \
+ 0, 0, \
+ cff_parse_ ## name, \
+ 0, 0 \
+ },
+
+#undef CFF_FIELD
+#define CFF_FIELD( code, name, kind ) \
+ { \
+ kind, \
+ code | CFFCODE, \
+ FT_FIELD_OFFSET( name ), \
+ FT_FIELD_SIZE( name ), \
+ 0, 0, 0 \
+ },
+
+#undef CFF_FIELD_DELTA
+#define CFF_FIELD_DELTA( code, name, max ) \
+ { \
+ cff_kind_delta, \
+ code | CFFCODE, \
+ FT_FIELD_OFFSET( name ), \
+ FT_FIELD_SIZE_DELTA( name ), \
+ 0, \
+ max, \
+ FT_FIELD_OFFSET( num_ ## name ) \
+ },
+
+#define CFFCODE_TOPDICT 0x1000
+#define CFFCODE_PRIVATE 0x2000
+
+ static const CFF_Field_Handler cff_field_handlers[] =
+ {
+
+#include "cfftoken.h"
+
+ { 0, 0, 0, 0, 0, 0, 0 }
+ };
+
+
+ FT_LOCAL_DEF FT_Error
+ CFF_Parser_Run( CFF_Parser* parser,
+ FT_Byte* start,
+ FT_Byte* limit )
+ {
+ FT_Byte* p = start;
+ FT_Error error = CFF_Err_Ok;
+
+
+ parser->top = parser->stack;
+ parser->start = start;
+ parser->limit = limit;
+ parser->cursor = start;
+
+ while ( p < limit )
+ {
+ FT_UInt v = *p;
+
+
+ if ( v >= 27 && v != 31 )
+ {
+ /* it's a number; we will push its position on the stack */
+ if ( parser->top - parser->stack >= CFF_MAX_STACK_DEPTH )
+ goto Stack_Overflow;
+
+ *parser->top ++ = p;
+
+ /* now, skip it */
+ if ( v == 30 )
+ {
+ /* skip real number */
+ p++;
+ for (;;)
+ {
+ if ( p >= limit )
+ goto Syntax_Error;
+ v = p[0] >> 4;
+ if ( v == 15 )
+ break;
+ v = p[0] & 0xF;
+ if ( v == 15 )
+ break;
+ p++;
+ }
+ }
+ else if ( v == 28 )
+ p += 2;
+ else if ( v == 29 )
+ p += 4;
+ else if ( v > 246 )
+ p += 1;
+ }
+ else
+ {
+ /* This is not a number, hence it's an operator. Compute its code */
+ /* and look for it in our current list. */
+
+ FT_UInt code;
+ FT_UInt num_args = (FT_UInt)
+ ( parser->top - parser->stack );
+ const CFF_Field_Handler* field;
+
+
+ /* first of all, a trivial check */
+ if ( num_args < 1 )
+ goto Stack_Underflow;
+
+ *parser->top = p;
+ code = v;
+ if ( v == 12 )
+ {
+ /* two byte operator */
+ p++;
+ code = 0x100 | p[0];
+ }
+ code = code | parser->object_code;
+
+ for ( field = cff_field_handlers; field->kind; field++ )
+ {
+ if ( field->code == (FT_Int)code )
+ {
+ /* we found our field's handler; read it */
+ FT_Long val;
+ FT_Byte* q = (FT_Byte*)parser->object + field->offset;
+
+
+ switch ( field->kind )
+ {
+ case cff_kind_bool:
+ case cff_kind_string:
+ case cff_kind_num:
+ val = cff_parse_num( parser->stack );
+ goto Store_Number;
+
+ case cff_kind_fixed:
+ val = cff_parse_fixed( parser->stack );
+
+ Store_Number:
+ switch ( field->size )
+ {
+ case 1:
+ *(FT_Byte*)q = (FT_Byte)val;
+ break;
+
+ case 2:
+ *(FT_Short*)q = (FT_Short)val;
+ break;
+
+ case 4:
+ *(FT_Int32*)q = (FT_Int)val;
+ break;
+
+ default: /* for 64-bit systems where long is 8 bytes */
+ *(FT_Long*)q = val;
+ }
+ break;
+
+ case cff_kind_delta:
+ {
+ FT_Byte* qcount = (FT_Byte*)parser->object +
+ field->count_offset;
+
+ FT_Byte** data = parser->stack;
+
+
+ if ( num_args > field->array_max )
+ num_args = field->array_max;
+
+ /* store count */
+ *qcount = (FT_Byte)num_args;
+
+ val = 0;
+ while ( num_args > 0 )
+ {
+ val += cff_parse_num( data++ );
+ switch ( field->size )
+ {
+ case 1:
+ *(FT_Byte*)q = (FT_Byte)val;
+ break;
+
+ case 2:
+ *(FT_Short*)q = (FT_Short)val;
+ break;
+
+ case 4:
+ *(FT_Int32*)q = (FT_Int)val;
+ break;
+
+ default: /* for 64-bit systems */
+ *(FT_Long*)q = val;
+ }
+
+ q += field->size;
+ num_args--;
+ }
+ }
+ break;
+
+ default: /* callback */
+ error = field->reader( parser );
+ if ( error )
+ goto Exit;
+ }
+ goto Found;
+ }
+ }
+
+ /* this is an unknown operator, or it is unsupported; */
+ /* we will ignore it for now. */
+
+ Found:
+ /* clear stack */
+ parser->top = parser->stack;
+ }
+ p++;
+ }
+
+ Exit:
+ return error;
+
+ Stack_Overflow:
+ error = CFF_Err_Invalid_Argument;
+ goto Exit;
+
+ Stack_Underflow:
+ error = CFF_Err_Invalid_Argument;
+ goto Exit;
+
+ Syntax_Error:
+ error = CFF_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cidgload.c */
+/* */
+/* CID-keyed Type1 Glyph Loader (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "cidload.h"
+#include "cidgload.h"
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_OUTLINE_H
+
+#include "ciderrs.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cidgload
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ cid_load_glyph( T1_Decoder* decoder,
+ FT_UInt glyph_index )
+ {
+ CID_Face face = (CID_Face)decoder->builder.face;
+ CID_Info* cid = &face->cid;
+ FT_Byte* p;
+ FT_UInt entry_len = cid->fd_bytes + cid->gd_bytes;
+ FT_UInt fd_select;
+ FT_ULong off1, glyph_len;
+ FT_Stream stream = face->root.stream;
+ FT_Error error = 0;
+
+
+ /* read the CID font dict index and charstring offset from the CIDMap */
+ if ( FILE_Seek( cid->data_offset + cid->cidmap_offset +
+ glyph_index * entry_len ) ||
+ ACCESS_Frame( 2 * entry_len ) )
+ goto Exit;
+
+ p = (FT_Byte*)stream->cursor;
+ fd_select = (FT_UInt) cid_get_offset( &p, (FT_Byte)cid->fd_bytes );
+ off1 = (FT_ULong)cid_get_offset( &p, (FT_Byte)cid->gd_bytes );
+ p += cid->fd_bytes;
+ glyph_len = cid_get_offset( &p, (FT_Byte)cid->gd_bytes ) - off1;
+
+ FORGET_Frame();
+
+ /* now, if the glyph is not empty, set up the subrs array, and parse */
+ /* the charstrings */
+ if ( glyph_len > 0 )
+ {
+ CID_FontDict* dict;
+ CID_Subrs* cid_subrs = face->subrs + fd_select;
+ FT_Byte* charstring;
+ FT_Memory memory = face->root.memory;
+
+
+ /* setup subrs */
+ decoder->num_subrs = cid_subrs->num_subrs;
+ decoder->subrs = cid_subrs->code;
+ decoder->subrs_len = 0;
+
+ /* setup font matrix */
+ dict = cid->font_dicts + fd_select;
+
+ decoder->font_matrix = dict->font_matrix;
+ decoder->font_offset = dict->font_offset;
+ decoder->lenIV = dict->private_dict.lenIV;
+
+ /* the charstrings are encoded (stupid!) */
+ /* load the charstrings, then execute it */
+
+ if ( ALLOC( charstring, glyph_len ) )
+ goto Exit;
+
+ if ( !FILE_Read_At( cid->data_offset + off1, charstring, glyph_len ) )
+ {
+ FT_Int cs_offset;
+
+
+ /* Adjustment for seed bytes. */
+ cs_offset = ( decoder->lenIV >= 0 ? decoder->lenIV : 0 );
+
+ /* Decrypt only if lenIV >= 0. */
+ if ( decoder->lenIV >= 0 )
+ cid_decrypt( charstring, glyph_len, 4330 );
+
+ error = decoder->funcs.parse_charstrings( decoder,
+ charstring + cs_offset,
+ glyph_len - cs_offset );
+ }
+
+ FREE( charstring );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+#if 0
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********** *********/
+ /********** *********/
+ /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/
+ /********** *********/
+ /********** The following code is in charge of computing *********/
+ /********** the maximum advance width of the font. It *********/
+ /********** quickly processes each glyph charstring to *********/
+ /********** extract the value from either a `sbw' or `seac' *********/
+ /********** operator. *********/
+ /********** *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_LOCAL_DEF FT_Error
+ CID_Compute_Max_Advance( CID_Face face,
+ FT_Int* max_advance )
+ {
+ FT_Error error;
+ T1_Decoder decoder;
+ FT_Int glyph_index;
+
+ PSAux_Interface* psaux = (PSAux_Interface*)face->psaux;
+
+
+ *max_advance = 0;
+
+ /* Initialize load decoder */
+ error = psaux->t1_decoder_funcs->init( &decoder,
+ (FT_Face)face,
+ 0, /* size */
+ 0, /* glyph slot */
+ 0, /* glyph names! XXX */
+ 0, /* blend == 0 */
+ cid_load_glyph );
+ if ( error )
+ return error;
+
+ decoder.builder.metrics_only = 1;
+ decoder.builder.load_points = 0;
+
+ /* for each glyph, parse the glyph charstring and extract */
+ /* the advance width */
+ for ( glyph_index = 0; glyph_index < face->root.num_glyphs;
+ glyph_index++ )
+ {
+ /* now get load the unscaled outline */
+ error = cid_load_glyph( &decoder, glyph_index );
+ /* ignore the error if one occurred - skip to next glyph */
+ }
+
+ *max_advance = decoder.builder.advance.x;
+
+ return CID_Err_Ok;
+ }
+
+
+#endif /* 0 */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********** *********/
+ /********** *********/
+ /********** UNHINTED GLYPH LOADER *********/
+ /********** *********/
+ /********** The following code is in charge of loading a *********/
+ /********** single outline. It completely ignores hinting *********/
+ /********** and is used when FT_LOAD_NO_HINTING is set. *********/
+ /********** *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_LOCAL_DEF FT_Error
+ CID_Load_Glyph( CID_GlyphSlot glyph,
+ CID_Size size,
+ FT_Int glyph_index,
+ FT_Int load_flags )
+ {
+ FT_Error error;
+ T1_Decoder decoder;
+ CID_Face face = (CID_Face)glyph->root.face;
+ FT_Bool hinting;
+
+ PSAux_Interface* psaux = (PSAux_Interface*)face->psaux;
+ FT_Matrix font_matrix;
+ FT_Vector font_offset;
+
+
+ if ( load_flags & FT_LOAD_NO_RECURSE )
+ load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+
+ glyph->x_scale = size->root.metrics.x_scale;
+ glyph->y_scale = size->root.metrics.y_scale;
+
+ glyph->root.outline.n_points = 0;
+ glyph->root.outline.n_contours = 0;
+
+ hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 &&
+ ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
+
+ glyph->root.format = ft_glyph_format_outline;
+
+ {
+ error = psaux->t1_decoder_funcs->init( &decoder,
+ (FT_Face)face,
+ (FT_Size)size,
+ (FT_GlyphSlot)glyph,
+ 0, /* glyph names -- XXX */
+ 0, /* blend == 0 */
+ cid_load_glyph );
+
+ /* set up the decoder */
+ decoder.builder.no_recurse = FT_BOOL(
+ ( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 ) );
+
+ error = cid_load_glyph( &decoder, glyph_index );
+
+ font_matrix = decoder.font_matrix;
+ font_offset = decoder.font_offset;
+
+ /* save new glyph tables */
+ psaux->t1_decoder_funcs->done( &decoder );
+ }
+
+ /* now, set the metrics -- this is rather simple, as */
+ /* the left side bearing is the xMin, and the top side */
+ /* bearing the yMax */
+ if ( !error )
+ {
+ glyph->root.outline.flags &= ft_outline_owner;
+ glyph->root.outline.flags |= ft_outline_reverse_fill;
+
+ /* for composite glyphs, return only left side bearing and */
+ /* advance width */
+ if ( load_flags & FT_LOAD_NO_RECURSE )
+ {
+ FT_Slot_Internal internal = glyph->root.internal;
+
+
+ glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x;
+ glyph->root.metrics.horiAdvance = decoder.builder.advance.x;
+
+ internal->glyph_matrix = font_matrix;
+ internal->glyph_delta = font_offset;
+ internal->glyph_transformed = 1;
+ }
+ else
+ {
+ FT_BBox cbox;
+ FT_Glyph_Metrics* metrics = &glyph->root.metrics;
+
+
+ /* copy the _unscaled_ advance width */
+ metrics->horiAdvance = decoder.builder.advance.x;
+ glyph->root.linearHoriAdvance = decoder.builder.advance.x;
+ glyph->root.internal->glyph_transformed = 0;
+
+ /* make up vertical metrics */
+ metrics->vertBearingX = 0;
+ metrics->vertBearingY = 0;
+ metrics->vertAdvance = 0;
+
+ glyph->root.linearVertAdvance = 0;
+ glyph->root.format = ft_glyph_format_outline;
+
+ if ( size && size->root.metrics.y_ppem < 24 )
+ glyph->root.outline.flags |= ft_outline_high_precision;
+
+ /* apply the font matrix */
+ FT_Outline_Transform( &glyph->root.outline, &font_matrix );
+
+ FT_Outline_Translate( &glyph->root.outline,
+ font_offset.x,
+ font_offset.y );
+
+ if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 )
+ {
+ /* scale the outline and the metrics */
+ FT_Int n;
+ FT_Outline* cur = decoder.builder.base;
+ FT_Vector* vec = cur->points;
+ FT_Fixed x_scale = glyph->x_scale;
+ FT_Fixed y_scale = glyph->y_scale;
+
+
+ /* First of all, scale the points */
+ for ( n = cur->n_points; n > 0; n--, vec++ )
+ {
+ vec->x = FT_MulFix( vec->x, x_scale );
+ vec->y = FT_MulFix( vec->y, y_scale );
+ }
+
+ FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
+
+ /* Then scale the metrics */
+ metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
+ metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
+
+ metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale );
+ metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale );
+ }
+
+ /* compute the other metrics */
+ FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
+
+ /* grid fit the bounding box if necessary */
+ if ( hinting )
+ {
+ cbox.xMin &= -64;
+ cbox.yMin &= -64;
+ cbox.xMax = ( cbox.xMax + 63 ) & -64;
+ cbox.yMax = ( cbox.yMax + 63 ) & -64;
+ }
+
+ metrics->width = cbox.xMax - cbox.xMin;
+ metrics->height = cbox.yMax - cbox.yMin;
+
+ metrics->horiBearingX = cbox.xMin;
+ metrics->horiBearingY = cbox.yMax;
+ }
+ }
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cidload.c */
+/* */
+/* CID-keyed Type1 font loader (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_CONFIG_CONFIG_H
+#include FT_MULTIPLE_MASTERS_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+
+#include "cidload.h"
+
+#include "ciderrs.h"
+
+#include <stdio.h>
+#include <ctype.h> /* for isspace(), isalnum() */
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cidload
+
+
+ /* read a single offset */
+ FT_LOCAL_DEF FT_Long
+ cid_get_offset( FT_Byte** start,
+ FT_Byte offsize )
+ {
+ FT_Long result;
+ FT_Byte* p = *start;
+
+
+ for ( result = 0; offsize > 0; offsize-- )
+ {
+ result <<= 8;
+ result |= *p++;
+ }
+
+ *start = p;
+ return result;
+ }
+
+
+ FT_LOCAL_DEF void
+ cid_decrypt( FT_Byte* buffer,
+ FT_Offset length,
+ FT_UShort seed )
+ {
+ while ( length > 0 )
+ {
+ FT_Byte plain;
+
+
+ plain = (FT_Byte)( *buffer ^ ( seed >> 8 ) );
+ seed = (FT_UShort)( ( *buffer + seed ) * 52845U + 22719 );
+ *buffer++ = plain;
+ length--;
+ }
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** TYPE 1 SYMBOL PARSING *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ static FT_Error
+ cid_load_keyword( CID_Face face,
+ CID_Loader* loader,
+ const T1_Field* keyword )
+ {
+ FT_Error error;
+ CID_Parser* parser = &loader->parser;
+ FT_Byte* object;
+ void* dummy_object;
+ CID_Info* cid = &face->cid;
+
+
+ /* if the keyword has a dedicated callback, call it */
+ if ( keyword->type == t1_field_callback )
+ {
+ keyword->reader( (FT_Face)face, parser );
+ error = parser->root.error;
+ goto Exit;
+ }
+
+ /* we must now compute the address of our target object */
+ switch ( keyword->location )
+ {
+ case t1_field_cid_info:
+ object = (FT_Byte*)cid;
+ break;
+
+ case t1_field_font_info:
+ object = (FT_Byte*)&cid->font_info;
+ break;
+
+ default:
+ {
+ CID_FontDict* dict;
+
+
+ if ( parser->num_dict < 0 )
+ {
+ FT_ERROR(( "cid_load_keyword: invalid use of `%s'!\n",
+ keyword->ident ));
+ error = CID_Err_Syntax_Error;
+ goto Exit;
+ }
+
+ dict = cid->font_dicts + parser->num_dict;
+ switch ( keyword->location )
+ {
+ case t1_field_private:
+ object = (FT_Byte*)&dict->private_dict;
+ break;
+
+ default:
+ object = (FT_Byte*)dict;
+ }
+ }
+ }
+
+ dummy_object = object;
+
+ /* now, load the keyword data in the object's field(s) */
+ if ( keyword->type == t1_field_integer_array ||
+ keyword->type == t1_field_fixed_array )
+ error = CID_Load_Field_Table( &loader->parser, keyword,
+ &dummy_object );
+ else
+ error = CID_Load_Field( &loader->parser, keyword, &dummy_object );
+ Exit:
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ parse_font_bbox( CID_Face face,
+ CID_Parser* parser )
+ {
+ FT_Fixed temp[4];
+ FT_BBox* bbox = &face->cid.font_bbox;
+
+
+ (void)CID_ToFixedArray( parser, 4, temp, 0 );
+ bbox->xMin = FT_RoundFix( temp[0] );
+ bbox->yMin = FT_RoundFix( temp[1] );
+ bbox->xMax = FT_RoundFix( temp[2] );
+ bbox->yMax = FT_RoundFix( temp[3] );
+
+ return CID_Err_Ok; /* this is a callback function; */
+ /* we must return an error code */
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ parse_font_matrix( CID_Face face,
+ CID_Parser* parser )
+ {
+ FT_Matrix* matrix;
+ FT_Vector* offset;
+ CID_FontDict* dict;
+ FT_Face root = (FT_Face)&face->root;
+ FT_Fixed temp[6];
+ FT_Fixed temp_scale;
+
+
+ if ( parser->num_dict >= 0 )
+ {
+ dict = face->cid.font_dicts + parser->num_dict;
+ matrix = &dict->font_matrix;
+ offset = &dict->font_offset;
+
+ (void)CID_ToFixedArray( parser, 6, temp, 3 );
+
+ temp_scale = ABS( temp[3] );
+
+ /* Set Units per EM based on FontMatrix values. We set the value to */
+ /* `1000/temp_scale', because temp_scale was already multiplied by */
+ /* 1000 (in t1_tofixed(), from psobjs.c). */
+ root->units_per_EM = (FT_UShort)( FT_DivFix( 0x10000L,
+ FT_DivFix( temp_scale, 1000 ) ) );
+
+ /* we need to scale the values by 1.0/temp[3] */
+ if ( temp_scale != 0x10000L )
+ {
+ temp[0] = FT_DivFix( temp[0], temp_scale );
+ temp[1] = FT_DivFix( temp[1], temp_scale );
+ temp[2] = FT_DivFix( temp[2], temp_scale );
+ temp[4] = FT_DivFix( temp[4], temp_scale );
+ temp[5] = FT_DivFix( temp[5], temp_scale );
+ temp[3] = 0x10000L;
+ }
+
+ matrix->xx = temp[0];
+ matrix->yx = temp[1];
+ matrix->xy = temp[2];
+ matrix->yy = temp[3];
+
+ /* note that the font offsets are expressed in integer font units */
+ offset->x = temp[4] >> 16;
+ offset->y = temp[5] >> 16;
+ }
+
+ return CID_Err_Ok; /* this is a callback function; */
+ /* we must return an error code */
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ parse_fd_array( CID_Face face,
+ CID_Parser* parser )
+ {
+ CID_Info* cid = &face->cid;
+ FT_Memory memory = face->root.memory;
+ FT_Error error = CID_Err_Ok;
+ FT_Long num_dicts;
+
+
+ num_dicts = CID_ToInt( parser );
+
+ if ( !cid->font_dicts )
+ {
+ FT_Int n;
+
+
+ if ( ALLOC_ARRAY( cid->font_dicts, num_dicts, CID_FontDict ) )
+ goto Exit;
+
+ cid->num_dicts = (FT_UInt)num_dicts;
+
+ /* don't forget to set a few defaults */
+ for ( n = 0; n < cid->num_dicts; n++ )
+ {
+ CID_FontDict* dict = cid->font_dicts + n;
+
+
+ /* default value for lenIV */
+ dict->private_dict.lenIV = 4;
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ static
+ const T1_Field cid_field_records[] =
+ {
+
+#include "cidtoken.h"
+
+ T1_FIELD_CALLBACK( "FontBBox", parse_font_bbox )
+ T1_FIELD_CALLBACK( "FDArray", parse_fd_array )
+ T1_FIELD_CALLBACK( "FontMatrix", parse_font_matrix )
+ { 0, t1_field_cid_info, t1_field_none, 0, 0, 0, 0, 0 }
+ };
+
+
+ static int
+ is_alpha( char c )
+ {
+ return ( isalnum( (int)c ) ||
+ c == '.' ||
+ c == '_' );
+ }
+
+
+ static FT_Error
+ cid_parse_dict( CID_Face face,
+ CID_Loader* loader,
+ FT_Byte* base,
+ FT_Long size )
+ {
+ CID_Parser* parser = &loader->parser;
+
+
+ parser->root.cursor = base;
+ parser->root.limit = base + size;
+ parser->root.error = 0;
+
+ {
+ FT_Byte* cur = base;
+ FT_Byte* limit = cur + size;
+
+
+ for ( ;cur < limit; cur++ )
+ {
+ /* look for `%ADOBeginFontDict' */
+ if ( *cur == '%' && cur + 20 < limit &&
+ strncmp( (char*)cur, "%ADOBeginFontDict", 17 ) == 0 )
+ {
+ cur += 17;
+
+ /* if /FDArray was found, then cid->num_dicts is > 0, and */
+ /* we can start increasing parser->num_dict */
+ if ( face->cid.num_dicts > 0 )
+ parser->num_dict++;
+ }
+ /* look for immediates */
+ else if ( *cur == '/' && cur + 2 < limit )
+ {
+ FT_Byte* cur2;
+ FT_Int len;
+
+
+ cur++;
+
+ cur2 = cur;
+ while ( cur2 < limit && is_alpha( *cur2 ) )
+ cur2++;
+
+ len = (FT_Int)( cur2 - cur );
+ if ( len > 0 && len < 22 )
+ {
+ /* now compare the immediate name to the keyword table */
+ const T1_Field* keyword = cid_field_records;
+
+
+ for (;;)
+ {
+ FT_Byte* name;
+
+
+ name = (FT_Byte*)keyword->ident;
+ if ( !name )
+ break;
+
+ if ( cur[0] == name[0] &&
+ len == (FT_Int)strlen( (const char*)name ) )
+ {
+ FT_Int n;
+
+
+ for ( n = 1; n < len; n++ )
+ if ( cur[n] != name[n] )
+ break;
+
+ if ( n >= len )
+ {
+ /* we found it - run the parsing callback */
+ parser->root.cursor = cur2;
+ CID_Skip_Spaces( parser );
+ parser->root.error = cid_load_keyword( face,
+ loader,
+ keyword );
+ if ( parser->root.error )
+ return parser->root.error;
+
+ cur = parser->root.cursor;
+ break;
+ }
+ }
+ keyword++;
+ }
+ }
+ }
+ }
+ }
+ return parser->root.error;
+ }
+
+
+ /* read the subrmap and the subrs of each font dict */
+ static FT_Error
+ cid_read_subrs( CID_Face face )
+ {
+ CID_Info* cid = &face->cid;
+ FT_Memory memory = face->root.memory;
+ FT_Stream stream = face->root.stream;
+ FT_Error error;
+ FT_Int n;
+ CID_Subrs* subr;
+ FT_UInt max_offsets = 0;
+ FT_ULong* offsets = 0;
+
+
+ if ( ALLOC_ARRAY( face->subrs, cid->num_dicts, CID_Subrs ) )
+ goto Exit;
+
+ subr = face->subrs;
+ for ( n = 0; n < cid->num_dicts; n++, subr++ )
+ {
+ CID_FontDict* dict = cid->font_dicts + n;
+ FT_Int lenIV = dict->private_dict.lenIV;
+ FT_UInt count, num_subrs = dict->num_subrs;
+ FT_ULong data_len;
+ FT_Byte* p;
+
+
+ /* reallocate offsets array if needed */
+ if ( num_subrs + 1 > max_offsets )
+ {
+ FT_UInt new_max = ( num_subrs + 1 + 3 ) & -4;
+
+
+ if ( REALLOC_ARRAY( offsets, max_offsets, new_max, FT_ULong ) )
+ goto Fail;
+
+ max_offsets = new_max;
+ }
+
+ /* read the subrmap's offsets */
+ if ( FILE_Seek( cid->data_offset + dict->subrmap_offset ) ||
+ ACCESS_Frame( ( num_subrs + 1 ) * dict->sd_bytes ) )
+ goto Fail;
+
+ p = (FT_Byte*)stream->cursor;
+ for ( count = 0; count <= num_subrs; count++ )
+ offsets[count] = cid_get_offset( &p, (FT_Byte)dict->sd_bytes );
+
+ FORGET_Frame();
+
+ /* now, compute the size of subrs charstrings, */
+ /* allocate, and read them */
+ data_len = offsets[num_subrs] - offsets[0];
+
+ if ( ALLOC_ARRAY( subr->code, num_subrs + 1, FT_Byte* ) ||
+ ALLOC( subr->code[0], data_len ) )
+ goto Fail;
+
+ if ( FILE_Seek( cid->data_offset + offsets[0] ) ||
+ FILE_Read( subr->code[0], data_len ) )
+ goto Exit;
+
+ /* set up pointers */
+ for ( count = 1; count <= num_subrs; count++ )
+ {
+ FT_UInt len;
+
+
+ len = offsets[count] - offsets[count - 1];
+ subr->code[count] = subr->code[count - 1] + len;
+ }
+
+ /* decrypt subroutines, but only if lenIV >= 0 */
+ if ( lenIV >= 0 )
+ {
+ for ( count = 0; count < num_subrs; count++ )
+ {
+ FT_UInt len;
+
+
+ len = offsets[count + 1] - offsets[count];
+ cid_decrypt( subr->code[count], len, 4330 );
+ }
+ }
+
+ subr->num_subrs = num_subrs;
+ }
+
+ Exit:
+ FREE( offsets );
+ return error;
+
+ Fail:
+ if ( face->subrs )
+ {
+ for ( n = 0; n < cid->num_dicts; n++ )
+ {
+ if ( face->subrs[n].code )
+ FREE( face->subrs[n].code[0] );
+
+ FREE( face->subrs[n].code );
+ }
+ FREE( face->subrs );
+ }
+ goto Exit;
+ }
+
+
+ static void
+ t1_init_loader( CID_Loader* loader,
+ CID_Face face )
+ {
+ FT_UNUSED( face );
+
+ MEM_Set( loader, 0, sizeof ( *loader ) );
+ }
+
+
+ static void
+ t1_done_loader( CID_Loader* loader )
+ {
+ CID_Parser* parser = &loader->parser;
+
+
+ /* finalize parser */
+ CID_Done_Parser( parser );
+ }
+
+
+ FT_LOCAL_DEF FT_Error
+ CID_Open_Face( CID_Face face )
+ {
+ CID_Loader loader;
+ CID_Parser* parser;
+ FT_Error error;
+
+
+ t1_init_loader( &loader, face );
+
+ parser = &loader.parser;
+ error = CID_New_Parser( parser, face->root.stream, face->root.memory,
+ (PSAux_Interface*)face->psaux );
+ if ( error )
+ goto Exit;
+
+ error = cid_parse_dict( face, &loader,
+ parser->postscript,
+ parser->postscript_len );
+ if ( error )
+ goto Exit;
+
+ face->cid.data_offset = loader.parser.data_offset;
+ error = cid_read_subrs( face );
+
+ Exit:
+ t1_done_loader( &loader );
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cidobjs.c */
+/* */
+/* CID objects manager (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include "cidgload.h"
+#include "cidload.h"
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+#include "ciderrs.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cidobjs
+
+
+ /*************************************************************************/
+ /* */
+ /* FACE FUNCTIONS */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* CID_Done_Face */
+ /* */
+ /* <Description> */
+ /* Finalizes a given face object. */
+ /* */
+ /* <Input> */
+ /* face :: A pointer to the face object to destroy. */
+ /* */
+ FT_LOCAL_DEF void
+ CID_Done_Face( CID_Face face )
+ {
+ FT_Memory memory;
+
+
+ if ( face )
+ {
+ CID_Info* cid = &face->cid;
+ T1_FontInfo* info = &cid->font_info;
+
+
+ memory = face->root.memory;
+
+ /* release FontInfo strings */
+ FREE( info->version );
+ FREE( info->notice );
+ FREE( info->full_name );
+ FREE( info->family_name );
+ FREE( info->weight );
+
+ /* release font dictionaries */
+ FREE( cid->font_dicts );
+ cid->num_dicts = 0;
+
+ /* release other strings */
+ FREE( cid->cid_font_name );
+ FREE( cid->registry );
+ FREE( cid->ordering );
+
+ face->root.family_name = 0;
+ face->root.style_name = 0;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* CID_Init_Face */
+ /* */
+ /* <Description> */
+ /* Initializes a given CID face object. */
+ /* */
+ /* <Input> */
+ /* stream :: The source font stream. */
+ /* */
+ /* face_index :: The index of the font face in the resource. */
+ /* */
+ /* num_params :: Number of additional generic parameters. Ignored. */
+ /* */
+ /* params :: Additional generic parameters. Ignored. */
+ /* */
+ /* <InOut> */
+ /* face :: The newly built face object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ CID_Init_Face( FT_Stream stream,
+ CID_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ FT_Error error;
+ PSNames_Interface* psnames;
+ PSAux_Interface* psaux;
+
+ FT_UNUSED( num_params );
+ FT_UNUSED( params );
+ FT_UNUSED( face_index );
+ FT_UNUSED( stream );
+
+
+ face->root.num_faces = 1;
+
+ psnames = (PSNames_Interface*)face->psnames;
+ if ( !psnames )
+ {
+ psnames = (PSNames_Interface*)FT_Get_Module_Interface(
+ FT_FACE_LIBRARY( face ), "psnames" );
+
+ face->psnames = psnames;
+ }
+
+ psaux = (PSAux_Interface*)face->psaux;
+ if ( !psaux )
+ {
+ psaux = (PSAux_Interface*)FT_Get_Module_Interface(
+ FT_FACE_LIBRARY( face ), "psaux" );
+
+ face->psaux = psaux;
+ }
+
+ /* open the tokenizer; this will also check the font format */
+ if ( FILE_Seek( 0 ) )
+ goto Exit;
+
+ error = CID_Open_Face( face );
+ if ( error )
+ goto Exit;
+
+ /* if we just wanted to check the format, leave successfully now */
+ if ( face_index < 0 )
+ goto Exit;
+
+ /* check the face index */
+ if ( face_index != 0 )
+ {
+ FT_ERROR(( "CID_Init_Face: invalid face index\n" ));
+ error = CID_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ /* Now, load the font program into the face object */
+ {
+ /* Init the face object fields */
+ /* Now set up root face fields */
+ {
+ FT_Face root = (FT_Face)&face->root;
+
+
+ root->num_glyphs = face->cid.cid_count;
+ root->num_charmaps = 0;
+
+ root->face_index = face_index;
+ root->face_flags = FT_FACE_FLAG_SCALABLE;
+
+ root->face_flags |= FT_FACE_FLAG_HORIZONTAL;
+
+ if ( face->cid.font_info.is_fixed_pitch )
+ root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+ /* XXX: TODO: add kerning with .afm support */
+
+ /* get style name -- be careful, some broken fonts only */
+ /* have a /FontName dictionary entry! */
+ root->family_name = face->cid.font_info.family_name;
+ if ( root->family_name )
+ {
+ char* full = face->cid.font_info.full_name;
+ char* family = root->family_name;
+
+ while ( *family && *full == *family )
+ {
+ family++;
+ full++;
+ }
+
+ root->style_name = ( *full == ' ' ) ? full + 1
+ : (char *)"Regular";
+ }
+ else
+ {
+ /* do we have a `/FontName'? */
+ if ( face->cid.cid_font_name )
+ {
+ root->family_name = face->cid.cid_font_name;
+ root->style_name = (char *)"Regular";
+ }
+ }
+
+ /* no embedded bitmap support */
+ root->num_fixed_sizes = 0;
+ root->available_sizes = 0;
+
+ root->bbox = face->cid.font_bbox;
+ if ( !root->units_per_EM )
+ root->units_per_EM = 1000;
+
+ root->ascender = (FT_Short)( face->cid.font_bbox.yMax >> 16 );
+ root->descender = (FT_Short)( face->cid.font_bbox.yMin >> 16 );
+ root->height = (FT_Short)(
+ ( ( root->ascender + root->descender ) * 12 ) / 10 );
+
+
+#if 0
+
+ /* now compute the maximum advance width */
+
+ root->max_advance_width = face->type1.private_dict.standard_width[0];
+
+ /* compute max advance width for proportional fonts */
+ if ( !face->type1.font_info.is_fixed_pitch )
+ {
+ FT_Int max_advance;
+
+
+ error = CID_Compute_Max_Advance( face, &max_advance );
+
+ /* in case of error, keep the standard width */
+ if ( !error )
+ root->max_advance_width = max_advance;
+ else
+ error = 0; /* clear error */
+ }
+
+ root->max_advance_height = root->height;
+
+#endif /* 0 */
+
+ root->underline_position = face->cid.font_info.underline_position;
+ root->underline_thickness = face->cid.font_info.underline_thickness;
+
+ root->internal->max_points = 0;
+ root->internal->max_contours = 0;
+ }
+ }
+
+#if 0
+
+ /* charmap support - synthetize unicode charmap when possible */
+ {
+ FT_Face root = &face->root;
+ FT_CharMap charmap = face->charmaprecs;
+
+
+ /* synthesize a Unicode charmap if there is support in the `psnames' */
+ /* module */
+ if ( face->psnames )
+ {
+ PSNames_Interface* psnames = (PSNames_Interface*)face->psnames;
+
+
+ if ( psnames->unicode_value )
+ {
+ error = psnames->build_unicodes(
+ root->memory,
+ face->type1.num_glyphs,
+ (const char**)face->type1.glyph_names,
+ &face->unicode_map );
+ if ( !error )
+ {
+ root->charmap = charmap;
+ charmap->face = (FT_Face)face;
+ charmap->encoding = ft_encoding_unicode;
+ charmap->platform_id = 3;
+ charmap->encoding_id = 1;
+ charmap++;
+ }
+
+ /* simply clear the error in case of failure (which really */
+ /* means that out of memory or no unicode glyph names) */
+ error = 0;
+ }
+ }
+
+ /* now, support either the standard, expert, or custom encodings */
+ charmap->face = (FT_Face)face;
+ charmap->platform_id = 7; /* a new platform id for Adobe fonts? */
+
+ switch ( face->type1.encoding_type )
+ {
+ case t1_encoding_standard:
+ charmap->encoding = ft_encoding_adobe_standard;
+ charmap->encoding_id = 0;
+ break;
+
+ case t1_encoding_expert:
+ charmap->encoding = ft_encoding_adobe_expert;
+ charmap->encoding_id = 1;
+ break;
+
+ default:
+ charmap->encoding = ft_encoding_adobe_custom;
+ charmap->encoding_id = 2;
+ break;
+ }
+
+ root->charmaps = face->charmaps;
+ root->num_charmaps = charmap - face->charmaprecs + 1;
+ face->charmaps[0] = &face->charmaprecs[0];
+ face->charmaps[1] = &face->charmaprecs[1];
+ }
+
+#endif /* 0 */
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* CID_Init_Driver */
+ /* */
+ /* <Description> */
+ /* Initializes a given CID driver object. */
+ /* */
+ /* <Input> */
+ /* driver :: A handle to the target driver object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ CID_Init_Driver( CID_Driver driver )
+ {
+ FT_UNUSED( driver );
+
+ return CID_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* CID_Done_Driver */
+ /* */
+ /* <Description> */
+ /* Finalizes a given CID driver. */
+ /* */
+ /* <Input> */
+ /* driver :: A handle to the target CID driver. */
+ /* */
+ FT_LOCAL_DEF void
+ CID_Done_Driver( CID_Driver driver )
+ {
+ FT_UNUSED( driver );
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cidparse.c */
+/* */
+/* CID-keyed Type1 parser (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_STREAM_H
+
+#include "cidparse.h"
+
+#include "ciderrs.h"
+
+#include <string.h> /* for strncmp() */
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cidparse
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** INPUT STREAM PARSER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_LOCAL_DEF FT_Error
+ CID_New_Parser( CID_Parser* parser,
+ FT_Stream stream,
+ FT_Memory memory,
+ PSAux_Interface* psaux )
+ {
+ FT_Error error;
+ FT_ULong base_offset, offset, ps_len;
+ FT_Byte buffer[256 + 10];
+ FT_Int buff_len;
+
+
+ MEM_Set( parser, 0, sizeof ( *parser ) );
+ psaux->t1_parser_funcs->init( &parser->root, 0, 0, memory );
+
+ parser->stream = stream;
+
+ base_offset = FILE_Pos();
+
+ /* first of all, check the font format in the header */
+ if ( ACCESS_Frame( 31 ) )
+ goto Exit;
+
+ if ( strncmp( (char *)stream->cursor,
+ "%!PS-Adobe-3.0 Resource-CIDFont", 31 ) )
+ {
+ FT_TRACE2(( "[not a valid CID-keyed font]\n" ));
+ error = CID_Err_Unknown_File_Format;
+ }
+
+ FORGET_Frame();
+ if ( error )
+ goto Exit;
+
+ /* now, read the rest of the file, until we find a `StartData' */
+ buff_len = 256;
+ for (;;)
+ {
+ FT_Byte *p, *limit = buffer + 256;
+ FT_ULong top_position;
+
+
+ /* fill input buffer */
+ buff_len -= 256;
+ if ( buff_len > 0 )
+ MEM_Move( buffer, limit, buff_len );
+
+ p = buffer + buff_len;
+
+ if ( FILE_Read( p, 256 + 10 - buff_len ) )
+ goto Exit;
+
+ top_position = FILE_Pos() - buff_len;
+ buff_len = 256 + 10;
+
+ /* look for `StartData' */
+ for ( p = buffer; p < limit; p++ )
+ {
+ if ( p[0] == 'S' && strncmp( (char*)p, "StartData", 9 ) == 0 )
+ {
+ /* save offset of binary data after `StartData' */
+ offset = (FT_ULong)( top_position - ( limit - p ) + 10 );
+ goto Found;
+ }
+ }
+ }
+
+ Found:
+ /* we have found the start of the binary data. We will now */
+ /* rewind and extract the frame of corresponding to the Postscript */
+ /* section */
+
+ ps_len = offset - base_offset;
+ if ( FILE_Seek( base_offset ) ||
+ EXTRACT_Frame( ps_len, parser->postscript ) )
+ goto Exit;
+
+ parser->data_offset = offset;
+ parser->postscript_len = ps_len;
+ parser->root.base = parser->postscript;
+ parser->root.cursor = parser->postscript;
+ parser->root.limit = parser->root.cursor + ps_len;
+ parser->num_dict = -1;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF void
+ CID_Done_Parser( CID_Parser* parser )
+ {
+ /* always free the private dictionary */
+ if ( parser->postscript )
+ {
+ FT_Stream stream = parser->stream;
+
+
+ RELEASE_Frame( parser->postscript );
+ }
+ parser->root.funcs.done( &parser->root );
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cidriver.c */
+/* */
+/* CID driver interface (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "cidriver.h"
+#include "cidgload.h"
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+#include "ciderrs.h"
+
+#include <string.h> /* for strcmp() */
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ciddriver
+
+
+
+ static const char*
+ cid_get_postscript_name( CID_Face face )
+ {
+ return (const char*)face->cid.cid_font_name;
+ }
+
+
+ static FT_Module_Interface
+ CID_Get_Interface( FT_Driver driver,
+ const FT_String* interface )
+ {
+ FT_UNUSED( driver );
+ FT_UNUSED( interface );
+
+ if ( strcmp( (const char*)interface, "postscript_name" ) == 0 )
+ return (FT_Module_Interface)cid_get_postscript_name;
+
+ return 0;
+ }
+
+
+#if 0 /* unimplemented yet */
+
+ static FT_Error
+ cid_Get_Kerning( T1_Face face,
+ FT_UInt left_glyph,
+ FT_UInt right_glyph,
+ FT_Vector* kerning )
+ {
+ CID_AFM* afm;
+
+
+ kerning->x = 0;
+ kerning->y = 0;
+
+ afm = (CID_AFM*)face->afm_data;
+ if ( afm )
+ CID_Get_Kerning( afm, left_glyph, right_glyph, kerning );
+
+ return CID_Err_Ok;
+ }
+
+
+#endif /* 0 */
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Cid_Get_Char_Index */
+ /* */
+ /* <Description> */
+ /* Uses a charmap to return a given character code's glyph index. */
+ /* */
+ /* <Input> */
+ /* charmap :: A handle to the source charmap object. */
+ /* */
+ /* charcode :: The character code. */
+ /* */
+ /* <Return> */
+ /* Glyph index. 0 means `undefined character code'. */
+ /* */
+ static FT_UInt
+ CID_Get_Char_Index( FT_CharMap charmap,
+ FT_Long charcode )
+ {
+ T1_Face face;
+ FT_UInt result = 0;
+ PSNames_Interface* psnames;
+
+
+ face = (T1_Face)charmap->face;
+ psnames = (PSNames_Interface*)face->psnames;
+ if ( psnames )
+ switch ( charmap->encoding )
+ {
+ /*******************************************************************/
+ /* */
+ /* Unicode encoding support */
+ /* */
+ case ft_encoding_unicode:
+ /* use the `PSNames' module to synthetize the Unicode charmap */
+ result = psnames->lookup_unicode( &face->unicode_map,
+ (FT_ULong)charcode );
+
+ /* the function returns 0xFFFF if the Unicode charcode has */
+ /* no corresponding glyph. */
+ if ( result == 0xFFFF )
+ result = 0;
+ goto Exit;
+
+ /*******************************************************************/
+ /* */
+ /* Custom Type 1 encoding */
+ /* */
+ case ft_encoding_adobe_custom:
+ {
+ T1_Encoding* encoding = &face->type1.encoding;
+
+
+ if ( charcode >= encoding->code_first &&
+ charcode <= encoding->code_last )
+ result = encoding->char_index[charcode];
+ goto Exit;
+ }
+
+ /*******************************************************************/
+ /* */
+ /* Adobe Standard & Expert encoding support */
+ /* */
+ default:
+ if ( charcode < 256 )
+ {
+ FT_UInt code;
+ FT_Int n;
+ const char* glyph_name;
+
+
+ code = psnames->adobe_std_encoding[charcode];
+ if ( charmap->encoding == ft_encoding_adobe_expert )
+ code = psnames->adobe_expert_encoding[charcode];
+
+ glyph_name = psnames->adobe_std_strings( code );
+ if ( !glyph_name )
+ break;
+
+ for ( n = 0; n < face->type1.num_glyphs; n++ )
+ {
+ const char* gname = face->type1.glyph_names[n];
+
+
+ if ( gname && gname[0] == glyph_name[0] &&
+ strcmp( gname, glyph_name ) == 0 )
+ {
+ result = n;
+ break;
+ }
+ }
+ }
+ }
+
+ Exit:
+ return result;
+ }
+
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Driver_Class t1cid_driver_class =
+ {
+ /* first of all, the FT_Module_Class fields */
+ {
+ ft_module_font_driver | ft_module_driver_scalable,
+ sizeof( FT_DriverRec ),
+ "t1cid", /* module name */
+ 0x10000L, /* version 1.0 of driver */
+ 0x20000L, /* requires FreeType 2.0 */
+
+ 0,
+
+ (FT_Module_Constructor)CID_Init_Driver,
+ (FT_Module_Destructor) CID_Done_Driver,
+ (FT_Module_Requester) CID_Get_Interface
+ },
+
+ /* then the other font drivers fields */
+ sizeof( CID_FaceRec ),
+ sizeof( CID_SizeRec ),
+ sizeof( CID_GlyphSlotRec ),
+
+ (FTDriver_initFace) CID_Init_Face,
+ (FTDriver_doneFace) CID_Done_Face,
+
+ (FTDriver_initSize) 0,
+ (FTDriver_doneSize) 0,
+ (FTDriver_initGlyphSlot)0,
+ (FTDriver_doneGlyphSlot)0,
+
+ (FTDriver_setCharSizes) 0,
+ (FTDriver_setPixelSizes)0,
+
+ (FTDriver_loadGlyph) CID_Load_Glyph,
+ (FTDriver_getCharIndex) CID_Get_Char_Index,
+
+ (FTDriver_getKerning) 0,
+ (FTDriver_attachFile) 0,
+
+ (FTDriver_getAdvances) 0
+ };
+
+
+#ifdef FT_CONFIG_OPTION_DYNAMIC_DRIVERS
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* getDriverClass */
+ /* */
+ /* <Description> */
+ /* This function is used when compiling the TrueType driver as a */
+ /* shared library (`.DLL' or `.so'). It will be used by the */
+ /* high-level library of FreeType to retrieve the address of the */
+ /* driver's generic interface. */
+ /* */
+ /* It shouldn't be implemented in a static build, as each driver must */
+ /* have the same function as an exported entry point. */
+ /* */
+ /* <Return> */
+ /* The address of the TrueType's driver generic interface. The */
+ /* format-specific interface can then be retrieved through the method */
+ /* interface->get_format_interface. */
+ /* */
+ FT_EXPORT_DEF( const FT_Driver_Class* )
+ getDriverClass( void )
+ {
+ return &t1cid_driver_class;
+ }
+
+
+#endif /* CONFIG_OPTION_DYNAMIC_DRIVERS */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftbase.c */
+/* */
+/* Single object library component (body only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include "ftcalc.c"
+#include "fttrigon.c"
+#include "ftobjs.c"
+#include "ftstream.c"
+#include "ftlist.c"
+#include "ftoutln.c"
+#include "ftnames.c"
+
+#if 0
+#include "ftextend.c"
+#endif
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftbbox.c */
+/* */
+/* FreeType bbox computation (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used */
+/* modified and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This component has a _single_ role: to compute exact outline bounding */
+ /* boxes. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_BBOX_H
+#include FT_IMAGE_H
+#include FT_OUTLINE_H
+#include FT_INTERNAL_CALC_H
+
+
+ typedef struct TBBox_Rec_
+ {
+ FT_Vector last;
+ FT_BBox bbox;
+
+ } TBBox_Rec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* BBox_Move_To */
+ /* */
+ /* <Description> */
+ /* This function is used as a `move_to' and `line_to' emitter during */
+ /* FT_Outline_Decompose(). It simply records the destination point */
+ /* in `user->last'; no further computations are necessary since we */
+ /* the cbox as the starting bbox which must be refined. */
+ /* */
+ /* <Input> */
+ /* to :: A pointer to the destination vector. */
+ /* */
+ /* <InOut> */
+ /* user :: A pointer to the current walk context. */
+ /* */
+ /* <Return> */
+ /* Always 0. Needed for the interface only. */
+ /* */
+ static int
+ BBox_Move_To( FT_Vector* to,
+ TBBox_Rec* user )
+ {
+ user->last = *to;
+
+ return 0;
+ }
+
+
+#define CHECK_X( p, bbox ) \
+ ( p->x < bbox.xMin || p->x > bbox.xMax )
+
+#define CHECK_Y( p, bbox ) \
+ ( p->y < bbox.yMin || p->y > bbox.yMax )
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* BBox_Conic_Check */
+ /* */
+ /* <Description> */
+ /* Finds the extrema of a 1-dimensional conic Bezier curve and update */
+ /* a bounding range. This version uses direct computation, as it */
+ /* doesn't need square roots. */
+ /* */
+ /* <Input> */
+ /* y1 :: The start coordinate. */
+ /* y2 :: The coordinate of the control point. */
+ /* y3 :: The end coordinate. */
+ /* */
+ /* <InOut> */
+ /* min :: The address of the current minimum. */
+ /* max :: The address of the current maximum. */
+ /* */
+ static void
+ BBox_Conic_Check( FT_Pos y1,
+ FT_Pos y2,
+ FT_Pos y3,
+ FT_Pos* min,
+ FT_Pos* max )
+ {
+ if ( y1 <= y3 )
+ {
+ if ( y2 == y1 ) /* Flat arc */
+ goto Suite;
+ }
+ else if ( y1 < y3 )
+ {
+ if ( y2 >= y1 && y2 <= y3 ) /* Ascending arc */
+ goto Suite;
+ }
+ else
+ {
+ if ( y2 >= y3 && y2 <= y1 ) /* Descending arc */
+ {
+ y2 = y1;
+ y1 = y3;
+ y3 = y2;
+ goto Suite;
+ }
+ }
+
+ y1 = y3 = y1 - FT_MulDiv( y2 - y1, y2 - y1, y1 - 2*y2 + y3 );
+
+ Suite:
+ if ( y1 < *min ) *min = y1;
+ if ( y3 > *max ) *max = y3;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* BBox_Conic_To */
+ /* */
+ /* <Description> */
+ /* This function is used as a `conic_to' emitter during */
+ /* FT_Raster_Decompose(). It checks a conic Bezier curve with the */
+ /* current bounding box, and computes its extrema if necessary to */
+ /* update it. */
+ /* */
+ /* <Input> */
+ /* control :: A pointer to a control point. */
+ /* to :: A pointer to the destination vector. */
+ /* */
+ /* <InOut> */
+ /* user :: The address of the current walk context. */
+ /* */
+ /* <Return> */
+ /* Always 0. Needed for the interface only. */
+ /* */
+ /* <Note> */
+ /* In the case of a non-monotonous arc, we compute directly the */
+ /* extremum coordinates, as it is sufficiently fast. */
+ /* */
+ static int
+ BBox_Conic_To( FT_Vector* control,
+ FT_Vector* to,
+ TBBox_Rec* user )
+ {
+ /* we don't need to check `to' since it is always an `on' point, thus */
+ /* within the bbox */
+
+ if ( CHECK_X( control, user->bbox ) )
+
+ BBox_Conic_Check( user->last.x,
+ control->x,
+ to->x,
+ &user->bbox.xMin,
+ &user->bbox.xMax );
+
+ if ( CHECK_Y( control, user->bbox ) )
+
+ BBox_Conic_Check( user->last.y,
+ control->y,
+ to->y,
+ &user->bbox.yMin,
+ &user->bbox.yMax );
+
+ user->last = *to;
+
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* BBox_Cubic_Check */
+ /* */
+ /* <Description> */
+ /* Finds the extrema of a 1-dimensional cubic Bezier curve and */
+ /* updates a bounding range. This version uses splitting because we */
+ /* don't want to use square roots and extra accuracies. */
+ /* */
+ /* <Input> */
+ /* p1 :: The start coordinate. */
+ /* p2 :: The coordinate of the first control point. */
+ /* p3 :: The coordinate of the second control point. */
+ /* p4 :: The end coordinate. */
+ /* */
+ /* <InOut> */
+ /* min :: The address of the current minimum. */
+ /* max :: The address of the current maximum. */
+ /* */
+#if 0
+ static void
+ BBox_Cubic_Check( FT_Pos p1,
+ FT_Pos p2,
+ FT_Pos p3,
+ FT_Pos p4,
+ FT_Pos* min,
+ FT_Pos* max )
+ {
+ FT_Pos stack[32*3 + 1], *arc;
+
+
+ arc = stack;
+
+ arc[0] = p1;
+ arc[1] = p2;
+ arc[2] = p3;
+ arc[3] = p4;
+
+ do
+ {
+ FT_Pos y1 = arc[0];
+ FT_Pos y2 = arc[1];
+ FT_Pos y3 = arc[2];
+ FT_Pos y4 = arc[3];
+
+
+ if ( y1 == y4 )
+ {
+ if ( y1 == y2 && y1 == y3 ) /* Flat */
+ goto Test;
+ }
+ else if ( y1 < y4 )
+ {
+ if ( y2 >= y1 && y2 <= y4 && y3 >= y1 && y3 <= y4 ) /* Ascending */
+ goto Test;
+ }
+ else
+ {
+ if ( y2 >= y4 && y2 <= y1 && y3 >= y4 && y3 <= y1 ) /* Descending */
+ {
+ y2 = y1;
+ y1 = y4;
+ y4 = y2;
+ goto Test;
+ }
+ }
+
+ /* Unknown direction -- split the arc in two */
+ arc[6] = y4;
+ arc[1] = y1 = ( y1 + y2 ) / 2;
+ arc[5] = y4 = ( y4 + y3 ) / 2;
+ y2 = ( y2 + y3 ) / 2;
+ arc[2] = y1 = ( y1 + y2 ) / 2;
+ arc[4] = y4 = ( y4 + y2 ) / 2;
+ arc[3] = ( y1 + y4 ) / 2;
+
+ arc += 3;
+ goto Suite;
+
+ Test:
+ if ( y1 < *min ) *min = y1;
+ if ( y4 > *max ) *max = y4;
+ arc -= 3;
+
+ Suite:
+ ;
+ } while ( arc >= stack );
+ }
+#else
+
+ static void
+ 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;
+ FT_Pos c = y2 - y1;
+ FT_Pos d = y1;
+ FT_Pos y;
+ FT_Fixed uu;
+
+ FT_UNUSED ( y4 );
+
+
+ /* The polynom is */
+ /* */
+ /* a*x^3 + 3b*x^2 + 3c*x + d . */
+ /* */
+ /* However, we also have */
+ /* */
+ /* dP/dx(u) = 0 , */
+ /* */
+ /* which implies that */
+ /* */
+ /* P(u) = b*u^2 + 2c*u + d */
+
+ if ( u > 0 && u < 0x10000L )
+ {
+ uu = FT_MulFix( u, u );
+ y = d + FT_MulFix( c, 2*u ) + FT_MulFix( b, uu );
+
+ if ( y < *min ) *min = y;
+ if ( y > *max ) *max = y;
+ }
+ }
+
+
+ static void
+ BBox_Cubic_Check( FT_Pos y1,
+ FT_Pos y2,
+ FT_Pos y3,
+ FT_Pos y4,
+ FT_Pos* min,
+ FT_Pos* max )
+ {
+ /* always compare first and last points */
+ if ( y1 < *min ) *min = y1;
+ else if ( y1 > *max ) *max = y1;
+
+ if ( y4 < *min ) *min = y4;
+ else if ( y4 > *max ) *max = y4;
+
+ /* now, try to see if there are split points here */
+ if ( y1 <= y4 )
+ {
+ /* flat or ascending arc test */
+ if ( y1 <= y2 && y2 <= y4 && y1 <= y3 && y3 <= y4 )
+ return;
+ }
+ else /* y1 > y4 */
+ {
+ /* descending arc test */
+ if ( y1 >= y2 && y2 >= y4 && y1 >= y3 && y3 >= y4 )
+ return;
+ }
+
+ /* There are some split points. Find them. */
+ {
+ FT_Pos a = y4 - 3*y3 + 3*y2 - y1;
+ FT_Pos b = y3 - 2*y2 + y1;
+ FT_Pos c = y2 - y1;
+ FT_Pos d;
+ FT_Fixed t;
+
+
+ /* We need to solve "ax^2+2bx+c" here, without floating points! */
+ /* The trick is to normalize to a different representation in order */
+ /* to use our 16.16 fixed point routines. */
+ /* */
+ /* We compute FT_MulFix(b,b) and FT_MulFix(a,c) after the */
+ /* the normalization. These values must fit into a single 16.16 */
+ /* value. */
+ /* */
+ /* We normalize a, b, and c to "8.16" fixed float values to ensure */
+ /* that their product is held in a "16.16" value. */
+ /* */
+ {
+ FT_ULong t1, t2;
+ 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 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 ensures that all values are now in the range */
+ /* -2^23..2^23, i.e. that they are now expressed as 8.16 */
+ /* fixed float numbers. */
+ /* */
+ /* This also means that we are 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 > 0x7FFFFFUL )
+ {
+ do
+ {
+ shift++;
+ t1 >>= 1;
+ } while ( t1 > 0x7FFFFFUL );
+
+ /* losing some bits of precision, but we use 24 of them */
+ /* for the computation anyway. */
+ a >>= shift;
+ b >>= shift;
+ c >>= shift;
+ }
+ else if ( t1 < 0x400000UL )
+ {
+ do
+ {
+ shift++;
+ t1 <<= 1;
+ } while ( t1 < 0x400000UL );
+
+ a <<= shift;
+ b <<= shift;
+ c <<= shift;
+ }
+ }
+
+ /* handle a == 0 */
+ if ( a == 0 )
+ {
+ if ( b != 0 )
+ {
+ t = - FT_DivFix( c, b ) / 2;
+ test_cubic_extrema( y1, y2, y3, y4, t, min, max );
+ }
+ }
+ else
+ {
+ /* solve the equation now */
+ d = FT_MulFix( b, b ) - FT_MulFix( a, c );
+ if ( d < 0 )
+ return;
+
+ if ( d == 0 )
+ {
+ /* there is a single split point at -b/a */
+ t = - FT_DivFix( b, a );
+ 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_extrema( y1, y2, y3, y4, t, min, max );
+
+ t = - FT_DivFix( b + d, a );
+ test_cubic_extrema( y1, y2, y3, y4, t, min, max );
+ }
+ }
+ }
+ }
+
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* BBox_Cubic_To */
+ /* */
+ /* <Description> */
+ /* This function is used as a `cubic_to' emitter during */
+ /* FT_Raster_Decompose(). It checks a cubic Bezier curve with the */
+ /* current bounding box, and computes its extrema if necessary to */
+ /* update it. */
+ /* */
+ /* <Input> */
+ /* control1 :: A pointer to the first control point. */
+ /* control2 :: A pointer to the second control point. */
+ /* to :: A pointer to the destination vector. */
+ /* */
+ /* <InOut> */
+ /* user :: The address of the current walk context. */
+ /* */
+ /* <Return> */
+ /* Always 0. Needed for the interface only. */
+ /* */
+ /* <Note> */
+ /* In the case of a non-monotonous arc, we don't compute directly */
+ /* extremum coordinates, we subdivise instead. */
+ /* */
+ static int
+ BBox_Cubic_To( FT_Vector* control1,
+ FT_Vector* control2,
+ FT_Vector* to,
+ TBBox_Rec* user )
+ {
+ /* we don't need to check `to' since it is always an `on' point, thus */
+ /* within the bbox */
+
+ if ( CHECK_X( control1, user->bbox ) ||
+ CHECK_X( control2, user->bbox ) )
+
+ BBox_Cubic_Check( user->last.x,
+ control1->x,
+ control2->x,
+ to->x,
+ &user->bbox.xMin,
+ &user->bbox.xMax );
+
+ if ( CHECK_Y( control1, user->bbox ) ||
+ CHECK_Y( control2, user->bbox ) )
+
+ BBox_Cubic_Check( user->last.y,
+ control1->y,
+ control2->y,
+ to->y,
+ &user->bbox.yMin,
+ &user->bbox.yMax );
+
+ user->last = *to;
+
+ return 0;
+ }
+
+
+ /* documentation is in ftbbox.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_Get_BBox( FT_Outline* outline,
+ FT_BBox *abbox )
+ {
+ FT_BBox cbox;
+ FT_BBox bbox;
+ FT_Vector* vec;
+ FT_UShort n;
+
+
+ if ( !abbox )
+ return FT_Err_Invalid_Argument;
+
+ if ( !outline )
+ return FT_Err_Invalid_Outline;
+
+ /* if outline is empty, return (0,0,0,0) */
+ if ( outline->n_points == 0 || outline->n_contours <= 0 )
+ {
+ abbox->xMin = abbox->xMax = 0;
+ abbox->yMin = abbox->yMax = 0;
+ return 0;
+ }
+
+ /* We compute the control box as well as the bounding box of */
+ /* all `on' points in the outline. Then, if the two boxes */
+ /* coincide, we exit immediately. */
+
+ vec = outline->points;
+ bbox.xMin = bbox.xMax = cbox.xMin = cbox.xMax = vec->x;
+ bbox.yMin = bbox.yMax = cbox.yMin = cbox.yMax = vec->y;
+ vec++;
+
+ for ( n = 1; n < outline->n_points; n++ )
+ {
+ FT_Pos x = vec->x;
+ FT_Pos y = vec->y;
+
+
+ /* update control box */
+ if ( x < cbox.xMin ) cbox.xMin = x;
+ if ( x > cbox.xMax ) cbox.xMax = x;
+
+ if ( y < cbox.yMin ) cbox.yMin = y;
+ if ( y > cbox.yMax ) cbox.yMax = y;
+
+ if ( FT_CURVE_TAG( outline->tags[n] ) == FT_Curve_Tag_On )
+ {
+ /* update bbox for `on' points only */
+ if ( x < bbox.xMin ) bbox.xMin = x;
+ if ( x > bbox.xMax ) bbox.xMax = x;
+
+ if ( y < bbox.yMin ) bbox.yMin = y;
+ if ( y > bbox.yMax ) bbox.yMax = y;
+ }
+
+ vec++;
+ }
+
+ /* test two boxes for equality */
+ if ( cbox.xMin < bbox.xMin || cbox.xMax > bbox.xMax ||
+ cbox.yMin < bbox.yMin || cbox.yMax > bbox.yMax )
+ {
+ /* the two boxes are different, now walk over the outline to */
+ /* get the Bezier arc extrema. */
+
+ static const FT_Outline_Funcs interface =
+ {
+ (FT_Outline_MoveTo_Func) BBox_Move_To,
+ (FT_Outline_LineTo_Func) BBox_Move_To,
+ (FT_Outline_ConicTo_Func)BBox_Conic_To,
+ (FT_Outline_CubicTo_Func)BBox_Cubic_To,
+ 0, 0
+ };
+
+ FT_Error error;
+ TBBox_Rec user;
+
+
+ user.bbox = bbox;
+
+ error = FT_Outline_Decompose( outline, &interface, &user );
+ if ( error )
+ return error;
+
+ *abbox = user.bbox;
+ }
+ else
+ *abbox = bbox;
+
+ return FT_Err_Ok;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftcache.c */
+/* */
+/* The FreeType Caching sub-system (body only). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "ftlru.c"
+#include "ftcmanag.c"
+#include "ftcglyph.c"
+#include "ftcchunk.c"
+#include "ftcimage.c"
+#include "ftcsbits.c"
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftcalc.c */
+/* */
+/* Arithmetic computations (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* Support for 1-complement arithmetic has been totally dropped in this */
+ /* release. You can still write your own code if you need it. */
+ /* */
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* Implementing basic computation routines. */
+ /* */
+ /* FT_MulDiv(), FT_MulFix(), FT_DivFix(), FT_RoundFix(), FT_CeilFix(), */
+ /* and FT_FloorFix() are declared in freetype.h. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+/* 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
+
+ typedef struct FT_Int64_
+ {
+ FT_UInt32 lo;
+ FT_UInt32 hi;
+
+ } FT_Int64;
+
+#endif /* FT_LONG64 */
+
+#endif /* !FT_CONFIG_OPTION_OLD_CALCS */
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_calc
+
+
+ /* The following three functions are available regardless of whether */
+ /* FT_LONG64 or FT_CONFIG_OPTION_OLD_CALCS is defined. */
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Fixed )
+ FT_RoundFix( FT_Fixed a )
+ {
+ return ( a >= 0 ) ? ( a + 0x8000L ) & -0x10000L
+ : -((-a + 0x8000L ) & -0x10000L );
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Fixed )
+ FT_CeilFix( FT_Fixed a )
+ {
+ return ( a >= 0 ) ? ( a + 0xFFFFL ) & -0x10000L
+ : -((-a + 0xFFFFL ) & -0x10000L );
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Fixed )
+ FT_FloorFix( FT_Fixed a )
+ {
+ return ( a >= 0 ) ? a & -0x10000L
+ : -((-a) & -0x10000L );
+ }
+
+
+#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 )
+ FT_Sqrt32( FT_Int32 x )
+ {
+ FT_ULong val, root, newroot, mask;
+
+
+ root = 0;
+ mask = 0x40000000L;
+ val = (FT_ULong)x;
+
+ do
+ {
+ newroot = root + mask;
+ if ( newroot <= val )
+ {
+ val -= newroot;
+ root = newroot + mask;
+ }
+
+ root >>= 1;
+ mask >>= 2;
+
+ } while ( mask != 0 );
+
+ return root;
+ }
+
+#endif /* FT_CONFIG_OPTION_OLD_CALCS */
+
+
+#ifdef FT_LONG64
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Long )
+ FT_MulDiv( FT_Long a,
+ FT_Long b,
+ FT_Long c )
+ {
+ FT_Int s;
+ FT_Long d;
+
+
+ s = 1;
+ if ( a < 0 ) { a = -a; s = -1; }
+ if ( b < 0 ) { b = -b; s = -s; }
+ if ( c < 0 ) { c = -c; s = -s; }
+
+ d = (FT_Long)( c > 0 ? ( (FT_Int64)a * b + ( c >> 1 ) ) / c
+ : 0x7FFFFFFFL );
+
+ return ( s > 0 ) ? d : -d;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Long )
+ FT_MulFix( FT_Long a,
+ FT_Long b )
+ {
+ FT_Int s = 1;
+ FT_Long c;
+
+
+ if ( a < 0 ) { a = -a; s = -1; }
+ if ( b < 0 ) { b = -b; s = -s; }
+
+ c = (FT_Long)( ( (FT_Int64)a * b + 0x8000 ) >> 16 );
+ return ( s > 0 ) ? c : -c ;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Long )
+ FT_DivFix( FT_Long a,
+ FT_Long b )
+ {
+ FT_Int32 s;
+ FT_UInt32 q;
+
+ s = 1;
+ if ( a < 0 ) { a = -a; s = -1; }
+ if ( b < 0 ) { b = -b; s = -s; }
+
+ if ( b == 0 )
+ /* check for division by 0 */
+ q = 0x7FFFFFFFL;
+ else
+ /* compute result directly */
+ q = (FT_UInt32)( ( ( (FT_Int64)a << 16 ) + ( b >> 1 ) ) / b );
+
+ return ( s < 0 ? -(FT_Long)q : (FT_Long)q );
+ }
+
+
+#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 */
+
+
+ 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_UInt32 r, q;
+ FT_Int i;
+
+
+ q = 0;
+ r = hi;
+
+ if ( r >= y )
+ return (FT_UInt32)0x7FFFFFFFL;
+
+ 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,
+ FT_Long b,
+ FT_Long c )
+ {
+ long s;
+
+
+ if ( a == 0 || b == c )
+ return a;
+
+ s = a; a = ABS( a );
+ s ^= b; b = ABS( b );
+ s ^= c; c = ABS( c );
+
+ if ( a <= 46340L && b <= 46340L && c <= 176095L && c > 0 )
+ {
+ a = ( a * b + ( c >> 1 ) ) / c;
+ }
+ else if ( c > 0 )
+ {
+ FT_Int64 temp, temp2;
+
+
+ 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, c );
+ }
+ else
+ a = 0x7FFFFFFFL;
+
+ return ( s < 0 ? -a : a );
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Long )
+ FT_MulFix( FT_Long a,
+ FT_Long b )
+ {
+ FT_Long s;
+ FT_ULong ua, ub;
+
+
+ if ( a == 0 || b == 0x10000L )
+ return a;
+
+ s = a; a = ABS(a);
+ s ^= b; b = ABS(b);
+
+ ua = (FT_ULong)a;
+ ub = (FT_ULong)b;
+
+ if ( ua <= 2048 && ub <= 1048576L )
+ {
+ ua = ( ua * ub + 0x8000 ) >> 16;
+ }
+ else
+ {
+ FT_ULong al = ua & 0xFFFF;
+
+
+ ua = ( ua >> 16 ) * ub + al * ( ub >> 16 ) +
+ ( ( al * ( ub & 0xFFFF ) + 0x8000 ) >> 16 );
+ }
+
+ return ( s < 0 ? -(FT_Long)ua : ua );
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Long )
+ FT_DivFix( FT_Long a,
+ FT_Long b )
+ {
+ FT_Int32 s;
+ FT_UInt32 q;
+
+
+ s = a; a = ABS(a);
+ s ^= b; b = ABS(b);
+
+ if ( b == 0 )
+ {
+ /* check for division by 0 */
+ q = 0x7FFFFFFFL;
+ }
+ else if ( ( a >> 16 ) == 0 )
+ {
+ /* compute result directly */
+ q = (FT_UInt32)( (a << 16) + (b >> 1) ) / (FT_UInt32)b;
+ }
+ else
+ {
+ /* we need more bits; we have to do it by hand */
+ FT_Int64 temp, temp2;
+
+ temp.hi = (FT_Int32) (a >> 16);
+ temp.lo = (FT_UInt32)(a << 16);
+ temp2.hi = 0;
+ temp2.lo = (FT_UInt32)( b >> 1 );
+ FT_Add64( &temp, &temp2, &temp );
+ 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_MulTo64( FT_Int32 x,
+ FT_Int32 y,
+ FT_Int64 *z )
+ {
+ FT_Int32 s;
+
+
+ s = x; x = ABS( x );
+ s ^= y; y = ABS( y );
+
+ ft_multo64( x, y, z );
+
+ if ( s < 0 )
+ {
+ z->lo = (FT_UInt32)-(FT_Int32)z->lo;
+ z->hi = ~z->hi + !( z->lo );
+ }
+ }
+
+
+ /* documentation is in ftcalc.h */
+
+ FT_EXPORT_DEF( FT_Int32 )
+ FT_Div64by32( FT_Int64* x,
+ FT_Int32 y )
+ {
+ FT_Int32 s;
+ FT_UInt32 q;
+
+
+ s = x->hi;
+ if ( s < 0 )
+ {
+ x->lo = (FT_UInt32)-(FT_Int32)x->lo;
+ x->hi = ~x->hi + !( x->lo );
+ }
+ s ^= y; y = ABS( y );
+
+ /* Shortcut */
+ if ( x->hi == 0 )
+ {
+ if ( y > 0 )
+ q = ( x->lo + ( y >> 1 ) ) / y;
+ else
+ q = 0x7FFFFFFFL;
+
+ return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q );
+ }
+
+ q = ft_div64by32( x->hi, x->lo, y );
+
+ return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q );
+ }
+
+
+#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 /* FT_LONG64 */
+
+
+ /* a not-so-fast but working 16.16 fixed point square root function */
+
+ FT_EXPORT_DEF( FT_Int32 )
+ FT_SqrtFixed( FT_Int32 x )
+ {
+ FT_UInt32 root, rem_hi, rem_lo, test_div;
+ FT_Int count;
+
+
+ root = 0;
+
+ if ( x > 0 )
+ {
+ rem_hi = 0;
+ rem_lo = x;
+ count = 24;
+ do
+ {
+ rem_hi = ( rem_hi << 2 ) | ( rem_lo >> 30 );
+ rem_lo <<= 2;
+ root <<= 1;
+ test_div = ( root << 1 ) + 1;
+
+ if ( rem_hi >= test_div )
+ {
+ rem_hi -= test_div;
+ root += 1;
+ }
+ } while ( --count );
+ }
+
+ return (FT_Int32)root;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftcchunk.c */
+/* */
+/* FreeType chunk cache cache (body). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_INTERNAL_CHUNK_H
+#include FT_LIST_H
+#include FT_ERRORS_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "ftcerror.h"
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** GLYPH NODES *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* create a new chunk node, setting its cache index and ref count */
+ FT_EXPORT_DEF( FT_Error )
+ FTC_ChunkNode_Init( FTC_ChunkNode node,
+ FTC_ChunkSet cset,
+ FT_UInt index,
+ FT_Bool alloc )
+ {
+ FTC_Chunk_Cache cache = cset->cache;
+ FTC_CacheNode_Data* data = FTC_CACHENODE_TO_DATA_P( &node->root );
+ FT_Error error = 0;
+
+
+ data->cache_index = (FT_UShort)cache->root.cache_index;
+ data->ref_count = (FT_Short) 0;
+ node->cset = cset;
+ node->cset_index = (FT_UShort)index;
+ node->num_elements = (unsigned short)(
+ ( index + 1 < cset->num_chunks )
+ ? cset->element_count
+ : cset->element_max - cset->element_count*index );
+ if ( alloc )
+ {
+ /* allocate elements array */
+ FT_Memory memory;
+
+
+ memory = cache->root.memory;
+ error = MEM_Alloc( node->elements,
+ cset->element_size * cset->element_count );
+ }
+
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FTC_ChunkNode_Destroy( FTC_ChunkNode node )
+ {
+ FTC_ChunkSet cset = node->cset;
+
+
+ /* remove from parent set table */
+ cset->chunks[node->cset_index] = 0;
+
+ /* destroy the node */
+ cset->clazz->destroy_node( node );
+ }
+
+
+ FT_EXPORT_DEF( FT_ULong )
+ FTC_ChunkNode_Size( FTC_ChunkNode node )
+ {
+ FTC_ChunkSet cset = node->cset;
+
+
+ return cset->clazz->size_node( node );
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FTC_CacheNode_Class ftc_chunk_cache_node_class =
+ {
+ (FTC_CacheNode_SizeFunc) FTC_ChunkNode_Size,
+ (FTC_CacheNode_DestroyFunc)FTC_ChunkNode_Destroy
+ };
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CHUNK SETS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_ChunkSet_New( FTC_Chunk_Cache cache,
+ FT_Pointer type,
+ FTC_ChunkSet *aset )
+ {
+ FT_Error error;
+ FT_Memory memory = cache->root.memory;
+ FTC_Manager manager = cache->root.manager;
+ FTC_ChunkSet cset = 0;
+
+ FTC_Chunk_Cache_Class* ccache_class;
+ FTC_ChunkSet_Class* clazz;
+
+
+ ccache_class = (FTC_Chunk_Cache_Class*)cache->root.clazz;
+ clazz = ccache_class->cset_class;
+
+ *aset = 0;
+
+ if ( ALLOC( cset, clazz->cset_byte_size ) )
+ goto Exit;
+
+ cset->cache = cache;
+ cset->manager = manager;
+ cset->memory = memory;
+ cset->clazz = clazz;
+
+ /* now compute element_max, element_count and element_size */
+ error = clazz->sizes( cset, type );
+ if ( error )
+ goto Exit;
+
+ /* compute maximum number of nodes */
+ cset->num_chunks = ( cset->element_max + cset->element_count - 1 ) /
+ cset->element_count;
+
+ /* allocate chunk pointers table */
+ if ( ALLOC_ARRAY( cset->chunks, cset->num_chunks, FTC_ChunkNode ) )
+ goto Exit;
+
+ /* initialize set by type if needed */
+ if ( clazz->init )
+ {
+ error = clazz->init( cset, type );
+ if ( error )
+ goto Exit;
+ }
+
+ *aset = cset;
+
+ Exit:
+ if ( error && cset )
+ {
+ FREE( cset->chunks );
+ FREE( cset );
+ }
+
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FTC_ChunkSet_Destroy( FTC_ChunkSet cset )
+ {
+ FTC_Chunk_Cache cache = cset->cache;
+ FTC_Manager manager = cache->root.manager;
+ FT_List glyphs_lru = &manager->global_lru;
+ FTC_ChunkNode* bucket = cset->chunks;
+ FTC_ChunkNode* bucket_limit = bucket + cset->num_chunks;
+ FT_Memory memory = cache->root.memory;
+
+ FTC_ChunkSet_Class* clazz = cset->clazz;
+
+
+ /* for each bucket, free the list of glyph nodes */
+ for ( ; bucket < bucket_limit; bucket++ )
+ {
+ FTC_ChunkNode node = bucket[0];
+ FT_ListNode lrunode;
+
+
+ if ( node )
+ {
+ lrunode = FTC_CHUNKNODE_TO_LRUNODE( node );
+
+ manager->num_bytes -= clazz->size_node( node );
+ manager->num_nodes--;
+
+ FT_List_Remove( glyphs_lru, lrunode );
+
+ clazz->destroy_node( node );
+
+ bucket[0] = 0;
+ }
+ }
+
+ if ( clazz->done )
+ clazz->done( cset );
+
+ FREE( cset->chunks );
+ FREE( cset );
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_ChunkSet_Lookup_Node( FTC_ChunkSet cset,
+ FT_UInt glyph_index,
+ FTC_ChunkNode *anode,
+ FT_UInt *anindex )
+ {
+ FTC_Chunk_Cache cache = cset->cache;
+ FTC_Manager manager = cache->root.manager;
+ FT_Error error = 0;
+
+ FTC_ChunkSet_Class* clazz = cset->clazz;
+
+
+ *anode = 0;
+
+ if ( glyph_index >= cset->element_max )
+ error = FTC_Err_Invalid_Argument;
+ else
+ {
+ FT_UInt chunk_size = cset->element_count;
+ FT_UInt chunk_index = glyph_index / chunk_size;
+ FTC_ChunkNode* pnode = cset->chunks + chunk_index;
+ FTC_ChunkNode node = *pnode;
+
+
+ if ( !node )
+ {
+ /* we didn't found the glyph image; we will now create a new one */
+ error = clazz->new_node( cset, chunk_index, &node );
+ if ( error )
+ goto Exit;
+
+ /* store the new chunk in the cset's table */
+ *pnode = node;
+
+ /* insert the node at the start the global LRU glyph list */
+ FT_List_Insert( &manager->global_lru,
+ FTC_CHUNKNODE_TO_LRUNODE( node ) );
+
+ manager->num_bytes += clazz->size_node( node );
+ manager->num_nodes++;
+
+ if ( manager->num_bytes > manager->max_bytes )
+ {
+ FTC_ChunkNode_Ref ( node );
+ FTC_Manager_Compress( manager );
+ FTC_ChunkNode_Unref ( node );
+ }
+ }
+
+ *anode = node;
+ *anindex = glyph_index - chunk_index * chunk_size;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CHUNK SETS LRU CALLBACKS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#define FTC_CSET_LRU_GET_CACHE( lru ) \
+ ( (FTC_Chunk_Cache)((lru)->user_data) )
+
+#define FTC_CSET_LRU_GET_MANAGER( lru ) \
+ FTC_CSET_LRU_GET_CACHE( lru )->manager
+
+#define FTC_LRUNODE_CSET( node ) \
+ ( (FTC_ChunkSet)(node)->root.data )
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_chunk_set_lru_init( FT_Lru lru,
+ FT_LruNode node )
+ {
+ FTC_Chunk_Cache cache = FTC_CSET_LRU_GET_CACHE( lru );
+ FT_Error error;
+ FTC_ChunkSet cset;
+
+
+ error = FTC_ChunkSet_New( cache,
+ (FT_Pointer)node->key,
+ &cset );
+ if ( !error )
+ {
+ /* good, now set the set index within the set object */
+ cset->cset_index = (FT_UInt)( node - lru->nodes );
+ node->root.data = cset;
+ }
+
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ ftc_chunk_set_lru_done( FT_Lru lru,
+ FT_LruNode node )
+ {
+ FTC_ChunkSet cset = FTC_LRUNODE_CSET( node );
+
+ FT_UNUSED( lru );
+
+
+ FTC_ChunkSet_Destroy( cset );
+ }
+
+
+ FT_CALLBACK_DEF( FT_Bool )
+ ftc_chunk_set_lru_compare( FT_LruNode node,
+ FT_LruKey key )
+ {
+ FTC_ChunkSet cset = FTC_LRUNODE_CSET( node );
+
+
+ return cset->clazz->compare( cset, (FT_Pointer)key );
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Lru_Class ftc_chunk_set_lru_class =
+ {
+ sizeof( FT_LruRec ),
+ ftc_chunk_set_lru_init,
+ ftc_chunk_set_lru_done,
+ 0, /* no flush */
+ ftc_chunk_set_lru_compare
+ };
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CHUNK CACHE OBJECTS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Chunk_Cache_Init( FTC_Chunk_Cache cache )
+ {
+ FT_Memory memory = cache->root.memory;
+ FT_Error error;
+
+ FTC_Chunk_Cache_Class* ccache_clazz;
+
+
+ /* set up root node_class to be used by manager */
+ cache->root.node_clazz =
+ (FTC_CacheNode_Class*)&ftc_chunk_cache_node_class;
+
+ /* setup `compare' shortcut */
+ ccache_clazz = (FTC_Chunk_Cache_Class*)cache->root.clazz;
+ cache->compare = ccache_clazz->cset_class->compare;
+
+ error = FT_Lru_New( &ftc_chunk_set_lru_class,
+ FTC_MAX_CHUNK_SETS,
+ cache,
+ memory,
+ 1, /* pre_alloc == TRUE */
+ &cache->csets_lru );
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FTC_Chunk_Cache_Done( FTC_Chunk_Cache cache )
+ {
+ /* discard glyph sets */
+ FT_Lru_Done( cache->csets_lru );
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Chunk_Cache_Lookup( FTC_Chunk_Cache cache,
+ FT_Pointer type,
+ FT_UInt gindex,
+ FTC_ChunkNode *anode,
+ FT_UInt *aindex )
+ {
+ FT_Error error;
+ FTC_ChunkSet cset;
+ FTC_ChunkNode node;
+ FT_UInt cindex;
+ FTC_Manager manager;
+
+
+ /* check for valid `desc' delayed to FT_Lru_Lookup() */
+
+ if ( !cache || !anode || !aindex )
+ return FTC_Err_Invalid_Argument;
+
+ *anode = 0;
+ *aindex = 0;
+ cset = cache->last_cset;
+
+ if ( !cset || !cache->compare( cset, type ) )
+ {
+ error = FT_Lru_Lookup( cache->csets_lru,
+ (FT_LruKey)type,
+ (FT_Pointer*)&cset );
+ cache->last_cset = cset;
+ if ( error )
+ goto Exit;
+ }
+
+ error = FTC_ChunkSet_Lookup_Node( cset, gindex, &node, &cindex );
+ if ( error )
+ goto Exit;
+
+ /* now compress the manager's cache pool if needed */
+ manager = cache->root.manager;
+ if ( manager->num_bytes > manager->max_bytes )
+ {
+ FTC_ChunkNode_Ref ( node );
+ FTC_Manager_Compress( manager );
+ FTC_ChunkNode_Unref ( node );
+ }
+
+ *anode = node;
+ *aindex = cindex;
+
+ Exit:
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftcglyph.c */
+/* */
+/* FreeType Glyph Image (FT_Glyph) cache (body). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_INTERNAL_GLYPH_H
+#include FT_ERRORS_H
+#include FT_LIST_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+
+#include "ftcerror.h"
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** GLYPH NODES *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* create a new glyph node, setting its cache index and ref count */
+ FT_EXPORT_DEF( void )
+ FTC_GlyphNode_Init( FTC_GlyphNode node,
+ FTC_GlyphSet gset,
+ FT_UInt gindex )
+ {
+ FTC_Glyph_Cache cache = gset->cache;
+ FTC_CacheNode_Data* data = FTC_CACHENODE_TO_DATA_P( &node->root );
+
+
+ data->cache_index = (FT_UShort)cache->root.cache_index;
+ data->ref_count = (FT_Short) 0;
+ node->gset_index = (FT_UShort)gset->gset_index;
+ node->glyph_index = (FT_UShort)gindex;
+ }
+
+
+ /* Important: This function is called from the cache manager to */
+ /* destroy a given cache node during `cache compression'. The */
+ /* second argument is always `cache.cache_data'. Thus be */
+ /* certain that the function FTC_Glyph_Cache_New() does indeed */
+ /* set its `cache_data' field correctly, otherwise bad things */
+ /* will happen! */
+
+ FT_EXPORT_DEF( void )
+ FTC_GlyphNode_Destroy( FTC_GlyphNode node,
+ FTC_Glyph_Cache cache )
+ {
+ FT_LruNode gset_lru = cache->gsets_lru->nodes + node->gset_index;
+ FTC_GlyphSet gset = (FTC_GlyphSet)gset_lru->root.data;
+ FT_UInt hash = node->glyph_index % gset->hash_size;
+
+
+ /* remove the node from its gset's bucket list */
+ {
+ FTC_GlyphNode* pnode = gset->buckets + hash;
+ FTC_GlyphNode cur;
+
+
+ for (;;)
+ {
+ cur = *pnode;
+ if ( !cur )
+ {
+ /* this should never happen */
+ FT_ERROR(( "FTC_GlyphNode_Destroy:"
+ " trying to delete an unlisted node!" ));
+ return;
+ }
+
+ if ( cur == node )
+ {
+ *pnode = cur->gset_next;
+ break;
+ }
+ pnode = &cur->gset_next;
+ }
+ }
+
+ /* destroy the node */
+ gset->clazz->destroy_node( node, gset );
+ }
+
+
+ /* Important: This function is called from the cache manager to */
+ /* size a given cache node during `cache compression'. The */
+ /* second argument is always `cache.user_data'. Thus be */
+ /* certain that the function FTC_Glyph_Cache_New() does indeed */
+ /* set its `user_data' field correctly, otherwise bad things */
+ /* will happen! */
+
+ FT_EXPORT_DEF( FT_ULong )
+ FTC_GlyphNode_Size( FTC_GlyphNode node,
+ FTC_Glyph_Cache cache )
+ {
+ FT_LruNode gset_lru = cache->gsets_lru->nodes + node->gset_index;
+ FTC_GlyphSet gset = (FTC_GlyphSet)gset_lru->root.data;
+
+
+ return gset->clazz->size_node( node, gset );
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FTC_CacheNode_Class ftc_glyph_cache_node_class =
+ {
+ (FTC_CacheNode_SizeFunc) FTC_GlyphNode_Size,
+ (FTC_CacheNode_DestroyFunc)FTC_GlyphNode_Destroy
+ };
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** GLYPH SETS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_GlyphSet_New( FTC_Glyph_Cache cache,
+ FT_Pointer type,
+ FTC_GlyphSet *aset )
+ {
+ FT_Error error;
+ FT_Memory memory = cache->root.memory;
+ FTC_Manager manager = cache->root.manager;
+ FTC_GlyphSet gset = 0;
+
+ FTC_Glyph_Cache_Class* gcache_class;
+ FTC_GlyphSet_Class* clazz;
+
+
+ gcache_class = (FTC_Glyph_Cache_Class*)cache->root.clazz;
+ clazz = gcache_class->gset_class;
+
+ *aset = 0;
+
+ if ( ALLOC( gset, clazz->gset_byte_size ) )
+ goto Exit;
+
+ gset->cache = cache;
+ gset->manager = manager;
+ gset->memory = memory;
+ gset->hash_size = FTC_GSET_HASH_SIZE_DEFAULT;
+ gset->clazz = clazz;
+
+ /* allocate buckets table */
+ if ( ALLOC_ARRAY( gset->buckets, gset->hash_size, FTC_GlyphNode ) )
+ goto Exit;
+
+ /* initialize gset by type if needed */
+ if ( clazz->init )
+ {
+ error = clazz->init( gset, type );
+ if ( error )
+ goto Exit;
+ }
+
+ *aset = gset;
+
+ Exit:
+ if ( error && gset )
+ {
+ FREE( gset->buckets );
+ FREE( gset );
+ }
+
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FTC_GlyphSet_Destroy( FTC_GlyphSet gset )
+ {
+ FTC_Glyph_Cache cache = gset->cache;
+ FTC_Manager manager = cache->root.manager;
+ FT_List glyphs_lru = &manager->global_lru;
+ FTC_GlyphNode* bucket = gset->buckets;
+ FTC_GlyphNode* bucket_limit = bucket + gset->hash_size;
+ FT_Memory memory = cache->root.memory;
+
+ FTC_GlyphSet_Class* clazz = gset->clazz;
+
+
+ /* for each bucket, free the list of glyph nodes */
+ for ( ; bucket < bucket_limit; bucket++ )
+ {
+ FTC_GlyphNode node = bucket[0];
+ FTC_GlyphNode next = 0;
+ FT_ListNode lrunode;
+
+
+ for ( ; node; node = next )
+ {
+ next = node->gset_next;
+ lrunode = FTC_GLYPHNODE_TO_LRUNODE( node );
+
+ manager->num_bytes -= clazz->size_node( node, gset );
+ manager->num_nodes--;
+
+ FT_List_Remove( glyphs_lru, lrunode );
+
+ clazz->destroy_node( node, gset );
+ }
+
+ bucket[0] = 0;
+ }
+
+ if ( clazz->done )
+ clazz->done( gset );
+
+ FREE( gset->buckets );
+ FREE( gset );
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_GlyphSet_Lookup_Node( FTC_GlyphSet gset,
+ FT_UInt glyph_index,
+ FTC_GlyphNode *anode )
+ {
+ FTC_Glyph_Cache cache = gset->cache;
+ FTC_Manager manager = cache->root.manager;
+ FT_UInt hash_index = glyph_index % gset->hash_size;
+ FTC_GlyphNode* bucket = gset->buckets + hash_index;
+ FTC_GlyphNode* pnode = bucket;
+ FTC_GlyphNode node;
+ FT_Error error;
+
+ FTC_GlyphSet_Class* clazz = gset->clazz;
+
+
+ *anode = 0;
+
+ for ( ;; )
+ {
+ node = *pnode;
+ if ( !node )
+ break;
+
+ if ( (FT_UInt)node->glyph_index == glyph_index )
+ {
+ /* we found it! -- move glyph to start of the lists */
+ *pnode = node->gset_next;
+ node->gset_next = bucket[0];
+ bucket[0] = node;
+
+ FT_List_Up( &manager->global_lru, FTC_GLYPHNODE_TO_LRUNODE( node ) );
+ *anode = node;
+ return 0;
+ }
+ /* go to next node in bucket */
+ pnode = &node->gset_next;
+ }
+
+ /* we didn't found the glyph image, we will now create a new one */
+ error = clazz->new_node( gset, glyph_index, &node );
+ if ( error )
+ goto Exit;
+
+ /* insert the node at the start of our bucket list */
+ node->gset_next = bucket[0];
+ bucket[0] = node;
+
+ /* insert the node at the start the global LRU glyph list */
+ FT_List_Insert( &manager->global_lru, FTC_GLYPHNODE_TO_LRUNODE( node ) );
+
+ manager->num_bytes += clazz->size_node( node, gset );
+ manager->num_nodes++;
+
+ if ( manager->num_bytes > manager->max_bytes )
+ {
+ FTC_GlyphNode_Ref ( node );
+ FTC_Manager_Compress( manager );
+ FTC_GlyphNode_Unref ( node );
+ }
+
+ *anode = node;
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** GLYPH SETS LRU CALLBACKS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#define FTC_GSET_LRU_GET_CACHE( lru ) \
+ ( (FTC_Glyph_Cache)(lru)->user_data )
+
+#define FTC_GSET_LRU_GET_MANAGER( lru ) \
+ FTC_GSET_LRU_GET_CACHE( lru )->manager
+
+#define FTC_LRUNODE_GSET( node ) \
+ ( (FTC_GlyphSet)(node)->root.data )
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_glyph_set_lru_init( FT_Lru lru,
+ FT_LruNode node )
+ {
+ FTC_Glyph_Cache cache = FTC_GSET_LRU_GET_CACHE( lru );
+ FT_Error error;
+ FTC_GlyphSet gset;
+
+
+ error = FTC_GlyphSet_New( cache, (FT_Pointer)node->key, &gset );
+ if ( !error )
+ {
+ /* good, now set the gset index within the gset object */
+ gset->gset_index = (FT_UInt)( node - lru->nodes );
+ node->root.data = gset;
+ }
+
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ ftc_glyph_set_lru_done( FT_Lru lru,
+ FT_LruNode node )
+ {
+ FTC_GlyphSet gset = FTC_LRUNODE_GSET( node );
+
+ FT_UNUSED( lru );
+
+
+ FTC_GlyphSet_Destroy( gset );
+ }
+
+
+ FT_CALLBACK_DEF( FT_Bool )
+ ftc_glyph_set_lru_compare( FT_LruNode node,
+ FT_LruKey key )
+ {
+ FTC_GlyphSet gset = FTC_LRUNODE_GSET( node );
+
+
+ return gset->clazz->compare( gset, (FT_Pointer)key );
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Lru_Class ftc_glyph_set_lru_class =
+ {
+ sizeof( FT_LruRec ),
+ ftc_glyph_set_lru_init,
+ ftc_glyph_set_lru_done,
+ 0, /* no flush */
+ ftc_glyph_set_lru_compare
+ };
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** GLYPH CACHE OBJECTS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Glyph_Cache_Init( FTC_Glyph_Cache cache )
+ {
+ FT_Memory memory = cache->root.memory;
+ FT_Error error;
+
+ FTC_Glyph_Cache_Class* gcache_clazz;
+
+
+ /* set up root node_class to be used by manager */
+ cache->root.node_clazz =
+ (FTC_CacheNode_Class*)&ftc_glyph_cache_node_class;
+
+ /* setup the `compare' shortcut */
+ gcache_clazz = (FTC_Glyph_Cache_Class*)cache->root.clazz;
+ cache->compare = gcache_clazz->gset_class->compare;
+
+ /* The following is extremely important for ftc_destroy_glyph_image() */
+ /* to work properly, as the second parameter that is sent to it */
+ /* through the cache manager is `cache_data' and must be set to */
+ /* `cache' here. */
+ /* */
+ cache->root.cache_data = cache;
+
+ error = FT_Lru_New( &ftc_glyph_set_lru_class,
+ FTC_MAX_GLYPH_SETS,
+ cache,
+ memory,
+ 1, /* pre_alloc == TRUE */
+ &cache->gsets_lru );
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FTC_Glyph_Cache_Done( FTC_Glyph_Cache cache )
+ {
+ /* discard glyph sets */
+ FT_Lru_Done( cache->gsets_lru );
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Glyph_Cache_Lookup( FTC_Glyph_Cache cache,
+ FT_Pointer type,
+ FT_UInt gindex,
+ FTC_GlyphNode *anode )
+ {
+ FT_Error error;
+ FTC_GlyphSet gset;
+ FTC_GlyphNode node;
+ FTC_Manager manager;
+
+
+ /* check for valid `desc' delayed to FT_Lru_Lookup() */
+
+ if ( !cache || !anode )
+ return FTC_Err_Invalid_Argument;
+
+ *anode = 0;
+ gset = cache->last_gset;
+
+ if ( !gset || !cache->compare( gset, type ) )
+ {
+ error = FT_Lru_Lookup( cache->gsets_lru,
+ (FT_LruKey)type,
+ (FT_Pointer*)&gset );
+ cache->last_gset = gset;
+ if ( error )
+ goto Exit;
+ }
+
+ error = FTC_GlyphSet_Lookup_Node( gset, gindex, &node );
+ if ( error )
+ goto Exit;
+
+ /* now compress the manager's cache pool if needed */
+ manager = cache->root.manager;
+ if ( manager->num_bytes > manager->max_bytes )
+ {
+ FTC_GlyphNode_Ref ( node );
+ FTC_Manager_Compress( manager );
+ FTC_GlyphNode_Unref ( node );
+ }
+
+ *anode = node;
+
+ Exit:
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftcimage.c */
+/* */
+/* FreeType Image cache (body). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_IMAGE_H
+#include FT_INTERNAL_MEMORY_H
+
+#include "ftcerror.h"
+
+#include <string.h> /* memcmp() */
+#include <stdlib.h> /* labs() */
+
+
+ /* the FT_Glyph image `glyph node' type */
+ typedef struct FTC_GlyphImageRec_
+ {
+ FTC_GlyphNodeRec root;
+ FT_Glyph ft_glyph;
+
+ } FTC_GlyphImageRec, *FTC_GlyphImage;
+
+
+ /* the glyph image queue type */
+ typedef struct FTC_ImageSetRec_
+ {
+ FTC_GlyphSetRec root;
+ FTC_Image_Desc description;
+
+ } FTC_ImageSetRec, *FTC_ImageSet;
+
+
+ typedef struct FTC_Image_CacheRec_
+ {
+ FTC_Glyph_CacheRec root;
+
+ } FTC_Image_CacheRec;
+
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** GLYPH IMAGE NODES *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_CALLBACK_DEF( void )
+ ftc_glyph_image_node_destroy( FTC_GlyphImage node,
+ FTC_GlyphSet gset )
+ {
+ FT_Memory memory = gset->memory;
+
+
+ FT_Done_Glyph( node->ft_glyph );
+ FREE( node );
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_glyph_image_node_new( FTC_GlyphSet gset,
+ FT_UInt glyph_index,
+ FTC_GlyphImage *anode )
+ {
+ FT_Memory memory = gset->memory;
+ FTC_ImageSet imageset = (FTC_ImageSet)gset;
+ FT_Error error;
+ FTC_GlyphImage node = 0;
+ FT_Face face;
+ FT_Size size;
+
+
+ /* allocate node */
+ if ( ALLOC( node, sizeof ( *node ) ) )
+ goto Exit;
+
+ /* initialize its inner fields */
+ FTC_GlyphNode_Init( FTC_GLYPHNODE( node ), gset, glyph_index );
+
+ /* we will now load the glyph image */
+ error = FTC_Manager_Lookup_Size( gset->manager,
+ &imageset->description.font,
+ &face, &size );
+ if ( !error )
+ {
+ FT_UInt gindex = node->root.glyph_index;
+ FT_UInt load_flags = FT_LOAD_DEFAULT;
+ FT_UInt image_type = imageset->description.image_type;
+
+
+ if ( FTC_IMAGE_FORMAT( image_type ) == ftc_image_format_bitmap )
+ {
+ load_flags |= FT_LOAD_RENDER;
+ if ( image_type & ftc_image_flag_monochrome )
+ load_flags |= FT_LOAD_MONOCHROME;
+
+ /* disable embedded bitmaps loading if necessary */
+ if ( image_type & ftc_image_flag_no_sbits )
+ load_flags |= FT_LOAD_NO_BITMAP;
+ }
+ else if ( FTC_IMAGE_FORMAT( image_type ) == ftc_image_format_outline )
+ {
+ /* disable embedded bitmaps loading */
+ load_flags |= FT_LOAD_NO_BITMAP;
+
+ if ( image_type & ftc_image_flag_unscaled )
+ load_flags |= FT_LOAD_NO_SCALE;
+ }
+
+ if ( image_type & ftc_image_flag_unhinted )
+ load_flags |= FT_LOAD_NO_HINTING;
+
+ if ( image_type & ftc_image_flag_autohinted )
+ load_flags |= FT_LOAD_FORCE_AUTOHINT;
+
+ error = FT_Load_Glyph( face, gindex, load_flags );
+ if ( !error )
+ {
+ if ( face->glyph->format == ft_glyph_format_bitmap ||
+ face->glyph->format == ft_glyph_format_outline )
+ {
+ /* ok, copy it */
+ FT_Glyph glyph;
+
+
+ error = FT_Get_Glyph( face->glyph, &glyph );
+ if ( !error )
+ node->ft_glyph = glyph;
+ }
+ else
+ error = FTC_Err_Invalid_Argument;
+ }
+ }
+
+ Exit:
+ if ( error && node )
+ FREE( node );
+
+ *anode = node;
+ return error;
+ }
+
+
+ /* this function is important because it is both part of */
+ /* an FTC_GlyphSet_Class and an FTC_CacheNode_Class */
+ /* */
+ FT_CALLBACK_DEF( FT_ULong )
+ ftc_glyph_image_node_size( FTC_GlyphImage node )
+ {
+ FT_ULong size = 0;
+ FT_Glyph glyph = node->ft_glyph;
+
+
+ switch ( glyph->format )
+ {
+ case ft_glyph_format_bitmap:
+ {
+ FT_BitmapGlyph bitg;
+
+
+ bitg = (FT_BitmapGlyph)glyph;
+ size = bitg->bitmap.rows * labs( bitg->bitmap.pitch ) +
+ sizeof ( *bitg );
+ }
+ break;
+
+ case ft_glyph_format_outline:
+ {
+ FT_OutlineGlyph outg;
+
+
+ outg = (FT_OutlineGlyph)glyph;
+ size = outg->outline.n_points *
+ ( sizeof( FT_Vector ) + sizeof ( FT_Byte ) ) +
+ outg->outline.n_contours * sizeof ( FT_Short ) +
+ sizeof ( *outg );
+ }
+ break;
+
+ default:
+ ;
+ }
+
+ size += sizeof ( *node );
+ return size;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** GLYPH IMAGE SETS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_image_set_init( FTC_ImageSet iset,
+ FTC_Image_Desc* type )
+ {
+ iset->description = *type;
+ return 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Bool )
+ ftc_image_set_compare( FTC_ImageSet iset,
+ FTC_Image_Desc* type )
+ {
+ return FT_BOOL( !memcmp( &iset->description, type, sizeof ( *type ) ) );
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FTC_GlyphSet_Class ftc_glyph_image_set_class =
+ {
+ sizeof( FTC_ImageSetRec ),
+
+ (FTC_GlyphSet_InitFunc) ftc_image_set_init,
+ (FTC_GlyphSet_DoneFunc) 0,
+ (FTC_GlyphSet_CompareFunc) ftc_image_set_compare,
+
+ (FTC_GlyphSet_NewNodeFunc) ftc_glyph_image_node_new,
+ (FTC_GlyphSet_SizeNodeFunc) ftc_glyph_image_node_size,
+ (FTC_GlyphSet_DestroyNodeFunc)ftc_glyph_image_node_destroy
+ };
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** GLYPH IMAGE CACHE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FTC_Glyph_Cache_Class ftc_glyph_image_cache_class =
+ {
+ {
+ sizeof( FTC_Image_CacheRec ),
+ (FTC_Cache_InitFunc) FTC_Glyph_Cache_Init,
+ (FTC_Cache_DoneFunc) FTC_Glyph_Cache_Done
+ },
+ (FTC_GlyphSet_Class*) &ftc_glyph_image_set_class
+ };
+
+
+ /* documentation is in ftcimage.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Image_Cache_New( FTC_Manager manager,
+ FTC_Image_Cache *acache )
+ {
+ return FTC_Manager_Register_Cache(
+ manager,
+ (FTC_Cache_Class*)&ftc_glyph_image_cache_class,
+ (FTC_Cache*)acache );
+ }
+
+
+ /* documentation is in ftcimage.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Image_Cache_Lookup( FTC_Image_Cache cache,
+ FTC_Image_Desc* desc,
+ FT_UInt gindex,
+ FT_Glyph *aglyph )
+ {
+ FT_Error error;
+ FTC_GlyphNode node;
+
+
+ /* some argument checks are delayed to FTC_Glyph_Cache_Lookup */
+
+ if ( !aglyph )
+ return FTC_Err_Invalid_Argument;
+
+ error = FTC_Glyph_Cache_Lookup( (FTC_Glyph_Cache)cache,
+ desc, gindex, &node );
+
+ if ( !error )
+ *aglyph = ((FTC_GlyphImage)node)->ft_glyph;
+
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftcmanag.c */
+/* */
+/* FreeType Cache Manager (body). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_MANAGER_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_LIST_H
+#include FT_SIZES_H
+
+#include "ftcerror.h"
+
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_cache
+
+#define FTC_LRU_GET_MANAGER( lru ) (FTC_Manager)lru->user_data
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** FACE & SIZE LRU CALLBACKS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_manager_init_face( FT_Lru lru,
+ FT_LruNode node )
+ {
+ FTC_Manager manager = FTC_LRU_GET_MANAGER( lru );
+ FT_Error error;
+ FT_Face face;
+
+
+ error = manager->request_face( (FTC_FaceID)node->key,
+ manager->library,
+ manager->request_data,
+ (FT_Face*)&node->root.data );
+ if ( !error )
+ {
+ /* destroy initial size object; it will be re-created later */
+ face = (FT_Face)node->root.data;
+ if ( face->size )
+ FT_Done_Size( face->size );
+ }
+
+ return error;
+ }
+
+
+ /* helper function for ftc_manager_done_face() */
+ FT_CALLBACK_DEF( FT_Bool )
+ ftc_manager_size_selector( FT_Lru lru,
+ FT_LruNode node,
+ FT_Pointer data )
+ {
+ FT_UNUSED( lru );
+
+ return FT_BOOL( ((FT_Size)node->root.data)->face == (FT_Face)data );
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ ftc_manager_done_face( FT_Lru lru,
+ FT_LruNode node )
+ {
+ FTC_Manager manager = FTC_LRU_GET_MANAGER( lru );
+ FT_Face face = (FT_Face)node->root.data;
+
+
+ /* we must begin by removing all sizes for the target face */
+ /* from the manager's list */
+ FT_Lru_Remove_Selection( manager->sizes_lru,
+ ftc_manager_size_selector,
+ face );
+
+ /* all right, we can discard the face now */
+ FT_Done_Face( face );
+ node->root.data = 0;
+ }
+
+
+ typedef struct FTC_FontRequest_
+ {
+ FT_Face face;
+ FT_UShort width;
+ FT_UShort height;
+
+ } FTC_FontRequest;
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_manager_init_size( FT_Lru lru,
+ FT_LruNode node )
+ {
+ FTC_FontRequest* font_req = (FTC_FontRequest*)node->key;
+ FT_Size size;
+ FT_Error error;
+ FT_Face face = font_req->face;
+
+ FT_UNUSED( lru );
+
+
+ node->root.data = 0;
+ error = FT_New_Size( face, &size );
+ if ( !error )
+ {
+ FT_Activate_Size( size );
+ error = FT_Set_Pixel_Sizes( face,
+ font_req->width,
+ font_req->height );
+ if ( error )
+ FT_Done_Size( size );
+ else
+ node->root.data = size;
+ }
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ ftc_manager_done_size( FT_Lru lru,
+ FT_LruNode node )
+ {
+ FT_UNUSED( lru );
+
+ FT_Done_Size( (FT_Size)node->root.data );
+ node->root.data = 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_manager_flush_size( FT_Lru lru,
+ FT_LruNode node,
+ FT_LruKey key )
+ {
+ FTC_FontRequest* req = (FTC_FontRequest*)key;
+ FT_Size size = (FT_Size)node->root.data;
+ FT_Error error;
+
+
+ if ( size->face == req->face )
+ {
+ FT_Activate_Size( size );
+ error = FT_Set_Pixel_Sizes( req->face, req->width, req->height );
+ if ( error )
+ FT_Done_Size( size );
+ }
+ else
+ {
+ FT_Done_Size( size );
+ node->key = key;
+ error = ftc_manager_init_size( lru, node );
+ }
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Bool )
+ ftc_manager_compare_size( FT_LruNode node,
+ FT_LruKey key )
+ {
+ FTC_FontRequest* req = (FTC_FontRequest*)key;
+ FT_Size size = (FT_Size)node->root.data;
+
+ FT_UNUSED( node );
+
+
+ return FT_BOOL( size->face == req->face &&
+ size->metrics.x_ppem == req->width &&
+ size->metrics.y_ppem == req->height );
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Lru_Class ftc_face_lru_class =
+ {
+ sizeof ( FT_LruRec ),
+ ftc_manager_init_face,
+ ftc_manager_done_face,
+ 0,
+ 0
+ };
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Lru_Class ftc_size_lru_class =
+ {
+ sizeof ( FT_LruRec ),
+ ftc_manager_init_size,
+ ftc_manager_done_size,
+ ftc_manager_flush_size,
+ ftc_manager_compare_size
+ };
+
+
+ /* documentation is in ftcache.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Manager_New( FT_Library library,
+ FT_UInt max_faces,
+ FT_UInt max_sizes,
+ FT_ULong max_bytes,
+ FTC_Face_Requester requester,
+ FT_Pointer req_data,
+ FTC_Manager *amanager )
+ {
+ FT_Error error;
+ FT_Memory memory;
+ FTC_Manager manager = 0;
+
+
+ if ( !library )
+ return FTC_Err_Invalid_Library_Handle;
+
+ memory = library->memory;
+
+ if ( ALLOC( manager, sizeof ( *manager ) ) )
+ goto Exit;
+
+ if ( max_faces == 0 )
+ max_faces = FTC_MAX_FACES_DEFAULT;
+
+ if ( max_sizes == 0 )
+ max_sizes = FTC_MAX_SIZES_DEFAULT;
+
+ if ( max_bytes == 0 )
+ max_bytes = FTC_MAX_BYTES_DEFAULT;
+
+ error = FT_Lru_New( &ftc_face_lru_class,
+ max_faces,
+ manager,
+ memory,
+ 1, /* pre_alloc = TRUE */
+ (FT_Lru*)&manager->faces_lru );
+ if ( error )
+ goto Exit;
+
+ error = FT_Lru_New( &ftc_size_lru_class,
+ max_sizes,
+ manager,
+ memory,
+ 1, /* pre_alloc = TRUE */
+ (FT_Lru*)&manager->sizes_lru );
+ if ( error )
+ goto Exit;
+
+ manager->library = library;
+ manager->max_bytes = max_bytes;
+ manager->request_face = requester;
+ manager->request_data = req_data;
+
+ *amanager = manager;
+
+ Exit:
+ if ( error && manager )
+ {
+ FT_Lru_Done( manager->faces_lru );
+ FT_Lru_Done( manager->sizes_lru );
+ FREE( manager );
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in ftcache.h */
+
+ FT_EXPORT_DEF( void )
+ FTC_Manager_Done( FTC_Manager manager )
+ {
+ FT_Memory memory;
+ FT_UInt index;
+
+
+ if ( !manager || !manager->library )
+ return;
+
+ memory = manager->library->memory;
+
+ /* now discard all caches */
+ for (index = 0; index < FTC_MAX_CACHES; index++ )
+ {
+ FTC_Cache cache = manager->caches[index];
+
+
+ if ( cache )
+ {
+ cache->clazz->done_cache( cache );
+ FREE( cache );
+ manager->caches[index] = 0;
+ }
+ }
+
+ /* discard faces and sizes */
+ FT_Lru_Done( manager->faces_lru );
+ manager->faces_lru = 0;
+
+ FT_Lru_Done( manager->sizes_lru );
+ manager->sizes_lru = 0;
+
+ FREE( manager );
+ }
+
+
+ /* documentation is in ftcache.h */
+
+ FT_EXPORT_DEF( void )
+ FTC_Manager_Reset( FTC_Manager manager )
+ {
+ if (manager )
+ {
+ FT_Lru_Reset( manager->sizes_lru );
+ FT_Lru_Reset( manager->faces_lru );
+ }
+ /* XXX: FIXME: flush the caches? */
+ }
+
+
+ /* documentation is in ftcache.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Manager_Lookup_Face( FTC_Manager manager,
+ FTC_FaceID face_id,
+ FT_Face *aface )
+ {
+ if ( !manager )
+ return FTC_Err_Invalid_Cache_Handle;
+
+ return FT_Lru_Lookup( manager->faces_lru,
+ (FT_LruKey)face_id,
+ (FT_Pointer*)aface );
+ }
+
+
+ /* documentation is in ftcache.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Manager_Lookup_Size( FTC_Manager manager,
+ FTC_Font font,
+ FT_Face *aface,
+ FT_Size *asize )
+ {
+ FTC_FontRequest req;
+ FT_Error error;
+
+
+ /* check for valid `manager' delayed to FTC_Manager_Lookup_Face() */
+
+ if ( aface )
+ *aface = 0;
+
+ if ( asize )
+ *asize = 0;
+
+ error = FTC_Manager_Lookup_Face( manager, font->face_id, aface );
+ if ( !error )
+ {
+ FT_Size size;
+
+
+ req.face = *aface;
+ req.width = font->pix_width;
+ req.height = font->pix_height;
+
+ error = FT_Lru_Lookup( manager->sizes_lru,
+ (FT_LruKey)&req,
+ (FT_Pointer*)&size );
+ if ( !error )
+ {
+ /* select the size as the current one for this face */
+ (*aface)->size = size;
+
+ if ( asize )
+ *asize = size;
+ }
+ }
+
+ return error;
+ }
+
+
+ /* `Compress' the manager's data, i.e., get rid of old cache nodes */
+ /* that are not referenced anymore in order to limit the total */
+ /* memory used by the cache. */
+
+ /* documentation is in ftcmanag.h */
+
+ FT_EXPORT_DEF( void )
+ FTC_Manager_Compress( FTC_Manager manager )
+ {
+ FT_ListNode node;
+
+
+ node = manager->global_lru.tail;
+ while ( manager->num_bytes > manager->max_bytes && node )
+ {
+ FTC_CacheNode cache_node = FTC_LIST_TO_CACHENODE( node );
+ FTC_CacheNode_Data* data = FTC_CACHENODE_TO_DATA_P( cache_node );
+ FTC_Cache cache;
+ FT_ListNode prev = node->prev;
+
+
+ if ( data->ref_count <= 0 )
+ {
+ /* ok, we are going to remove this node */
+ FT_List_Remove( &manager->global_lru, node );
+
+ /* finalize cache node */
+ cache = manager->caches[data->cache_index];
+ if ( cache )
+ {
+ FTC_CacheNode_Class* clazz = cache->node_clazz;
+
+
+ manager->num_bytes -= clazz->size_node( cache_node,
+ cache->cache_data );
+
+ clazz->destroy_node( cache_node, cache->cache_data );
+ }
+ else
+ {
+ /* this should never happen! */
+ FT_ERROR(( "FTC_Manager_Compress: Cache Manager is corrupted!\n" ));
+ }
+
+ /* check, just in case of general corruption :-) */
+ if ( manager->num_nodes <= 0 )
+ FT_ERROR(( "FTC_Manager_Compress: Invalid cache node count!\n" ));
+ else
+ manager->num_nodes--;
+ }
+ node = prev;
+ }
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_Manager_Register_Cache( FTC_Manager manager,
+ FTC_Cache_Class* clazz,
+ FTC_Cache *acache )
+ {
+ FT_Error error = FTC_Err_Invalid_Argument;
+
+
+ if ( manager && clazz && acache )
+ {
+ FT_Memory memory = manager->library->memory;
+ FTC_Cache cache;
+ FT_UInt index = 0;
+
+
+ /* by default, return 0 */
+ *acache = 0;
+
+ /* check for an empty cache slot in the manager's table */
+ for ( index = 0; index < FTC_MAX_CACHES; index++ )
+ {
+ if ( manager->caches[index] == 0 )
+ break;
+ }
+
+ /* return an error if there are too many registered caches */
+ if ( index >= FTC_MAX_CACHES )
+ {
+ error = FTC_Err_Too_Many_Caches;
+ FT_ERROR(( "FTC_Manager_Register_Cache:" ));
+ FT_ERROR(( " too many registered caches\n" ));
+ goto Exit;
+ }
+
+ if ( !ALLOC( cache, clazz->cache_byte_size ) )
+ {
+ cache->manager = manager;
+ cache->memory = memory;
+ cache->clazz = clazz;
+
+ /* THIS IS VERY IMPORTANT! IT WILL WRETCH THE MANAGER */
+ /* IF IT IS NOT SET CORRECTLY */
+ cache->cache_index = index;
+
+ if ( clazz->init_cache )
+ error = clazz->init_cache( cache );
+
+ if ( error )
+ FREE( cache );
+ else
+ manager->caches[index] = *acache = cache;
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftcsbits.c */
+/* */
+/* FreeType sbits manager (body). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_SMALL_BITMAPS_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_ERRORS_H
+
+#include "ftcerror.h"
+
+#include <string.h> /* memcmp() */
+
+
+#define FTC_SBITSET_ELEMENT_COUNT 16
+
+
+ typedef struct FTC_SBitSetRec_
+ {
+ FTC_ChunkSetRec root;
+ FTC_Image_Desc desc;
+
+ } FTC_SBitSetRec, *FTC_SBitSet;
+
+
+ typedef struct FTC_SBit_CacheRec_
+ {
+ FTC_Chunk_CacheRec root;
+
+ } FTC_SBit_CacheRec;
+
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** SBIT CACHE NODES *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_CALLBACK_DEF( void )
+ ftc_sbit_chunk_node_destroy( FTC_ChunkNode node )
+ {
+ FTC_ChunkSet cset = node->cset;
+ FT_Memory memory = cset->memory;
+ FT_UInt count = node->num_elements;
+ FTC_SBit sbit = (FTC_SBit)node->elements;
+
+
+ for ( ; count > 0; sbit++, count-- )
+ FREE( sbit->buffer );
+
+ FREE( node->elements );
+ FREE( node );
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_bitmap_copy( FT_Memory memory,
+ FT_Bitmap* source,
+ FTC_SBit target )
+ {
+ FT_Error error;
+ FT_Int pitch = source->pitch;
+ FT_ULong size;
+
+
+ if ( pitch < 0 )
+ pitch = -pitch;
+
+ size = (FT_ULong)( pitch * source->rows );
+
+ if ( !ALLOC( target->buffer, size ) )
+ MEM_Copy( target->buffer, source->buffer, size );
+
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_sbit_chunk_node_new( FTC_ChunkSet cset,
+ FT_UInt index,
+ FTC_ChunkNode *anode )
+ {
+ FT_Error error;
+ FT_Memory memory = cset->memory;
+ FTC_SBitSet sbitset = (FTC_SBitSet)cset;
+ FTC_ChunkNode node = 0;
+ FT_Face face;
+ FT_Size size;
+
+
+ /* allocate node */
+ if ( ALLOC( node, sizeof ( *node ) ) )
+ goto Exit;
+
+ /* initialize its inner fields */
+ error = FTC_ChunkNode_Init( node, cset, index, 1 );
+ if ( error )
+ goto Exit;
+
+ /* we will now load all glyph images for this chunk */
+ error = FTC_Manager_Lookup_Size( cset->manager,
+ &sbitset->desc.font,
+ &face, &size );
+ if ( !error )
+ {
+ FT_UInt glyph_index = index * cset->element_count;
+ FT_UInt load_flags = FT_LOAD_DEFAULT;
+ FT_UInt image_type = sbitset->desc.image_type;
+ FT_UInt count = node->num_elements;
+ FTC_SBit sbit = (FTC_SBit)node->elements;
+
+
+ /* determine load flags, depending on the font description's */
+ /* image type */
+
+ if ( FTC_IMAGE_FORMAT( image_type ) == ftc_image_format_bitmap )
+ {
+ if ( image_type & ftc_image_flag_monochrome )
+ load_flags |= FT_LOAD_MONOCHROME;
+
+ /* disable embedded bitmaps loading if necessary */
+ if ( image_type & ftc_image_flag_no_sbits )
+ load_flags |= FT_LOAD_NO_BITMAP;
+ }
+ else
+ {
+ FT_ERROR(( "FTC_SBit_Cache: cannot load scalable glyphs in an"
+ " sbit cache, please check your arguments!\n" ));
+ error = FTC_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ /* always render glyphs to bitmaps */
+ load_flags |= FT_LOAD_RENDER;
+
+ if ( image_type & ftc_image_flag_unhinted )
+ load_flags |= FT_LOAD_NO_HINTING;
+
+ if ( image_type & ftc_image_flag_autohinted )
+ load_flags |= FT_LOAD_FORCE_AUTOHINT;
+
+ /* load a chunk of small bitmaps in a row */
+ for ( ; count > 0; count--, glyph_index++, sbit++ )
+ {
+ /* by default, indicates a `missing' glyph */
+ sbit->buffer = 0;
+
+ error = FT_Load_Glyph( face, glyph_index, load_flags );
+ if ( !error )
+ {
+ FT_Int temp;
+ FT_GlyphSlot slot = face->glyph;
+ FT_Bitmap* bitmap = &slot->bitmap;
+ FT_Int xadvance, yadvance;
+
+
+ /* check that our values fit into 8-bit containers! */
+ /* If this is not the case, our bitmap is too large */
+ /* and we will leave it as `missing' with sbit.buffer = 0 */
+
+#define CHECK_CHAR( d ) ( temp = (FT_Char)d, temp == d )
+#define CHECK_BYTE( d ) ( temp = (FT_Byte)d, temp == d )
+
+ /* XXX: FIXME: add support for vertical layouts maybe */
+
+ /* horizontal advance in pixels */
+ xadvance = ( slot->metrics.horiAdvance + 32 ) >> 6;
+ yadvance = ( slot->metrics.vertAdvance + 32 ) >> 6;
+
+ if ( CHECK_BYTE( bitmap->rows ) &&
+ CHECK_BYTE( bitmap->width ) &&
+ CHECK_CHAR( bitmap->pitch ) &&
+ CHECK_CHAR( slot->bitmap_left ) &&
+ CHECK_CHAR( slot->bitmap_top ) &&
+ CHECK_CHAR( xadvance ) &&
+ CHECK_CHAR( yadvance ) )
+ {
+ sbit->width = (FT_Byte)bitmap->width;
+ sbit->height = (FT_Byte)bitmap->rows;
+ sbit->pitch = (FT_Char)bitmap->pitch;
+ sbit->left = (FT_Char)slot->bitmap_left;
+ sbit->top = (FT_Char)slot->bitmap_top;
+ sbit->xadvance = (FT_Char)xadvance;
+ sbit->yadvance = (FT_Char)yadvance;
+ sbit->format = (FT_Byte)bitmap->pixel_mode;
+
+ /* grab the bitmap when possible */
+ if ( slot->flags & ft_glyph_own_bitmap )
+ {
+ slot->flags &= ~ft_glyph_own_bitmap;
+ sbit->buffer = bitmap->buffer;
+ }
+ else
+ {
+ /* copy the bitmap into a new buffer -- ignore error */
+ ftc_bitmap_copy( memory, bitmap, sbit );
+ }
+ }
+ }
+ }
+
+ /* ignore the errors that might have occurred -- */
+ /* we recognize unloaded glyphs with `sbit.buffer == 0' */
+ error = 0;
+ }
+
+ Exit:
+ if ( error && node )
+ {
+ FREE( node->elements );
+ FREE( node );
+ }
+
+ *anode = node;
+
+ return error;
+ }
+
+
+ /* this function is important because it is both part of */
+ /* an FTC_ChunkSet_Class and an FTC_CacheNode_Class */
+ /* */
+ FT_CALLBACK_DEF( FT_ULong )
+ ftc_sbit_chunk_node_size( FTC_ChunkNode node )
+ {
+ FT_ULong size;
+ FTC_ChunkSet cset = node->cset;
+ FT_UInt count = node->num_elements;
+ FT_Int pitch;
+ FTC_SBit sbit = (FTC_SBit)node->elements;
+
+
+ /* the node itself */
+ size = sizeof ( *node );
+
+ /* the sbit records */
+ size += cset->element_count * sizeof ( FTC_SBitRec );
+
+ for ( ; count > 0; count--, sbit++ )
+ {
+ if ( sbit->buffer )
+ {
+ pitch = sbit->pitch;
+ if ( pitch < 0 )
+ pitch = -pitch;
+
+ /* add the size of a given glyph image */
+ size += pitch * sbit->height;
+ }
+ }
+
+ return size;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** SBIT CHUNK SETS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_sbit_chunk_set_sizes( FTC_ChunkSet cset,
+ FTC_Image_Desc* desc )
+ {
+ FT_Error error;
+ FT_Face face;
+
+
+ cset->element_count = FTC_SBITSET_ELEMENT_COUNT;
+ cset->element_size = sizeof ( FTC_SBitRec );
+
+ /* lookup the FT_Face to obtain the number of glyphs */
+ error = FTC_Manager_Lookup_Face( cset->manager,
+ desc->font.face_id, &face );
+ if ( !error )
+ cset->element_max = face->num_glyphs;
+
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ftc_sbit_chunk_set_init( FTC_SBitSet sset,
+ FTC_Image_Desc* type )
+ {
+ sset->desc = *type;
+
+ return 0;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Bool )
+ ftc_sbit_chunk_set_compare( FTC_SBitSet sset,
+ FTC_Image_Desc* type )
+ {
+ return FT_BOOL( !memcmp( &sset->desc, type, sizeof ( *type ) ) );
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FTC_ChunkSet_Class ftc_sbit_chunk_set_class =
+ {
+ sizeof( FTC_SBitSetRec ),
+
+ (FTC_ChunkSet_InitFunc) ftc_sbit_chunk_set_init,
+ (FTC_ChunkSet_DoneFunc) 0,
+ (FTC_ChunkSet_CompareFunc) ftc_sbit_chunk_set_compare,
+ (FTC_ChunkSet_SizesFunc) ftc_sbit_chunk_set_sizes,
+
+ (FTC_ChunkSet_NewNodeFunc) ftc_sbit_chunk_node_new,
+ (FTC_ChunkSet_SizeNodeFunc) ftc_sbit_chunk_node_size,
+ (FTC_ChunkSet_DestroyNodeFunc)ftc_sbit_chunk_node_destroy
+ };
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** SBITS CACHE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FTC_Chunk_Cache_Class ftc_sbit_cache_class =
+ {
+ {
+ sizeof( FTC_SBit_CacheRec ),
+ (FTC_Cache_InitFunc)FTC_Chunk_Cache_Init,
+ (FTC_Cache_DoneFunc)FTC_Chunk_Cache_Done
+ },
+ (FTC_ChunkSet_Class*)&ftc_sbit_chunk_set_class
+ };
+
+
+ /* documentation is in ftcsbits.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_SBit_Cache_New( FTC_Manager manager,
+ FTC_SBit_Cache *acache )
+ {
+ return FTC_Manager_Register_Cache(
+ manager,
+ (FTC_Cache_Class*)&ftc_sbit_cache_class,
+ (FTC_Cache*)acache );
+ }
+
+
+ /* documentation is in ftcsbits.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FTC_SBit_Cache_Lookup( FTC_SBit_Cache cache,
+ FTC_Image_Desc* desc,
+ FT_UInt gindex,
+ FTC_SBit *ansbit )
+ {
+ FT_Error error;
+ FTC_ChunkNode node;
+ FT_UInt cindex;
+
+
+ /* argument checks delayed to FTC_Chunk_Cache_Lookup */
+ if ( !ansbit )
+ return FTC_Err_Invalid_Argument;
+
+ *ansbit = 0;
+ error = FTC_Chunk_Cache_Lookup( &cache->root, desc, gindex,
+ &node, &cindex );
+ if ( !error )
+ *ansbit = (FTC_SBit)node->elements + cindex;
+
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftdebug.c */
+/* */
+/* Debugging and logging component (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This component contains various macros and functions used to ease the */
+ /* debugging of the FreeType engine. Its main purpose is in assertion */
+ /* checking, tracing, and error detection. */
+ /* */
+ /* There are now three debugging modes: */
+ /* */
+ /* - trace mode */
+ /* */
+ /* Error and trace messages are sent to the log file (which can be the */
+ /* standard error output). */
+ /* */
+ /* - error mode */
+ /* */
+ /* Only error messages are generated. */
+ /* */
+ /* - release mode: */
+ /* */
+ /* No error message is sent or generated. The code is free from any */
+ /* debugging parts. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+ char ft_trace_levels[trace_max];
+#endif
+
+
+#if defined( FT_DEBUG_LEVEL_ERROR ) || defined( FT_DEBUG_LEVEL_TRACE )
+
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+ FT_EXPORT_DEF( void )
+ FT_Message( const char* fmt, ... )
+ {
+ va_list ap;
+
+
+ va_start( ap, fmt );
+ vprintf( fmt, ap );
+ va_end( ap );
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FT_Panic( const char* fmt, ... )
+ {
+ va_list ap;
+
+
+ va_start( ap, fmt );
+ vprintf( fmt, ap );
+ va_end( ap );
+
+ exit( EXIT_FAILURE );
+ }
+
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+
+ FT_EXPORT_DEF( void )
+ FT_SetTraceLevel( FT_Trace component,
+ char level )
+ {
+ if ( component >= trace_max )
+ return;
+
+ /* if component is `trace_any', change _all_ levels at once */
+ if ( component == trace_any )
+ {
+ int n;
+
+
+ for ( n = trace_any; n < trace_max; n++ )
+ ft_trace_levels[n] = level;
+ }
+ else /* otherwise, only change individual component */
+ ft_trace_levels[component] = level;
+ }
+
+#endif /* FT_DEBUG_LEVEL_TRACE */
+
+#endif /* FT_DEBUG_LEVEL_TRACE || FT_DEBUG_LEVEL_ERROR */
+
+
+ /* ANSI C doesn't allow empty files, so we insert a dummy symbol */
+ extern const int ft_debug_dummy;
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftextend.c */
+/* */
+/* FreeType extensions implementation (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* This is an updated version of the extension component, now located */
+ /* in the main library's source directory. It allows the dynamic */
+ /* registration/use of various face object extensions through a simple */
+ /* API. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_EXTEND_H
+#include FT_INTERNAL_DEBUG_H
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_extend
+
+
+ typedef struct FT_Extension_Registry_
+ {
+ FT_Int num_extensions;
+ FT_Long cur_offset;
+ FT_Extension_Class classes[FT_MAX_EXTENSIONS];
+
+ } FT_Extension_Registry;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Init_Extensions */
+ /* */
+ /* <Description> */
+ /* Initializes the extension component. */
+ /* */
+ /* <InOut> */
+ /* driver :: A handle to the driver object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ FT_Init_Extensions( FT_Driver driver )
+ {
+ FT_Error error;
+ FT_Memory memory;
+ FT_Extension_Registry* registry;
+
+
+ memory = driver->root.library->memory;
+ if ( ALLOC( registry, sizeof ( *registry ) ) )
+ return error;
+
+ registry->num_extensions = 0;
+ registry->cur_offset = 0;
+ driver->extensions = registry;
+
+ FT_TRACE2(( "FT_Init_Extensions: success\n" ));
+
+ return FT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Done_Extensions */
+ /* */
+ /* <Description> */
+ /* Finalizes the extension component. */
+ /* */
+ /* <InOut> */
+ /* driver :: A handle to the driver object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ FT_Done_Extensions( FT_Driver driver )
+ {
+ FT_Memory memory = driver->root.memory;
+
+
+ FREE( driver->extensions );
+ return FT_Err_Ok;
+ }
+
+
+ /* documentation is in ftextend.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Register_Extension( FT_Driver driver,
+ FT_Extension_Class* clazz )
+ {
+ FT_Extension_Registry* registry;
+
+
+ if ( !driver )
+ return FT_Err_Invalid_Driver_Handle;
+
+ if ( !clazz )
+ return FT_Err_Invalid_Argument;
+
+ registry = (FT_Extension_Registry*)driver->extensions;
+ if ( registry )
+ {
+ FT_Int n = registry->num_extensions;
+ FT_Extension_Class* cur = registry->classes + n;
+
+
+ if ( n >= FT_MAX_EXTENSIONS )
+ return FT_Err_Too_Many_Extensions;
+
+ *cur = *clazz;
+
+ cur->offset = registry->cur_offset;
+
+ registry->num_extensions++;
+ registry->cur_offset +=
+ ( cur->size + FT_ALIGNMENT - 1 ) & -FT_ALIGNMENT;
+
+ FT_TRACE1(( "FT_Register_Extension: `%s' successfully registered\n",
+ cur->id ));
+ }
+
+ return FT_Err_Ok;
+ }
+
+
+ /* documentation is in ftextend.h */
+
+ FT_EXPORT_DEF( void* )
+ FT_Get_Extension( FT_Face face,
+ const char* extension_id,
+ void** extension_interface )
+ {
+ FT_Extension_Registry* registry;
+
+
+ if ( !face || !extension_id || !extension_interface )
+ return 0;
+
+ registry = (FT_Extension_Registry*)face->driver->extensions;
+ if ( registry && face->extensions )
+ {
+ FT_Extension_Class* cur = registry->classes;
+ FT_Extension_Class* limit = cur + registry->num_extensions;
+
+
+ for ( ; cur < limit; cur++ )
+ if ( strcmp( cur->id, extension_id ) == 0 )
+ {
+ *extension_interface = cur->interface;
+
+ FT_TRACE1(( "FT_Get_Extension: got `%s'\n", extension_id ));
+
+ return (void*)((char*)face->extensions + cur->offset);
+ }
+ }
+
+ /* could not find the extension id */
+
+ FT_ERROR(( "FT_Get_Extension: couldn't find `%s'\n", extension_id ));
+
+ *extension_interface = 0;
+
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Destroy_Extensions */
+ /* */
+ /* <Description> */
+ /* Destroys all extensions within a face object. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the face object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Called by the face object destructor. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ FT_Destroy_Extensions( FT_Face face )
+ {
+ FT_Extension_Registry* registry;
+ FT_Memory memory;
+
+
+ registry = (FT_Extension_Registry*)face->driver->extensions;
+ if ( registry && face->extensions )
+ {
+ FT_Extension_Class* cur = registry->classes;
+ FT_Extension_Class* limit = cur + registry->num_extensions;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ char* ext = (char*)face->extensions + cur->offset;
+
+ if ( cur->finalize )
+ cur->finalize( ext, face );
+ }
+
+ memory = face->driver->root.memory;
+ FREE( face->extensions );
+ }
+
+ return FT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Create_Extensions */
+ /* */
+ /* <Description> */
+ /* Creates an extension object within a face object for all */
+ /* registered extensions. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the face object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Called by the face object constructor. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ FT_Create_Extensions( FT_Face face )
+ {
+ FT_Extension_Registry* registry;
+ FT_Memory memory;
+ FT_Error error;
+
+
+ face->extensions = 0;
+
+ /* load extensions registry; exit successfully if none is there */
+
+ registry = (FT_Extension_Registry*)face->driver->extensions;
+ if ( !registry )
+ return FT_Err_Ok;
+
+ memory = face->driver->root.memory;
+ if ( ALLOC( face->extensions, registry->cur_offset ) )
+ return error;
+
+ {
+ FT_Extension_Class* cur = registry->classes;
+ FT_Extension_Class* limit = cur + registry->num_extensions;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ char* ext = (char*)face->extensions + cur->offset;
+
+ if ( cur->init )
+ {
+ error = cur->init( ext, face );
+ if ( error )
+ break;
+ }
+ }
+ }
+
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftglyph.c */
+/* */
+/* FreeType convenience functions to handle glyphs (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* This file contains the definition of several convenience functions */
+ /* that can be used by client applications to easily retrieve glyph */
+ /* bitmaps and outlines from a given face. */
+ /* */
+ /* These functions should be optional if you are writing a font server */
+ /* or text layout engine on top of FreeType. However, they are pretty */
+ /* handy for many other simple uses of the library. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_GLYPH_H
+#include FT_OUTLINE_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_glyph
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** Convenience functions ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Matrix_Multiply( FT_Matrix* a,
+ FT_Matrix* b )
+ {
+ FT_Fixed xx, xy, yx, yy;
+
+
+ if ( !a || !b )
+ return;
+
+ xx = FT_MulFix( a->xx, b->xx ) + FT_MulFix( a->xy, b->yx );
+ xy = FT_MulFix( a->xx, b->xy ) + FT_MulFix( a->xy, b->yy );
+ yx = FT_MulFix( a->yx, b->xx ) + FT_MulFix( a->yy, b->yx );
+ yy = FT_MulFix( a->yx, b->xy ) + FT_MulFix( a->yy, b->yy );
+
+ b->xx = xx; b->xy = xy;
+ b->yx = yx; b->yy = yy;
+ }
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Matrix_Invert( FT_Matrix* matrix )
+ {
+ FT_Pos delta, xx, yy;
+
+
+ if ( !matrix )
+ return FT_Err_Invalid_Argument;
+
+ /* compute discriminant */
+ delta = FT_MulFix( matrix->xx, matrix->yy ) -
+ FT_MulFix( matrix->xy, matrix->yx );
+
+ if ( !delta )
+ return FT_Err_Invalid_Argument; /* matrix can't be inverted */
+
+ matrix->xy = - FT_DivFix( matrix->xy, delta );
+ matrix->yx = - FT_DivFix( matrix->yx, delta );
+
+ xx = matrix->xx;
+ yy = matrix->yy;
+
+ matrix->xx = FT_DivFix( yy, delta );
+ matrix->yy = FT_DivFix( xx, delta );
+
+ return FT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** FT_BitmapGlyph support ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static FT_Error
+ ft_bitmap_copy( FT_Memory memory,
+ FT_Bitmap* source,
+ FT_Bitmap* target )
+ {
+ FT_Error error;
+ FT_Int pitch = source->pitch;
+ FT_ULong size;
+
+
+ *target = *source;
+
+ if ( pitch < 0 )
+ pitch = -pitch;
+
+ size = (FT_ULong)( pitch * source->rows );
+
+ if ( !ALLOC( target->buffer, size ) )
+ MEM_Copy( target->buffer, source->buffer, size );
+
+ return error;
+ }
+
+
+ static FT_Error
+ ft_bitmap_glyph_init( FT_BitmapGlyph glyph,
+ FT_GlyphSlot slot )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_Library library = FT_GLYPH(glyph)->library;
+ FT_Memory memory = library->memory;
+
+
+ if ( slot->format != ft_glyph_format_bitmap )
+ {
+ error = FT_Err_Invalid_Glyph_Format;
+ goto Exit;
+ }
+
+ /* grab the bitmap in the slot - do lazy copying whenever possible */
+ glyph->bitmap = slot->bitmap;
+ glyph->left = slot->bitmap_left;
+ glyph->top = slot->bitmap_top;
+
+ if ( slot->flags & ft_glyph_own_bitmap )
+ slot->flags &= ~ft_glyph_own_bitmap;
+ else
+ {
+ /* copy the bitmap into a new buffer */
+ error = ft_bitmap_copy( memory, &slot->bitmap, &glyph->bitmap );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ ft_bitmap_glyph_copy( FT_BitmapGlyph source,
+ FT_BitmapGlyph target )
+ {
+ FT_Memory memory = source->root.library->memory;
+
+
+ target->left = source->left;
+ target->top = source->top;
+
+ return ft_bitmap_copy( memory, &source->bitmap, &target->bitmap );
+ }
+
+
+ static void
+ ft_bitmap_glyph_done( FT_BitmapGlyph glyph )
+ {
+ FT_Memory memory = FT_GLYPH(glyph)->library->memory;
+
+
+ FREE( glyph->bitmap.buffer );
+ }
+
+
+ static void
+ ft_bitmap_glyph_bbox( FT_BitmapGlyph glyph,
+ FT_BBox* cbox )
+ {
+ cbox->xMin = glyph->left << 6;
+ cbox->xMax = cbox->xMin + ( glyph->bitmap.width << 6 );
+ cbox->yMax = glyph->top << 6;
+ cbox->yMin = cbox->yMax - ( glyph->bitmap.rows << 6 );
+ }
+
+
+ const FT_Glyph_Class ft_bitmap_glyph_class =
+ {
+ sizeof( FT_BitmapGlyphRec ),
+ ft_glyph_format_bitmap,
+
+ (FT_Glyph_Init_Func) ft_bitmap_glyph_init,
+ (FT_Glyph_Done_Func) ft_bitmap_glyph_done,
+ (FT_Glyph_Copy_Func) ft_bitmap_glyph_copy,
+ (FT_Glyph_Transform_Func)0,
+ (FT_Glyph_BBox_Func) ft_bitmap_glyph_bbox,
+ (FT_Glyph_Prepare_Func) 0
+ };
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** FT_OutlineGlyph support ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ static FT_Error
+ ft_outline_glyph_init( FT_OutlineGlyph glyph,
+ FT_GlyphSlot slot )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_Library library = FT_GLYPH(glyph)->library;
+ FT_Outline* source = &slot->outline;
+ FT_Outline* target = &glyph->outline;
+
+
+ /* check format in glyph slot */
+ if ( slot->format != ft_glyph_format_outline )
+ {
+ error = FT_Err_Invalid_Glyph_Format;
+ goto Exit;
+ }
+
+ /* allocate new outline */
+ error = FT_Outline_New( library, source->n_points, source->n_contours,
+ &glyph->outline );
+ if ( error )
+ goto Exit;
+
+ /* copy it */
+ MEM_Copy( target->points, source->points,
+ source->n_points * sizeof ( FT_Vector ) );
+
+ MEM_Copy( target->tags, source->tags,
+ source->n_points * sizeof ( FT_Byte ) );
+
+ MEM_Copy( target->contours, source->contours,
+ source->n_contours * sizeof ( FT_Short ) );
+
+ /* copy all flags, except the `ft_outline_owner' one */
+ target->flags = source->flags | ft_outline_owner;
+
+ Exit:
+ return error;
+ }
+
+
+ static void
+ ft_outline_glyph_done( FT_OutlineGlyph glyph )
+ {
+ FT_Outline_Done( FT_GLYPH( glyph )->library, &glyph->outline );
+ }
+
+
+ static FT_Error
+ ft_outline_glyph_copy( FT_OutlineGlyph source,
+ FT_OutlineGlyph target )
+ {
+ FT_Error error;
+ FT_Library library = FT_GLYPH( source )->library;
+
+
+ error = FT_Outline_New( library, source->outline.n_points,
+ source->outline.n_contours, &target->outline );
+ if ( !error )
+ FT_Outline_Copy( &source->outline, &target->outline );
+
+ return error;
+ }
+
+
+ static void
+ ft_outline_glyph_transform( FT_OutlineGlyph glyph,
+ FT_Matrix* matrix,
+ FT_Vector* delta )
+ {
+ if ( matrix )
+ FT_Outline_Transform( &glyph->outline, matrix );
+
+ if ( delta )
+ FT_Outline_Translate( &glyph->outline, delta->x, delta->y );
+ }
+
+
+ static void
+ ft_outline_glyph_bbox( FT_OutlineGlyph glyph,
+ FT_BBox* bbox )
+ {
+ FT_Outline_Get_CBox( &glyph->outline, bbox );
+ }
+
+
+ static FT_Error
+ ft_outline_glyph_prepare( FT_OutlineGlyph glyph,
+ FT_GlyphSlot slot )
+ {
+ slot->format = ft_glyph_format_outline;
+ slot->outline = glyph->outline;
+ slot->outline.flags &= ~ft_outline_owner;
+
+ return FT_Err_Ok;
+ }
+
+
+ const FT_Glyph_Class ft_outline_glyph_class =
+ {
+ sizeof( FT_OutlineGlyphRec ),
+ ft_glyph_format_outline,
+
+ (FT_Glyph_Init_Func) ft_outline_glyph_init,
+ (FT_Glyph_Done_Func) ft_outline_glyph_done,
+ (FT_Glyph_Copy_Func) ft_outline_glyph_copy,
+ (FT_Glyph_Transform_Func)ft_outline_glyph_transform,
+ (FT_Glyph_BBox_Func) ft_outline_glyph_bbox,
+ (FT_Glyph_Prepare_Func) ft_outline_glyph_prepare
+ };
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** FT_Glyph class and API ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static FT_Error
+ ft_new_glyph( FT_Library library,
+ const FT_Glyph_Class* clazz,
+ FT_Glyph* aglyph )
+ {
+ FT_Memory memory = library->memory;
+ FT_Error error;
+ FT_Glyph glyph;
+
+
+ *aglyph = 0;
+
+ if ( !ALLOC( glyph, clazz->glyph_size ) )
+ {
+ glyph->library = library;
+ glyph->clazz = clazz;
+ glyph->format = clazz->glyph_format;
+
+ *aglyph = glyph;
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Glyph_Copy( FT_Glyph source,
+ FT_Glyph *target )
+ {
+ FT_Glyph copy;
+ FT_Error error;
+ const FT_Glyph_Class* clazz;
+
+
+ /* check arguments */
+ if ( !target || !source || !source->clazz )
+ {
+ error = FT_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ *target = 0;
+
+ clazz = source->clazz;
+ error = ft_new_glyph( source->library, clazz, © );
+ if ( error )
+ goto Exit;
+
+ copy->advance = source->advance;
+ copy->format = source->format;
+
+ if ( clazz->glyph_copy )
+ error = clazz->glyph_copy( source, copy );
+
+ if ( error )
+ FT_Done_Glyph( copy );
+ else
+ *target = copy;
+
+ Exit:
+ return error;
+ }
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_Glyph( FT_GlyphSlot slot,
+ FT_Glyph *aglyph )
+ {
+ FT_Library library = slot->library;
+ FT_Error error;
+ FT_Glyph glyph;
+
+ const FT_Glyph_Class* clazz = 0;
+
+
+ if ( !slot )
+ return FT_Err_Invalid_Slot_Handle;
+
+ if ( !aglyph )
+ return FT_Err_Invalid_Argument;
+
+ /* if it is a bitmap, that's easy :-) */
+ if ( slot->format == ft_glyph_format_bitmap )
+ clazz = &ft_bitmap_glyph_class;
+
+ /* it it is an outline too */
+ else if ( slot->format == ft_glyph_format_outline )
+ clazz = &ft_outline_glyph_class;
+
+ else
+ {
+ /* try to find a renderer that supports the glyph image format */
+ FT_Renderer render = FT_Lookup_Renderer( library, slot->format, 0 );
+
+
+ if ( render )
+ clazz = &render->glyph_class;
+ }
+
+ if ( !clazz )
+ {
+ error = FT_Err_Invalid_Glyph_Format;
+ goto Exit;
+ }
+
+ /* create FT_Glyph object */
+ error = ft_new_glyph( library, clazz, &glyph );
+ if ( error )
+ goto Exit;
+
+ /* copy advance while converting it to 16.16 format */
+ glyph->advance.x = slot->advance.x << 10;
+ glyph->advance.y = slot->advance.y << 10;
+
+ /* now import the image from the glyph slot */
+ error = clazz->glyph_init( glyph, slot );
+
+ /* if an error occurred, destroy the glyph */
+ if ( error )
+ FT_Done_Glyph( glyph );
+ else
+ *aglyph = glyph;
+
+ Exit:
+ return error;
+ }
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Glyph_Transform( FT_Glyph glyph,
+ FT_Matrix* matrix,
+ FT_Vector* delta )
+ {
+ const FT_Glyph_Class* clazz;
+ FT_Error error = FT_Err_Ok;
+
+
+ if ( !glyph || !glyph->clazz )
+ error = FT_Err_Invalid_Argument;
+ else
+ {
+ clazz = glyph->clazz;
+ if ( clazz->glyph_transform )
+ {
+ /* transform glyph image */
+ clazz->glyph_transform( glyph, matrix, delta );
+
+ /* transform advance vector */
+ if ( matrix )
+ FT_Vector_Transform( &glyph->advance, matrix );
+ }
+ else
+ error = FT_Err_Invalid_Glyph_Format;
+ }
+ return error;
+ }
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Glyph_Get_CBox( FT_Glyph glyph,
+ FT_UInt bbox_mode,
+ FT_BBox *acbox )
+ {
+ const FT_Glyph_Class* clazz;
+
+
+ if ( !acbox )
+ return;
+
+ acbox->xMin = acbox->yMin = acbox->xMax = acbox->yMax = 0;
+
+ if ( !glyph || !glyph->clazz )
+ return;
+ else
+ {
+ clazz = glyph->clazz;
+ if ( !clazz->glyph_bbox )
+ return;
+ else
+ {
+ /* retrieve bbox in 26.6 coordinates */
+ clazz->glyph_bbox( glyph, acbox );
+
+ /* perform grid fitting if needed */
+ if ( bbox_mode & ft_glyph_bbox_gridfit )
+ {
+ acbox->xMin &= -64;
+ acbox->yMin &= -64;
+ acbox->xMax = ( acbox->xMax + 63 ) & -64;
+ acbox->yMax = ( acbox->yMax + 63 ) & -64;
+ }
+
+ /* convert to integer pixels if needed */
+ if ( bbox_mode & ft_glyph_bbox_truncate )
+ {
+ acbox->xMin >>= 6;
+ acbox->yMin >>= 6;
+ acbox->xMax >>= 6;
+ acbox->yMax >>= 6;
+ }
+ }
+ }
+ return;
+ }
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Glyph_To_Bitmap( FT_Glyph* the_glyph,
+ FT_ULong render_mode,
+ FT_Vector* origin,
+ FT_Bool destroy )
+ {
+ FT_GlyphSlotRec dummy;
+ FT_Error error;
+ FT_Glyph glyph;
+ FT_BitmapGlyph bitmap;
+
+ const FT_Glyph_Class* clazz;
+
+
+ /* check argument */
+ if ( !the_glyph )
+ goto Bad;
+
+ /* we render the glyph into a glyph bitmap using a `dummy' glyph slot */
+ /* then calling FT_Render_Glyph_Internal() */
+
+ glyph = *the_glyph;
+ if ( !glyph )
+ goto Bad;
+
+ clazz = glyph->clazz;
+ if ( !clazz || !clazz->glyph_prepare )
+ goto Bad;
+
+ MEM_Set( &dummy, 0, sizeof ( dummy ) );
+ dummy.library = glyph->library;
+ dummy.format = clazz->glyph_format;
+
+ /* if `origin' is set, translate the glyph image */
+ if ( origin )
+ FT_Glyph_Transform( glyph, 0, origin );
+
+ /* create result bitmap glyph */
+ error = ft_new_glyph( glyph->library, &ft_bitmap_glyph_class,
+ (FT_Glyph*)&bitmap );
+ if ( error )
+ goto Exit;
+
+ /* prepare dummy slot for rendering */
+ error = clazz->glyph_prepare( glyph, &dummy );
+ if ( !error )
+ error = FT_Render_Glyph_Internal( glyph->library, &dummy, render_mode );
+
+ if ( error )
+ {
+ FT_Done_Glyph( FT_GLYPH( bitmap ) );
+ goto Exit;
+ }
+
+ if ( !destroy && origin )
+ {
+ FT_Vector v;
+
+
+ v.x = -origin->x;
+ v.y = -origin->y;
+ FT_Glyph_Transform( glyph, 0, &v );
+ }
+
+ /* in case of success, copy the bitmap to the glyph bitmap */
+ if ( !error )
+ {
+ error = ft_bitmap_glyph_init( bitmap, &dummy );
+ if ( error )
+ {
+ /* this should never happen, but let's be safe */
+ FT_Done_Glyph( FT_GLYPH( bitmap ) );
+ goto Exit;
+ }
+
+ /* copy advance */
+ bitmap->root.advance = glyph->advance;
+
+ if ( destroy )
+ FT_Done_Glyph( glyph );
+
+ *the_glyph = FT_GLYPH( bitmap );
+ }
+
+ Exit:
+ return error;
+
+ Bad:
+ error = FT_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Done_Glyph( FT_Glyph glyph )
+ {
+ if ( glyph )
+ {
+ FT_Memory memory = glyph->library->memory;
+ const FT_Glyph_Class* clazz = glyph->clazz;
+
+
+ if ( clazz->glyph_done )
+ clazz->glyph_done( glyph );
+
+ FREE( glyph );
+ }
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftgrays.c */
+/* */
+/* A new `perfect' anti-aliasing renderer (body). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* This file can be compiled without the rest of the FreeType engine, */
+ /* by defining the _STANDALONE_ macro when compiling it. You also need */
+ /* to put the files `ftgrays.h' and `ftimage.h' into the current */
+ /* compilation directory. Typically, you could do something like */
+ /* */
+ /* - copy `src/base/ftgrays.c' to your current directory */
+ /* */
+ /* - copy `include/freetype/ftimage.h' and */
+ /* `include/freetype/ftgrays.h' to the same directory */
+ /* */
+ /* - compile `ftgrays' with the _STANDALONE_ macro defined, as in */
+ /* */
+ /* cc -c -D_STANDALONE_ ftgrays.c */
+ /* */
+ /* The renderer can be initialized with a call to */
+ /* `ft_gray_raster.gray_raster_new'; an anti-aliased bitmap can be */
+ /* generated with a call to `ft_gray_raster.gray_raster_render'. */
+ /* */
+ /* See the comments and documentation in the file `ftimage.h' for */
+ /* more details on how the raster works. */
+ /* */
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* This is a new anti-aliasing scan-converter for FreeType 2. The */
+ /* algorithm used here is _very_ different from the one in the standard */
+ /* `ftraster' module. Actually, `ftgrays' computes the _exact_ */
+ /* coverage of the outline on each pixel cell. */
+ /* */
+ /* It is based on ideas that I initially found in Raph Levien's */
+ /* excellent LibArt graphics library (see http://www.levien.com/libart */
+ /* for more information, though the web pages do not tell anything */
+ /* about the renderer; you'll have to dive into the source code to */
+ /* understand how it works). */
+ /* */
+ /* Note, however, that this is a _very_ different implementation */
+ /* compared to Raph's. Coverage information is stored in a very */
+ /* different way, and I don't use sorted vector paths. Also, it */
+ /* doesn't use floating point values. */
+ /* */
+ /* This renderer has the following advantages: */
+ /* */
+ /* - It doesn't need an intermediate bitmap. Instead, one can supply */
+ /* a callback function that will be called by the renderer to draw */
+ /* gray spans on any target surface. You can thus do direct */
+ /* composition on any kind of bitmap, provided that you give the */
+ /* renderer the right callback. */
+ /* */
+ /* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on */
+ /* each pixel cell */
+ /* */
+ /* - It performs a single pass on the outline (the `standard' FT2 */
+ /* renderer makes two passes). */
+ /* */
+ /* - It can easily be modified to render to _any_ number of gray levels */
+ /* cheaply. */
+ /* */
+ /* - For small (< 20) pixel sizes, it is faster than the standard */
+ /* renderer. */
+ /* */
+ /*************************************************************************/
+
+
+#include <string.h> /* for memcpy() */
+#include <setjmp.h>
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_aaraster
+
+
+#define ErrRaster_MemoryOverflow -4
+
+#ifdef _STANDALONE_
+
+
+#define ErrRaster_Invalid_Mode -2
+#define ErrRaster_Invalid_Outline -1
+
+#include "ftimage.h"
+#include "ftgrays.h"
+
+ /* This macro is used to indicate that a function parameter is unused. */
+ /* Its purpose is simply to reduce compiler warnings. Note also that */
+ /* simply defining it as `(void)x' doesn't avoid warnings with certain */
+ /* ANSI compilers (e.g. LCC). */
+#define FT_UNUSED( x ) (x) = (x)
+
+ /* Disable the tracing mechanism for simplicity -- developers can */
+ /* activate it easily by redefining these two macros. */
+#ifndef FT_ERROR
+#define FT_ERROR( x ) do ; while ( 0 ) /* nothing */
+#endif
+
+#ifndef FT_TRACE
+#define FT_TRACE( x ) do ; while ( 0 ) /* nothing */
+#endif
+
+
+#else /* _STANDALONE_ */
+
+
+#include <ft2build.h>
+#include "ftgrays.h"
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_OUTLINE_H
+
+#include "ftsmerrs.h"
+
+#define ErrRaster_Invalid_Mode Smooth_Err_Cannot_Render_Glyph
+#define ErrRaster_Invalid_Outline Smooth_Err_Invalid_Outline
+
+
+#endif /* _STANDALONE_ */
+
+
+ /* define this to dump debugging information */
+#define xxxDEBUG_GRAYS
+
+ /* as usual, for the speed hungry :-) */
+
+#ifndef FT_STATIC_RASTER
+
+
+#define RAS_ARG PRaster raster
+#define RAS_ARG_ PRaster raster,
+
+#define RAS_VAR raster
+#define RAS_VAR_ raster,
+
+#define ras (*raster)
+
+
+#else /* FT_STATIC_RASTER */
+
+
+#define RAS_ARG /* empty */
+#define RAS_ARG_ /* empty */
+#define RAS_VAR /* empty */
+#define RAS_VAR_ /* empty */
+
+ static TRaster ras;
+
+
+#endif /* FT_STATIC_RASTER */
+
+
+ /* must be at least 6 bits! */
+#define PIXEL_BITS 8
+
+#define ONE_PIXEL ( 1L << PIXEL_BITS )
+#define PIXEL_MASK ( -1L << PIXEL_BITS )
+#define TRUNC( x ) ( (x) >> PIXEL_BITS )
+#define SUBPIXELS( x ) ( (x) << PIXEL_BITS )
+#define FLOOR( x ) ( (x) & -ONE_PIXEL )
+#define CEILING( x ) ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL )
+#define ROUND( x ) ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL )
+
+#if PIXEL_BITS >= 6
+#define UPSCALE( x ) ( (x) << ( PIXEL_BITS - 6 ) )
+#define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) )
+#else
+#define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) )
+#define DOWNSCALE( x ) ( (x) << ( 6 - PIXEL_BITS ) )
+#endif
+
+ /* Define this if you want to use a more compact storage scheme. This */
+ /* increases the number of cells available in the render pool but slows */
+ /* down the rendering a bit. It is useful if you have a really tiny */
+ /* render pool. */
+#define xxxGRAYS_COMPACT
+
+
+ /*************************************************************************/
+ /* */
+ /* TYPE DEFINITIONS */
+ /* */
+
+ /* don't change the following types to FT_Int or FT_Pos, since we might */
+ /* need to define them to "float" or "double" when experimenting with */
+ /* new algorithms */
+
+ typedef int TScan; /* integer scanline/pixel coordinate */
+ typedef long TPos; /* sub-pixel coordinate */
+
+ /* determine the type used to store cell areas. This normally takes at */
+ /* least PIXEL_BYTES*2 + 1. On 16-bit systems, we need to use `long' */
+ /* instead of `int', otherwise bad things happen */
+
+#if PIXEL_BITS <= 7
+
+ typedef int TArea;
+
+#else /* PIXEL_BITS >= 8 */
+
+ /* approximately determine the size of integers using an ANSI-C header */
+#include <limits.h>
+
+#if UINT_MAX == 0xFFFFU
+ typedef long TArea;
+#else
+ typedef int TArea;
+#endif
+
+#endif /* PIXEL_BITS >= 8 */
+
+
+ /* maximal number of gray spans in a call to the span callback */
+#define FT_MAX_GRAY_SPANS 32
+
+
+#ifdef GRAYS_COMPACT
+
+ typedef struct TCell_
+ {
+ short x : 14;
+ short y : 14;
+ int cover : PIXEL_BITS + 2;
+ int area : PIXEL_BITS * 2 + 2;
+
+ } TCell, *PCell;
+
+#else /* GRAYS_COMPACT */
+
+ typedef struct TCell_
+ {
+ TScan x;
+ TScan y;
+ int cover;
+ TArea area;
+
+ } TCell, *PCell;
+
+#endif /* GRAYS_COMPACT */
+
+
+ typedef struct TRaster_
+ {
+ PCell cells;
+ int max_cells;
+ int num_cells;
+
+ TScan min_ex, max_ex;
+ TScan min_ey, max_ey;
+
+ TArea area;
+ int cover;
+ int invalid;
+
+ TScan ex, ey;
+ TScan cx, cy;
+ TPos x, y;
+
+ TScan last_ey;
+
+ FT_Vector bez_stack[32 * 3 + 1];
+ int lev_stack[32];
+
+ FT_Outline outline;
+ FT_Bitmap target;
+ FT_BBox clip_box;
+
+ FT_Span gray_spans[FT_MAX_GRAY_SPANS];
+ int num_gray_spans;
+
+ FT_Raster_Span_Func render_span;
+ void* render_span_data;
+ int span_y;
+
+ int band_size;
+ int band_shoot;
+ int conic_level;
+ int cubic_level;
+
+ void* memory;
+ jmp_buf jump_buffer;
+
+ } TRaster, *PRaster;
+
+
+ /*************************************************************************/
+ /* */
+ /* Initialize the cells table. */
+ /* */
+ static void
+ gray_init_cells( RAS_ARG_ void* buffer,
+ long byte_size )
+ {
+ ras.cells = (PCell)buffer;
+ ras.max_cells = byte_size / sizeof ( TCell );
+ ras.num_cells = 0;
+ ras.area = 0;
+ ras.cover = 0;
+ ras.invalid = 1;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Compute the outline bounding box. */
+ /* */
+ static void
+ gray_compute_cbox( RAS_ARG )
+ {
+ FT_Outline* outline = &ras.outline;
+ FT_Vector* vec = outline->points;
+ FT_Vector* limit = vec + outline->n_points;
+
+
+ if ( outline->n_points <= 0 )
+ {
+ ras.min_ex = ras.max_ex = 0;
+ ras.min_ey = ras.max_ey = 0;
+ return;
+ }
+
+ ras.min_ex = ras.max_ex = vec->x;
+ ras.min_ey = ras.max_ey = vec->y;
+
+ vec++;
+
+ for ( ; vec < limit; vec++ )
+ {
+ TPos x = vec->x;
+ TPos y = vec->y;
+
+
+ if ( x < ras.min_ex ) ras.min_ex = x;
+ if ( x > ras.max_ex ) ras.max_ex = x;
+ if ( y < ras.min_ey ) ras.min_ey = y;
+ if ( y > ras.max_ey ) ras.max_ey = y;
+ }
+
+ /* truncate the bounding box to integer pixels */
+ ras.min_ex = ras.min_ex >> 6;
+ ras.min_ey = ras.min_ey >> 6;
+ ras.max_ex = ( ras.max_ex + 63 ) >> 6;
+ ras.max_ey = ( ras.max_ey + 63 ) >> 6;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Record the current cell in the table. */
+ /* */
+ static void
+ gray_record_cell( RAS_ARG )
+ {
+ PCell cell;
+
+
+ if ( !ras.invalid && ( ras.area | ras.cover ) )
+ {
+ if ( ras.num_cells >= ras.max_cells )
+ longjmp( ras.jump_buffer, 1 );
+
+ cell = ras.cells + ras.num_cells++;
+ cell->x = ras.ex - ras.min_ex;
+ cell->y = ras.ey - ras.min_ey;
+ cell->area = ras.area;
+ cell->cover = ras.cover;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Set the current cell to a new position. */
+ /* */
+ static void
+ gray_set_cell( RAS_ARG_ TScan ex,
+ TScan ey )
+ {
+ int invalid, record, clean;
+
+
+ /* Move the cell pointer to a new position. We set the `invalid' */
+ /* flag to indicate that the cell isn't part of those we're interested */
+ /* in during the render phase. This means that: */
+ /* */
+ /* . the new vertical position must be within min_ey..max_ey-1. */
+ /* . the new horizontal position must be strictly less than max_ex */
+ /* */
+ /* Note that if a cell is to the left of the clipping region, it is */
+ /* actually set to the (min_ex-1) horizontal position. */
+
+ record = 0;
+ clean = 1;
+
+ invalid = ( ey < ras.min_ey || ey >= ras.max_ey || ex >= ras.max_ex );
+ if ( !invalid )
+ {
+ /* All cells that are on the left of the clipping region go to the */
+ /* min_ex - 1 horizontal position. */
+ if ( ex < ras.min_ex )
+ ex = ras.min_ex - 1;
+
+ /* if our position is new, then record the previous cell */
+ if ( ex != ras.ex || ey != ras.ey )
+ record = 1;
+ else
+ clean = ras.invalid; /* do not clean if we didn't move from */
+ /* a valid cell */
+ }
+
+ /* record the previous cell if needed (i.e., if we changed the cell */
+ /* position, of changed the `invalid' flag) */
+ if ( ras.invalid != invalid || record )
+ gray_record_cell( RAS_VAR );
+
+ if ( clean )
+ {
+ ras.area = 0;
+ ras.cover = 0;
+ }
+
+ ras.invalid = invalid;
+ ras.ex = ex;
+ ras.ey = ey;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Start a new contour at a given cell. */
+ /* */
+ static void
+ gray_start_cell( RAS_ARG_ TScan ex,
+ TScan ey )
+ {
+ if ( ex < ras.min_ex )
+ ex = ras.min_ex - 1;
+
+ ras.area = 0;
+ ras.cover = 0;
+ ras.ex = ex;
+ ras.ey = ey;
+ ras.last_ey = SUBPIXELS( ey );
+ ras.invalid = 0;
+
+ gray_set_cell( RAS_VAR_ ex, ey );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Render a scanline as one or more cells. */
+ /* */
+ static void
+ gray_render_scanline( RAS_ARG_ TScan ey,
+ TPos x1,
+ TScan y1,
+ TPos x2,
+ TScan y2 )
+ {
+ TScan ex1, ex2, fx1, fx2, delta;
+ long p, first, dx;
+ int incr, lift, mod, rem;
+
+
+ dx = x2 - x1;
+
+ ex1 = TRUNC( x1 ); /* if (ex1 >= ras.max_ex) ex1 = ras.max_ex-1; */
+ ex2 = TRUNC( x2 ); /* if (ex2 >= ras.max_ex) ex2 = ras.max_ex-1; */
+ fx1 = x1 - SUBPIXELS( ex1 );
+ fx2 = x2 - SUBPIXELS( ex2 );
+
+ /* trivial case. Happens often */
+ if ( y1 == y2 )
+ {
+ gray_set_cell( RAS_VAR_ ex2, ey );
+ return;
+ }
+
+ /* everything is located in a single cell. That is easy! */
+ /* */
+ if ( ex1 == ex2 )
+ {
+ delta = y2 - y1;
+ ras.area += (TArea)( fx1 + fx2 ) * delta;
+ ras.cover += delta;
+ return;
+ }
+
+ /* ok, we'll have to render a run of adjacent cells on the same */
+ /* scanline... */
+ /* */
+ p = ( ONE_PIXEL - fx1 ) * ( y2 - y1 );
+ first = ONE_PIXEL;
+ incr = 1;
+
+ if ( dx < 0 )
+ {
+ p = fx1 * ( y2 - y1 );
+ first = 0;
+ incr = -1;
+ dx = -dx;
+ }
+
+ delta = p / dx;
+ mod = p % dx;
+ if ( mod < 0 )
+ {
+ delta--;
+ mod += dx;
+ }
+
+ ras.area += (TArea)( fx1 + first ) * delta;
+ ras.cover += delta;
+
+ ex1 += incr;
+ gray_set_cell( RAS_VAR_ ex1, ey );
+ y1 += delta;
+
+ if ( ex1 != ex2 )
+ {
+ p = ONE_PIXEL * ( y2 - y1 );
+ lift = p / dx;
+ rem = p % dx;
+ if ( rem < 0 )
+ {
+ lift--;
+ rem += dx;
+ }
+
+ mod -= dx;
+
+ while ( ex1 != ex2 )
+ {
+ delta = lift;
+ mod += rem;
+ if ( mod >= 0 )
+ {
+ mod -= dx;
+ delta++;
+ }
+
+ ras.area += (TArea)ONE_PIXEL * delta;
+ ras.cover += delta;
+ y1 += delta;
+ ex1 += incr;
+ gray_set_cell( RAS_VAR_ ex1, ey );
+ }
+ }
+
+ delta = y2 - y1;
+ ras.area += (TArea)( fx2 + ONE_PIXEL - first ) * delta;
+ ras.cover += delta;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Render a given line as a series of scanlines. */
+ /* */
+ static void
+ gray_render_line( RAS_ARG_ TPos to_x,
+ TPos to_y )
+ {
+ TScan ey1, ey2, fy1, fy2;
+ TPos dx, dy, x, x2;
+ int p, rem, mod, lift, delta, first, incr;
+
+
+ ey1 = TRUNC( ras.last_ey );
+ ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
+ fy1 = ras.y - ras.last_ey;
+ fy2 = to_y - SUBPIXELS( ey2 );
+
+ dx = to_x - ras.x;
+ dy = to_y - ras.y;
+
+ /* XXX: we should do something about the trivial case where dx == 0, */
+ /* as it happens very often! */
+
+ /* perform vertical clipping */
+ {
+ TScan min, max;
+
+
+ min = ey1;
+ max = ey2;
+ if ( ey1 > ey2 )
+ {
+ min = ey2;
+ max = ey1;
+ }
+ if ( min >= ras.max_ey || max < ras.min_ey )
+ goto End;
+ }
+
+ /* everything is on a single scanline */
+ if ( ey1 == ey2 )
+ {
+ gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 );
+ goto End;
+ }
+
+ /* ok, we have to render several scanlines */
+ p = ( ONE_PIXEL - fy1 ) * dx;
+ first = ONE_PIXEL;
+ incr = 1;
+
+ if ( dy < 0 )
+ {
+ p = fy1 * dx;
+ first = 0;
+ incr = -1;
+ dy = -dy;
+ }
+
+ delta = p / dy;
+ mod = p % dy;
+ if ( mod < 0 )
+ {
+ delta--;
+ mod += dy;
+ }
+
+ x = ras.x + delta;
+ gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, first );
+
+ ey1 += incr;
+ gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
+
+ if ( ey1 != ey2 )
+ {
+ p = ONE_PIXEL * dx;
+ lift = p / dy;
+ rem = p % dy;
+ if ( rem < 0 )
+ {
+ lift--;
+ rem += dy;
+ }
+ mod -= dy;
+
+ while ( ey1 != ey2 )
+ {
+ delta = lift;
+ mod += rem;
+ if ( mod >= 0 )
+ {
+ mod -= dy;
+ delta++;
+ }
+
+ x2 = x + delta;
+ gray_render_scanline( RAS_VAR_ ey1, x, ONE_PIXEL - first, x2, first );
+ x = x2;
+
+ ey1 += incr;
+ gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
+ }
+ }
+
+ gray_render_scanline( RAS_VAR_ ey1, x, ONE_PIXEL - first, to_x, fy2 );
+
+ End:
+ ras.x = to_x;
+ ras.y = to_y;
+ ras.last_ey = SUBPIXELS( ey2 );
+ }
+
+
+ static void
+ gray_split_conic( FT_Vector* base )
+ {
+ TPos a, b;
+
+
+ base[4].x = base[2].x;
+ b = base[1].x;
+ a = base[3].x = ( base[2].x + b ) / 2;
+ b = base[1].x = ( base[0].x + b ) / 2;
+ base[2].x = ( a + b ) / 2;
+
+ base[4].y = base[2].y;
+ b = base[1].y;
+ a = base[3].y = ( base[2].y + b ) / 2;
+ b = base[1].y = ( base[0].y + b ) / 2;
+ base[2].y = ( a + b ) / 2;
+ }
+
+
+ static void
+ gray_render_conic( RAS_ARG_ FT_Vector* control,
+ FT_Vector* to )
+ {
+ TPos dx, dy;
+ int top, level;
+ int* levels;
+ FT_Vector* arc;
+
+
+ dx = DOWNSCALE( ras.x ) + to->x - ( control->x << 1 );
+ if ( dx < 0 )
+ dx = -dx;
+ dy = DOWNSCALE( ras.y ) + to->y - ( control->y << 1 );
+ if ( dy < 0 )
+ dy = -dy;
+ if ( dx < dy )
+ dx = dy;
+
+ level = 1;
+ dx = dx / ras.conic_level;
+ while ( dx > 0 )
+ {
+ dx >>= 2;
+ level++;
+ }
+
+ /* a shortcut to speed things up */
+ if ( level <= 1 )
+ {
+ /* we compute the mid-point directly in order to avoid */
+ /* calling gray_split_conic() */
+ TPos to_x, to_y, mid_x, mid_y;
+
+
+ to_x = UPSCALE( to->x );
+ to_y = UPSCALE( to->y );
+ mid_x = ( ras.x + to_x + 2 * UPSCALE( control->x ) ) / 4;
+ mid_y = ( ras.y + to_y + 2 * UPSCALE( control->y ) ) / 4;
+
+ gray_render_line( RAS_VAR_ mid_x, mid_y );
+ gray_render_line( RAS_VAR_ to_x, to_y );
+ return;
+ }
+
+ arc = ras.bez_stack;
+ levels = ras.lev_stack;
+ top = 0;
+ levels[0] = level;
+
+ arc[0].x = UPSCALE( to->x );
+ arc[0].y = UPSCALE( to->y );
+ arc[1].x = UPSCALE( control->x );
+ arc[1].y = UPSCALE( control->y );
+ arc[2].x = ras.x;
+ arc[2].y = ras.y;
+
+ while ( top >= 0 )
+ {
+ level = levels[top];
+ if ( level > 1 )
+ {
+ /* check that the arc crosses the current band */
+ TPos min, max, y;
+
+
+ min = max = arc[0].y;
+
+ y = arc[1].y;
+ if ( y < min ) min = y;
+ if ( y > max ) max = y;
+
+ y = arc[2].y;
+ if ( y < min ) min = y;
+ if ( y > max ) max = y;
+
+ if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 )
+ goto Draw;
+
+ gray_split_conic( arc );
+ arc += 2;
+ top++;
+ levels[top] = levels[top - 1] = level - 1;
+ continue;
+ }
+
+ Draw:
+ {
+ TPos to_x, to_y, mid_x, mid_y;
+
+
+ to_x = arc[0].x;
+ to_y = arc[0].y;
+ mid_x = ( ras.x + to_x + 2 * arc[1].x ) / 4;
+ mid_y = ( ras.y + to_y + 2 * arc[1].y ) / 4;
+
+ gray_render_line( RAS_VAR_ mid_x, mid_y );
+ gray_render_line( RAS_VAR_ to_x, to_y );
+
+ top--;
+ arc -= 2;
+ }
+ }
+ return;
+ }
+
+
+ static void
+ gray_split_cubic( FT_Vector* base )
+ {
+ TPos a, b, c, d;
+
+
+ base[6].x = base[3].x;
+ c = base[1].x;
+ d = base[2].x;
+ base[1].x = a = ( base[0].x + c ) / 2;
+ base[5].x = b = ( base[3].x + d ) / 2;
+ c = ( c + d ) / 2;
+ base[2].x = a = ( a + c ) / 2;
+ base[4].x = b = ( b + c ) / 2;
+ base[3].x = ( a + b ) / 2;
+
+ base[6].y = base[3].y;
+ c = base[1].y;
+ d = base[2].y;
+ base[1].y = a = ( base[0].y + c ) / 2;
+ base[5].y = b = ( base[3].y + d ) / 2;
+ c = ( c + d ) / 2;
+ base[2].y = a = ( a + c ) / 2;
+ base[4].y = b = ( b + c ) / 2;
+ base[3].y = ( a + b ) / 2;
+ }
+
+
+ static void
+ gray_render_cubic( RAS_ARG_ FT_Vector* control1,
+ FT_Vector* control2,
+ FT_Vector* to )
+ {
+ TPos dx, dy, da, db;
+ int top, level;
+ int* levels;
+ FT_Vector* arc;
+
+
+ dx = DOWNSCALE( ras.x ) + to->x - ( control1->x << 1 );
+ if ( dx < 0 )
+ dx = -dx;
+ dy = DOWNSCALE( ras.y ) + to->y - ( control1->y << 1 );
+ if ( dy < 0 )
+ dy = -dy;
+ if ( dx < dy )
+ dx = dy;
+ da = dx;
+
+ dx = DOWNSCALE( ras.x ) + to->x - 3 * ( control1->x + control2->x );
+ if ( dx < 0 )
+ dx = -dx;
+ dy = DOWNSCALE( ras.y ) + to->y - 3 * ( control1->x + control2->y );
+ if ( dy < 0 )
+ dy = -dy;
+ if ( dx < dy )
+ dx = dy;
+ db = dx;
+
+ level = 1;
+ da = da / ras.cubic_level;
+ db = db / ras.conic_level;
+ while ( da > 0 || db > 0 )
+ {
+ da >>= 2;
+ db >>= 3;
+ level++;
+ }
+
+ if ( level <= 1 )
+ {
+ TPos to_x, to_y, mid_x, mid_y;
+
+
+ to_x = UPSCALE( to->x );
+ to_y = UPSCALE( to->y );
+ mid_x = ( ras.x + to_x +
+ 3 * UPSCALE( control1->x + control2->x ) ) / 8;
+ mid_y = ( ras.y + to_y +
+ 3 * UPSCALE( control1->y + control2->y ) ) / 8;
+
+ gray_render_line( RAS_VAR_ mid_x, mid_y );
+ gray_render_line( RAS_VAR_ to_x, to_y );
+ return;
+ }
+
+ arc = ras.bez_stack;
+ arc[0].x = UPSCALE( to->x );
+ arc[0].y = UPSCALE( to->y );
+ arc[1].x = UPSCALE( control2->x );
+ arc[1].y = UPSCALE( control2->y );
+ arc[2].x = UPSCALE( control1->x );
+ arc[2].y = UPSCALE( control1->y );
+ arc[3].x = ras.x;
+ arc[3].y = ras.y;
+
+ levels = ras.lev_stack;
+ top = 0;
+ levels[0] = level;
+
+ while ( top >= 0 )
+ {
+ level = levels[top];
+ if ( level > 1 )
+ {
+ /* check that the arc crosses the current band */
+ TPos min, max, y;
+
+
+ min = max = arc[0].y;
+ y = arc[1].y;
+ if ( y < min ) min = y;
+ if ( y > max ) max = y;
+ y = arc[2].y;
+ if ( y < min ) min = y;
+ if ( y > max ) max = y;
+ y = arc[3].y;
+ if ( y < min ) min = y;
+ if ( y > max ) max = y;
+ if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 )
+ goto Draw;
+ gray_split_cubic( arc );
+ arc += 3;
+ top ++;
+ levels[top] = levels[top - 1] = level - 1;
+ continue;
+ }
+
+ Draw:
+ {
+ TPos to_x, to_y, mid_x, mid_y;
+
+
+ to_x = arc[0].x;
+ to_y = arc[0].y;
+ mid_x = ( ras.x + to_x + 3 * ( arc[1].x + arc[2].x ) ) / 8;
+ mid_y = ( ras.y + to_y + 3 * ( arc[1].y + arc[2].y ) ) / 8;
+
+ gray_render_line( RAS_VAR_ mid_x, mid_y );
+ gray_render_line( RAS_VAR_ to_x, to_y );
+ top --;
+ arc -= 3;
+ }
+ }
+ return;
+ }
+
+
+ /* a macro comparing two cell pointers. Returns true if a <= b. */
+#if 1
+
+#define PACK( a ) ( ( (long)(a)->y << 16 ) + (a)->x )
+#define LESS_THAN( a, b ) ( PACK( a ) < PACK( b ) )
+
+#else /* 1 */
+
+#define LESS_THAN( a, b ) ( (a)->y < (b)->y || \
+ ( (a)->y == (b)->y && (a)->x < (b)->x ) )
+
+#endif /* 1 */
+
+#define SWAP_CELLS( a, b, temp ) do \
+ { \
+ temp = *(a); \
+ *(a) = *(b); \
+ *(b) = temp; \
+ } while ( 0 )
+#define DEBUG_SORT
+#define QUICK_SORT
+
+#ifdef SHELL_SORT
+
+ /* a simple shell sort algorithm that works directly on our */
+ /* cells table */
+ static void
+ gray_shell_sort ( PCell cells,
+ int count )
+ {
+ PCell i, j, limit = cells + count;
+ TCell temp;
+ int gap;
+
+
+ /* compute initial gap */
+ for ( gap = 0; ++gap < count; gap *= 3 )
+ ;
+
+ while ( gap /= 3 )
+ {
+ for ( i = cells + gap; i < limit; i++ )
+ {
+ for ( j = i - gap; ; j -= gap )
+ {
+ PCell k = j + gap;
+
+
+ if ( LESS_THAN( j, k ) )
+ break;
+
+ SWAP_CELLS( j, k, temp );
+
+ if ( j < cells + gap )
+ break;
+ }
+ }
+ }
+ }
+
+#endif /* SHELL_SORT */
+
+
+#ifdef QUICK_SORT
+
+ /* This is a non-recursive quicksort that directly process our cells */
+ /* array. It should be faster than calling the stdlib qsort(), and we */
+ /* can even tailor our insertion threshold... */
+
+#define QSORT_THRESHOLD 9 /* below this size, a sub-array will be sorted */
+ /* through a normal insertion sort */
+
+ static void
+ gray_quick_sort( PCell cells,
+ int count )
+ {
+ PCell stack[40]; /* should be enough ;-) */
+ PCell* top; /* top of stack */
+ PCell base, limit;
+ TCell temp;
+
+
+ limit = cells + count;
+ base = cells;
+ top = stack;
+
+ for (;;)
+ {
+ int len = (int)( limit - base );
+ PCell i, j, pivot;
+
+
+ if ( len > QSORT_THRESHOLD )
+ {
+ /* we use base + len/2 as the pivot */
+ pivot = base + len / 2;
+ SWAP_CELLS( base, pivot, temp );
+
+ i = base + 1;
+ j = limit - 1;
+
+ /* now ensure that *i <= *base <= *j */
+ if ( LESS_THAN( j, i ) )
+ SWAP_CELLS( i, j, temp );
+
+ if ( LESS_THAN( base, i ) )
+ SWAP_CELLS( base, i, temp );
+
+ if ( LESS_THAN( j, base ) )
+ SWAP_CELLS( base, j, temp );
+
+ for (;;)
+ {
+ do i++; while ( LESS_THAN( i, base ) );
+ do j--; while ( LESS_THAN( base, j ) );
+
+ if ( i > j )
+ break;
+
+ SWAP_CELLS( i, j, temp );
+ }
+
+ SWAP_CELLS( base, j, temp );
+
+ /* now, push the largest sub-array */
+ if ( j - base > limit - i )
+ {
+ top[0] = base;
+ top[1] = j;
+ base = i;
+ }
+ else
+ {
+ top[0] = i;
+ top[1] = limit;
+ limit = j;
+ }
+ top += 2;
+ }
+ else
+ {
+ /* the sub-array is small, perform insertion sort */
+ j = base;
+ i = j + 1;
+
+ for ( ; i < limit; j = i, i++ )
+ {
+ for ( ; LESS_THAN( j + 1, j ); j-- )
+ {
+ SWAP_CELLS( j + 1, j, temp );
+ if ( j == base )
+ break;
+ }
+ }
+ if ( top > stack )
+ {
+ top -= 2;
+ base = top[0];
+ limit = top[1];
+ }
+ else
+ break;
+ }
+ }
+ }
+
+#endif /* QUICK_SORT */
+
+
+#ifdef DEBUG_GRAYS
+#ifdef DEBUG_SORT
+
+ static int
+ gray_check_sort( PCell cells,
+ int count )
+ {
+ PCell p, q;
+
+
+ for ( p = cells + count - 2; p >= cells; p-- )
+ {
+ q = p + 1;
+ if ( !LESS_THAN( p, q ) )
+ return 0;
+ }
+ return 1;
+ }
+
+#endif /* DEBUG_SORT */
+#endif /* DEBUG_GRAYS */
+
+
+ static int
+ gray_move_to( FT_Vector* to,
+ FT_Raster raster )
+ {
+ TPos x, y;
+
+
+ /* record current cell, if any */
+ gray_record_cell( (PRaster)raster );
+
+ /* start to a new position */
+ x = UPSCALE( to->x );
+ y = UPSCALE( to->y );
+
+ gray_start_cell( (PRaster)raster, TRUNC( x ), TRUNC( y ) );
+
+ ((PRaster)raster)->x = x;
+ ((PRaster)raster)->y = y;
+ return 0;
+ }
+
+
+ static int
+ gray_line_to( FT_Vector* to,
+ FT_Raster raster )
+ {
+ gray_render_line( (PRaster)raster,
+ UPSCALE( to->x ), UPSCALE( to->y ) );
+ return 0;
+ }
+
+
+ static int
+ gray_conic_to( FT_Vector* control,
+ FT_Vector* to,
+ FT_Raster raster )
+ {
+ gray_render_conic( (PRaster)raster, control, to );
+ return 0;
+ }
+
+
+ static int
+ gray_cubic_to( FT_Vector* control1,
+ FT_Vector* control2,
+ FT_Vector* to,
+ FT_Raster raster )
+ {
+ gray_render_cubic( (PRaster)raster, control1, control2, to );
+ return 0;
+ }
+
+
+ static void
+ gray_render_span( int y,
+ int count,
+ FT_Span* spans,
+ PRaster raster )
+ {
+ unsigned char* p;
+ FT_Bitmap* map = &raster->target;
+
+
+ /* first of all, compute the scanline offset */
+ p = (unsigned char*)map->buffer - y * map->pitch;
+ if ( map->pitch >= 0 )
+ p += ( map->rows - 1 ) * map->pitch;
+
+ for ( ; count > 0; count--, spans++ )
+ {
+ if ( spans->coverage )
+#if 1
+ memset( p + spans->x, (unsigned char)spans->coverage, spans->len );
+#else /* 1 */
+ {
+ q = p + spans->x;
+ limit = q + spans->len;
+ for ( ; q < limit; q++ )
+ q[0] = (unsigned char)spans->coverage;
+ }
+#endif /* 1 */
+ }
+ }
+
+
+#ifdef DEBUG_GRAYS
+
+#include <stdio.h>
+
+ static void
+ gray_dump_cells( RAS_ARG )
+ {
+ PCell cell, limit;
+ int y = -1;
+
+
+ cell = ras.cells;
+ limit = cell + ras.num_cells;
+
+ for ( ; cell < limit; cell++ )
+ {
+ if ( cell->y != y )
+ {
+ fprintf( stderr, "\n%2d: ", cell->y );
+ y = cell->y;
+ }
+ fprintf( stderr, "[%d %d %d]",
+ cell->x, cell->area, cell->cover );
+ }
+ fprintf(stderr, "\n" );
+ }
+
+#endif /* DEBUG_GRAYS */
+
+
+ static void
+ gray_hline( RAS_ARG_ TScan x,
+ TScan y,
+ TPos area,
+ int acount )
+ {
+ FT_Span* span;
+ int count;
+ int coverage;
+
+
+ /* compute the coverage line's coverage, depending on the */
+ /* outline fill rule */
+ /* */
+ /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
+ /* */
+ coverage = area >> ( PIXEL_BITS * 2 + 1 - 8); /* use range 0..256 */
+
+ if ( ras.outline.flags & ft_outline_even_odd_fill )
+ {
+ if ( coverage < 0 )
+ coverage = -coverage;
+
+ while ( coverage >= 512 )
+ coverage -= 512;
+
+ if ( coverage > 256 )
+ coverage = 512 - coverage;
+ else if ( coverage == 256 )
+ coverage = 255;
+ }
+ else
+ {
+ /* normal non-zero winding rule */
+ if ( coverage < 0 )
+ coverage = -coverage;
+
+ if ( coverage >= 256 )
+ coverage = 255;
+ }
+
+ y += ras.min_ey;
+ x += ras.min_ex;
+
+ if ( coverage )
+ {
+ /* see if we can add this span to the current list */
+ count = ras.num_gray_spans;
+ span = ras.gray_spans + count - 1;
+ if ( count > 0 &&
+ ras.span_y == y &&
+ (int)span->x + span->len == (int)x &&
+ span->coverage == coverage )
+ {
+ span->len = (unsigned short)( span->len + acount );
+ return;
+ }
+
+ if ( ras.span_y != y || count >= FT_MAX_GRAY_SPANS )
+ {
+ if ( ras.render_span && count > 0 )
+ ras.render_span( ras.span_y, count, ras.gray_spans,
+ ras.render_span_data );
+ /* ras.render_span( span->y, ras.gray_spans, count ); */
+
+#ifdef DEBUG_GRAYS
+
+ if ( ras.span_y >= 0 )
+ {
+ int n;
+
+
+ fprintf( stderr, "y=%3d ", ras.span_y );
+ span = ras.gray_spans;
+ for ( n = 0; n < count; n++, span++ )
+ fprintf( stderr, "[%d..%d]:%02x ",
+ span->x, span->x + span->len - 1, span->coverage );
+ fprintf( stderr, "\n" );
+ }
+
+#endif /* DEBUG_GRAYS */
+
+ ras.num_gray_spans = 0;
+ ras.span_y = y;
+
+ count = 0;
+ span = ras.gray_spans;
+ }
+ else
+ span++;
+
+ /* add a gray span to the current list */
+ span->x = (short)x;
+ span->len = (unsigned short)acount;
+ span->coverage = (unsigned char)coverage;
+ ras.num_gray_spans++;
+ }
+ }
+
+
+ static void
+ gray_sweep( RAS_ARG_ FT_Bitmap* target )
+ {
+ TScan x, y, cover;
+ TArea area;
+ PCell start, cur, limit;
+
+ FT_UNUSED( target );
+
+ if ( ras.num_cells == 0 )
+ return;
+
+ cur = ras.cells;
+ limit = cur + ras.num_cells;
+
+ cover = 0;
+ ras.span_y = -1;
+ ras.num_gray_spans = 0;
+
+ for (;;)
+ {
+ start = cur;
+ y = start->y;
+ x = start->x;
+
+ area = start->area;
+ cover += start->cover;
+
+ /* accumulate all start cells */
+ for (;;)
+ {
+ ++cur;
+ if ( cur >= limit || cur->y != start->y || cur->x != start->x )
+ break;
+
+ area += cur->area;
+ cover += cur->cover;
+ }
+
+ /* if the start cell has a non-null area, we must draw an */
+ /* individual gray pixel there */
+ if ( area && x >= 0 )
+ {
+ gray_hline( RAS_VAR_ x, y, cover * ( ONE_PIXEL * 2 ) - area, 1 );
+ x++;
+ }
+
+ if ( x < 0 )
+ x = 0;
+
+ if ( cur < limit && start->y == cur->y )
+ {
+ /* draw a gray span between the start cell and the current one */
+ if ( cur->x > x )
+ gray_hline( RAS_VAR_ x, y,
+ cover * ( ONE_PIXEL * 2 ), cur->x - x );
+ }
+ else
+ {
+ /* draw a gray span until the end of the clipping region */
+ if ( cover && x < ras.max_ex - ras.min_ex )
+ gray_hline( RAS_VAR_ x, y,
+ cover * ( ONE_PIXEL * 2 ),
+ ras.max_ex - x - ras.min_ex );
+ cover = 0;
+ }
+
+ if ( cur >= limit )
+ break;
+ }
+
+ if ( ras.render_span && ras.num_gray_spans > 0 )
+ ras.render_span( ras.span_y, ras.num_gray_spans,
+ ras.gray_spans, ras.render_span_data );
+
+#ifdef DEBUG_GRAYS
+
+ {
+ int n;
+ FT_Span* span;
+
+
+ fprintf( stderr, "y=%3d ", ras.span_y );
+ span = ras.gray_spans;
+ for ( n = 0; n < ras.num_gray_spans; n++, span++ )
+ fprintf( stderr, "[%d..%d]:%02x ",
+ span->x, span->x + span->len - 1, span->coverage );
+ fprintf( stderr, "\n" );
+ }
+
+#endif /* DEBUG_GRAYS */
+
+ }
+
+
+#ifdef _STANDALONE_
+
+ /*************************************************************************/
+ /* */
+ /* The following function should only compile in stand_alone mode, */
+ /* i.e., when building this component without the rest of FreeType. */
+ /* */
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Decompose */
+ /* */
+ /* <Description> */
+ /* Walks over an outline's structure to decompose it into individual */
+ /* segments and Bezier arcs. This function is also able to emit */
+ /* `move to' and `close to' operations to indicate the start and end */
+ /* of new contours in the outline. */
+ /* */
+ /* <Input> */
+ /* outline :: A pointer to the source target. */
+ /* */
+ /* interface :: A table of `emitters', i.e,. function pointers called */
+ /* during decomposition to indicate path operations. */
+ /* */
+ /* user :: A typeless pointer which is passed to each emitter */
+ /* during the decomposition. It can be used to store */
+ /* the state during the decomposition. */
+ /* */
+ /* <Return> */
+ /* Error code. 0 means sucess. */
+ /* */
+ static
+ int FT_Outline_Decompose( FT_Outline* outline,
+ const FT_Outline_Funcs* interface,
+ void* user )
+ {
+#undef SCALED
+#if 0
+#define SCALED( x ) ( ( (x) << shift ) - delta )
+#else
+#define SCALED( x ) (x)
+#endif
+
+ FT_Vector v_last;
+ FT_Vector v_control;
+ FT_Vector v_start;
+
+ FT_Vector* point;
+ FT_Vector* limit;
+ char* tags;
+
+ int n; /* index of contour in outline */
+ int first; /* index of first point in contour */
+ int error;
+ char tag; /* current point's state */
+
+#if 0
+ int shift = interface->shift;
+ FT_Pos delta = interface->delta;
+#endif
+
+
+ first = 0;
+
+ for ( n = 0; n < outline->n_contours; n++ )
+ {
+ int last; /* index of last point in contour */
+
+
+ last = outline->contours[n];
+ limit = outline->points + last;
+
+ v_start = outline->points[first];
+ v_last = outline->points[last];
+
+ v_start.x = SCALED( v_start.x ); v_start.y = SCALED( v_start.y );
+ v_last.x = SCALED( v_last.x ); v_last.y = SCALED( v_last.y );
+
+ v_control = v_start;
+
+ point = outline->points + first;
+ tags = outline->tags + first;
+ tag = FT_CURVE_TAG( tags[0] );
+
+ /* A contour cannot start with a cubic control point! */
+ if ( tag == FT_Curve_Tag_Cubic )
+ goto Invalid_Outline;
+
+ /* check first point to determine origin */
+ if ( tag == FT_Curve_Tag_Conic )
+ {
+ /* first point is conic control. Yes, this happens. */
+ if ( FT_CURVE_TAG( outline->tags[last] ) == FT_Curve_Tag_On )
+ {
+ /* start at last point if it is on the curve */
+ v_start = v_last;
+ limit--;
+ }
+ else
+ {
+ /* if both first and last points are conic, */
+ /* start at their middle and record its position */
+ /* for closure */
+ v_start.x = ( v_start.x + v_last.x ) / 2;
+ v_start.y = ( v_start.y + v_last.y ) / 2;
+
+ v_last = v_start;
+ }
+ point--;
+ tags--;
+ }
+
+ error = interface->move_to( &v_start, user );
+ if ( error )
+ goto Exit;
+
+ while ( point < limit )
+ {
+ point++;
+ tags++;
+
+ tag = FT_CURVE_TAG( tags[0] );
+ switch ( tag )
+ {
+ case FT_Curve_Tag_On: /* emit a single line_to */
+ {
+ FT_Vector vec;
+
+
+ vec.x = SCALED( point->x );
+ vec.y = SCALED( point->y );
+
+ error = interface->line_to( &vec, user );
+ if ( error )
+ goto Exit;
+ continue;
+ }
+
+ case FT_Curve_Tag_Conic: /* consume conic arcs */
+ {
+ v_control.x = SCALED( point->x );
+ v_control.y = SCALED( point->y );
+
+ Do_Conic:
+ if ( point < limit )
+ {
+ FT_Vector vec;
+ FT_Vector v_middle;
+
+
+ point++;
+ tags++;
+ tag = FT_CURVE_TAG( tags[0] );
+
+ vec.x = SCALED( point->x );
+ vec.y = SCALED( point->y );
+
+ if ( tag == FT_Curve_Tag_On )
+ {
+ error = interface->conic_to( &v_control, &vec, user );
+ if ( error )
+ goto Exit;
+ continue;
+ }
+
+ if ( tag != FT_Curve_Tag_Conic )
+ goto Invalid_Outline;
+
+ v_middle.x = ( v_control.x + vec.x ) / 2;
+ v_middle.y = ( v_control.y + vec.y ) / 2;
+
+ error = interface->conic_to( &v_control, &v_middle, user );
+ if ( error )
+ goto Exit;
+
+ v_control = vec;
+ goto Do_Conic;
+ }
+
+ error = interface->conic_to( &v_control, &v_start, user );
+ goto Close;
+ }
+
+ default: /* FT_Curve_Tag_Cubic */
+ {
+ FT_Vector vec1, vec2;
+
+
+ if ( point + 1 > limit ||
+ FT_CURVE_TAG( tags[1] ) != FT_Curve_Tag_Cubic )
+ goto Invalid_Outline;
+
+ point += 2;
+ tags += 2;
+
+ vec1.x = SCALED( point[-2].x ); vec1.y = SCALED( point[-2].y );
+ vec2.x = SCALED( point[-1].x ); vec2.y = SCALED( point[-1].y );
+
+ if ( point <= limit )
+ {
+ FT_Vector vec;
+
+
+ vec.x = SCALED( point->x );
+ vec.y = SCALED( point->y );
+
+ error = interface->cubic_to( &vec1, &vec2, &vec, user );
+ if ( error )
+ goto Exit;
+ continue;
+ }
+
+ error = interface->cubic_to( &vec1, &vec2, &v_start, user );
+ goto Close;
+ }
+ }
+ }
+
+ /* close the contour with a line segment */
+ error = interface->line_to( &v_start, user );
+
+ Close:
+ if ( error )
+ goto Exit;
+
+ first = last + 1;
+ }
+
+ return 0;
+
+ Exit:
+ return error;
+
+ Invalid_Outline:
+ return ErrRaster_Invalid_Outline;
+ }
+
+#endif /* _STANDALONE_ */
+
+
+ typedef struct TBand_
+ {
+ FT_Pos min, max;
+
+ } TBand;
+
+
+ static int
+ gray_convert_glyph_inner( RAS_ARG )
+ {
+ static
+ const FT_Outline_Funcs interface =
+ {
+ (FT_Outline_MoveTo_Func) gray_move_to,
+ (FT_Outline_LineTo_Func) gray_line_to,
+ (FT_Outline_ConicTo_Func)gray_conic_to,
+ (FT_Outline_CubicTo_Func)gray_cubic_to,
+ 0,
+ 0
+ };
+
+ volatile int error = 0;
+
+ if ( setjmp( ras.jump_buffer ) == 0 )
+ {
+ error = FT_Outline_Decompose( &ras.outline, &interface, &ras );
+ gray_record_cell( RAS_VAR );
+ }
+ else
+ {
+ error = ErrRaster_MemoryOverflow;
+ }
+
+ return error;
+ }
+
+
+ static int
+ gray_convert_glyph( RAS_ARG )
+ {
+ TBand bands[40], *band;
+ int n, num_bands;
+ TPos min, max, max_y;
+ FT_BBox* clip;
+
+
+ /* Set up state in the raster object */
+ gray_compute_cbox( RAS_VAR );
+
+ /* clip to target bitmap, exit if nothing to do */
+ clip = &ras.clip_box;
+
+ if ( ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax ||
+ ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax )
+ return 0;
+
+ if ( ras.min_ex < clip->xMin ) ras.min_ex = clip->xMin;
+ if ( ras.min_ey < clip->yMin ) ras.min_ey = clip->yMin;
+
+ if ( ras.max_ex > clip->xMax ) ras.max_ex = clip->xMax;
+ if ( ras.max_ey > clip->yMax ) ras.max_ey = clip->yMax;
+
+ /* simple heuristic used to speed-up the bezier decomposition -- see */
+ /* the code in gray_render_conic() and gray_render_cubic() for more */
+ /* details */
+ ras.conic_level = 32;
+ ras.cubic_level = 16;
+
+ {
+ int level = 0;
+
+
+ if ( ras.max_ex > 24 || ras.max_ey > 24 )
+ level++;
+ if ( ras.max_ex > 120 || ras.max_ey > 120 )
+ level++;
+
+ ras.conic_level <<= level;
+ ras.cubic_level <<= level;
+ }
+
+ /* setup vertical bands */
+ num_bands = ( ras.max_ey - ras.min_ey ) / ras.band_size;
+ if ( num_bands == 0 ) num_bands = 1;
+ if ( num_bands >= 39 ) num_bands = 39;
+
+ ras.band_shoot = 0;
+
+ min = ras.min_ey;
+ max_y = ras.max_ey;
+
+ for ( n = 0; n < num_bands; n++, min = max )
+ {
+ max = min + ras.band_size;
+ if ( n == num_bands - 1 || max > max_y )
+ max = max_y;
+
+ bands[0].min = min;
+ bands[0].max = max;
+ band = bands;
+
+ while ( band >= bands )
+ {
+ FT_Pos bottom, top, middle;
+ int error;
+
+
+ ras.num_cells = 0;
+ ras.invalid = 1;
+ ras.min_ey = band->min;
+ ras.max_ey = band->max;
+
+#if 1
+ error = gray_convert_glyph_inner( RAS_VAR );
+#else
+ error = FT_Outline_Decompose( outline, &interface, &ras ) ||
+ gray_record_cell( RAS_VAR );
+#endif
+
+ if ( !error )
+ {
+#ifdef SHELL_SORT
+ gray_shell_sort( ras.cells, ras.num_cells );
+#else
+ gray_quick_sort( ras.cells, ras.num_cells );
+#endif
+
+#ifdef DEBUG_GRAYS
+ gray_check_sort( ras.cells, ras.num_cells );
+ gray_dump_cells( RAS_VAR );
+#endif
+
+ gray_sweep( RAS_VAR_ &ras.target );
+ band--;
+ continue;
+ }
+ else if ( error != ErrRaster_MemoryOverflow )
+ return 1;
+
+ /* render pool overflow, we will reduce the render band by half */
+ bottom = band->min;
+ top = band->max;
+ middle = bottom + ( ( top - bottom ) >> 1 );
+
+ /* waoow! This is too complex for a single scanline, something */
+ /* must be really rotten here! */
+ if ( middle == bottom )
+ {
+#ifdef DEBUG_GRAYS
+ fprintf( stderr, "Rotten glyph!\n" );
+#endif
+ return 1;
+ }
+
+ if ( bottom-top >= ras.band_size )
+ ras.band_shoot++;
+
+ band[1].min = bottom;
+ band[1].max = middle;
+ band[0].min = middle;
+ band[0].max = top;
+ band++;
+ }
+ }
+
+ if ( ras.band_shoot > 8 && ras.band_size > 16 )
+ ras.band_size = ras.band_size / 2;
+
+ return 0;
+ }
+
+
+ extern int
+ gray_raster_render( PRaster raster,
+ FT_Raster_Params* params )
+ {
+ FT_Outline* outline = (FT_Outline*)params->source;
+ FT_Bitmap* target_map = params->target;
+
+
+ if ( !raster || !raster->cells || !raster->max_cells )
+ return -1;
+
+ /* return immediately if the outline is empty */
+ if ( outline->n_points == 0 || outline->n_contours <= 0 )
+ return 0;
+
+ if ( !outline || !outline->contours || !outline->points )
+ return ErrRaster_Invalid_Outline;
+
+ if ( outline->n_points !=
+ outline->contours[outline->n_contours - 1] + 1 )
+ return ErrRaster_Invalid_Outline;
+
+ /* if direct mode is not set, we must have a target bitmap */
+ if ( ( params->flags & ft_raster_flag_direct ) == 0 &&
+ ( !target_map || !target_map->buffer ) )
+ return -1;
+
+ /* this version does not support monochrome rendering */
+ if ( !( params->flags & ft_raster_flag_aa ) )
+ return ErrRaster_Invalid_Mode;
+
+ /* compute clipping box */
+ if ( ( params->flags & ft_raster_flag_direct ) == 0 )
+ {
+ /* compute clip box from target pixmap */
+ ras.clip_box.xMin = 0;
+ ras.clip_box.yMin = 0;
+ ras.clip_box.xMax = target_map->width;
+ ras.clip_box.yMax = target_map->rows;
+ }
+ else if ( params->flags & ft_raster_flag_clip )
+ {
+ ras.clip_box = params->clip_box;
+ }
+ else
+ {
+ ras.clip_box.xMin = -32768L;
+ ras.clip_box.yMin = -32768L;
+ ras.clip_box.xMax = 32767L;
+ ras.clip_box.yMax = 32767L;
+ }
+
+ ras.outline = *outline;
+ ras.num_cells = 0;
+ ras.invalid = 1;
+
+ if ( target_map )
+ ras.target = *target_map;
+
+ ras.render_span = (FT_Raster_Span_Func)gray_render_span;
+ ras.render_span_data = &ras;
+
+ if ( params->flags & ft_raster_flag_direct )
+ {
+ ras.render_span = (FT_Raster_Span_Func)params->gray_spans;
+ ras.render_span_data = params->user;
+ }
+
+ return gray_convert_glyph( (PRaster)raster );
+ }
+
+
+ /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/
+ /**** a static object. *****/
+
+#ifdef _STANDALONE_
+
+ static int
+ gray_raster_new( void* memory,
+ FT_Raster* araster )
+ {
+ static TRaster the_raster;
+
+ FT_UNUSED( memory );
+
+
+ *araster = (FT_Raster)&the_raster;
+ memset( &the_raster, 0, sizeof ( the_raster ) );
+
+ return 0;
+ }
+
+
+ static void
+ gray_raster_done( FT_Raster raster )
+ {
+ /* nothing */
+ FT_UNUSED( raster );
+ }
+
+#else /* _STANDALONE_ */
+
+ static int
+ gray_raster_new( FT_Memory memory,
+ FT_Raster* araster )
+ {
+ FT_Error error;
+ PRaster raster;
+
+
+ *araster = 0;
+ if ( !ALLOC( raster, sizeof ( TRaster ) ) )
+ {
+ raster->memory = memory;
+ *araster = (FT_Raster)raster;
+ }
+
+ return error;
+ }
+
+
+ static void
+ gray_raster_done( FT_Raster raster )
+ {
+ FT_Memory memory = (FT_Memory)((PRaster)raster)->memory;
+
+
+ FREE( raster );
+ }
+
+#endif /* _STANDALONE_ */
+
+
+ static void
+ gray_raster_reset( FT_Raster raster,
+ const char* pool_base,
+ long pool_size )
+ {
+ PRaster rast = (PRaster)raster;
+
+
+ if ( raster && pool_base && pool_size >= 4096 )
+ gray_init_cells( rast, (char*)pool_base, pool_size );
+
+ rast->band_size = ( pool_size / sizeof ( TCell ) ) / 8;
+ }
+
+
+ const FT_Raster_Funcs ft_grays_raster =
+ {
+ ft_glyph_format_outline,
+
+ (FT_Raster_New_Func) gray_raster_new,
+ (FT_Raster_Reset_Func) gray_raster_reset,
+ (FT_Raster_Set_Mode_Func) 0,
+ (FT_Raster_Render_Func) gray_raster_render,
+ (FT_Raster_Done_Func) gray_raster_done
+ };
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftinit.c */
+/* */
+/* FreeType initialization layer (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* The purpose of this file is to implement the following two */
+ /* functions: */
+ /* */
+ /* FT_Add_Default_Modules(): */
+ /* This function is used to add the set of default modules to a */
+ /* fresh new library object. The set is taken from the header file */
+ /* `freetype/config/ftmodule.h'. See the document `FreeType 2.0 */
+ /* Build System' for more information. */
+ /* */
+ /* FT_Init_FreeType(): */
+ /* This function creates a system object for the current platform, */
+ /* builds a library out of it, then calls FT_Default_Drivers(). */
+ /* */
+ /* Note that even if FT_Init_FreeType() uses the implementation of the */
+ /* system object defined at build time, client applications are still */
+ /* able to provide their own `ftsystem.c'. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_MODULE_H
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_init
+
+#undef FT_USE_MODULE
+#ifdef __cplusplus
+#define FT_USE_MODULE( x ) extern "C" const FT_Module_Class* x;
+#else
+#define FT_USE_MODULE( x ) extern const FT_Module_Class* x;
+#endif
+
+
+#include FT_CONFIG_MODULES_H
+
+
+#undef FT_USE_MODULE
+#define FT_USE_MODULE( x ) (const FT_Module_Class*)&x,
+
+ static
+ const FT_Module_Class* const ft_default_modules[] =
+ {
+#include FT_CONFIG_MODULES_H
+ 0
+ };
+
+
+ /* documentation is in ftmodule.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Add_Default_Modules( FT_Library library )
+ {
+ FT_Error error;
+ const FT_Module_Class* const* cur;
+
+
+ /* test for valid `library' delayed to FT_Add_Module() */
+
+ cur = ft_default_modules;
+ while ( *cur )
+ {
+ error = FT_Add_Module( library, *cur );
+ /* notify errors, but don't stop */
+ if ( error )
+ {
+ FT_ERROR(( "FT_Add_Default_Module: Cannot install `%s', error = %x\n",
+ (*cur)->module_name, error ));
+ }
+ cur++;
+ }
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Init_FreeType( FT_Library *alibrary )
+ {
+ FT_Error error;
+ FT_Memory memory;
+
+
+ /* First of all, allocate a new system object -- this function is part */
+ /* of the system-specific component, i.e. `ftsystem.c'. */
+
+ memory = FT_New_Memory();
+ if ( !memory )
+ {
+ FT_ERROR(( "FT_Init_FreeType: cannot find memory manager\n" ));
+ return FT_Err_Unimplemented_Feature;
+ }
+
+ /* build a library out of it, then fill it with the set of */
+ /* default drivers. */
+
+ error = FT_New_Library( memory, alibrary );
+ if ( !error )
+ FT_Add_Default_Modules( *alibrary );
+
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Done_FreeType( FT_Library library )
+ {
+ if ( library )
+ {
+ FT_Memory memory = library->memory;
+
+
+ /* Discard the library object */
+ FT_Done_Library( library );
+
+ /* discard memory manager */
+ FT_Done_Memory( memory );
+ }
+
+ return FT_Err_Ok;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftlist.c */
+/* */
+/* Generic list support for FreeType (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* This file implements functions relative to list processing. Its */
+ /* data structures are defined in `freetype/internal/ftlist.h'. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_LIST_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_list
+
+
+ /* documentation is in ftlist.h */
+
+ FT_EXPORT_DEF( FT_ListNode )
+ FT_List_Find( FT_List list,
+ void* data )
+ {
+ FT_ListNode cur;
+
+
+ cur = list->head;
+ while ( cur )
+ {
+ if ( cur->data == data )
+ return cur;
+
+ cur = cur->next;
+ }
+
+ return (FT_ListNode)0;
+ }
+
+
+ /* documentation is in ftlist.h */
+
+ FT_EXPORT_DEF( void )
+ FT_List_Add( FT_List list,
+ FT_ListNode node )
+ {
+ FT_ListNode before = list->tail;
+
+
+ node->next = 0;
+ node->prev = before;
+
+ if ( before )
+ before->next = node;
+ else
+ list->head = node;
+
+ list->tail = node;
+ }
+
+
+ /* documentation is in ftlist.h */
+
+ FT_EXPORT_DEF( void )
+ FT_List_Insert( FT_List list,
+ FT_ListNode node )
+ {
+ FT_ListNode after = list->head;
+
+
+ node->next = after;
+ node->prev = 0;
+
+ if ( !after )
+ list->tail = node;
+ else
+ after->prev = node;
+
+ list->head = node;
+ }
+
+
+ /* documentation is in ftlist.h */
+
+ FT_EXPORT_DEF( void )
+ FT_List_Remove( FT_List list,
+ FT_ListNode node )
+ {
+ FT_ListNode before, after;
+
+
+ before = node->prev;
+ after = node->next;
+
+ if ( before )
+ before->next = after;
+ else
+ list->head = after;
+
+ if ( after )
+ after->prev = before;
+ else
+ list->tail = before;
+ }
+
+
+ /* documentation is in ftlist.h */
+
+ FT_EXPORT_DEF( void )
+ FT_List_Up( FT_List list,
+ FT_ListNode node )
+ {
+ FT_ListNode before, after;
+
+
+ before = node->prev;
+ after = node->next;
+
+ /* check whether we are already on top of the list */
+ if ( !before )
+ return;
+
+ before->next = after;
+
+ if ( after )
+ after->prev = before;
+ else
+ list->tail = before;
+
+ node->prev = 0;
+ node->next = list->head;
+ list->head->prev = node;
+ list->head = node;
+ }
+
+
+ /* documentation is in ftlist.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_List_Iterate( FT_List list,
+ FT_List_Iterator iterator,
+ void* user )
+ {
+ FT_ListNode cur = list->head;
+ FT_Error error = FT_Err_Ok;
+
+
+ while ( cur )
+ {
+ FT_ListNode next = cur->next;
+
+
+ error = iterator( cur, user );
+ if ( error )
+ break;
+
+ cur = next;
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in ftlist.h */
+
+ FT_EXPORT_DEF( void )
+ FT_List_Finalize( FT_List list,
+ FT_List_Destructor destroy,
+ FT_Memory memory,
+ void* user )
+ {
+ FT_ListNode cur;
+
+
+ cur = list->head;
+ while ( cur )
+ {
+ FT_ListNode next = cur->next;
+ void* data = cur->data;
+
+
+ if ( destroy )
+ destroy( memory, data, user );
+
+ FREE( cur );
+ cur = next;
+ }
+
+ list->head = 0;
+ list->tail = 0;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftlru.c */
+/* */
+/* Simple LRU list-cache (body). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_INTERNAL_LRU_H
+#include FT_LIST_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "ftcerror.h"
+
+
+ static void
+ lru_build_free_list( FT_LruNode nodes,
+ FT_UInt count,
+ FT_List free_list )
+ {
+ FT_LruNode node = nodes;
+ FT_LruNode limit = node + count;
+
+
+ free_list->head = free_list->tail = 0;
+ for ( ; node < limit; node++ )
+ FT_List_Add( free_list, (FT_ListNode)node );
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Lru_New( const FT_Lru_Class* clazz,
+ FT_UInt max_elements,
+ FT_Pointer user_data,
+ FT_Memory memory,
+ FT_Bool pre_alloc,
+ FT_Lru *anlru )
+ {
+ FT_Error error;
+ FT_Lru lru;
+
+
+ if ( !anlru )
+ return FTC_Err_Invalid_Argument;
+
+ *anlru = 0;
+ if ( !ALLOC( lru, sizeof ( *lru ) ) )
+ {
+ if ( pre_alloc )
+ {
+ /* allocate static array of lru list nodes */
+ if ( ALLOC_ARRAY( lru->nodes, max_elements, FT_LruNodeRec ) )
+ {
+ FREE( lru );
+ goto Exit;
+ }
+
+ /* build the `free_nodes' list from the array */
+ lru_build_free_list( lru->nodes, max_elements, &lru->free_nodes );
+ }
+
+ /* initialize common fields */
+ lru->clazz = (FT_Lru_Class*)clazz;
+ lru->max_elements = max_elements;
+ lru->memory = memory;
+ lru->user_data = user_data;
+
+ *anlru = lru;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FT_Lru_Reset( FT_Lru lru )
+ {
+ FT_ListNode node;
+ FT_Lru_Class* clazz;
+ FT_Memory memory;
+
+
+ if ( !lru )
+ return;
+
+ node = lru->elements.head;
+ clazz = lru->clazz;
+ memory = lru->memory;
+
+ while ( node )
+ {
+ FT_ListNode next = node->next;
+
+
+ clazz->done_element( lru, (FT_LruNode)node );
+ if ( !lru->nodes )
+ FREE( node );
+
+ node = next;
+ }
+
+ /* rebuild free list if necessary */
+ if ( lru->nodes )
+ lru_build_free_list( lru->nodes, lru->max_elements, &lru->free_nodes );
+
+ lru->elements.head = lru->elements.tail = 0;
+ lru->num_elements = 0;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FT_Lru_Done( FT_Lru lru )
+ {
+ FT_Memory memory;
+
+
+ if ( !lru )
+ return;
+
+ memory = lru->memory;
+
+ FT_Lru_Reset( lru );
+
+ FREE( lru->nodes );
+ FREE( lru );
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Lru_Lookup_Node( FT_Lru lru,
+ FT_LruKey key,
+ FT_LruNode *anode )
+ {
+ FT_Error error = 0;
+ FT_ListNode node;
+ FT_Lru_Class* clazz;
+ FT_LruNode found = 0;
+ FT_Memory memory;
+
+
+ if ( !lru || !key || !anode )
+ return FTC_Err_Invalid_Argument;
+
+ node = lru->elements.head;
+ clazz = lru->clazz;
+ memory = lru->memory;
+
+ if ( clazz->compare_element )
+ {
+ for ( ; node; node = node->next )
+ if ( clazz->compare_element( (FT_LruNode)node, key ) )
+ {
+ found = (FT_LruNode)node;
+ break;
+ }
+ }
+ else
+ {
+ for ( ; node; node = node->next )
+ if ( ((FT_LruNode)node)->key == key )
+ {
+ found = (FT_LruNode)node;
+ break;
+ }
+ }
+
+ if ( found )
+ {
+ /* move element to top of list */
+ FT_List_Up( &lru->elements, node );
+ }
+ else
+ {
+ /* we haven't found the relevant element. We will now try */
+ /* to create a new one. */
+ if ( lru->num_elements >= lru->max_elements )
+ {
+ /* this lru list is full; we will now flush */
+ /* the oldest node */
+ FT_LruNode lru_node;
+
+
+ node = lru->elements.tail;
+ lru_node = (FT_LruNode)node;
+ found = lru_node;
+
+ if ( clazz->flush_element )
+ error = clazz->flush_element( lru, lru_node, key );
+ else
+ {
+ clazz->done_element( lru, lru_node );
+ lru_node->key = key;
+ node->data = 0;
+ error = clazz->init_element( lru, lru_node );
+ }
+
+ if ( !error )
+ {
+ /* now, move element to top of list */
+ FT_List_Up( &lru->elements, node );
+ }
+ else
+ {
+ /* in case of error, the node must be discarded */
+ FT_List_Remove( &lru->elements, node );
+ lru->num_elements--;
+
+ if ( lru->nodes )
+ FT_List_Insert( &lru->free_nodes, node );
+ else
+ FREE( lru_node );
+
+ found = 0;
+ }
+ }
+ else
+ {
+ FT_LruNode lru_node;
+
+
+ /* create a new lru list node, then the element for it */
+ if ( lru->nodes )
+ {
+ node = lru->free_nodes.head;
+ lru_node = (FT_LruNode)node;
+ lru_node->key = key;
+
+ error = clazz->init_element( lru, lru_node );
+ if ( error )
+ goto Exit;
+
+ FT_List_Remove( &lru->free_nodes, node );
+ }
+ else
+ {
+ if ( ALLOC( lru_node, sizeof ( *lru_node ) ) )
+ goto Exit;
+
+ lru_node->key = key;
+ error = clazz->init_element( lru, lru_node );
+ if ( error )
+ {
+ FREE( lru_node );
+ goto Exit;
+ }
+ }
+
+ found = lru_node;
+ node = (FT_ListNode)lru_node;
+ FT_List_Insert( &lru->elements, node );
+ lru->num_elements++;
+ }
+ }
+
+ Exit:
+ *anode = found;
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Lru_Lookup( FT_Lru lru,
+ FT_LruKey key,
+ FT_Pointer *anobject )
+ {
+ FT_Error error;
+ FT_LruNode node;
+
+
+ /* check for valid `lru' and `key' delayed to FT_Lru_Lookup_Node() */
+
+ if ( !anobject )
+ return FTC_Err_Invalid_Argument;
+
+ *anobject = 0;
+ error = FT_Lru_Lookup_Node( lru, key, &node );
+ if ( !error )
+ *anobject = node->root.data;
+
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FT_Lru_Remove_Node( FT_Lru lru,
+ FT_LruNode node )
+ {
+ if ( !lru || !node )
+ return;
+
+ if ( lru->num_elements > 0 )
+ {
+ FT_List_Remove( &lru->elements, (FT_ListNode)node );
+ lru->clazz->done_element( lru, node );
+
+ if ( lru->nodes )
+ FT_List_Insert( &lru->free_nodes, (FT_ListNode)node );
+ else
+ {
+ FT_Memory memory = lru->memory;
+
+
+ FREE( node );
+ }
+
+ lru->num_elements--;
+ }
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FT_Lru_Remove_Selection( FT_Lru lru,
+ FT_Lru_Selector selector,
+ FT_Pointer data )
+ {
+ if ( !lru || !selector )
+ return;
+
+ if ( lru->num_elements > 0 )
+ {
+ FT_ListNode node = lru->elements.head;
+ FT_ListNode next;
+
+
+ while ( node )
+ {
+ next = node->next;
+ if ( selector( lru, (FT_LruNode)node, data ) )
+ {
+ /* remove this element from the list, and destroy it */
+ FT_Lru_Remove_Node( lru, (FT_LruNode)node );
+ }
+ node = next;
+ }
+ }
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftmac.c */
+/* */
+/* Mac FOND support. Written by just@letterror.com. */
+/* */
+/* Copyright 1996-2001 by */
+/* Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*
+ Notes
+
+ Mac suitcase files can (and often do!) contain multiple fonts. To
+ support this I use the face_index argument of FT_(Open|New)_Face()
+ functions, and pretend the suitcase file is a collection.
+ Warning: although the FOND driver sets face->num_faces field to the
+ number of available fonts, but the Type 1 driver sets it to 1 anyway.
+ So this field is currently not reliable, and I don't see a clean way
+ to resolve that. The face_index argument translates to
+ Get1IndResource( 'FOND', face_index + 1 );
+ so clients should figure out the resource index of the FOND.
+ (I'll try to provide some example code for this at some point.)
+
+
+ The Mac FOND support works roughly like this:
+
+ - Check whether the offered stream points to a Mac suitcase file.
+ This is done by checking the file type: it has to be 'FFIL' or 'tfil'.
+ The stream that gets passed to our init_face() routine is a stdio
+ stream, which isn't usable for us, since the FOND resources live
+ in the resource fork. So we just grab the stream->pathname field.
+
+ - Read the FOND resource into memory, then check whether there is
+ a TrueType font and/or (!) a Type 1 font available.
+
+ - If there is a Type 1 font available (as a separate 'LWFN' file),
+ read its data into memory, massage it slightly so it becomes
+ PFB data, wrap it into a memory stream, load the Type 1 driver
+ and delegate the rest of the work to it by calling FT_Open_Face().
+ (XXX TODO: after this has been done, the kerning data from the FOND
+ resource should be appended to the face: on the Mac there are usually
+ no AFM files available. However, this is tricky since we need to map
+ Mac char codes to ps glyph names to glyph ID's...)
+
+ - If there is a TrueType font (an 'sfnt' resource), read it into
+ memory, wrap it into a memory stream, load the TrueType driver
+ and delegate the rest of the work to it, by calling FT_Open_Face().
+ */
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_INTERNAL_STREAM_H
+#include "truetype/ttobjs.h"
+#include "type1/t1objs.h"
+
+#include <Resources.h>
+#include <Fonts.h>
+#include <Errors.h>
+
+#include <ctype.h> /* for isupper() and isalnum() */
+
+#include FT_MAC_H
+
+
+
+ /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over
+ TrueType in case *both* are available (this is not common,
+ but it *is* possible). */
+#ifndef PREFER_LWFN
+#define PREFER_LWFN 1
+#endif
+
+
+
+ /* Quick'n'dirty Pascal string to C string converter.
+ Warning: this call is not thread safe! Use with caution. */
+ static char*
+ p2c_str( unsigned char* pstr )
+ {
+ static char cstr[256];
+
+
+ strncpy( cstr, (char*)pstr + 1, pstr[0] );
+ cstr[pstr[0]] = '\0';
+ return cstr;
+ }
+
+
+ /* Given a pathname, fill in a file spec. */
+ static int
+ file_spec_from_path( const char* pathname,
+ FSSpec* spec )
+ {
+ Str255 p_path;
+ FT_ULong path_len;
+
+
+ /* convert path to a pascal string */
+ path_len = strlen( pathname );
+ if ( path_len > 255 )
+ return -1;
+ p_path[0] = (unsigned char)path_len;
+ strncpy( (char*)p_path + 1, pathname, path_len );
+
+ if ( FSMakeFSSpec( 0, 0, p_path, spec ) != noErr )
+ return -1;
+ else
+ return 0;
+ }
+
+
+ /* Return the file type of the file specified by spec. */
+ static OSType
+ get_file_type( FSSpec* spec )
+ {
+ FInfo finfo;
+
+
+ if ( FSpGetFInfo( spec, &finfo ) != noErr )
+ return 0; /* file might not exist */
+
+ return finfo.fdType;
+ }
+
+
+ /* Given a PostScript font name, create the Macintosh LWFN file name. */
+ static void
+ create_lwfn_name( char* ps_name,
+ Str255 lwfn_file_name )
+ {
+ int max = 5, count = 0;
+ FT_Byte* p = lwfn_file_name;
+ FT_Byte* q = (FT_Byte*)ps_name;
+
+
+ lwfn_file_name[0] = 0;
+
+ while ( *q )
+ {
+ if ( isupper( *q ) )
+ {
+ if ( count )
+ max = 3;
+ count = 0;
+ }
+ if ( count < max && ( isalnum( *q ) || *q == '_' ) )
+ {
+ *++p = *q;
+ lwfn_file_name[0]++;
+ count++;
+ }
+ q++;
+ }
+ }
+
+
+ /* Given a file reference, answer its location as a vRefNum
+ and a dirID. */
+ static FT_Error
+ get_file_location( short ref_num,
+ short* v_ref_num,
+ long* dir_id,
+ unsigned char* file_name )
+ {
+ FCBPBRec pb;
+ OSErr error;
+
+ pb.ioNamePtr = file_name;
+ pb.ioVRefNum = 0;
+ pb.ioRefNum = ref_num;
+ pb.ioFCBIndx = 0;
+
+
+ error = PBGetFCBInfoSync( &pb );
+ if ( error == noErr )
+ {
+ *v_ref_num = pb.ioFCBVRefNum;
+ *dir_id = pb.ioFCBParID;
+ }
+ return error;
+ }
+
+
+ /* Make a file spec for an LWFN file from a FOND resource and
+ a file name. */
+ static FT_Error
+ make_lwfn_spec( Handle fond,
+ unsigned char* file_name,
+ FSSpec* spec )
+ {
+ FT_Error error;
+ short ref_num, v_ref_num;
+ long dir_id;
+ Str255 fond_file_name;
+
+
+ ref_num = HomeResFile( fond );
+
+ error = ResError();
+ if ( !error )
+ error = get_file_location( ref_num, &v_ref_num,
+ &dir_id, fond_file_name );
+ if ( !error )
+ error = FSMakeFSSpec( v_ref_num, dir_id, file_name, spec );
+
+ return error;
+ }
+
+
+ /* Look inside the FOND data, answer whether there should be an SFNT
+ resource, and answer the name of a possible LWFN Type 1 file. */
+ static void
+ parse_fond( char* fond_data,
+ short* have_sfnt,
+ short* sfnt_id,
+ Str255 lwfn_file_name )
+ {
+ AsscEntry* assoc;
+ FamRec* fond;
+
+
+ *sfnt_id = 0;
+ *have_sfnt = 0;
+ lwfn_file_name[0] = 0;
+
+ fond = (FamRec*)fond_data;
+ assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
+
+ if ( assoc->fontSize == 0 )
+ {
+ *have_sfnt = 1;
+ *sfnt_id = assoc->fontID;
+ }
+
+ if ( fond->ffStylOff )
+ {
+ unsigned char* p = (unsigned char*)fond_data;
+ StyleTable* style;
+ unsigned short string_count;
+ unsigned char* name_table = 0;
+ char ps_name[256];
+ unsigned char* names[64];
+ int i;
+
+
+ p += fond->ffStylOff;
+ style = (StyleTable*)p;
+ p += sizeof ( StyleTable );
+ string_count = *(unsigned short*)(p);
+ p += sizeof ( short );
+
+ for ( i = 0 ; i < string_count && i < 64; i++ )
+ {
+ names[i] = p;
+ p += names[i][0];
+ p++;
+ }
+ strcpy( ps_name, p2c_str( names[0] ) ); /* Family name */
+
+ if ( style->indexes[0] > 1 )
+ {
+ unsigned char* suffixes = names[style->indexes[0] - 1];
+
+
+ for ( i=1; i<=suffixes[0]; i++ )
+ strcat( ps_name, p2c_str( names[suffixes[i] - 1 ] ) );
+ }
+ create_lwfn_name( ps_name, lwfn_file_name );
+ }
+ }
+
+
+ /* Read Type 1 data from the POST resources inside the LWFN file,
+ return a PFB buffer. This is somewhat convoluted because the FT2
+ PFB parser wants the ASCII header as one chunk, and the LWFN
+ chunks are often not organized that way, so we'll glue chunks
+ of the same type together. */
+ static FT_Error
+ read_lwfn( FT_Memory memory,
+ FSSpec* lwfn_spec,
+ FT_Byte** pfb_data,
+ FT_ULong* size )
+ {
+ FT_Error error = FT_Err_Ok;
+ short res_ref, res_id;
+ unsigned char *buffer, *p, *size_p;
+ FT_ULong total_size = 0;
+ FT_ULong post_size, pfb_chunk_size;
+ Handle post_data;
+ char code, last_code;
+
+
+ res_ref = FSpOpenResFile( lwfn_spec, fsRdPerm );
+ if ( ResError() )
+ return FT_Err_Out_Of_Memory;
+ UseResFile( res_ref );
+
+ /* First pass: load all POST resources, and determine the size of
+ the output buffer. */
+ res_id = 501;
+ last_code = -1;
+
+ for (;;)
+ {
+ post_data = Get1Resource( 'POST', res_id++ );
+ if ( post_data == NULL )
+ break; /* we're done */
+
+ code = (*post_data)[0];
+
+ if ( code != last_code )
+ {
+ if ( code == 5 )
+ total_size += 2; /* just the end code */
+ else
+ total_size += 6; /* code + 4 bytes chunk length */
+ }
+
+ total_size += GetHandleSize( post_data ) - 2;
+ last_code = code;
+ }
+
+ if ( ALLOC( buffer, (FT_Long)total_size ) )
+ goto Error;
+
+ /* Second pass: append all POST data to the buffer, add PFB fields.
+ Glue all consecutive chunks of the same type together. */
+ p = buffer;
+ res_id = 501;
+ last_code = -1;
+ pfb_chunk_size = 0;
+
+ for (;;)
+ {
+ post_data = Get1Resource( 'POST', res_id++ );
+ if ( post_data == NULL )
+ break; /* we're done */
+
+ post_size = (FT_ULong)GetHandleSize( post_data ) - 2;
+ code = (*post_data)[0];
+
+ if ( code != last_code )
+ {
+
+ if ( last_code != -1 )
+ {
+ /* we're done adding a chunk, fill in the size field */
+ *size_p++ = (FT_Byte)( pfb_chunk_size & 0xFF );
+ *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8 ) & 0xFF );
+ *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF );
+ *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF );
+ pfb_chunk_size = 0;
+ }
+
+ *p++ = 0x80;
+ if ( code == 5 )
+ *p++ = 0x03; /* the end */
+ else if ( code == 2 )
+ *p++ = 0x02; /* binary segment */
+ else
+ *p++ = 0x01; /* ASCII segment */
+
+ if ( code != 5 )
+ {
+ size_p = p; /* save for later */
+ p += 4; /* make space for size field */
+ }
+ }
+
+ memcpy( p, *post_data + 2, post_size );
+ pfb_chunk_size += post_size;
+ p += post_size;
+ last_code = code;
+ }
+
+ *pfb_data = buffer;
+ *size = total_size;
+
+ Error:
+ CloseResFile( res_ref );
+ return error;
+ }
+
+
+ /* Finalizer for a memory stream; gets called by FT_Done_Face().
+ It frees the memory it uses. */
+ static void
+ memory_stream_close( FT_Stream stream )
+ {
+ FT_Memory memory = stream->memory;
+
+
+ FREE( stream->base );
+
+ stream->size = 0;
+ stream->base = 0;
+ stream->close = 0;
+ }
+
+
+ /* Create a new memory stream from a buffer and a size. */
+ static FT_Error
+ new_memory_stream( FT_Library library,
+ FT_Byte* base,
+ FT_ULong size,
+ FT_Stream_Close close,
+ FT_Stream* astream )
+ {
+ FT_Error error;
+ FT_Memory memory;
+ FT_Stream stream;
+
+
+ if ( !library )
+ return FT_Err_Invalid_Library_Handle;
+
+ if ( !base )
+ return FT_Err_Invalid_Argument;
+
+ *astream = 0;
+ memory = library->memory;
+ if ( ALLOC( stream, sizeof ( *stream ) ) )
+ goto Exit;
+
+ FT_New_Memory_Stream( library,
+ base,
+ size,
+ stream );
+
+ stream->close = close;
+
+ *astream = stream;
+
+ Exit:
+ return error;
+ }
+
+
+ /* Create a new FT_Face given a buffer and a driver name. */
+ static FT_Error
+ open_face_from_buffer( FT_Library library,
+ FT_Byte* base,
+ FT_ULong size,
+ FT_Long face_index,
+ char* driver_name,
+ FT_Face* aface )
+ {
+ FT_Open_Args args;
+ FT_Error error;
+ FT_Stream stream;
+ FT_Memory memory = library->memory;
+
+
+ error = new_memory_stream( library,
+ base,
+ size,
+ memory_stream_close,
+ &stream );
+ if ( error )
+ {
+ FREE( base );
+ return error;
+ }
+
+ args.flags = ft_open_stream;
+ args.stream = stream;
+ if ( driver_name )
+ {
+ args.flags = args.flags | ft_open_driver;
+ args.driver = FT_Get_Module( library, driver_name );
+ }
+
+ error = FT_Open_Face( library, &args, face_index, aface );
+ if ( error == FT_Err_Ok )
+ (*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
+ else
+ {
+ FT_Done_Stream( stream );
+ FREE( stream );
+ }
+ return error;
+ }
+
+
+ /* Create a new FT_Face from a file spec to an LWFN file. */
+ static FT_Error
+ FT_New_Face_From_LWFN( FT_Library library,
+ FSSpec* spec,
+ FT_Long face_index,
+ FT_Face* aface )
+ {
+ FT_Byte* pfb_data;
+ FT_ULong pfb_size;
+ FT_Error error;
+ FT_Memory memory = library->memory;
+
+
+ error = read_lwfn( library->memory, spec, &pfb_data, &pfb_size );
+ if ( error )
+ return error;
+
+#if 0
+ {
+ FILE* f;
+ char* path;
+
+
+ path = p2c_str( spec->name );
+ strcat( path, ".PFB" );
+ f = fopen( path, "wb" );
+ if ( f )
+ {
+ fwrite( pfb_data, 1, pfb_size, f );
+ fclose( f );
+ }
+ }
+#endif
+
+ return open_face_from_buffer( library,
+ pfb_data,
+ pfb_size,
+ face_index,
+ "type1",
+ aface );
+ }
+
+
+ /* Create a new FT_Face from an SFNT resource, specified by res ID. */
+ static FT_Error
+ FT_New_Face_From_SFNT( FT_Library library,
+ short sfnt_id,
+ FT_Long face_index,
+ FT_Face* aface )
+ {
+ Handle sfnt = NULL;
+ FT_Byte* sfnt_data;
+ size_t sfnt_size;
+ FT_Stream stream = NULL;
+ FT_Error error = 0;
+ FT_Memory memory = library->memory;
+
+
+ sfnt = GetResource( 'sfnt', sfnt_id );
+ if ( ResError() )
+ return FT_Err_Invalid_Handle;
+
+ sfnt_size = (FT_ULong)GetHandleSize( sfnt );
+ if ( ALLOC( sfnt_data, (FT_Long)sfnt_size ) )
+ {
+ ReleaseResource( sfnt );
+ return error;
+ }
+
+ HLock( sfnt );
+ memcpy( sfnt_data, *sfnt, sfnt_size );
+ HUnlock( sfnt );
+ ReleaseResource( sfnt );
+
+ return open_face_from_buffer( library,
+ sfnt_data,
+ sfnt_size,
+ face_index,
+ "truetype",
+ aface );
+ }
+
+
+ /* Create a new FT_Face from a file spec to a suitcase file. */
+ static FT_Error
+ FT_New_Face_From_Suitcase( FT_Library library,
+ FSSpec* spec,
+ FT_Long face_index,
+ FT_Face* aface )
+ {
+ FT_Error error = FT_Err_Ok;
+ short res_ref, res_index;
+ Handle fond;
+
+
+ res_ref = FSpOpenResFile( spec, fsRdPerm );
+ if ( ResError() )
+ return FT_Err_Cannot_Open_Resource;
+ UseResFile( res_ref );
+
+ /* face_index may be -1, in which case we
+ just need to do a sanity check */
+ if ( face_index < 0 )
+ res_index = 1;
+ else
+ {
+ res_index = (short)( face_index + 1 );
+ face_index = 0;
+ }
+ fond = Get1IndResource( 'FOND', res_index );
+ if ( ResError() )
+ {
+ error = FT_Err_Cannot_Open_Resource;
+ goto Error;
+ }
+
+ error = FT_New_Face_From_FOND( library, fond, face_index, aface );
+
+ Error:
+ CloseResFile( res_ref );
+ return error;
+ }
+
+
+ /* documentation in ftmac.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_New_Face_From_FOND( FT_Library library,
+ Handle fond,
+ FT_Long face_index,
+ FT_Face *aface )
+ {
+ short sfnt_id, have_sfnt, have_lwfn = 0;
+ Str255 lwfn_file_name;
+ short fond_id;
+ OSType fond_type;
+ Str255 fond_name;
+ FSSpec lwfn_spec;
+ FT_Error error = FT_Err_Unknown_File_Format;
+
+
+ GetResInfo(fond, &fond_id, &fond_type, fond_name);
+ if ( ResError() != noErr || fond_type != 'FOND' )
+ return FT_Err_Invalid_File_Format;
+
+ HLock( fond );
+ parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name );
+ HUnlock( fond );
+
+ if ( lwfn_file_name[0] )
+ {
+ if ( make_lwfn_spec( fond, lwfn_file_name, &lwfn_spec ) == FT_Err_Ok )
+ have_lwfn = 1; /* yeah, we got one! */
+ else
+ have_lwfn = 0; /* no LWFN file found */
+ }
+
+ if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
+ return FT_New_Face_From_LWFN( library,
+ &lwfn_spec,
+ face_index,
+ aface );
+ else if ( have_sfnt )
+ return FT_New_Face_From_SFNT( library,
+ sfnt_id,
+ face_index,
+ aface );
+
+ return FT_Err_Unknown_File_Format;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_New_Face */
+ /* */
+ /* <Description> */
+ /* This is the Mac-specific implementation of FT_New_Face. In */
+ /* addition to the standard FT_New_Face() functionality, it also */
+ /* accepts pathnames to Mac suitcase files. For further */
+ /* documentation see the original FT_New_Face() in freetype.h. */
+ /* */
+ FT_EXPORT_DEF( FT_Error )
+ FT_New_Face( FT_Library library,
+ const char* pathname,
+ FT_Long face_index,
+ FT_Face *aface )
+ {
+ FT_Open_Args args;
+ FSSpec spec;
+ OSType file_type;
+
+
+ /* test for valid `library' and `aface' delayed to FT_Open_Face() */
+ if ( !pathname )
+ return FT_Err_Invalid_Argument;
+
+ if ( file_spec_from_path( pathname, &spec ) )
+ return FT_Err_Invalid_Argument;
+
+ file_type = get_file_type( &spec );
+ if ( file_type == 'FFIL' || file_type == 'tfil' )
+ return FT_New_Face_From_Suitcase( library, &spec, face_index, aface );
+ else if ( file_type == 'LWFN' )
+ return FT_New_Face_From_LWFN( library, &spec, face_index, aface );
+ else
+ {
+ args.flags = ft_open_pathname;
+ args.pathname = (char*)pathname;
+
+ return FT_Open_Face( library, &args, face_index, aface );
+ }
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftmm.c */
+/* */
+/* Multiple Master font support (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_MULTIPLE_MASTERS_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_mm
+
+
+ /* documentation is in ftmm.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_Multi_Master( FT_Face face,
+ FT_Multi_Master *amaster )
+ {
+ FT_Error error;
+
+
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ error = FT_Err_Invalid_Argument;
+
+ if ( FT_HAS_MULTIPLE_MASTERS( face ) )
+ {
+ FT_Driver driver = face->driver;
+ FT_Get_MM_Func func;
+
+
+ func = (FT_Get_MM_Func)driver->root.clazz->get_interface(
+ FT_MODULE( driver ), "get_mm" );
+ if ( func )
+ error = func( face, amaster );
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in ftmm.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Set_MM_Design_Coordinates( FT_Face face,
+ FT_UInt num_coords,
+ FT_Long* coords )
+ {
+ FT_Error error;
+
+
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ error = FT_Err_Invalid_Argument;
+
+ if ( FT_HAS_MULTIPLE_MASTERS( face ) )
+ {
+ FT_Driver driver = face->driver;
+ FT_Set_MM_Design_Func func;
+
+
+ func = (FT_Set_MM_Design_Func)driver->root.clazz->get_interface(
+ FT_MODULE( driver ), "set_mm_design" );
+ if ( func )
+ error = func( face, num_coords, coords );
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in ftmm.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Set_MM_Blend_Coordinates( FT_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords )
+ {
+ FT_Error error;
+
+
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ error = FT_Err_Invalid_Argument;
+
+ if ( FT_HAS_MULTIPLE_MASTERS( face ) )
+ {
+ FT_Driver driver = face->driver;
+ FT_Set_MM_Blend_Func func;
+
+
+ func = (FT_Set_MM_Blend_Func)driver->root.clazz->get_interface(
+ FT_MODULE( driver ), "set_mm_blend" );
+ if ( func )
+ error = func( face, num_coords, coords );
+ }
+
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftnames.c */
+/* */
+/* Simple interface to access SFNT name tables (which are used */
+/* to hold font names, copyright info, notices, etc.) (body). */
+/* */
+/* This is _not_ used to retrieve glyph names! */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_SFNT_NAMES_H
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+
+
+#ifdef TT_CONFIG_OPTION_SFNT_NAMES
+
+
+ /* documentation is in ftnames.h */
+
+ FT_EXPORT_DEF( FT_UInt )
+ FT_Get_Sfnt_Name_Count( FT_Face face )
+ {
+ return (face && FT_IS_SFNT( face )) ? ((TT_Face)face)->num_names : 0;
+ }
+
+
+ /* documentation is in ftnames.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_Sfnt_Name( FT_Face face,
+ FT_UInt index,
+ FT_SfntName *aname )
+ {
+ FT_Error error = FT_Err_Invalid_Argument;
+
+
+ if ( aname && face && FT_IS_SFNT( face ) )
+ {
+ TT_Face ttface = (TT_Face)face;
+
+
+ if ( index < (FT_UInt)ttface->num_names )
+ {
+ TT_NameRec* name = ttface->name_table.names + index;
+
+
+ aname->platform_id = name->platformID;
+ aname->encoding_id = name->encodingID;
+ aname->language_id = name->languageID;
+ aname->name_id = name->nameID;
+ aname->string = (FT_Byte*)name->string;
+ aname->string_len = name->stringLength;
+
+ error = FT_Err_Ok;
+ }
+ }
+
+ return error;
+ }
+
+
+#endif /* TT_CONFIG_OPTION_SFNT_NAMES */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftobjs.c */
+/* */
+/* The FreeType private base classes (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_LIST_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TABLES_H
+
+#include <string.h> /* for strcmp() */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** M E M O R Y ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_memory
+
+
+ /* documentation is in ftmemory.h */
+
+ FT_BASE_DEF( FT_Error )
+ FT_Alloc( FT_Memory memory,
+ FT_Long size,
+ void* *P )
+ {
+ FT_Assert( P != 0 );
+
+ if ( size > 0 )
+ {
+ *P = memory->alloc( memory, size );
+ if ( !*P )
+ {
+ FT_ERROR(( "FT_Alloc:" ));
+ FT_ERROR(( " Out of memory? (%ld requested)\n",
+ size ));
+
+ return FT_Err_Out_Of_Memory;
+ }
+ MEM_Set( *P, 0, size );
+ }
+ else
+ *P = NULL;
+
+ FT_TRACE7(( "FT_Alloc:" ));
+ FT_TRACE7(( " size = %ld, block = 0x%08p, ref = 0x%08p\n",
+ size, *P, P ));
+
+ return FT_Err_Ok;
+ }
+
+
+ /* documentation is in ftmemory.h */
+
+ FT_BASE_DEF( FT_Error )
+ FT_Realloc( FT_Memory memory,
+ FT_Long current,
+ FT_Long size,
+ void** P )
+ {
+ void* Q;
+
+
+ FT_Assert( P != 0 );
+
+ /* if the original pointer is NULL, call FT_Alloc() */
+ if ( !*P )
+ return FT_Alloc( memory, size, P );
+
+ /* if the new block if zero-sized, clear the current one */
+ if ( size <= 0 )
+ {
+ FT_Free( memory, P );
+ return FT_Err_Ok;
+ }
+
+ Q = memory->realloc( memory, current, size, *P );
+ if ( !Q )
+ goto Fail;
+
+ *P = Q;
+ return FT_Err_Ok;
+
+ Fail:
+ FT_ERROR(( "FT_Realloc:" ));
+ FT_ERROR(( " Failed (current %ld, requested %ld)\n",
+ current, size ));
+ return FT_Err_Out_Of_Memory;
+ }
+
+
+ /* documentation is in ftmemory.h */
+
+ FT_BASE_DEF( void )
+ FT_Free( FT_Memory memory,
+ void** P )
+ {
+ FT_TRACE7(( "FT_Free:" ));
+ FT_TRACE7(( " Freeing block 0x%08p, ref 0x%08p\n",
+ P, P ? *P : (void*)0 ));
+
+ if ( P && *P )
+ {
+ memory->free( memory, *P );
+ *P = 0;
+ }
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** S T R E A M ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ft_new_input_stream */
+ /* */
+ /* <Description> */
+ /* Creates a new input stream object from an FT_Open_Args structure. */
+ /* */
+ /* <Note> */
+ /* The function expects a valid `astream' parameter. */
+ /* */
+ static FT_Error
+ ft_new_input_stream( FT_Library library,
+ FT_Open_Args* args,
+ FT_Stream* astream )
+ {
+ FT_Error error;
+ FT_Memory memory;
+ FT_Stream stream;
+
+
+ if ( !library )
+ return FT_Err_Invalid_Library_Handle;
+
+ if ( !args )
+ return FT_Err_Invalid_Argument;
+
+ *astream = 0;
+ memory = library->memory;
+ if ( ALLOC( stream, sizeof ( *stream ) ) )
+ goto Exit;
+
+ stream->memory = memory;
+
+ /* now, look at the stream flags */
+ if ( args->flags & ft_open_memory )
+ {
+ error = 0;
+ FT_New_Memory_Stream( library,
+ (FT_Byte*)args->memory_base,
+ args->memory_size,
+ stream );
+ }
+ else if ( args->flags & ft_open_pathname )
+ {
+ error = FT_New_Stream( args->pathname, stream );
+ stream->pathname.pointer = args->pathname;
+ }
+ else if ( ( args->flags & ft_open_stream ) && args->stream )
+ {
+ /* in this case, we do not need to allocate a new stream object */
+ /* since the caller is responsible for closing it himself */
+ FREE( stream );
+ stream = args->stream;
+ }
+ else
+ error = FT_Err_Invalid_Argument;
+
+ if ( error )
+ FREE( stream );
+
+ *astream = stream;
+
+ Exit:
+ return error;
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Done_Stream( FT_Stream stream )
+ {
+ if ( stream && stream->close )
+ {
+ stream->close( stream );
+ stream->close = 0;
+ }
+ }
+
+
+ static void
+ ft_done_stream( FT_Stream* astream,
+ FT_Int external )
+ {
+ FT_Stream stream = *astream;
+
+
+ if ( stream->close )
+ stream->close( stream );
+
+ if ( !external )
+ {
+ FT_Memory memory = stream->memory;
+
+
+ FREE( stream );
+ }
+ *astream = 0;
+ }
+
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_objs
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** G L Y P H L O A D E R ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* The glyph loader is a simple object which is used to load a set of */
+ /* glyphs easily. It is critical for the correct loading of composites. */
+ /* */
+ /* Ideally, one can see it as a stack of abstract `glyph' objects. */
+ /* */
+ /* loader.base Is really the bottom of the stack. It describes a */
+ /* single glyph image made of the juxtaposition of */
+ /* several glyphs (those `in the stack'). */
+ /* */
+ /* loader.current Describes the top of the stack, on which a new */
+ /* glyph can be loaded. */
+ /* */
+ /* Rewind Clears the stack. */
+ /* Prepare Set up `loader.current' for addition of a new glyph */
+ /* image. */
+ /* Add Add the `current' glyph image to the `base' one, */
+ /* and prepare for another one. */
+ /* */
+ /* The glyph loader is now a base object. Each driver used to */
+ /* re-implement it in one way or the other, which wasted code and */
+ /* energy. */
+ /* */
+ /*************************************************************************/
+
+
+ /* create a new glyph loader */
+ FT_BASE_DEF( FT_Error )
+ FT_GlyphLoader_New( FT_Memory memory,
+ FT_GlyphLoader* *aloader )
+ {
+ FT_GlyphLoader* loader;
+ FT_Error error;
+
+
+ if ( !ALLOC( loader, sizeof ( *loader ) ) )
+ {
+ loader->memory = memory;
+ *aloader = loader;
+ }
+ return error;
+ }
+
+
+ /* rewind the glyph loader - reset counters to 0 */
+ FT_BASE_DEF( void )
+ FT_GlyphLoader_Rewind( FT_GlyphLoader* loader )
+ {
+ FT_GlyphLoad* base = &loader->base;
+ FT_GlyphLoad* current = &loader->current;
+
+
+ base->outline.n_points = 0;
+ base->outline.n_contours = 0;
+ base->num_subglyphs = 0;
+
+ *current = *base;
+ }
+
+
+ /* reset the glyph loader, frees all allocated tables */
+ /* and starts from zero */
+ FT_BASE_DEF( void )
+ FT_GlyphLoader_Reset( FT_GlyphLoader* loader )
+ {
+ FT_Memory memory = loader->memory;
+
+
+ FREE( loader->base.outline.points );
+ FREE( loader->base.outline.tags );
+ FREE( loader->base.outline.contours );
+ FREE( loader->base.extra_points );
+ FREE( loader->base.subglyphs );
+
+ loader->max_points = 0;
+ loader->max_contours = 0;
+ loader->max_subglyphs = 0;
+
+ FT_GlyphLoader_Rewind( loader );
+ }
+
+
+ /* delete a glyph loader */
+ FT_BASE_DEF( void )
+ FT_GlyphLoader_Done( FT_GlyphLoader* loader )
+ {
+ if ( loader )
+ {
+ FT_Memory memory = loader->memory;
+
+
+ FT_GlyphLoader_Reset( loader );
+ FREE( loader );
+ }
+ }
+
+
+ /* re-adjust the `current' outline fields */
+ static void
+ FT_GlyphLoader_Adjust_Points( FT_GlyphLoader* loader )
+ {
+ FT_Outline* base = &loader->base.outline;
+ FT_Outline* current = &loader->current.outline;
+
+
+ current->points = base->points + base->n_points;
+ current->tags = base->tags + base->n_points;
+ current->contours = base->contours + base->n_contours;
+
+ /* handle extra points table - if any */
+ if ( loader->use_extra )
+ loader->current.extra_points =
+ loader->base.extra_points + base->n_points;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_GlyphLoader_Create_Extra( FT_GlyphLoader* loader )
+ {
+ FT_Error error;
+ FT_Memory memory = loader->memory;
+
+
+ if ( !ALLOC_ARRAY( loader->base.extra_points,
+ loader->max_points, FT_Vector ) )
+ {
+ loader->use_extra = 1;
+ FT_GlyphLoader_Adjust_Points( loader );
+ }
+ return error;
+ }
+
+
+ /* re-adjust the `current' subglyphs field */
+ static void
+ FT_GlyphLoader_Adjust_Subglyphs( FT_GlyphLoader* loader )
+ {
+ FT_GlyphLoad* base = &loader->base;
+ FT_GlyphLoad* current = &loader->current;
+
+
+ current->subglyphs = base->subglyphs + base->num_subglyphs;
+ }
+
+
+ /* Ensure that we can add `n_points' and `n_contours' to our glyph. this */
+ /* function reallocates its outline tables if necessary. Note that it */
+ /* DOESN'T change the number of points within the loader! */
+ /* */
+ FT_BASE_DEF( FT_Error )
+ FT_GlyphLoader_Check_Points( FT_GlyphLoader* loader,
+ FT_UInt n_points,
+ FT_UInt n_contours )
+ {
+ FT_Memory memory = loader->memory;
+ FT_Error error = FT_Err_Ok;
+ FT_Outline* base = &loader->base.outline;
+ FT_Outline* current = &loader->current.outline;
+ FT_Bool adjust = 1;
+
+ FT_UInt new_max, old_max;
+
+
+ /* check points & tags */
+ new_max = base->n_points + current->n_points + n_points;
+ old_max = loader->max_points;
+
+ if ( new_max > old_max )
+ {
+ new_max = ( new_max + 7 ) & -8;
+
+ if ( REALLOC_ARRAY( base->points, old_max, new_max, FT_Vector ) ||
+ REALLOC_ARRAY( base->tags, old_max, new_max, FT_Byte ) )
+ goto Exit;
+
+ if ( loader->use_extra &&
+ REALLOC_ARRAY( loader->base.extra_points, old_max,
+ new_max, FT_Vector ) )
+ goto Exit;
+
+ adjust = 1;
+ loader->max_points = new_max;
+ }
+
+ /* check contours */
+ old_max = loader->max_contours;
+ new_max = base->n_contours + current->n_contours +
+ n_contours;
+ if ( new_max > old_max )
+ {
+ new_max = ( new_max + 3 ) & -4;
+ if ( REALLOC_ARRAY( base->contours, old_max, new_max, FT_Short ) )
+ goto Exit;
+
+ adjust = 1;
+ loader->max_contours = new_max;
+ }
+
+ if ( adjust )
+ FT_GlyphLoader_Adjust_Points( loader );
+
+ Exit:
+ return error;
+ }
+
+
+ /* Ensure that we can add `n_subglyphs' to our glyph. this function */
+ /* reallocates its subglyphs table if necessary. Note that it DOES */
+ /* NOT change the number of subglyphs within the loader! */
+ /* */
+ FT_BASE_DEF( FT_Error )
+ FT_GlyphLoader_Check_Subglyphs( FT_GlyphLoader* loader,
+ FT_UInt n_subs )
+ {
+ FT_Memory memory = loader->memory;
+ FT_Error error = FT_Err_Ok;
+ FT_UInt new_max, old_max;
+
+ FT_GlyphLoad* base = &loader->base;
+ FT_GlyphLoad* current = &loader->current;
+
+
+ new_max = base->num_subglyphs + current->num_subglyphs + n_subs;
+ old_max = loader->max_subglyphs;
+ if ( new_max > old_max )
+ {
+ new_max = ( new_max + 1 ) & -2;
+ if ( REALLOC_ARRAY( base->subglyphs, old_max, new_max, FT_SubGlyph ) )
+ goto Exit;
+
+ loader->max_subglyphs = new_max;
+
+ FT_GlyphLoader_Adjust_Subglyphs( loader );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /* prepare loader for the addition of a new glyph on top of the base one */
+ FT_BASE_DEF( void )
+ FT_GlyphLoader_Prepare( FT_GlyphLoader* loader )
+ {
+ FT_GlyphLoad* current = &loader->current;
+
+
+ current->outline.n_points = 0;
+ current->outline.n_contours = 0;
+ current->num_subglyphs = 0;
+
+ FT_GlyphLoader_Adjust_Points ( loader );
+ FT_GlyphLoader_Adjust_Subglyphs( loader );
+ }
+
+
+ /* add current glyph to the base image - and prepare for another */
+ FT_BASE_DEF( void )
+ FT_GlyphLoader_Add( FT_GlyphLoader* loader )
+ {
+ FT_GlyphLoad* base = &loader->base;
+ FT_GlyphLoad* current = &loader->current;
+
+ FT_UInt n_curr_contours = current->outline.n_contours;
+ FT_UInt n_base_points = base->outline.n_points;
+ FT_UInt n;
+
+
+ base->outline.n_points =
+ (short)( base->outline.n_points + current->outline.n_points );
+ base->outline.n_contours =
+ (short)( base->outline.n_contours + current->outline.n_contours );
+
+ base->num_subglyphs += current->num_subglyphs;
+
+ /* adjust contours count in newest outline */
+ for ( n = 0; n < n_curr_contours; n++ )
+ current->outline.contours[n] =
+ (short)( current->outline.contours[n] + n_base_points );
+
+ /* prepare for another new glyph image */
+ FT_GlyphLoader_Prepare( loader );
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_GlyphLoader_Copy_Points( FT_GlyphLoader* target,
+ FT_GlyphLoader* source )
+ {
+ FT_Error error;
+ FT_UInt num_points = source->base.outline.n_points;
+ FT_UInt num_contours = source->base.outline.n_contours;
+
+
+ error = FT_GlyphLoader_Check_Points( target, num_points, num_contours );
+ if ( !error )
+ {
+ FT_Outline* out = &target->base.outline;
+ FT_Outline* in = &source->base.outline;
+
+
+ MEM_Copy( out->points, in->points,
+ num_points * sizeof ( FT_Vector ) );
+ MEM_Copy( out->tags, in->tags,
+ num_points * sizeof ( char ) );
+ MEM_Copy( out->contours, in->contours,
+ num_contours * sizeof ( short ) );
+
+ /* do we need to copy the extra points? */
+ if ( target->use_extra && source->use_extra )
+ MEM_Copy( target->base.extra_points, source->base.extra_points,
+ num_points * sizeof ( FT_Vector ) );
+
+ out->n_points = (short)num_points;
+ out->n_contours = (short)num_contours;
+
+ FT_GlyphLoader_Adjust_Points( target );
+ }
+
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** FACE, SIZE & GLYPH SLOT OBJECTS ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ static FT_Error
+ ft_glyphslot_init( FT_GlyphSlot slot )
+ {
+ FT_Driver driver = slot->face->driver;
+ FT_Driver_Class* clazz = driver->clazz;
+ FT_Memory memory = driver->root.memory;
+ FT_Error error = FT_Err_Ok;
+ FT_Slot_Internal internal;
+
+
+ slot->library = driver->root.library;
+
+ if ( ALLOC( internal, sizeof ( *internal ) ) )
+ goto Exit;
+
+ slot->internal = internal;
+
+ if ( FT_DRIVER_USES_OUTLINES( driver ) )
+ error = FT_GlyphLoader_New( memory, &internal->loader );
+
+ if ( !error && clazz->init_slot )
+ error = clazz->init_slot( slot );
+
+ Exit:
+ return error;
+ }
+
+
+ static void
+ ft_glyphslot_clear( FT_GlyphSlot slot )
+ {
+ /* free bitmap if needed */
+ if ( slot->flags & ft_glyph_own_bitmap )
+ {
+ FT_Memory memory = FT_FACE_MEMORY( slot->face );
+
+
+ FREE( slot->bitmap.buffer );
+ slot->flags &= ~ft_glyph_own_bitmap;
+ }
+
+ /* clear all public fields in the glyph slot */
+ MEM_Set( &slot->metrics, 0, sizeof ( slot->metrics ) );
+ MEM_Set( &slot->outline, 0, sizeof ( slot->outline ) );
+ MEM_Set( &slot->bitmap, 0, sizeof ( slot->bitmap ) );
+
+ slot->bitmap_left = 0;
+ slot->bitmap_top = 0;
+ slot->num_subglyphs = 0;
+ slot->subglyphs = 0;
+ slot->control_data = 0;
+ slot->control_len = 0;
+ slot->other = 0;
+ slot->format = ft_glyph_format_none;
+
+ slot->linearHoriAdvance = 0;
+ slot->linearVertAdvance = 0;
+ }
+
+
+ static void
+ ft_glyphslot_done( FT_GlyphSlot slot )
+ {
+ FT_Driver driver = slot->face->driver;
+ FT_Driver_Class* clazz = driver->clazz;
+ FT_Memory memory = driver->root.memory;
+
+
+ if ( clazz->done_slot )
+ clazz->done_slot( slot );
+
+ /* free bitmap buffer if needed */
+ if ( slot->flags & ft_glyph_own_bitmap )
+ FREE( slot->bitmap.buffer );
+
+ /* free glyph loader */
+ if ( FT_DRIVER_USES_OUTLINES( driver ) )
+ {
+ FT_GlyphLoader_Done( slot->internal->loader );
+ slot->internal->loader = 0;
+ }
+
+ FREE( slot->internal );
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_BASE_DEF( FT_Error )
+ FT_New_GlyphSlot( FT_Face face,
+ FT_GlyphSlot *aslot )
+ {
+ FT_Error error;
+ FT_Driver driver;
+ FT_Driver_Class* clazz;
+ FT_Memory memory;
+ FT_GlyphSlot slot;
+
+
+ if ( !face || !aslot || !face->driver )
+ return FT_Err_Invalid_Argument;
+
+ *aslot = 0;
+
+ driver = face->driver;
+ clazz = driver->clazz;
+ memory = driver->root.memory;
+
+ FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" ));
+ if ( !ALLOC( slot, clazz->slot_object_size ) )
+ {
+ slot->face = face;
+
+ error = ft_glyphslot_init( slot );
+ if ( error )
+ {
+ ft_glyphslot_done( slot );
+ FREE( slot );
+ goto Exit;
+ }
+
+ *aslot = slot;
+ }
+
+ Exit:
+ FT_TRACE4(( "FT_New_GlyphSlot: Return %d\n", error ));
+ return error;
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_BASE_DEF( void )
+ FT_Done_GlyphSlot( FT_GlyphSlot slot )
+ {
+ if ( slot )
+ {
+ FT_Driver driver = slot->face->driver;
+ FT_Memory memory = driver->root.memory;
+ FT_GlyphSlot* parent;
+ FT_GlyphSlot cur;
+
+
+ /* Remove slot from its parent face's list */
+ parent = &slot->face->glyph;
+ cur = *parent;
+
+ while ( cur )
+ {
+ if ( cur == slot )
+ {
+ *parent = cur->next;
+ ft_glyphslot_done( slot );
+ FREE( slot );
+ break;
+ }
+ cur = cur->next;
+ }
+ }
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Set_Transform( FT_Face face,
+ FT_Matrix* matrix,
+ FT_Vector* delta )
+ {
+ FT_Face_Internal internal;
+
+
+ if ( !face )
+ return;
+
+ internal = face->internal;
+
+ internal->transform_flags = 0;
+
+ if ( !matrix )
+ {
+ internal->transform_matrix.xx = 0x10000L;
+ internal->transform_matrix.xy = 0;
+ internal->transform_matrix.yx = 0;
+ internal->transform_matrix.yy = 0x10000L;
+ matrix = &internal->transform_matrix;
+ }
+ else
+ internal->transform_matrix = *matrix;
+
+ /* set transform_flags bit flag 0 if `matrix' isn't the identity */
+ if ( ( matrix->xy | matrix->yx ) ||
+ matrix->xx != 0x10000L ||
+ matrix->yy != 0x10000L )
+ internal->transform_flags |= 1;
+
+ if ( !delta )
+ {
+ internal->transform_delta.x = 0;
+ internal->transform_delta.y = 0;
+ delta = &internal->transform_delta;
+ }
+ else
+ internal->transform_delta = *delta;
+
+ /* set transform_flags bit flag 1 if `delta' isn't the null vector */
+ if ( delta->x | delta->y )
+ internal->transform_flags |= 2;
+ }
+
+
+ static FT_Renderer
+ ft_lookup_glyph_renderer( FT_GlyphSlot slot );
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Load_Glyph( FT_Face face,
+ FT_UInt glyph_index,
+ FT_Int load_flags )
+ {
+ FT_Error error;
+ FT_Driver driver;
+ FT_GlyphSlot slot;
+ FT_Library library;
+ FT_Bool autohint;
+ FT_Module hinter;
+
+
+ if ( !face || !face->size || !face->glyph )
+ return FT_Err_Invalid_Face_Handle;
+
+ if ( glyph_index >= (FT_UInt)face->num_glyphs )
+ return FT_Err_Invalid_Argument;
+
+ slot = face->glyph;
+ ft_glyphslot_clear( slot );
+
+ driver = face->driver;
+
+ /* when the flag NO_RECURSE is set, we disable hinting and scaling */
+ if ( load_flags & FT_LOAD_NO_RECURSE )
+ {
+ /* disable scaling, hinting, and transformation */
+ load_flags |= FT_LOAD_NO_SCALE |
+ FT_LOAD_NO_HINTING |
+ FT_LOAD_IGNORE_TRANSFORM;
+
+ /* disable bitmap rendering */
+ load_flags &= ~FT_LOAD_RENDER;
+ }
+
+ /* do we need to load the glyph through the auto-hinter? */
+ library = driver->root.library;
+ hinter = library->auto_hinter;
+ autohint =
+ FT_BOOL( hinter &&
+ !( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING ) ) &&
+ FT_DRIVER_IS_SCALABLE( driver ) &&
+ FT_DRIVER_USES_OUTLINES( driver ) );
+ if ( autohint )
+ {
+ if ( FT_DRIVER_HAS_HINTER( driver ) &&
+ !( load_flags & FT_LOAD_FORCE_AUTOHINT ) )
+ autohint = 0;
+ }
+
+ if ( autohint )
+ {
+ FT_AutoHinter_Interface* hinting;
+
+
+ hinting = (FT_AutoHinter_Interface*)hinter->clazz->module_interface;
+
+ error = hinting->load_glyph( (FT_AutoHinter)hinter,
+ slot, face->size,
+ glyph_index, load_flags );
+ }
+ else
+ error = driver->clazz->load_glyph( slot,
+ face->size,
+ glyph_index,
+ load_flags );
+ if ( error )
+ goto Exit;
+
+ /* compute the advance */
+ if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
+ {
+ slot->advance.x = 0;
+ slot->advance.y = slot->metrics.vertAdvance;
+ }
+ else
+ {
+ slot->advance.x = slot->metrics.horiAdvance;
+ slot->advance.y = 0;
+ }
+
+ /* compute the linear advance in 16.16 pixels */
+ if ( ( load_flags & FT_LOAD_LINEAR_DESIGN ) == 0 )
+ {
+ FT_UInt EM = face->units_per_EM;
+ FT_Size_Metrics* metrics = &face->size->metrics;
+
+ slot->linearHoriAdvance = FT_MulDiv( slot->linearHoriAdvance,
+ (FT_Long)metrics->x_ppem << 16, EM );
+
+ slot->linearVertAdvance = FT_MulDiv( slot->linearVertAdvance,
+ (FT_Long)metrics->y_ppem << 16, EM );
+ }
+
+ if ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) == 0 )
+ {
+ FT_Face_Internal internal = face->internal;
+
+
+ /* now, transform the glyph image if needed */
+ if ( internal->transform_flags )
+ {
+ /* get renderer */
+ FT_Renderer renderer = ft_lookup_glyph_renderer( slot );
+
+
+ if ( renderer )
+ error = renderer->clazz->transform_glyph(
+ renderer, slot,
+ &internal->transform_matrix,
+ &internal->transform_delta );
+ /* transform advance */
+ FT_Vector_Transform( &slot->advance, &internal->transform_matrix );
+ }
+ }
+
+ /* do we need to render the image now? */
+ if ( !error &&
+ slot->format != ft_glyph_format_bitmap &&
+ slot->format != ft_glyph_format_composite &&
+ load_flags & FT_LOAD_RENDER )
+ {
+ error = FT_Render_Glyph( slot,
+ ( load_flags & FT_LOAD_MONOCHROME )
+ ? ft_render_mode_mono
+ : ft_render_mode_normal );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Load_Char( FT_Face face,
+ FT_ULong char_code,
+ FT_Int load_flags )
+ {
+ FT_UInt glyph_index;
+
+
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ glyph_index = (FT_UInt)char_code;
+ if ( face->charmap )
+ glyph_index = FT_Get_Char_Index( face, char_code );
+
+ return FT_Load_Glyph( face, glyph_index, load_flags );
+ }
+
+
+ /* destructor for sizes list */
+ static void
+ destroy_size( FT_Memory memory,
+ FT_Size size,
+ FT_Driver driver )
+ {
+ /* finalize client-specific data */
+ if ( size->generic.finalizer )
+ size->generic.finalizer( size );
+
+ /* finalize format-specific stuff */
+ if ( driver->clazz->done_size )
+ driver->clazz->done_size( size );
+
+ FREE( size->internal );
+ FREE( size );
+ }
+
+
+ /* destructor for faces list */
+ static void
+ destroy_face( FT_Memory memory,
+ FT_Face face,
+ FT_Driver driver )
+ {
+ FT_Driver_Class* clazz = driver->clazz;
+
+
+ /* discard auto-hinting data */
+ if ( face->autohint.finalizer )
+ face->autohint.finalizer( face->autohint.data );
+
+ /* Discard glyph slots for this face */
+ /* Beware! FT_Done_GlyphSlot() changes the field `face->glyph' */
+ while ( face->glyph )
+ FT_Done_GlyphSlot( face->glyph );
+
+ /* Discard all sizes for this face */
+ FT_List_Finalize( &face->sizes_list,
+ (FT_List_Destructor)destroy_size,
+ memory,
+ driver );
+ face->size = 0;
+
+ /* Now discard client data */
+ if ( face->generic.finalizer )
+ face->generic.finalizer( face );
+
+ /* finalize format-specific stuff */
+ if ( clazz->done_face )
+ clazz->done_face( face );
+
+ /* close the stream for this face if needed */
+ ft_done_stream(
+ &face->stream,
+ ( face->face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 );
+
+ /* get rid of it */
+ if ( face->internal )
+ {
+ FREE( face->internal->postscript_name );
+ FREE( face->internal );
+ }
+ FREE( face );
+ }
+
+
+ static void
+ Destroy_Driver( FT_Driver driver )
+ {
+ FT_List_Finalize( &driver->faces_list,
+ (FT_List_Destructor)destroy_face,
+ driver->root.memory,
+ driver );
+
+ /* check whether we need to drop the driver's glyph loader */
+ if ( FT_DRIVER_USES_OUTLINES( driver ) )
+ FT_GlyphLoader_Done( driver->glyph_loader );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* open_face */
+ /* */
+ /* <Description> */
+ /* This function does some work for FT_Open_Face(). */
+ /* */
+ static FT_Error
+ open_face( FT_Driver driver,
+ FT_Stream stream,
+ FT_Long face_index,
+ FT_Int num_params,
+ FT_Parameter* params,
+ FT_Face* aface )
+ {
+ FT_Memory memory;
+ FT_Driver_Class* clazz;
+ FT_Face face = 0;
+ FT_Error error;
+ FT_Face_Internal internal;
+
+
+ clazz = driver->clazz;
+ memory = driver->root.memory;
+
+ /* allocate the face object and perform basic initialization */
+ if ( ALLOC( face, clazz->face_object_size ) )
+ goto Fail;
+
+ if ( ALLOC( internal, sizeof ( *internal ) ) )
+ goto Fail;
+
+ face->internal = internal;
+
+ face->driver = driver;
+ face->memory = memory;
+ face->stream = stream;
+
+ error = clazz->init_face( stream,
+ face,
+ face_index,
+ num_params,
+ params );
+ if ( error )
+ goto Fail;
+
+ *aface = face;
+
+ Fail:
+ if ( error )
+ {
+ clazz->done_face( face );
+ FREE( face->internal );
+ FREE( face );
+ *aface = 0;
+ }
+
+ return error;
+ }
+
+
+ /* there's a Mac-specific extended implementation of FT_New_Face() */
+ /* in src/mac/ftmac.c */
+
+#ifndef macintosh
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_New_Face( FT_Library library,
+ const char* pathname,
+ FT_Long face_index,
+ FT_Face *aface )
+ {
+ FT_Open_Args args;
+
+
+ /* test for valid `library' and `aface' delayed to FT_Open_Face() */
+ if ( !pathname )
+ return FT_Err_Invalid_Argument;
+
+ args.flags = ft_open_pathname;
+ args.pathname = (char*)pathname;
+
+ return FT_Open_Face( library, &args, face_index, aface );
+ }
+
+#endif /* !macintosh */
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_New_Memory_Face( FT_Library library,
+ const FT_Byte* file_base,
+ FT_Long file_size,
+ FT_Long face_index,
+ FT_Face *aface )
+ {
+ FT_Open_Args args;
+
+
+ /* test for valid `library' and `face' delayed to FT_Open_Face() */
+ if ( !file_base )
+ return FT_Err_Invalid_Argument;
+
+ args.flags = ft_open_memory;
+ args.memory_base = file_base;
+ args.memory_size = file_size;
+
+ return FT_Open_Face( library, &args, face_index, aface );
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Open_Face( FT_Library library,
+ FT_Open_Args* args,
+ FT_Long face_index,
+ FT_Face *aface )
+ {
+ FT_Error error;
+ FT_Driver driver;
+ FT_Memory memory;
+ FT_Stream stream;
+ FT_Face face = 0;
+ FT_ListNode node = 0;
+ FT_Bool external_stream;
+
+
+ /* test for valid `library' delayed to */
+ /* ft_new_input_stream() */
+
+ if ( !aface || !args )
+ return FT_Err_Invalid_Argument;
+
+ *aface = 0;
+
+ external_stream = FT_BOOL( ( args->flags & ft_open_stream ) &&
+ args->stream );
+
+ /* create input stream */
+ error = ft_new_input_stream( library, args, &stream );
+ if ( error )
+ goto Exit;
+
+ memory = library->memory;
+
+ /* If the font driver is specified in the `args' structure, use */
+ /* it. Otherwise, we scan the list of registered drivers. */
+ if ( ( args->flags & ft_open_driver ) && args->driver )
+ {
+ driver = FT_DRIVER( args->driver );
+
+ /* not all modules are drivers, so check... */
+ if ( FT_MODULE_IS_DRIVER( driver ) )
+ {
+ FT_Int num_params = 0;
+ FT_Parameter* params = 0;
+
+
+ if ( args->flags & ft_open_params )
+ {
+ num_params = args->num_params;
+ params = args->params;
+ }
+
+ error = open_face( driver, stream, face_index,
+ num_params, params, &face );
+ if ( !error )
+ goto Success;
+ }
+ else
+ error = FT_Err_Invalid_Handle;
+
+ ft_done_stream( &stream, external_stream );
+ goto Fail;
+ }
+ else
+ {
+ /* check each font driver for an appropriate format */
+ FT_Module* cur = library->modules;
+ FT_Module* limit = cur + library->num_modules;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ /* not all modules are font drivers, so check... */
+ if ( FT_MODULE_IS_DRIVER( cur[0] ) )
+ {
+ FT_Int num_params = 0;
+ FT_Parameter* params = 0;
+
+
+ driver = FT_DRIVER( cur[0] );
+
+ if ( args->flags & ft_open_params )
+ {
+ num_params = args->num_params;
+ params = args->params;
+ }
+
+ error = open_face( driver, stream, face_index,
+ num_params, params, &face );
+ if ( !error )
+ goto Success;
+
+ if ( FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format )
+ goto Fail2;
+ }
+ }
+
+ /* no driver is able to handle this format */
+ error = FT_Err_Unknown_File_Format;
+
+ Fail2:
+ ft_done_stream( &stream, external_stream );
+ goto Fail;
+ }
+
+ Success:
+ FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" ));
+
+ /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */
+ if ( external_stream )
+ face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM;
+
+ /* add the face object to its driver's list */
+ if ( ALLOC( node, sizeof ( *node ) ) )
+ goto Fail;
+
+ node->data = face;
+ /* don't assume driver is the same as face->driver, so use */
+ /* face->driver instead. */
+ FT_List_Add( &face->driver->faces_list, node );
+
+ /* now allocate a glyph slot object for the face */
+ {
+ FT_GlyphSlot slot;
+
+
+ FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" ));
+
+ error = FT_New_GlyphSlot( face, &slot );
+ if ( error )
+ goto Fail;
+
+ face->glyph = slot;
+ }
+
+ /* finally, allocate a size object for the face */
+ {
+ FT_Size size;
+
+
+ FT_TRACE4(( "FT_Open_Face: Creating size object\n" ));
+
+ error = FT_New_Size( face, &size );
+ if ( error )
+ goto Fail;
+
+ face->size = size;
+ }
+
+ /* initialize internal face data */
+ {
+ FT_Face_Internal internal = face->internal;
+
+
+ internal->transform_matrix.xx = 0x10000L;
+ internal->transform_matrix.xy = 0;
+ internal->transform_matrix.yx = 0;
+ internal->transform_matrix.yy = 0x10000L;
+
+ internal->transform_delta.x = 0;
+ internal->transform_delta.y = 0;
+ }
+
+ *aface = face;
+ goto Exit;
+
+ Fail:
+ FT_Done_Face( face );
+
+ Exit:
+ FT_TRACE4(( "FT_Open_Face: Return %d\n", error ));
+
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Attach_File( FT_Face face,
+ const char* filepathname )
+ {
+ FT_Open_Args open;
+
+
+ /* test for valid `face' delayed to FT_Attach_Stream() */
+
+ if ( !filepathname )
+ return FT_Err_Invalid_Argument;
+
+ open.flags = ft_open_pathname;
+ open.pathname = (char*)filepathname;
+
+ return FT_Attach_Stream( face, &open );
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Attach_Stream( FT_Face face,
+ FT_Open_Args* parameters )
+ {
+ FT_Stream stream;
+ FT_Error error;
+ FT_Driver driver;
+
+ FT_Driver_Class* clazz;
+
+
+ /* test for valid `parameters' delayed to ft_new_input_stream() */
+
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ driver = face->driver;
+ if ( !driver )
+ return FT_Err_Invalid_Driver_Handle;
+
+ error = ft_new_input_stream( driver->root.library, parameters, &stream );
+ if ( error )
+ goto Exit;
+
+ /* we implement FT_Attach_Stream in each driver through the */
+ /* `attach_file' interface */
+
+ error = FT_Err_Unimplemented_Feature;
+ clazz = driver->clazz;
+ if ( clazz->attach_file )
+ error = clazz->attach_file( face, stream );
+
+ /* close the attached stream */
+ ft_done_stream( &stream,
+ (FT_Bool)( parameters->stream &&
+ ( parameters->flags & ft_open_stream ) ) );
+
+ Exit:
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Done_Face( FT_Face face )
+ {
+ FT_Error error;
+ FT_Driver driver;
+ FT_Memory memory;
+ FT_ListNode node;
+
+
+ error = FT_Err_Invalid_Face_Handle;
+ if ( face && face->driver )
+ {
+ driver = face->driver;
+ memory = driver->root.memory;
+
+ /* find face in driver's list */
+ node = FT_List_Find( &driver->faces_list, face );
+ if ( node )
+ {
+ /* remove face object from the driver's list */
+ FT_List_Remove( &driver->faces_list, node );
+ FREE( node );
+
+ /* now destroy the object proper */
+ destroy_face( memory, face, driver );
+ error = FT_Err_Ok;
+ }
+ }
+ return error;
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_New_Size( FT_Face face,
+ FT_Size *asize )
+ {
+ FT_Error error;
+ FT_Memory memory;
+ FT_Driver driver;
+ FT_Driver_Class* clazz;
+
+ FT_Size size = 0;
+ FT_ListNode node = 0;
+
+
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ if ( !asize )
+ return FT_Err_Invalid_Size_Handle;
+
+ if ( !face->driver )
+ return FT_Err_Invalid_Driver_Handle;
+
+ *asize = 0;
+
+ driver = face->driver;
+ clazz = driver->clazz;
+ memory = face->memory;
+
+ /* Allocate new size object and perform basic initialisation */
+ if ( ALLOC( size, clazz->size_object_size ) ||
+ ALLOC( node, sizeof ( FT_ListNodeRec ) ) )
+ goto Exit;
+
+ size->face = face;
+
+ /* for now, do not use any internal fields in size objects */
+ size->internal = 0;
+
+ if ( clazz->init_size )
+ error = clazz->init_size( size );
+
+ /* in case of success, add to the face's list */
+ if ( !error )
+ {
+ *asize = size;
+ node->data = size;
+ FT_List_Add( &face->sizes_list, node );
+ }
+
+ Exit:
+ if ( error )
+ {
+ FREE( node );
+ FREE( size );
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Done_Size( FT_Size size )
+ {
+ FT_Error error;
+ FT_Driver driver;
+ FT_Memory memory;
+ FT_Face face;
+ FT_ListNode node;
+
+
+ if ( !size )
+ return FT_Err_Invalid_Size_Handle;
+
+ face = size->face;
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ driver = face->driver;
+ if ( !driver )
+ return FT_Err_Invalid_Driver_Handle;
+
+ memory = driver->root.memory;
+
+ error = FT_Err_Ok;
+ node = FT_List_Find( &face->sizes_list, size );
+ if ( node )
+ {
+ FT_List_Remove( &face->sizes_list, node );
+ FREE( node );
+
+ if ( face->size == size )
+ {
+ face->size = 0;
+ if ( face->sizes_list.head )
+ face->size = (FT_Size)(face->sizes_list.head->data);
+ }
+
+ destroy_size( memory, size, driver );
+ }
+ else
+ error = FT_Err_Invalid_Size_Handle;
+
+ return error;
+ }
+
+
+ static void
+ ft_recompute_scaled_metrics( FT_Face face,
+ FT_Size_Metrics* metrics )
+ {
+ /* Compute root ascender, descender, test height, and max_advance */
+
+ metrics->ascender = ( FT_MulFix( face->ascender,
+ metrics->y_scale ) + 32 ) & -64;
+
+ metrics->descender = ( FT_MulFix( face->descender,
+ metrics->y_scale ) + 32 ) & -64;
+
+ metrics->height = ( FT_MulFix( face->height,
+ metrics->y_scale ) + 32 ) & -64;
+
+ metrics->max_advance = ( FT_MulFix( face->max_advance_width,
+ metrics->x_scale ) + 32 ) & -64;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Set_Char_Size( FT_Face face,
+ FT_F26Dot6 char_width,
+ FT_F26Dot6 char_height,
+ FT_UInt horz_resolution,
+ FT_UInt vert_resolution )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_Driver driver;
+ FT_Driver_Class* clazz;
+ FT_Size_Metrics* metrics;
+ FT_Long dim_x, dim_y;
+
+
+ if ( !face || !face->size || !face->driver )
+ return FT_Err_Invalid_Face_Handle;
+
+ driver = face->driver;
+ metrics = &face->size->metrics;
+
+ if ( !char_width )
+ char_width = char_height;
+
+ else if ( !char_height )
+ char_height = char_width;
+
+ if ( !horz_resolution )
+ horz_resolution = 72;
+
+ if ( !vert_resolution )
+ vert_resolution = 72;
+
+ driver = face->driver;
+ clazz = driver->clazz;
+
+ /* default processing -- this can be overridden by the driver */
+ if ( char_width < 1 * 64 )
+ char_width = 1 * 64;
+ if ( char_height < 1 * 64 )
+ char_height = 1 * 64;
+
+ /* Compute pixel sizes in 26.6 units */
+ dim_x = ( ( ( char_width * horz_resolution ) / 72 ) + 32 ) & -64;
+ dim_y = ( ( ( char_height * vert_resolution ) / 72 ) + 32 ) & -64;
+
+ metrics->x_ppem = (FT_UShort)( dim_x >> 6 );
+ metrics->y_ppem = (FT_UShort)( dim_y >> 6 );
+
+ metrics->x_scale = 0x10000L;
+ metrics->y_scale = 0x10000L;
+
+ if ( face->face_flags & FT_FACE_FLAG_SCALABLE )
+ {
+ metrics->x_scale = FT_DivFix( dim_x, face->units_per_EM );
+ metrics->y_scale = FT_DivFix( dim_y, face->units_per_EM );
+
+ ft_recompute_scaled_metrics( face, metrics );
+ }
+
+ if ( clazz->set_char_sizes )
+ error = clazz->set_char_sizes( face->size,
+ char_width,
+ char_height,
+ horz_resolution,
+ vert_resolution );
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Set_Pixel_Sizes( FT_Face face,
+ FT_UInt pixel_width,
+ FT_UInt pixel_height )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_Driver driver;
+ FT_Driver_Class* clazz;
+ FT_Size_Metrics* metrics = &face->size->metrics;
+
+
+ if ( !face || !face->size || !face->driver )
+ return FT_Err_Invalid_Face_Handle;
+
+ driver = face->driver;
+ clazz = driver->clazz;
+
+ /* default processing -- this can be overridden by the driver */
+ if ( pixel_width == 0 )
+ pixel_width = pixel_height;
+
+ else if ( pixel_height == 0 )
+ pixel_height = pixel_width;
+
+ if ( pixel_width < 1 )
+ pixel_width = 1;
+ if ( pixel_height < 1 )
+ pixel_height = 1;
+
+ metrics->x_ppem = (FT_UShort)pixel_width;
+ metrics->y_ppem = (FT_UShort)pixel_height;
+
+ if ( face->face_flags & FT_FACE_FLAG_SCALABLE )
+ {
+ metrics->x_scale = FT_DivFix( metrics->x_ppem << 6,
+ face->units_per_EM );
+
+ metrics->y_scale = FT_DivFix( metrics->y_ppem << 6,
+ face->units_per_EM );
+
+ ft_recompute_scaled_metrics( face, metrics );
+ }
+
+ if ( clazz->set_pixel_sizes )
+ error = clazz->set_pixel_sizes( face->size,
+ pixel_width,
+ pixel_height );
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_Kerning( FT_Face face,
+ FT_UInt left_glyph,
+ FT_UInt right_glyph,
+ FT_UInt kern_mode,
+ FT_Vector *akerning )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_Driver driver;
+
+
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ if ( !akerning )
+ return FT_Err_Invalid_Argument;
+
+ driver = face->driver;
+
+ akerning->x = 0;
+ akerning->y = 0;
+
+ if ( driver->clazz->get_kerning )
+ {
+ error = driver->clazz->get_kerning( face,
+ left_glyph,
+ right_glyph,
+ akerning );
+ if ( !error )
+ {
+ if ( kern_mode != ft_kerning_unscaled )
+ {
+ akerning->x = FT_MulFix( akerning->x, face->size->metrics.x_scale );
+ akerning->y = FT_MulFix( akerning->y, face->size->metrics.y_scale );
+
+ if ( kern_mode != ft_kerning_unfitted )
+ {
+ akerning->x = ( akerning->x + 32 ) & -64;
+ akerning->y = ( akerning->y + 32 ) & -64;
+ }
+ }
+ }
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Select_Charmap( FT_Face face,
+ FT_Encoding encoding )
+ {
+ FT_CharMap* cur;
+ FT_CharMap* limit;
+
+
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ cur = face->charmaps;
+ if ( !cur )
+ return FT_Err_Invalid_CharMap_Handle;
+
+ limit = cur + face->num_charmaps;
+
+ for ( ; cur < limit; cur++ )
+ {
+ if ( cur[0]->encoding == encoding )
+ {
+ face->charmap = cur[0];
+ return 0;
+ }
+ }
+
+ return FT_Err_Invalid_Argument;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Set_Charmap( FT_Face face,
+ FT_CharMap charmap )
+ {
+ FT_CharMap* cur;
+ FT_CharMap* limit;
+
+
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ cur = face->charmaps;
+ if ( !cur )
+ return FT_Err_Invalid_CharMap_Handle;
+
+ limit = cur + face->num_charmaps;
+
+ for ( ; cur < limit; cur++ )
+ {
+ if ( cur[0] == charmap )
+ {
+ face->charmap = cur[0];
+ return 0;
+ }
+ }
+ return FT_Err_Invalid_Argument;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_UInt )
+ FT_Get_Char_Index( FT_Face face,
+ FT_ULong charcode )
+ {
+ FT_UInt result;
+ FT_Driver driver;
+
+
+ result = 0;
+ if ( face && face->charmap )
+ {
+ driver = face->driver;
+ result = driver->clazz->get_char_index( face->charmap, charcode );
+ }
+ return result;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_UInt )
+ FT_Get_Name_Index( FT_Face face,
+ FT_String* glyph_name )
+ {
+ FT_UInt result = 0;
+
+
+ if ( face && FT_HAS_GLYPH_NAMES( face ) )
+ {
+ /* now, lookup for glyph name */
+ FT_Driver driver = face->driver;
+ FT_Module_Class* clazz = FT_MODULE_CLASS( driver );
+
+
+ if ( clazz->get_interface )
+ {
+ FT_Name_Index_Requester requester;
+
+
+ requester = (FT_Name_Index_Requester)clazz->get_interface(
+ FT_MODULE( driver ), "name_index" );
+ if ( requester )
+ result = requester( face, glyph_name );
+ }
+ }
+
+ return result;
+ }
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_Glyph_Name( FT_Face face,
+ FT_UInt glyph_index,
+ FT_Pointer buffer,
+ FT_UInt buffer_max )
+ {
+ FT_Error error = FT_Err_Invalid_Argument;
+
+
+ /* clean up buffer */
+ if ( buffer && buffer_max > 0 )
+ ((FT_Byte*)buffer)[0] = 0;
+
+ if ( face &&
+ glyph_index < (FT_UInt)face->num_glyphs &&
+ FT_HAS_GLYPH_NAMES( face ) )
+ {
+ /* now, lookup for glyph name */
+ FT_Driver driver = face->driver;
+ FT_Module_Class* clazz = FT_MODULE_CLASS( driver );
+
+
+ if ( clazz->get_interface )
+ {
+ FT_Glyph_Name_Requester requester;
+
+
+ requester = (FT_Glyph_Name_Requester)clazz->get_interface(
+ FT_MODULE( driver ), "glyph_name" );
+ if ( requester )
+ error = requester( face, glyph_index, buffer, buffer_max );
+ }
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( const char* )
+ FT_Get_Postscript_Name( FT_Face face )
+ {
+ const char* result = NULL;
+
+ if ( !face )
+ goto Exit;
+
+ result = face->internal->postscript_name;
+ if ( !result )
+ {
+ /* now, lookup for glyph name */
+ FT_Driver driver = face->driver;
+ FT_Module_Class* clazz = FT_MODULE_CLASS( driver );
+
+ if ( clazz->get_interface )
+ {
+ FT_PSName_Requester requester;
+
+ requester = (FT_PSName_Requester)clazz->get_interface(
+ FT_MODULE( driver ), "postscript_name" );
+ if ( requester )
+ result = requester( face );
+ }
+ }
+ Exit:
+ return result;
+ }
+
+
+ /* documentation is in tttables.h */
+
+ FT_EXPORT_DEF( void* )
+ FT_Get_Sfnt_Table( FT_Face face,
+ FT_Sfnt_Tag tag )
+ {
+ void* table = 0;
+ FT_Get_Sfnt_Table_Func func;
+ FT_Driver driver;
+
+
+ if ( !face || !FT_IS_SFNT( face ) )
+ goto Exit;
+
+ driver = face->driver;
+ func = (FT_Get_Sfnt_Table_Func)driver->root.clazz->get_interface(
+ FT_MODULE( driver ), "get_sfnt" );
+ if ( func )
+ table = func( face, tag );
+
+ Exit:
+ return table;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Activate_Size( FT_Size size )
+ {
+ FT_Face face;
+
+
+ if ( size == NULL )
+ return FT_Err_Bad_Argument;
+
+ face = size->face;
+ if ( face == NULL || face->driver == NULL )
+ return FT_Err_Bad_Argument;
+
+ /* we don't need anything more complex than that; all size objects */
+ /* are already listed by the face */
+ face->size = size;
+
+ return FT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** R E N D E R E R S ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* lookup a renderer by glyph format in the library's list */
+ FT_BASE_DEF( FT_Renderer )
+ FT_Lookup_Renderer( FT_Library library,
+ FT_Glyph_Format format,
+ FT_ListNode* node )
+ {
+ FT_ListNode cur;
+ FT_Renderer result = 0;
+
+
+ if ( !library )
+ goto Exit;
+
+ cur = library->renderers.head;
+
+ if ( node )
+ {
+ if ( *node )
+ cur = (*node)->next;
+ *node = 0;
+ }
+
+ while ( cur )
+ {
+ FT_Renderer renderer = FT_RENDERER( cur->data );
+
+
+ if ( renderer->glyph_format == format )
+ {
+ if ( node )
+ *node = cur;
+
+ result = renderer;
+ break;
+ }
+ cur = cur->next;
+ }
+
+ Exit:
+ return result;
+ }
+
+
+ static FT_Renderer
+ ft_lookup_glyph_renderer( FT_GlyphSlot slot )
+ {
+ FT_Face face = slot->face;
+ FT_Library library = FT_FACE_LIBRARY( face );
+ FT_Renderer result = library->cur_renderer;
+
+
+ if ( !result || result->glyph_format != slot->format )
+ result = FT_Lookup_Renderer( library, slot->format, 0 );
+
+ return result;
+ }
+
+
+ static void
+ ft_set_current_renderer( FT_Library library )
+ {
+ FT_Renderer renderer;
+
+
+ renderer = FT_Lookup_Renderer( library, ft_glyph_format_outline, 0 );
+ library->cur_renderer = renderer;
+ }
+
+
+ static FT_Error
+ ft_add_renderer( FT_Module module )
+ {
+ FT_Library library = module->library;
+ FT_Memory memory = library->memory;
+ FT_Error error;
+ FT_ListNode node;
+
+
+ if ( ALLOC( node, sizeof ( *node ) ) )
+ goto Exit;
+
+ {
+ FT_Renderer render = FT_RENDERER( module );
+ FT_Renderer_Class* clazz = (FT_Renderer_Class*)module->clazz;
+
+
+ render->clazz = clazz;
+ render->glyph_format = clazz->glyph_format;
+
+ /* allocate raster object if needed */
+ if ( clazz->glyph_format == ft_glyph_format_outline &&
+ clazz->raster_class->raster_new )
+ {
+ error = clazz->raster_class->raster_new( memory, &render->raster );
+ if ( error )
+ goto Fail;
+
+ render->raster_render = clazz->raster_class->raster_render;
+ render->render = clazz->render_glyph;
+ }
+
+ /* add to list */
+ node->data = module;
+ FT_List_Add( &library->renderers, node );
+
+ ft_set_current_renderer( library );
+ }
+
+ Fail:
+ if ( error )
+ FREE( node );
+
+ Exit:
+ return error;
+ }
+
+
+ static void
+ ft_remove_renderer( FT_Module module )
+ {
+ FT_Library library = module->library;
+ FT_Memory memory = library->memory;
+ FT_ListNode node;
+
+
+ node = FT_List_Find( &library->renderers, module );
+ if ( node )
+ {
+ FT_Renderer render = FT_RENDERER( module );
+
+
+ /* release raster object, if any */
+ if ( render->raster )
+ render->clazz->raster_class->raster_done( render->raster );
+
+ /* remove from list */
+ FT_List_Remove( &library->renderers, node );
+ FREE( node );
+
+ ft_set_current_renderer( library );
+ }
+ }
+
+
+ /* documentation is in ftrender.h */
+
+ FT_EXPORT_DEF( FT_Renderer )
+ FT_Get_Renderer( FT_Library library,
+ FT_Glyph_Format format )
+ {
+ /* test for valid `library' delayed to FT_Lookup_Renderer() */
+
+ return FT_Lookup_Renderer( library, format, 0 );
+ }
+
+
+ /* documentation is in ftrender.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Set_Renderer( FT_Library library,
+ FT_Renderer renderer,
+ FT_UInt num_params,
+ FT_Parameter* parameters )
+ {
+ FT_ListNode node;
+ FT_Error error = FT_Err_Ok;
+
+
+ if ( !library )
+ return FT_Err_Invalid_Library_Handle;
+
+ if ( !renderer )
+ return FT_Err_Invalid_Argument;
+
+ node = FT_List_Find( &library->renderers, renderer );
+ if ( !node )
+ {
+ error = FT_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ FT_List_Up( &library->renderers, node );
+
+ if ( renderer->glyph_format == ft_glyph_format_outline )
+ library->cur_renderer = renderer;
+
+ if ( num_params > 0 )
+ {
+ FTRenderer_setMode set_mode = renderer->clazz->set_mode;
+
+
+ for ( ; num_params > 0; num_params-- )
+ {
+ error = set_mode( renderer, parameters->tag, parameters->data );
+ if ( error )
+ break;
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Render_Glyph_Internal( FT_Library library,
+ FT_GlyphSlot slot,
+ FT_UInt render_mode )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_Renderer renderer;
+
+
+ /* if it is already a bitmap, no need to do anything */
+ switch ( slot->format )
+ {
+ case ft_glyph_format_bitmap: /* already a bitmap, don't do anything */
+ break;
+
+ default:
+ {
+ FT_ListNode node = 0;
+ FT_Bool update = 0;
+
+
+ /* small shortcut for the very common case */
+ if ( slot->format == ft_glyph_format_outline )
+ {
+ renderer = library->cur_renderer;
+ node = library->renderers.head;
+ }
+ else
+ renderer = FT_Lookup_Renderer( library, slot->format, &node );
+
+ error = FT_Err_Unimplemented_Feature;
+ while ( renderer )
+ {
+ error = renderer->render( renderer, slot, render_mode, 0 );
+ if ( !error ||
+ FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph )
+ break;
+
+ /* FT_Err_Cannot_Render_Glyph is returned if the render mode */
+ /* is unsupported by the current renderer for this glyph image */
+ /* format. */
+
+ /* now, look for another renderer that supports the same */
+ /* format. */
+ renderer = FT_Lookup_Renderer( library, slot->format, &node );
+ update = 1;
+ }
+
+ /* if we changed the current renderer for the glyph image format */
+ /* we need to select it as the next current one */
+ if ( !error && update && renderer )
+ FT_Set_Renderer( library, renderer, 0, 0 );
+ }
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Render_Glyph( FT_GlyphSlot slot,
+ FT_UInt render_mode )
+ {
+ FT_Library library;
+
+
+ if ( !slot )
+ return FT_Err_Invalid_Argument;
+
+ library = FT_FACE_LIBRARY( slot->face );
+
+ return FT_Render_Glyph_Internal( library, slot, render_mode );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** M O D U L E S ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Destroy_Module */
+ /* */
+ /* <Description> */
+ /* Destroys a given module object. For drivers, this also destroys */
+ /* all child faces. */
+ /* */
+ /* <InOut> */
+ /* module :: A handle to the target driver object. */
+ /* */
+ /* <Note> */
+ /* The driver _must_ be LOCKED! */
+ /* */
+ static void
+ Destroy_Module( FT_Module module )
+ {
+ FT_Memory memory = module->memory;
+ FT_Module_Class* clazz = module->clazz;
+ FT_Library library = module->library;
+
+
+ /* finalize client-data - before anything else */
+ if ( module->generic.finalizer )
+ module->generic.finalizer( module );
+
+ if ( library && library->auto_hinter == module )
+ library->auto_hinter = 0;
+
+ /* if the module is a renderer */
+ if ( FT_MODULE_IS_RENDERER( module ) )
+ ft_remove_renderer( module );
+
+ /* if the module is a font driver, add some steps */
+ if ( FT_MODULE_IS_DRIVER( module ) )
+ Destroy_Driver( FT_DRIVER( module ) );
+
+ /* finalize the module object */
+ if ( clazz->module_done )
+ clazz->module_done( module );
+
+ /* discard it */
+ FREE( module );
+ }
+
+
+ /* documentation is in ftmodule.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Add_Module( FT_Library library,
+ const FT_Module_Class* clazz )
+ {
+ FT_Error error;
+ FT_Memory memory;
+ FT_Module module;
+ FT_UInt nn;
+
+
+#define FREETYPE_VER_FIXED ( ( (FT_Long)FREETYPE_MAJOR << 16 ) | \
+ FREETYPE_MINOR )
+
+ if ( !library )
+ return FT_Err_Invalid_Library_Handle;
+
+ if ( !clazz )
+ return FT_Err_Invalid_Argument;
+
+ /* check freetype version */
+ if ( clazz->module_requires > FREETYPE_VER_FIXED )
+ return FT_Err_Invalid_Version;
+
+ /* look for a module with the same name in the library's table */
+ for ( nn = 0; nn < library->num_modules; nn++ )
+ {
+ module = library->modules[nn];
+ if ( strcmp( module->clazz->module_name, clazz->module_name ) == 0 )
+ {
+ /* this installed module has the same name, compare their versions */
+ if ( clazz->module_version <= module->clazz->module_version )
+ return FT_Err_Lower_Module_Version;
+
+ /* remove the module from our list, then exit the loop to replace */
+ /* it by our new version.. */
+ FT_Remove_Module( library, module );
+ break;
+ }
+ }
+
+ memory = library->memory;
+ error = FT_Err_Ok;
+
+ if ( library->num_modules >= FT_MAX_MODULES )
+ {
+ error = FT_Err_Too_Many_Drivers;
+ goto Exit;
+ }
+
+ /* allocate module object */
+ if ( ALLOC( module,clazz->module_size ) )
+ goto Exit;
+
+ /* base initialization */
+ module->library = library;
+ module->memory = memory;
+ module->clazz = (FT_Module_Class*)clazz;
+
+ /* check whether the module is a renderer - this must be performed */
+ /* before the normal module initialization */
+ if ( FT_MODULE_IS_RENDERER( module ) )
+ {
+ /* add to the renderers list */
+ error = ft_add_renderer( module );
+ if ( error )
+ goto Fail;
+ }
+
+ /* is the module a auto-hinter? */
+ if ( FT_MODULE_IS_HINTER( module ) )
+ library->auto_hinter = module;
+
+ /* if the module is a font driver */
+ if ( FT_MODULE_IS_DRIVER( module ) )
+ {
+ /* allocate glyph loader if needed */
+ FT_Driver driver = FT_DRIVER( module );
+
+
+ driver->clazz = (FT_Driver_Class*)module->clazz;
+ if ( FT_DRIVER_USES_OUTLINES( driver ) )
+ {
+ error = FT_GlyphLoader_New( memory, &driver->glyph_loader );
+ if ( error )
+ goto Fail;
+ }
+ }
+
+ if ( clazz->module_init )
+ {
+ error = clazz->module_init( module );
+ if ( error )
+ goto Fail;
+ }
+
+ /* add module to the library's table */
+ library->modules[library->num_modules++] = module;
+
+ Exit:
+ return error;
+
+ Fail:
+ if ( FT_MODULE_IS_DRIVER( module ) )
+ {
+ FT_Driver driver = FT_DRIVER( module );
+
+
+ if ( FT_DRIVER_USES_OUTLINES( driver ) )
+ FT_GlyphLoader_Done( driver->glyph_loader );
+ }
+
+ if ( FT_MODULE_IS_RENDERER( module ) )
+ {
+ FT_Renderer renderer = FT_RENDERER( module );
+
+
+ if ( renderer->raster )
+ renderer->clazz->raster_class->raster_done( renderer->raster );
+ }
+
+ FREE( module );
+ goto Exit;
+ }
+
+
+ /* documentation is in ftmodule.h */
+
+ FT_EXPORT_DEF( FT_Module )
+ FT_Get_Module( FT_Library library,
+ const char* module_name )
+ {
+ FT_Module result = 0;
+ FT_Module* cur;
+ FT_Module* limit;
+
+
+ if ( !library || !module_name )
+ return result;
+
+ cur = library->modules;
+ limit = cur + library->num_modules;
+
+ for ( ; cur < limit; cur++ )
+ if ( strcmp( cur[0]->clazz->module_name, module_name ) == 0 )
+ {
+ result = cur[0];
+ break;
+ }
+
+ return result;
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_BASE_DEF( const void* )
+ FT_Get_Module_Interface( FT_Library library,
+ const char* mod_name )
+ {
+ FT_Module module;
+
+
+ /* test for valid `library' delayed to FT_Get_Module() */
+
+ module = FT_Get_Module( library, mod_name );
+
+ return module ? module->clazz->module_interface : 0;
+ }
+
+
+ /* documentation is in ftmodule.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Remove_Module( FT_Library library,
+ FT_Module module )
+ {
+ /* try to find the module from the table, then remove it from there */
+
+ if ( !library )
+ return FT_Err_Invalid_Library_Handle;
+
+ if ( module )
+ {
+ FT_Module* cur = library->modules;
+ FT_Module* limit = cur + library->num_modules;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ if ( cur[0] == module )
+ {
+ /* remove it from the table */
+ library->num_modules--;
+ limit--;
+ while ( cur < limit )
+ {
+ cur[0] = cur[1];
+ cur++;
+ }
+ limit[0] = 0;
+
+ /* destroy the module */
+ Destroy_Module( module );
+
+ return FT_Err_Ok;
+ }
+ }
+ }
+ return FT_Err_Invalid_Driver_Handle;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** L I B R A R Y ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* documentation is in ftmodule.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_New_Library( FT_Memory memory,
+ FT_Library *alibrary )
+ {
+ FT_Library library = 0;
+ FT_Error error;
+
+
+ if ( !memory )
+ return FT_Err_Invalid_Argument;
+
+ /* first of all, allocate the library object */
+ if ( ALLOC( library, sizeof ( *library ) ) )
+ return error;
+
+ library->memory = memory;
+
+ /* allocate the render pool */
+ library->raster_pool_size = FT_RENDER_POOL_SIZE;
+ if ( ALLOC( library->raster_pool, FT_RENDER_POOL_SIZE ) )
+ goto Fail;
+
+ /* That's ok now */
+ *alibrary = library;
+
+ return FT_Err_Ok;
+
+ Fail:
+ FREE( library );
+ return error;
+ }
+
+
+ /* documentation is in ftmodule.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Done_Library( FT_Library library )
+ {
+ FT_Memory memory;
+ FT_UInt n;
+
+
+ if ( !library )
+ return FT_Err_Invalid_Library_Handle;
+
+ memory = library->memory;
+
+ /* Discard client-data */
+ if ( library->generic.finalizer )
+ library->generic.finalizer( library );
+
+ /* Close all modules in the library */
+ for ( n = 0; n < library->num_modules; n++ )
+ {
+ FT_Module module = library->modules[n];
+
+
+ if ( module )
+ {
+ Destroy_Module( module );
+ library->modules[n] = 0;
+ }
+ }
+
+ /* Destroy raster objects */
+ FREE( library->raster_pool );
+ library->raster_pool_size = 0;
+
+ FREE( library );
+ return FT_Err_Ok;
+ }
+
+
+ /* documentation is in ftmodule.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Set_Debug_Hook( FT_Library library,
+ FT_UInt hook_index,
+ FT_DebugHook_Func debug_hook )
+ {
+ if ( library && debug_hook &&
+ hook_index <
+ ( sizeof ( library->debug_hooks ) / sizeof ( void* ) ) )
+ library->debug_hooks[hook_index] = debug_hook;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftoutln.c */
+/* */
+/* FreeType outline management (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* All functions are declared in freetype.h. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_OUTLINE_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_outline
+
+
+ static
+ const FT_Outline null_outline = { 0, 0, 0, 0, 0, 0 };
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_Decompose( FT_Outline* outline,
+ const FT_Outline_Funcs* interface,
+ void* user )
+ {
+#undef SCALED
+#define SCALED( x ) ( ( (x) << shift ) - delta )
+
+ FT_Vector v_last;
+ FT_Vector v_control;
+ FT_Vector v_start;
+
+ FT_Vector* point;
+ FT_Vector* limit;
+ char* tags;
+
+ FT_Error error;
+
+ FT_Int n; /* index of contour in outline */
+ FT_UInt first; /* index of first point in contour */
+ FT_Int tag; /* current point's state */
+
+ FT_Int shift;
+ FT_Pos delta;
+
+
+ if ( !outline || !interface )
+ return FT_Err_Invalid_Argument;
+
+ shift = interface->shift;
+ delta = interface->delta;
+ first = 0;
+
+ for ( n = 0; n < outline->n_contours; n++ )
+ {
+ FT_Int last; /* index of last point in contour */
+
+
+ last = outline->contours[n];
+ limit = outline->points + last;
+
+ v_start = outline->points[first];
+ v_last = outline->points[last];
+
+ v_start.x = SCALED( v_start.x ); v_start.y = SCALED( v_start.y );
+ v_last.x = SCALED( v_last.x ); v_last.y = SCALED( v_last.y );
+
+ v_control = v_start;
+
+ point = outline->points + first;
+ tags = outline->tags + first;
+ tag = FT_CURVE_TAG( tags[0] );
+
+ /* A contour cannot start with a cubic control point! */
+ if ( tag == FT_Curve_Tag_Cubic )
+ goto Invalid_Outline;
+
+ /* check first point to determine origin */
+ if ( tag == FT_Curve_Tag_Conic )
+ {
+ /* first point is conic control. Yes, this happens. */
+ if ( FT_CURVE_TAG( outline->tags[last] ) == FT_Curve_Tag_On )
+ {
+ /* start at last point if it is on the curve */
+ v_start = v_last;
+ limit--;
+ }
+ else
+ {
+ /* if both first and last points are conic, */
+ /* start at their middle and record its position */
+ /* for closure */
+ v_start.x = ( v_start.x + v_last.x ) / 2;
+ v_start.y = ( v_start.y + v_last.y ) / 2;
+
+ v_last = v_start;
+ }
+ point--;
+ tags--;
+ }
+
+ error = interface->move_to( &v_start, user );
+ if ( error )
+ goto Exit;
+
+ while ( point < limit )
+ {
+ point++;
+ tags++;
+
+ tag = FT_CURVE_TAG( tags[0] );
+ switch ( tag )
+ {
+ case FT_Curve_Tag_On: /* emit a single line_to */
+ {
+ FT_Vector vec;
+
+
+ vec.x = SCALED( point->x );
+ vec.y = SCALED( point->y );
+
+ error = interface->line_to( &vec, user );
+ if ( error )
+ goto Exit;
+ continue;
+ }
+
+ case FT_Curve_Tag_Conic: /* consume conic arcs */
+ v_control.x = SCALED( point->x );
+ v_control.y = SCALED( point->y );
+
+ Do_Conic:
+ if ( point < limit )
+ {
+ FT_Vector vec;
+ FT_Vector v_middle;
+
+
+ point++;
+ tags++;
+ tag = FT_CURVE_TAG( tags[0] );
+
+ vec.x = SCALED( point->x );
+ vec.y = SCALED( point->y );
+
+ if ( tag == FT_Curve_Tag_On )
+ {
+ error = interface->conic_to( &v_control, &vec, user );
+ if ( error )
+ goto Exit;
+ continue;
+ }
+
+ if ( tag != FT_Curve_Tag_Conic )
+ goto Invalid_Outline;
+
+ v_middle.x = ( v_control.x + vec.x ) / 2;
+ v_middle.y = ( v_control.y + vec.y ) / 2;
+
+ error = interface->conic_to( &v_control, &v_middle, user );
+ if ( error )
+ goto Exit;
+
+ v_control = vec;
+ goto Do_Conic;
+ }
+
+ error = interface->conic_to( &v_control, &v_start, user );
+ goto Close;
+
+ default: /* FT_Curve_Tag_Cubic */
+ {
+ FT_Vector vec1, vec2;
+
+
+ if ( point + 1 > limit ||
+ FT_CURVE_TAG( tags[1] ) != FT_Curve_Tag_Cubic )
+ goto Invalid_Outline;
+
+ point += 2;
+ tags += 2;
+
+ vec1.x = SCALED( point[-2].x ); vec1.y = SCALED( point[-2].y );
+ vec2.x = SCALED( point[-1].x ); vec2.y = SCALED( point[-1].y );
+
+ if ( point <= limit )
+ {
+ FT_Vector vec;
+
+
+ vec.x = SCALED( point->x );
+ vec.y = SCALED( point->y );
+
+ error = interface->cubic_to( &vec1, &vec2, &vec, user );
+ if ( error )
+ goto Exit;
+ continue;
+ }
+
+ error = interface->cubic_to( &vec1, &vec2, &v_start, user );
+ goto Close;
+ }
+ }
+ }
+
+ /* close the contour with a line segment */
+ error = interface->line_to( &v_start, user );
+
+ Close:
+ if ( error )
+ goto Exit;
+
+ first = last + 1;
+ }
+
+ return 0;
+
+ Exit:
+ return error;
+
+ Invalid_Outline:
+ return FT_Err_Invalid_Outline;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_New_Internal( FT_Memory memory,
+ FT_UInt numPoints,
+ FT_Int numContours,
+ FT_Outline *anoutline )
+ {
+ FT_Error error;
+
+
+ if ( !anoutline || !memory )
+ return FT_Err_Invalid_Argument;
+
+ *anoutline = null_outline;
+
+ if ( ALLOC_ARRAY( anoutline->points, numPoints * 2L, FT_Pos ) ||
+ ALLOC_ARRAY( anoutline->tags, numPoints, FT_Byte ) ||
+ ALLOC_ARRAY( anoutline->contours, numContours, FT_UShort ) )
+ goto Fail;
+
+ anoutline->n_points = (FT_UShort)numPoints;
+ anoutline->n_contours = (FT_Short)numContours;
+ anoutline->flags |= ft_outline_owner;
+
+ return FT_Err_Ok;
+
+ Fail:
+ anoutline->flags |= ft_outline_owner;
+ FT_Outline_Done_Internal( memory, anoutline );
+
+ return error;
+ }
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_New( FT_Library library,
+ FT_UInt numPoints,
+ FT_Int numContours,
+ FT_Outline *anoutline )
+ {
+ if ( !library )
+ return FT_Err_Invalid_Library_Handle;
+
+ return FT_Outline_New_Internal( library->memory, numPoints,
+ numContours, anoutline );
+ }
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_Copy( FT_Outline* source,
+ FT_Outline *target )
+ {
+ FT_Int is_owner;
+
+
+ if ( !source || !target ||
+ source->n_points != target->n_points ||
+ source->n_contours != target->n_contours )
+ return FT_Err_Invalid_Argument;
+
+ MEM_Copy( target->points, source->points,
+ source->n_points * sizeof ( FT_Vector ) );
+
+ MEM_Copy( target->tags, source->tags,
+ source->n_points * sizeof ( FT_Byte ) );
+
+ MEM_Copy( target->contours, source->contours,
+ source->n_contours * sizeof ( FT_Short ) );
+
+ /* copy all flags, except the `ft_outline_owner' one */
+ is_owner = target->flags & ft_outline_owner;
+ target->flags = source->flags;
+
+ target->flags &= ~ft_outline_owner;
+ target->flags |= is_owner;
+
+ return FT_Err_Ok;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_Done_Internal( FT_Memory memory,
+ FT_Outline* outline )
+ {
+ if ( outline )
+ {
+ if ( outline->flags & ft_outline_owner )
+ {
+ FREE( outline->points );
+ FREE( outline->tags );
+ FREE( outline->contours );
+ }
+ *outline = null_outline;
+
+ return FT_Err_Ok;
+ }
+ else
+ return FT_Err_Invalid_Argument;
+ }
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_Done( FT_Library library,
+ FT_Outline* outline )
+ {
+ /* check for valid `outline' in FT_Outline_Done_Internal() */
+
+ if ( !library )
+ return FT_Err_Invalid_Library_Handle;
+
+ return FT_Outline_Done_Internal( library->memory, outline );
+ }
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Outline_Get_CBox( FT_Outline* outline,
+ FT_BBox *acbox )
+ {
+ FT_Pos xMin, yMin, xMax, yMax;
+
+
+ if ( outline && acbox )
+ {
+ if ( outline->n_points == 0 )
+ {
+ xMin = 0;
+ yMin = 0;
+ xMax = 0;
+ yMax = 0;
+ }
+ else
+ {
+ FT_Vector* vec = outline->points;
+ FT_Vector* limit = vec + outline->n_points;
+
+
+ xMin = xMax = vec->x;
+ yMin = yMax = vec->y;
+ vec++;
+
+ for ( ; vec < limit; vec++ )
+ {
+ FT_Pos x, y;
+
+
+ x = vec->x;
+ if ( x < xMin ) xMin = x;
+ if ( x > xMax ) xMax = x;
+
+ y = vec->y;
+ if ( y < yMin ) yMin = y;
+ if ( y > yMax ) yMax = y;
+ }
+ }
+ acbox->xMin = xMin;
+ acbox->xMax = xMax;
+ acbox->yMin = yMin;
+ acbox->yMax = yMax;
+ }
+ }
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Outline_Translate( FT_Outline* outline,
+ FT_Pos xOffset,
+ FT_Pos yOffset )
+ {
+ FT_UShort n;
+ FT_Vector* vec = outline->points;
+
+
+ for ( n = 0; n < outline->n_points; n++ )
+ {
+ vec->x += xOffset;
+ vec->y += yOffset;
+ vec++;
+ }
+ }
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Outline_Reverse( FT_Outline* outline )
+ {
+ FT_UShort n;
+ FT_Int first, last;
+
+
+ first = 0;
+
+ for ( n = 0; n < outline->n_contours; n++ )
+ {
+ last = outline->contours[n];
+
+ /* reverse point table */
+ {
+ FT_Vector* p = outline->points + first;
+ FT_Vector* q = outline->points + last;
+ FT_Vector swap;
+
+
+ while ( p < q )
+ {
+ swap = *p;
+ *p = *q;
+ *q = swap;
+ p++;
+ q--;
+ }
+ }
+
+ /* reverse tags table */
+ {
+ char* p = outline->tags + first;
+ char* q = outline->tags + last;
+ char swap;
+
+
+ while ( p < q )
+ {
+ swap = *p;
+ *p = *q;
+ *q = swap;
+ p++;
+ q--;
+ }
+ }
+
+ first = last + 1;
+ }
+
+ outline->flags ^= ft_outline_reverse_fill;
+ }
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_Render( FT_Library library,
+ FT_Outline* outline,
+ FT_Raster_Params* params )
+ {
+ FT_Error error;
+ FT_Bool update = 0;
+ FT_Renderer renderer;
+ FT_ListNode node;
+
+
+ if ( !library )
+ return FT_Err_Invalid_Library_Handle;
+
+ if ( !params )
+ return FT_Err_Invalid_Argument;
+
+ renderer = library->cur_renderer;
+ node = library->renderers.head;
+
+ params->source = (void*)outline;
+
+ error = FT_Err_Cannot_Render_Glyph;
+ while ( renderer )
+ {
+ error = renderer->raster_render( renderer->raster, params );
+ if ( !error || FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph )
+ break;
+
+ /* FT_Err_Cannot_Render_Glyph is returned if the render mode */
+ /* is unsupported by the current renderer for this glyph image */
+ /* format */
+
+ /* now, look for another renderer that supports the same */
+ /* format */
+ renderer = FT_Lookup_Renderer( library, ft_glyph_format_outline,
+ &node );
+ update = 1;
+ }
+
+ /* if we changed the current renderer for the glyph image format */
+ /* we need to select it as the next current one */
+ if ( !error && update && renderer )
+ FT_Set_Renderer( library, renderer, 0, 0 );
+
+ return error;
+ }
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_Get_Bitmap( FT_Library library,
+ FT_Outline* outline,
+ FT_Bitmap *abitmap )
+ {
+ FT_Raster_Params params;
+
+
+ if ( !abitmap )
+ return FT_Err_Invalid_Argument;
+
+ /* other checks are delayed to FT_Outline_Render() */
+
+ params.target = abitmap;
+ params.flags = 0;
+
+ if ( abitmap->pixel_mode == ft_pixel_mode_grays )
+ params.flags |= ft_raster_flag_aa;
+
+ return FT_Outline_Render( library, outline, ¶ms );
+ }
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Vector_Transform( FT_Vector* vector,
+ FT_Matrix* matrix )
+ {
+ FT_Pos xz, yz;
+
+
+ if ( !vector || !matrix )
+ return;
+
+ xz = FT_MulFix( vector->x, matrix->xx ) +
+ FT_MulFix( vector->y, matrix->xy );
+
+ yz = FT_MulFix( vector->x, matrix->yx ) +
+ FT_MulFix( vector->y, matrix->yy );
+
+ vector->x = xz;
+ vector->y = yz;
+ }
+
+
+ /* documentation is in ftoutln.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Outline_Transform( FT_Outline* outline,
+ FT_Matrix* matrix )
+ {
+ FT_Vector* vec = outline->points;
+ FT_Vector* limit = vec + outline->n_points;
+
+
+ for ( ; vec < limit; vec++ )
+ FT_Vector_Transform( vec, matrix );
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftraster.c */
+/* */
+/* The FreeType glyph rasterizer (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* This is a rewrite of the FreeType 1.x scan-line converter */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include "ftraster.h"
+#include FT_INTERNAL_CALC_H /* for FT_MulDiv only */
+
+
+ /*************************************************************************/
+ /* */
+ /* A simple technical note on how the raster works */
+ /* ----------------------------------------------- */
+ /* */
+ /* Converting an outline into a bitmap is achieved in several steps: */
+ /* */
+ /* 1 - Decomposing the outline into successive `profiles'. Each */
+ /* profile is simply an array of scanline intersections on a given */
+ /* dimension. A profile's main attributes are */
+ /* */
+ /* o its scanline position boundaries, i.e. `Ymin' and `Ymax'. */
+ /* */
+ /* o an array of intersection coordinates for each scanline */
+ /* between `Ymin' and `Ymax'. */
+ /* */
+ /* o a direction, indicating whether it was built going `up' or */
+ /* `down', as this is very important for filling rules. */
+ /* */
+ /* 2 - Sweeping the target map's scanlines in order to compute segment */
+ /* `spans' which are then filled. Additionally, this pass */
+ /* performs drop-out control. */
+ /* */
+ /* The outline data is parsed during step 1 only. The profiles are */
+ /* built from the bottom of the render pool, used as a stack. The */
+ /* following graphics shows the profile list under construction: */
+ /* */
+ /* ____________________________________________________________ _ _ */
+ /* | | | | | */
+ /* | profile | coordinates for | profile | coordinates for |--> */
+ /* | 1 | profile 1 | 2 | profile 2 |--> */
+ /* |_________|___________________|_________|_________________|__ _ _ */
+ /* */
+ /* ^ ^ */
+ /* | | */
+ /* start of render pool top */
+ /* */
+ /* The top of the profile stack is kept in the `top' variable. */
+ /* */
+ /* As you can see, a profile record is pushed on top of the render */
+ /* pool, which is then followed by its coordinates/intersections. If */
+ /* a change of direction is detected in the outline, a new profile is */
+ /* generated until the end of the outline. */
+ /* */
+ /* Note that when all profiles have been generated, the function */
+ /* Finalize_Profile_Table() is used to record, for each profile, its */
+ /* bottom-most scanline as well as the scanline above its upmost */
+ /* boundary. These positions are called `y-turns' because they (sort */
+ /* of) correspond to local extrema. They are stored in a sorted list */
+ /* built from the top of the render pool as a downwards stack: */
+ /* */
+ /* _ _ _______________________________________ */
+ /* | | */
+ /* <--| sorted list of | */
+ /* <--| extrema scanlines | */
+ /* _ _ __________________|____________________| */
+ /* */
+ /* ^ ^ */
+ /* | | */
+ /* maxBuff sizeBuff = end of pool */
+ /* */
+ /* This list is later used during the sweep phase in order to */
+ /* optimize performance (see technical note on the sweep below). */
+ /* */
+ /* Of course, the raster detects whether the two stacks collide and */
+ /* handles the situation propertly. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /** **/
+ /** CONFIGURATION MACROS **/
+ /** **/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* define DEBUG_RASTER if you want to compile a debugging version */
+#define xxxDEBUG_RASTER
+
+ /* The default render pool size in bytes */
+#define RASTER_RENDER_POOL 8192
+
+ /* undefine FT_RASTER_OPTION_ANTI_ALIASING if you do not want to support */
+ /* 5-levels anti-aliasing */
+#ifdef FT_CONFIG_OPTION_5_GRAY_LEVELS
+#define FT_RASTER_OPTION_ANTI_ALIASING
+#endif
+
+ /* The size of the two-lines intermediate bitmap used */
+ /* for anti-aliasing, in bytes. */
+#define RASTER_GRAY_LINES 2048
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /** **/
+ /** OTHER MACROS (do not change) **/
+ /** **/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_raster
+
+
+#ifdef _STANDALONE_
+
+
+ /* This macro is used to indicate that a function parameter is unused. */
+ /* Its purpose is simply to reduce compiler warnings. Note also that */
+ /* simply defining it as `(void)x' doesn't avoid warnings with certain */
+ /* ANSI compilers (e.g. LCC). */
+#define FT_UNUSED( x ) (x) = (x)
+
+ /* Disable the tracing mechanism for simplicity -- developers can */
+ /* activate it easily by redefining these two macros. */
+#ifndef FT_ERROR
+#define FT_ERROR( x ) do ; while ( 0 ) /* nothing */
+#endif
+
+#ifndef FT_TRACE
+#define FT_TRACE( x ) do ; while ( 0 ) /* nothing */
+#endif
+
+#define Raster_Err_None 0
+#define Raster_Err_Not_Ini -1
+#define Raster_Err_Overflow -2
+#define Raster_Err_Neg_Height -3
+#define Raster_Err_Invalid -4
+#define Raster_Err_Unsupported -5
+
+
+#else /* _STANDALONE_ */
+
+
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H /* for FT_TRACE() and FT_ERROR() */
+
+#include "rasterrs.h"
+
+#define Raster_Err_None Raster_Err_Ok
+#define Raster_Err_Not_Ini Raster_Err_Raster_Uninitialized
+#define Raster_Err_Overflow Raster_Err_Raster_Overflow
+#define Raster_Err_Neg_Height Raster_Err_Raster_Negative_Height
+#define Raster_Err_Invalid Raster_Err_Invalid_Outline
+#define Raster_Err_Unsupported Raster_Err_Cannot_Render_Glyph
+
+
+#endif /* _STANDALONE_ */
+
+
+ /* FMulDiv means `Fast MulDiv'; it is used in case where `b' is */
+ /* typically a small value and the result of a*b is known to fit into */
+ /* 32 bits. */
+#define FMulDiv( a, b, c ) ( (a) * (b) / (c) )
+
+ /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */
+ /* for clipping computations. It simply uses the FT_MulDiv() function */
+ /* defined in `ftcalc.h'. */
+#define SMulDiv FT_MulDiv
+
+ /* The rasterizer is a very general purpose component; please leave */
+ /* the following redefinitions there (you never know your target */
+ /* environment). */
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef NULL
+#define NULL (void*)0
+#endif
+
+#ifndef SUCCESS
+#define SUCCESS 0
+#endif
+
+#ifndef FAILURE
+#define FAILURE 1
+#endif
+
+
+#define MaxBezier 32 /* The maximum number of stacked Bezier curves. */
+ /* Setting this constant to more than 32 is a */
+ /* pure waste of space. */
+
+#define Pixel_Bits 6 /* fractional bits of *input* coordinates */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /** **/
+ /** SIMPLE TYPE DECLARATIONS **/
+ /** **/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ typedef int Int;
+ typedef unsigned int UInt;
+ typedef short Short;
+ typedef unsigned short UShort, *PUShort;
+ typedef long Long, *PLong;
+ typedef unsigned long ULong;
+
+ typedef unsigned char Byte, *PByte;
+ typedef char Bool;
+
+ typedef struct TPoint_
+ {
+ Long x;
+ Long y;
+
+ } TPoint;
+
+
+ typedef enum TFlow_
+ {
+ Flow_None = 0,
+ Flow_Up = 1,
+ Flow_Down = -1
+
+ } TFlow;
+
+
+ /* States of each line, arc, and profile */
+ typedef enum TStates_
+ {
+ Unknown,
+ Ascending,
+ Descending,
+ Flat
+
+ } TStates;
+
+
+ typedef struct TProfile_ TProfile;
+ typedef TProfile* PProfile;
+
+ struct TProfile_
+ {
+ FT_F26Dot6 X; /* current coordinate during sweep */
+ PProfile link; /* link to next profile - various purpose */
+ PLong offset; /* start of profile's data in render pool */
+ int flow; /* Profile orientation: Asc/Descending */
+ long height; /* profile's height in scanlines */
+ long start; /* profile's starting scanline */
+
+ unsigned countL; /* number of lines to step before this */
+ /* profile becomes drawable */
+
+ PProfile next; /* next profile in same contour, used */
+ /* during drop-out control */
+ };
+
+ typedef PProfile TProfileList;
+ typedef PProfile* PProfileList;
+
+
+ /* Simple record used to implement a stack of bands, required */
+ /* by the sub-banding mechanism */
+ typedef struct TBand_
+ {
+ Short y_min; /* band's minimum */
+ Short y_max; /* band's maximum */
+
+ } TBand;
+
+
+#define AlignProfileSize \
+ ( ( sizeof ( TProfile ) + sizeof ( long ) - 1 ) / sizeof ( long ) )
+
+
+#ifdef TT_STATIC_RASTER
+
+
+#define RAS_ARGS /* void */
+#define RAS_ARG /* void */
+
+#define RAS_VARS /* void */
+#define RAS_VAR /* void */
+
+#define FT_UNUSED_RASTER do ; while ( 0 )
+
+
+#else /* TT_STATIC_RASTER */
+
+
+#define RAS_ARGS TRaster_Instance* raster,
+#define RAS_ARG TRaster_Instance* raster
+
+#define RAS_VARS raster,
+#define RAS_VAR raster
+
+#define FT_UNUSED_RASTER FT_UNUSED( raster )
+
+
+#endif /* TT_STATIC_RASTER */
+
+
+ typedef struct TRaster_Instance_ TRaster_Instance;
+
+
+ /* prototypes used for sweep function dispatch */
+ typedef void
+ Function_Sweep_Init( RAS_ARGS Short* min,
+ Short* max );
+
+ typedef void
+ Function_Sweep_Span( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right );
+
+ typedef void
+ Function_Sweep_Step( RAS_ARG );
+
+
+ /* NOTE: These operations are only valid on 2's complement processors */
+
+#define FLOOR( x ) ( (x) & -ras.precision )
+#define CEILING( x ) ( ( (x) + ras.precision - 1 ) & -ras.precision )
+#define TRUNC( x ) ( (signed long)(x) >> ras.precision_bits )
+#define FRAC( x ) ( (x) & ( ras.precision - 1 ) )
+#define SCALED( x ) ( ( (x) << ras.scale_shift ) - ras.precision_half )
+
+ /* Note that I have moved the location of some fields in the */
+ /* structure to ensure that the most used variables are used */
+ /* at the top. Thus, their offset can be coded with less */
+ /* opcodes, and it results in a smaller executable. */
+
+ struct TRaster_Instance_
+ {
+ Int precision_bits; /* precision related variables */
+ Int precision;
+ Int precision_half;
+ Long precision_mask;
+ Int precision_shift;
+ Int precision_step;
+ Int precision_jitter;
+
+ Int scale_shift; /* == precision_shift for bitmaps */
+ /* == precision_shift+1 for pixmaps */
+
+ PLong buff; /* The profiles buffer */
+ PLong sizeBuff; /* Render pool size */
+ PLong maxBuff; /* Profiles buffer size */
+ PLong top; /* Current cursor in buffer */
+
+ FT_Error error;
+
+ Int numTurns; /* number of Y-turns in outline */
+
+ TPoint* arc; /* current Bezier arc pointer */
+
+ UShort bWidth; /* target bitmap width */
+ PByte bTarget; /* target bitmap buffer */
+ PByte gTarget; /* target pixmap buffer */
+
+ Long lastX, lastY, minY, maxY;
+
+ UShort num_Profs; /* current number of profiles */
+
+ Bool fresh; /* signals a fresh new profile which */
+ /* 'start' field must be completed */
+ Bool joint; /* signals that the last arc ended */
+ /* exactly on a scanline. Allows */
+ /* removal of doublets */
+ PProfile cProfile; /* current profile */
+ PProfile fProfile; /* head of linked list of profiles */
+ PProfile gProfile; /* contour's first profile in case */
+ /* of impact */
+
+ TStates state; /* rendering state */
+
+ FT_Bitmap target; /* description of target bit/pixmap */
+ FT_Outline outline;
+
+ Long traceOfs; /* current offset in target bitmap */
+ Long traceG; /* current offset in target pixmap */
+
+ Short traceIncr; /* sweep's increment in target bitmap */
+
+ Short gray_min_x; /* current min x during gray rendering */
+ Short gray_max_x; /* current max x during gray rendering */
+
+ /* dispatch variables */
+
+ Function_Sweep_Init* Proc_Sweep_Init;
+ Function_Sweep_Span* Proc_Sweep_Span;
+ Function_Sweep_Span* Proc_Sweep_Drop;
+ Function_Sweep_Step* Proc_Sweep_Step;
+
+ Byte dropOutControl; /* current drop_out control method */
+
+ Bool second_pass; /* indicates wether a horizontal pass */
+ /* should be performed to control */
+ /* drop-out accurately when calling */
+ /* Render_Glyph. Note that there is */
+ /* no horizontal pass during gray */
+ /* rendering. */
+
+ TPoint arcs[3 * MaxBezier + 1]; /* The Bezier stack */
+
+ TBand band_stack[16]; /* band stack used for sub-banding */
+ Int band_top; /* band stack top */
+
+ Int count_table[256]; /* Look-up table used to quickly count */
+ /* set bits in a gray 2x2 cell */
+
+ void* memory;
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+ Byte grays[5]; /* Palette of gray levels used for */
+ /* render. */
+
+ Byte gray_lines[RASTER_GRAY_LINES];
+ /* Intermediate table used to render the */
+ /* graylevels pixmaps. */
+ /* gray_lines is a buffer holding two */
+ /* monochrome scanlines */
+
+ Short gray_width; /* width in bytes of one monochrome */
+ /* intermediate scanline of gray_lines. */
+ /* Each gray pixel takes 2 bits long there */
+
+ /* The gray_lines must hold 2 lines, thus with size */
+ /* in bytes of at least `gray_width*2'. */
+
+#endif /* FT_RASTER_ANTI_ALIASING */
+
+#if 0
+ PByte flags; /* current flags table */
+ PUShort outs; /* current outlines table */
+ FT_Vector* coords;
+
+ UShort nPoints; /* number of points in current glyph */
+ Short nContours; /* number of contours in current glyph */
+#endif
+
+ };
+
+
+#ifdef FT_CONFIG_OPTION_STATIC_RASTER
+
+ static TRaster_Instance cur_ras;
+#define ras cur_ras
+
+#else
+
+#define ras (*raster)
+
+#endif /* FT_CONFIG_OPTION_STATIC_RASTER */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /** **/
+ /** PROFILES COMPUTATION **/
+ /** **/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Set_High_Precision */
+ /* */
+ /* <Description> */
+ /* Sets precision variables according to param flag. */
+ /* */
+ /* <Input> */
+ /* High :: Set to True for high precision (typically for ppem < 18), */
+ /* false otherwise. */
+ /* */
+ static void
+ Set_High_Precision( RAS_ARGS Int High )
+ {
+ if ( High )
+ {
+ ras.precision_bits = 10;
+ ras.precision_step = 128;
+ ras.precision_jitter = 24;
+ }
+ else
+ {
+ ras.precision_bits = 6;
+ ras.precision_step = 32;
+ ras.precision_jitter = 2;
+ }
+
+ FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" ));
+
+ ras.precision = 1L << ras.precision_bits;
+ ras.precision_half = ras.precision / 2;
+ ras.precision_shift = ras.precision_bits - Pixel_Bits;
+ ras.precision_mask = -ras.precision;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* New_Profile */
+ /* */
+ /* <Description> */
+ /* Creates a new profile in the render pool. */
+ /* */
+ /* <Input> */
+ /* aState :: The state/orientation of the new profile. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success. FAILURE in case of overflow or of incoherent */
+ /* profile. */
+ /* */
+ static Bool
+ New_Profile( RAS_ARGS TStates aState )
+ {
+ if ( !ras.fProfile )
+ {
+ ras.cProfile = (PProfile)ras.top;
+ ras.fProfile = ras.cProfile;
+ ras.top += AlignProfileSize;
+ }
+
+ if ( ras.top >= ras.maxBuff )
+ {
+ ras.error = Raster_Err_Overflow;
+ return FAILURE;
+ }
+
+ switch ( aState )
+ {
+ case Ascending:
+ ras.cProfile->flow = Flow_Up;
+ FT_TRACE6(( "New ascending profile = %lx\n", (long)ras.cProfile ));
+ break;
+
+ case Descending:
+ ras.cProfile->flow = Flow_Down;
+ FT_TRACE6(( "New descending profile = %lx\n", (long)ras.cProfile ));
+ break;
+
+ default:
+ FT_ERROR(( "New_Profile: invalid profile direction!\n" ));
+ ras.error = Raster_Err_Invalid;
+ return FAILURE;
+ }
+
+ ras.cProfile->start = 0;
+ ras.cProfile->height = 0;
+ ras.cProfile->offset = ras.top;
+ ras.cProfile->link = (PProfile)0;
+ ras.cProfile->next = (PProfile)0;
+
+ if ( !ras.gProfile )
+ ras.gProfile = ras.cProfile;
+
+ ras.state = aState;
+ ras.fresh = TRUE;
+ ras.joint = FALSE;
+
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* End_Profile */
+ /* */
+ /* <Description> */
+ /* Finalizes the current profile. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success. FAILURE in case of overflow or incoherency. */
+ /* */
+ static Bool
+ End_Profile( RAS_ARG )
+ {
+ Long h;
+ PProfile oldProfile;
+
+
+ h = (Long)( ras.top - ras.cProfile->offset );
+
+ if ( h < 0 )
+ {
+ FT_ERROR(( "End_Profile: negative height encountered!\n" ));
+ ras.error = Raster_Err_Neg_Height;
+ return FAILURE;
+ }
+
+ if ( h > 0 )
+ {
+ FT_TRACE6(( "Ending profile %lx, start = %ld, height = %ld\n",
+ (long)ras.cProfile, ras.cProfile->start, h ));
+
+ oldProfile = ras.cProfile;
+ ras.cProfile->height = h;
+ ras.cProfile = (PProfile)ras.top;
+
+ ras.top += AlignProfileSize;
+
+ ras.cProfile->height = 0;
+ ras.cProfile->offset = ras.top;
+ oldProfile->next = ras.cProfile;
+ ras.num_Profs++;
+ }
+
+ if ( ras.top >= ras.maxBuff )
+ {
+ FT_TRACE1(( "overflow in End_Profile\n" ));
+ ras.error = Raster_Err_Overflow;
+ return FAILURE;
+ }
+
+ ras.joint = FALSE;
+
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Insert_Y_Turn */
+ /* */
+ /* <Description> */
+ /* Inserts a salient into the sorted list placed on top of the render */
+ /* pool. */
+ /* */
+ /* <Input> */
+ /* New y scanline position. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success. FAILURE in case of overflow. */
+ /* */
+ static Bool
+ Insert_Y_Turn( RAS_ARGS Int y )
+ {
+ PLong y_turns;
+ Int y2, n;
+
+
+ n = ras.numTurns - 1;
+ y_turns = ras.sizeBuff - ras.numTurns;
+
+ /* look for first y value that is <= */
+ while ( n >= 0 && y < y_turns[n] )
+ n--;
+
+ /* if it is <, simply insert it, ignore if == */
+ if ( n >= 0 && y > y_turns[n] )
+ while ( n >= 0 )
+ {
+ y2 = y_turns[n];
+ y_turns[n] = y;
+ y = y2;
+ n--;
+ }
+
+ if ( n < 0 )
+ {
+ if ( ras.maxBuff <= ras.top )
+ {
+ ras.error = Raster_Err_Overflow;
+ return FAILURE;
+ }
+ ras.maxBuff--;
+ ras.numTurns++;
+ ras.sizeBuff[-ras.numTurns] = y;
+ }
+
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Finalize_Profile_Table */
+ /* */
+ /* <Description> */
+ /* Adjusts all links in the profiles list. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success. FAILURE in case of overflow. */
+ /* */
+ static Bool
+ Finalize_Profile_Table( RAS_ARG )
+ {
+ Int bottom, top;
+ UShort n;
+ PProfile p;
+
+
+ n = ras.num_Profs;
+
+ if ( n > 1 )
+ {
+ p = ras.fProfile;
+ while ( n > 0 )
+ {
+ if ( n > 1 )
+ p->link = (PProfile)( p->offset + p->height );
+ else
+ p->link = NULL;
+
+ switch ( p->flow )
+ {
+ case Flow_Down:
+ bottom = p->start - p->height+1;
+ top = p->start;
+ p->start = bottom;
+ p->offset += p->height - 1;
+ break;
+
+ case Flow_Up:
+ default:
+ bottom = p->start;
+ top = p->start + p->height - 1;
+ }
+
+ if ( Insert_Y_Turn( RAS_VARS bottom ) ||
+ Insert_Y_Turn( RAS_VARS top + 1 ) )
+ return FAILURE;
+
+ p = p->link;
+ n--;
+ }
+ }
+ else
+ ras.fProfile = NULL;
+
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Split_Conic */
+ /* */
+ /* <Description> */
+ /* Subdivides one conic Bezier into two joint sub-arcs in the Bezier */
+ /* stack. */
+ /* */
+ /* <Input> */
+ /* None (subdivided Bezier is taken from the top of the stack). */
+ /* */
+ /* <Note> */
+ /* This routine is the `beef' of this component. It is _the_ inner */
+ /* loop that should be optimized to hell to get the best performance. */
+ /* */
+ static void
+ Split_Conic( TPoint* base )
+ {
+ Long a, b;
+
+
+ base[4].x = base[2].x;
+ b = base[1].x;
+ a = base[3].x = ( base[2].x + b ) / 2;
+ b = base[1].x = ( base[0].x + b ) / 2;
+ base[2].x = ( a + b ) / 2;
+
+ base[4].y = base[2].y;
+ b = base[1].y;
+ a = base[3].y = ( base[2].y + b ) / 2;
+ b = base[1].y = ( base[0].y + b ) / 2;
+ base[2].y = ( a + b ) / 2;
+
+ /* hand optimized. gcc doesn't seem to be too good at common */
+ /* expression substitution and instruction scheduling ;-) */
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Split_Cubic */
+ /* */
+ /* <Description> */
+ /* Subdivides a third-order Bezier arc into two joint sub-arcs in the */
+ /* Bezier stack. */
+ /* */
+ /* <Note> */
+ /* This routine is the `beef' of the component. It is one of _the_ */
+ /* inner loops that should be optimized like hell to get the best */
+ /* performance. */
+ /* */
+ static void
+ Split_Cubic( TPoint* base )
+ {
+ Long a, b, c, d;
+
+
+ base[6].x = base[3].x;
+ c = base[1].x;
+ d = base[2].x;
+ base[1].x = a = ( base[0].x + c + 1 ) >> 1;
+ base[5].x = b = ( base[3].x + d + 1 ) >> 1;
+ c = ( c + d + 1 ) >> 1;
+ base[2].x = a = ( a + c + 1 ) >> 1;
+ base[4].x = b = ( b + c + 1 ) >> 1;
+ base[3].x = ( a + b + 1 ) >> 1;
+
+ base[6].y = base[3].y;
+ c = base[1].y;
+ d = base[2].y;
+ base[1].y = a = ( base[0].y + c + 1 ) >> 1;
+ base[5].y = b = ( base[3].y + d + 1 ) >> 1;
+ c = ( c + d + 1 ) >> 1;
+ base[2].y = a = ( a + c + 1 ) >> 1;
+ base[4].y = b = ( b + c + 1 ) >> 1;
+ base[3].y = ( a + b + 1 ) >> 1;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Line_Up */
+ /* */
+ /* <Description> */
+ /* Computes the x-coordinates of an ascending line segment and stores */
+ /* them in the render pool. */
+ /* */
+ /* <Input> */
+ /* x1 :: The x-coordinate of the segment's start point. */
+ /* */
+ /* y1 :: The y-coordinate of the segment's start point. */
+ /* */
+ /* x2 :: The x-coordinate of the segment's end point. */
+ /* */
+ /* y2 :: The y-coordinate of the segment's end point. */
+ /* */
+ /* miny :: A lower vertical clipping bound value. */
+ /* */
+ /* maxy :: An upper vertical clipping bound value. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on render pool overflow. */
+ /* */
+ static Bool
+ Line_Up( RAS_ARGS Long x1,
+ Long y1,
+ Long x2,
+ Long y2,
+ Long miny,
+ Long maxy )
+ {
+ Long Dx, Dy;
+ Int e1, e2, f1, f2, size; /* XXX: is `Short' sufficient? */
+ Long Ix, Rx, Ax;
+
+ PLong top;
+
+
+ Dx = x2 - x1;
+ Dy = y2 - y1;
+
+ if ( Dy <= 0 || y2 < miny || y1 > maxy )
+ return SUCCESS;
+
+ if ( y1 < miny )
+ {
+ /* Take care: miny-y1 can be a very large value; we use */
+ /* a slow MulDiv function to avoid clipping bugs */
+ x1 += SMulDiv( Dx, miny - y1, Dy );
+ e1 = TRUNC( miny );
+ f1 = 0;
+ }
+ else
+ {
+ e1 = TRUNC( y1 );
+ f1 = FRAC( y1 );
+ }
+
+ if ( y2 > maxy )
+ {
+ /* x2 += FMulDiv( Dx, maxy - y2, Dy ); UNNECESSARY */
+ e2 = TRUNC( maxy );
+ f2 = 0;
+ }
+ else
+ {
+ e2 = TRUNC( y2 );
+ f2 = FRAC( y2 );
+ }
+
+ if ( f1 > 0 )
+ {
+ if ( e1 == e2 )
+ return SUCCESS;
+ else
+ {
+ x1 += FMulDiv( Dx, ras.precision - f1, Dy );
+ e1 += 1;
+ }
+ }
+ else
+ if ( ras.joint )
+ {
+ ras.top--;
+ ras.joint = FALSE;
+ }
+
+ ras.joint = (char)( f2 == 0 );
+
+ if ( ras.fresh )
+ {
+ ras.cProfile->start = e1;
+ ras.fresh = FALSE;
+ }
+
+ size = e2 - e1 + 1;
+ if ( ras.top + size >= ras.maxBuff )
+ {
+ ras.error = Raster_Err_Overflow;
+ return FAILURE;
+ }
+
+ if ( Dx > 0 )
+ {
+ Ix = ( ras.precision * Dx ) / Dy;
+ Rx = ( ras.precision * Dx ) % Dy;
+ Dx = 1;
+ }
+ else
+ {
+ Ix = -( ( ras.precision * -Dx ) / Dy );
+ Rx = ( ras.precision * -Dx ) % Dy;
+ Dx = -1;
+ }
+
+ Ax = -Dy;
+ top = ras.top;
+
+ while ( size > 0 )
+ {
+ *top++ = x1;
+
+ x1 += Ix;
+ Ax += Rx;
+ if ( Ax >= 0 )
+ {
+ Ax -= Dy;
+ x1 += Dx;
+ }
+ size--;
+ }
+
+ ras.top = top;
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Line_Down */
+ /* */
+ /* <Description> */
+ /* Computes the x-coordinates of an descending line segment and */
+ /* stores them in the render pool. */
+ /* */
+ /* <Input> */
+ /* x1 :: The x-coordinate of the segment's start point. */
+ /* */
+ /* y1 :: The y-coordinate of the segment's start point. */
+ /* */
+ /* x2 :: The x-coordinate of the segment's end point. */
+ /* */
+ /* y2 :: The y-coordinate of the segment's end point. */
+ /* */
+ /* miny :: A lower vertical clipping bound value. */
+ /* */
+ /* maxy :: An upper vertical clipping bound value. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on render pool overflow. */
+ /* */
+ static Bool
+ Line_Down( RAS_ARGS Long x1,
+ Long y1,
+ Long x2,
+ Long y2,
+ Long miny,
+ Long maxy )
+ {
+ Bool result, fresh;
+
+
+ fresh = ras.fresh;
+
+ result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny );
+
+ if ( fresh && !ras.fresh )
+ ras.cProfile->start = -ras.cProfile->start;
+
+ return result;
+ }
+
+
+ /* A function type describing the functions used to split Bezier arcs */
+ typedef void (*TSplitter)( TPoint* base );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Bezier_Up */
+ /* */
+ /* <Description> */
+ /* Computes the x-coordinates of an ascending Bezier arc and stores */
+ /* them in the render pool. */
+ /* */
+ /* <Input> */
+ /* degree :: The degree of the Bezier arc (either 2 or 3). */
+ /* */
+ /* splitter :: The function to split Bezier arcs. */
+ /* */
+ /* miny :: A lower vertical clipping bound value. */
+ /* */
+ /* maxy :: An upper vertical clipping bound value. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on render pool overflow. */
+ /* */
+ static Bool
+ Bezier_Up( RAS_ARGS Int degree,
+ TSplitter splitter,
+ Long miny,
+ Long maxy )
+ {
+ Long y1, y2, e, e2, e0;
+ Short f1;
+
+ TPoint* arc;
+ TPoint* start_arc;
+
+ PLong top;
+
+
+ arc = ras.arc;
+ y1 = arc[degree].y;
+ y2 = arc[0].y;
+ top = ras.top;
+
+ if ( y2 < miny || y1 > maxy )
+ goto Fin;
+
+ e2 = FLOOR( y2 );
+
+ if ( e2 > maxy )
+ e2 = maxy;
+
+ e0 = miny;
+
+ if ( y1 < miny )
+ e = miny;
+ else
+ {
+ e = CEILING( y1 );
+ f1 = (Short)( FRAC( y1 ) );
+ e0 = e;
+
+ if ( f1 == 0 )
+ {
+ if ( ras.joint )
+ {
+ top--;
+ ras.joint = FALSE;
+ }
+
+ *top++ = arc[degree].x;
+
+ e += ras.precision;
+ }
+ }
+
+ if ( ras.fresh )
+ {
+ ras.cProfile->start = TRUNC( e0 );
+ ras.fresh = FALSE;
+ }
+
+ if ( e2 < e )
+ goto Fin;
+
+ if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff )
+ {
+ ras.top = top;
+ ras.error = Raster_Err_Overflow;
+ return FAILURE;
+ }
+
+ start_arc = arc;
+
+ while ( arc >= start_arc && e <= e2 )
+ {
+ ras.joint = FALSE;
+
+ y2 = arc[0].y;
+
+ if ( y2 > e )
+ {
+ y1 = arc[degree].y;
+ if ( y2 - y1 >= ras.precision_step )
+ {
+ splitter( arc );
+ arc += degree;
+ }
+ else
+ {
+ *top++ = arc[degree].x + FMulDiv( arc[0].x-arc[degree].x,
+ e - y1, y2 - y1 );
+ arc -= degree;
+ e += ras.precision;
+ }
+ }
+ else
+ {
+ if ( y2 == e )
+ {
+ ras.joint = TRUE;
+ *top++ = arc[0].x;
+
+ e += ras.precision;
+ }
+ arc -= degree;
+ }
+ }
+
+ Fin:
+ ras.top = top;
+ ras.arc -= degree;
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Bezier_Down */
+ /* */
+ /* <Description> */
+ /* Computes the x-coordinates of an descending Bezier arc and stores */
+ /* them in the render pool. */
+ /* */
+ /* <Input> */
+ /* degree :: The degree of the Bezier arc (either 2 or 3). */
+ /* */
+ /* splitter :: The function to split Bezier arcs. */
+ /* */
+ /* miny :: A lower vertical clipping bound value. */
+ /* */
+ /* maxy :: An upper vertical clipping bound value. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on render pool overflow. */
+ /* */
+ static Bool
+ Bezier_Down( RAS_ARGS Int degree,
+ TSplitter splitter,
+ Long miny,
+ Long maxy )
+ {
+ TPoint* arc = ras.arc;
+ Bool result, fresh;
+
+
+ arc[0].y = -arc[0].y;
+ arc[1].y = -arc[1].y;
+ arc[2].y = -arc[2].y;
+ if ( degree > 2 )
+ arc[3].y = -arc[3].y;
+
+ fresh = ras.fresh;
+
+ result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny );
+
+ if ( fresh && !ras.fresh )
+ ras.cProfile->start = -ras.cProfile->start;
+
+ arc[0].y = -arc[0].y;
+ return result;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Line_To */
+ /* */
+ /* <Description> */
+ /* Injects a new line segment and adjusts Profiles list. */
+ /* */
+ /* <Input> */
+ /* x :: The x-coordinate of the segment's end point (its start point */
+ /* is stored in `LastX'). */
+ /* */
+ /* y :: The y-coordinate of the segment's end point (its start point */
+ /* is stored in `LastY'). */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on render pool overflow or incorrect */
+ /* profile. */
+ /* */
+ static Bool
+ Line_To( RAS_ARGS Long x,
+ Long y )
+ {
+ /* First, detect a change of direction */
+
+ switch ( ras.state )
+ {
+ case Unknown:
+ if ( y > ras.lastY )
+ {
+ if ( New_Profile( RAS_VARS Ascending ) )
+ return FAILURE;
+ }
+ else
+ {
+ if ( y < ras.lastY )
+ if ( New_Profile( RAS_VARS Descending ) )
+ return FAILURE;
+ }
+ break;
+
+ case Ascending:
+ if ( y < ras.lastY )
+ {
+ if ( End_Profile( RAS_VAR ) ||
+ New_Profile( RAS_VARS Descending ) )
+ return FAILURE;
+ }
+ break;
+
+ case Descending:
+ if ( y > ras.lastY )
+ {
+ if ( End_Profile( RAS_VAR ) ||
+ New_Profile( RAS_VARS Ascending ) )
+ return FAILURE;
+ }
+ break;
+
+ default:
+ ;
+ }
+
+ /* Then compute the lines */
+
+ switch ( ras.state )
+ {
+ case Ascending:
+ if ( Line_Up( RAS_VARS ras.lastX, ras.lastY,
+ x, y, ras.minY, ras.maxY ) )
+ return FAILURE;
+ break;
+
+ case Descending:
+ if ( Line_Down( RAS_VARS ras.lastX, ras.lastY,
+ x, y, ras.minY, ras.maxY ) )
+ return FAILURE;
+ break;
+
+ default:
+ ;
+ }
+
+ ras.lastX = x;
+ ras.lastY = y;
+
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Conic_To */
+ /* */
+ /* <Description> */
+ /* Injects a new conic arc and adjusts the profile list. */
+ /* */
+ /* <Input> */
+ /* cx :: The x-coordinate of the arc's new control point. */
+ /* */
+ /* cy :: The y-coordinate of the arc's new control point. */
+ /* */
+ /* x :: The x-coordinate of the arc's end point (its start point is */
+ /* stored in `LastX'). */
+ /* */
+ /* y :: The y-coordinate of the arc's end point (its start point is */
+ /* stored in `LastY'). */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on render pool overflow or incorrect */
+ /* profile. */
+ /* */
+ static Bool
+ Conic_To( RAS_ARGS Long cx,
+ Long cy,
+ Long x,
+ Long y )
+ {
+ Long y1, y2, y3, x3, ymin, ymax;
+ TStates state_bez;
+
+
+ ras.arc = ras.arcs;
+ ras.arc[2].x = ras.lastX;
+ ras.arc[2].y = ras.lastY;
+ ras.arc[1].x = cx; ras.arc[1].y = cy;
+ ras.arc[0].x = x; ras.arc[0].y = y;
+
+ do
+ {
+ y1 = ras.arc[2].y;
+ y2 = ras.arc[1].y;
+ y3 = ras.arc[0].y;
+ x3 = ras.arc[0].x;
+
+ /* first, categorize the Bezier arc */
+
+ if ( y1 <= y3 )
+ {
+ ymin = y1;
+ ymax = y3;
+ }
+ else
+ {
+ ymin = y3;
+ ymax = y1;
+ }
+
+ if ( y2 < ymin || y2 > ymax )
+ {
+ /* this arc has no given direction, split it! */
+ Split_Conic( ras.arc );
+ ras.arc += 2;
+ }
+ else if ( y1 == y3 )
+ {
+ /* this arc is flat, ignore it and pop it from the Bezier stack */
+ ras.arc -= 2;
+ }
+ else
+ {
+ /* the arc is y-monotonous, either ascending or descending */
+ /* detect a change of direction */
+ state_bez = y1 < y3 ? Ascending : Descending;
+ if ( ras.state != state_bez )
+ {
+ /* finalize current profile if any */
+ if ( ras.state != Unknown &&
+ End_Profile( RAS_VAR ) )
+ goto Fail;
+
+ /* create a new profile */
+ if ( New_Profile( RAS_VARS state_bez ) )
+ goto Fail;
+ }
+
+ /* now call the appropriate routine */
+ if ( state_bez == Ascending )
+ {
+ if ( Bezier_Up( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
+ goto Fail;
+ }
+ else
+ if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
+ goto Fail;
+ }
+
+ } while ( ras.arc >= ras.arcs );
+
+ ras.lastX = x3;
+ ras.lastY = y3;
+
+ return SUCCESS;
+
+ Fail:
+ return FAILURE;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Cubic_To */
+ /* */
+ /* <Description> */
+ /* Injects a new cubic arc and adjusts the profile list. */
+ /* */
+ /* <Input> */
+ /* cx1 :: The x-coordinate of the arc's first new control point. */
+ /* */
+ /* cy1 :: The y-coordinate of the arc's first new control point. */
+ /* */
+ /* cx2 :: The x-coordinate of the arc's second new control point. */
+ /* */
+ /* cy2 :: The y-coordinate of the arc's second new control point. */
+ /* */
+ /* x :: The x-coordinate of the arc's end point (its start point is */
+ /* stored in `LastX'). */
+ /* */
+ /* y :: The y-coordinate of the arc's end point (its start point is */
+ /* stored in `LastY'). */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on render pool overflow or incorrect */
+ /* profile. */
+ /* */
+ static Bool
+ Cubic_To( RAS_ARGS Long cx1,
+ Long cy1,
+ Long cx2,
+ Long cy2,
+ Long x,
+ Long y )
+ {
+ Long y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2;
+ TStates state_bez;
+
+
+ ras.arc = ras.arcs;
+ ras.arc[3].x = ras.lastX;
+ ras.arc[3].y = ras.lastY;
+ ras.arc[2].x = cx1; ras.arc[2].y = cy1;
+ ras.arc[1].x = cx2; ras.arc[1].y = cy2;
+ ras.arc[0].x = x; ras.arc[0].y = y;
+
+ do
+ {
+ y1 = ras.arc[3].y;
+ y2 = ras.arc[2].y;
+ y3 = ras.arc[1].y;
+ y4 = ras.arc[0].y;
+ x4 = ras.arc[0].x;
+
+ /* first, categorize the Bezier arc */
+
+ if ( y1 <= y4 )
+ {
+ ymin1 = y1;
+ ymax1 = y4;
+ }
+ else
+ {
+ ymin1 = y4;
+ ymax1 = y1;
+ }
+
+ if ( y2 <= y3 )
+ {
+ ymin2 = y2;
+ ymax2 = y3;
+ }
+ else
+ {
+ ymin2 = y3;
+ ymax2 = y2;
+ }
+
+ if ( ymin2 < ymin1 || ymax2 > ymax1 )
+ {
+ /* this arc has no given direction, split it! */
+ Split_Cubic( ras.arc );
+ ras.arc += 3;
+ }
+ else if ( y1 == y4 )
+ {
+ /* this arc is flat, ignore it and pop it from the Bezier stack */
+ ras.arc -= 3;
+ }
+ else
+ {
+ state_bez = ( y1 <= y4 ) ? Ascending : Descending;
+
+ /* detect a change of direction */
+ if ( ras.state != state_bez )
+ {
+ if ( ras.state != Unknown &&
+ End_Profile( RAS_VAR ) )
+ goto Fail;
+
+ if ( New_Profile( RAS_VARS state_bez ) )
+ goto Fail;
+ }
+
+ /* compute intersections */
+ if ( state_bez == Ascending )
+ {
+ if ( Bezier_Up( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
+ goto Fail;
+ }
+ else
+ if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
+ goto Fail;
+ }
+
+ } while ( ras.arc >= ras.arcs );
+
+ ras.lastX = x4;
+ ras.lastY = y4;
+
+ return SUCCESS;
+
+ Fail:
+ return FAILURE;
+ }
+
+
+#undef SWAP_
+#define SWAP_( x, y ) do \
+ { \
+ Long swap = x; \
+ \
+ \
+ x = y; \
+ y = swap; \
+ } while ( 0 )
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Decompose_Curve */
+ /* */
+ /* <Description> */
+ /* Scans the outline arays in order to emit individual segments and */
+ /* Beziers by calling Line_To() and Bezier_To(). It handles all */
+ /* weird cases, like when the first point is off the curve, or when */
+ /* there are simply no `on' points in the contour! */
+ /* */
+ /* <Input> */
+ /* first :: The index of the first point in the contour. */
+ /* */
+ /* last :: The index of the last point in the contour. */
+ /* */
+ /* flipped :: If set, flip the direction of the curve. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE on error. */
+ /* */
+ static Bool
+ Decompose_Curve( RAS_ARGS UShort first,
+ UShort last,
+ int flipped )
+ {
+ FT_Vector v_last;
+ FT_Vector v_control;
+ FT_Vector v_start;
+
+ FT_Vector* points;
+ FT_Vector* point;
+ FT_Vector* limit;
+ char* tags;
+
+ unsigned tag; /* current point's state */
+
+
+ points = ras.outline.points;
+ limit = points + last;
+
+ v_start.x = SCALED( points[first].x );
+ v_start.y = SCALED( points[first].y );
+ v_last.x = SCALED( points[last].x );
+ v_last.y = SCALED( points[last].y );
+
+ if ( flipped )
+ {
+ SWAP_( v_start.x, v_start.y );
+ SWAP_( v_last.x, v_last.y );
+ }
+
+ v_control = v_start;
+
+ point = points + first;
+ tags = ras.outline.tags + first;
+ tag = FT_CURVE_TAG( tags[0] );
+
+ /* A contour cannot start with a cubic control point! */
+ if ( tag == FT_Curve_Tag_Cubic )
+ goto Invalid_Outline;
+
+ /* check first point to determine origin */
+ if ( tag == FT_Curve_Tag_Conic )
+ {
+ /* first point is conic control. Yes, this happens. */
+ if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_Curve_Tag_On )
+ {
+ /* start at last point if it is on the curve */
+ v_start = v_last;
+ limit--;
+ }
+ else
+ {
+ /* if both first and last points are conic, */
+ /* start at their middle and record its position */
+ /* for closure */
+ v_start.x = ( v_start.x + v_last.x ) / 2;
+ v_start.y = ( v_start.y + v_last.y ) / 2;
+
+ v_last = v_start;
+ }
+ point--;
+ tags--;
+ }
+
+ ras.lastX = v_start.x;
+ ras.lastY = v_start.y;
+
+ while ( point < limit )
+ {
+ point++;
+ tags++;
+
+ tag = FT_CURVE_TAG( tags[0] );
+
+ switch ( tag )
+ {
+ case FT_Curve_Tag_On: /* emit a single line_to */
+ {
+ Long x, y;
+
+
+ x = SCALED( point->x );
+ y = SCALED( point->y );
+ if ( flipped )
+ SWAP_( x, y );
+
+ if ( Line_To( RAS_VARS x, y ) )
+ goto Fail;
+ continue;
+ }
+
+ case FT_Curve_Tag_Conic: /* consume conic arcs */
+ v_control.x = SCALED( point[0].x );
+ v_control.y = SCALED( point[0].y );
+
+ if ( flipped )
+ SWAP_( v_control.x, v_control.y );
+
+ Do_Conic:
+ if ( point < limit )
+ {
+ FT_Vector v_middle;
+ Long x, y;
+
+
+ point++;
+ tags++;
+ tag = FT_CURVE_TAG( tags[0] );
+
+ x = SCALED( point[0].x );
+ y = SCALED( point[0].y );
+
+ if ( flipped )
+ SWAP_( x, y );
+
+ if ( tag == FT_Curve_Tag_On )
+ {
+ if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) )
+ goto Fail;
+ continue;
+ }
+
+ if ( tag != FT_Curve_Tag_Conic )
+ goto Invalid_Outline;
+
+ v_middle.x = ( v_control.x + x ) / 2;
+ v_middle.y = ( v_control.y + y ) / 2;
+
+ if ( Conic_To( RAS_VARS v_control.x, v_control.y,
+ v_middle.x, v_middle.y ) )
+ goto Fail;
+
+ v_control.x = x;
+ v_control.y = y;
+
+ goto Do_Conic;
+ }
+
+ if ( Conic_To( RAS_VARS v_control.x, v_control.y,
+ v_start.x, v_start.y ) )
+ goto Fail;
+
+ goto Close;
+
+ default: /* FT_Curve_Tag_Cubic */
+ {
+ Long x1, y1, x2, y2, x3, y3;
+
+
+ if ( point + 1 > limit ||
+ FT_CURVE_TAG( tags[1] ) != FT_Curve_Tag_Cubic )
+ goto Invalid_Outline;
+
+ point += 2;
+ tags += 2;
+
+ x1 = SCALED( point[-2].x );
+ y1 = SCALED( point[-2].y );
+ x2 = SCALED( point[-1].x );
+ y2 = SCALED( point[-1].y );
+ x3 = SCALED( point[ 0].x );
+ y3 = SCALED( point[ 0].y );
+
+ if ( flipped )
+ {
+ SWAP_( x1, y1 );
+ SWAP_( x2, y2 );
+ SWAP_( x3, y3 );
+ }
+
+ if ( point <= limit )
+ {
+ if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) )
+ goto Fail;
+ continue;
+ }
+
+ if ( Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y ) )
+ goto Fail;
+ goto Close;
+ }
+ }
+ }
+
+ /* close the contour with a line segment */
+ if ( Line_To( RAS_VARS v_start.x, v_start.y ) )
+ goto Fail;
+
+ Close:
+ return SUCCESS;
+
+ Invalid_Outline:
+ ras.error = Raster_Err_Invalid;
+
+ Fail:
+ return FAILURE;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Convert_Glyph */
+ /* */
+ /* <Description> */
+ /* Converts a glyph into a series of segments and arcs and makes a */
+ /* profiles list with them. */
+ /* */
+ /* <Input> */
+ /* flipped :: If set, flip the direction of curve. */
+ /* */
+ /* <Return> */
+ /* SUCCESS on success, FAILURE if any error was encountered during */
+ /* rendering. */
+ /* */
+ static Bool
+ Convert_Glyph( RAS_ARGS int flipped )
+ {
+ int i;
+ unsigned start;
+
+ PProfile lastProfile;
+
+
+ ras.fProfile = NULL;
+ ras.joint = FALSE;
+ ras.fresh = FALSE;
+
+ ras.maxBuff = ras.sizeBuff - AlignProfileSize;
+
+ ras.numTurns = 0;
+
+ ras.cProfile = (PProfile)ras.top;
+ ras.cProfile->offset = ras.top;
+ ras.num_Profs = 0;
+
+ start = 0;
+
+ for ( i = 0; i < ras.outline.n_contours; i++ )
+ {
+ ras.state = Unknown;
+ ras.gProfile = NULL;
+
+ if ( Decompose_Curve( RAS_VARS (unsigned short)start,
+ ras.outline.contours[i],
+ flipped ) )
+ return FAILURE;
+
+ start = ras.outline.contours[i] + 1;
+
+ /* We must now see whether the extreme arcs join or not */
+ if ( FRAC( ras.lastY ) == 0 &&
+ ras.lastY >= ras.minY &&
+ ras.lastY <= ras.maxY )
+ if ( ras.gProfile && ras.gProfile->flow == ras.cProfile->flow )
+ ras.top--;
+ /* Note that ras.gProfile can be nil if the contour was too small */
+ /* to be drawn. */
+
+ lastProfile = ras.cProfile;
+ if ( End_Profile( RAS_VAR ) )
+ return FAILURE;
+
+ /* close the `next profile in contour' linked list */
+ if ( ras.gProfile )
+ lastProfile->next = ras.gProfile;
+ }
+
+ if ( Finalize_Profile_Table( RAS_VAR ) )
+ return FAILURE;
+
+ return (Bool)( ras.top < ras.maxBuff ? SUCCESS : FAILURE );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /** **/
+ /** SCAN-LINE SWEEPS AND DRAWING **/
+ /** **/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* Init_Linked */
+ /* */
+ /* Initializes an empty linked list. */
+ /* */
+ static void
+ Init_Linked( TProfileList* l )
+ {
+ *l = NULL;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* InsNew */
+ /* */
+ /* Inserts a new profile in a linked list. */
+ /* */
+ static void
+ InsNew( PProfileList list,
+ PProfile profile )
+ {
+ PProfile *old, current;
+ Long x;
+
+
+ old = list;
+ current = *old;
+ x = profile->X;
+
+ while ( current )
+ {
+ if ( x < current->X )
+ break;
+ old = ¤t->link;
+ current = *old;
+ }
+
+ profile->link = current;
+ *old = profile;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* DelOld */
+ /* */
+ /* Removes an old profile from a linked list. */
+ /* */
+ static void
+ DelOld( PProfileList list,
+ PProfile profile )
+ {
+ PProfile *old, current;
+
+
+ old = list;
+ current = *old;
+
+ while ( current )
+ {
+ if ( current == profile )
+ {
+ *old = current->link;
+ return;
+ }
+
+ old = ¤t->link;
+ current = *old;
+ }
+
+ /* we should never get there, unless the profile was not part of */
+ /* the list. */
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Sort */
+ /* */
+ /* Sorts a trace list. In 95%, the list is already sorted. We need */
+ /* an algorithm which is fast in this case. Bubble sort is enough */
+ /* and simple. */
+ /* */
+ static void
+ Sort( PProfileList list )
+ {
+ PProfile *old, current, next;
+
+
+ /* First, set the new X coordinate of each profile */
+ current = *list;
+ while ( current )
+ {
+ current->X = *current->offset;
+ current->offset += current->flow;
+ current->height--;
+ current = current->link;
+ }
+
+ /* Then sort them */
+ old = list;
+ current = *old;
+
+ if ( !current )
+ return;
+
+ next = current->link;
+
+ while ( next )
+ {
+ if ( current->X <= next->X )
+ {
+ old = ¤t->link;
+ current = *old;
+
+ if ( !current )
+ return;
+ }
+ else
+ {
+ *old = next;
+ current->link = next->link;
+ next->link = current;
+
+ old = list;
+ current = *old;
+ }
+
+ next = current->link;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Vertical Sweep Procedure Set */
+ /* */
+ /* These four routines are used during the vertical black/white sweep */
+ /* phase by the generic Draw_Sweep() function. */
+ /* */
+ /*************************************************************************/
+
+ static void
+ Vertical_Sweep_Init( RAS_ARGS Short* min,
+ Short* max )
+ {
+ Long pitch = ras.target.pitch;
+
+ FT_UNUSED( max );
+
+
+ ras.traceIncr = (Short)-pitch;
+ ras.traceOfs = -*min * pitch;
+ if ( pitch > 0 )
+ ras.traceOfs += ( ras.target.rows - 1 ) * pitch;
+
+ ras.gray_min_x = 0;
+ ras.gray_max_x = 0;
+ }
+
+
+ static void
+ Vertical_Sweep_Span( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right )
+ {
+ Long e1, e2;
+ int c1, c2;
+ Byte f1, f2;
+ Byte* target;
+
+ FT_UNUSED( y );
+ FT_UNUSED( left );
+ FT_UNUSED( right );
+
+
+ /* Drop-out control */
+
+ e1 = TRUNC( CEILING( x1 ) );
+
+ if ( x2 - x1 - ras.precision <= ras.precision_jitter )
+ e2 = e1;
+ else
+ e2 = TRUNC( FLOOR( x2 ) );
+
+ if ( e2 >= 0 && e1 < ras.bWidth )
+ {
+ if ( e1 < 0 )
+ e1 = 0;
+ if ( e2 >= ras.bWidth )
+ e2 = ras.bWidth - 1;
+
+ c1 = (Short)( e1 >> 3 );
+ c2 = (Short)( e2 >> 3 );
+
+ f1 = (Byte) ( 0xFF >> ( e1 & 7 ) );
+ f2 = (Byte) ~( 0x7F >> ( e2 & 7 ) );
+
+ if ( ras.gray_min_x > c1 ) ras.gray_min_x = (short)c1;
+ if ( ras.gray_max_x < c2 ) ras.gray_max_x = (short)c2;
+
+ target = ras.bTarget + ras.traceOfs + c1;
+ c2 -= c1;
+
+ if ( c2 > 0 )
+ {
+ target[0] |= f1;
+
+ /* memset() is slower than the following code on many platforms. */
+ /* This is due to the fact that, in the vast majority of cases, */
+ /* the span length in bytes is relatively small. */
+ c2--;
+ while ( c2 > 0 )
+ {
+ *(++target) = 0xFF;
+ c2--;
+ }
+ target[1] |= f2;
+ }
+ else
+ *target |= ( f1 & f2 );
+ }
+ }
+
+
+ static void
+ Vertical_Sweep_Drop( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right )
+ {
+ Long e1, e2;
+ Short c1, f1;
+
+
+ /* Drop-out control */
+
+ e1 = CEILING( x1 );
+ e2 = FLOOR ( x2 );
+
+ if ( e1 > e2 )
+ {
+ if ( e1 == e2 + ras.precision )
+ {
+ switch ( ras.dropOutControl )
+ {
+ case 1:
+ e1 = e2;
+ break;
+
+ case 4:
+ e1 = CEILING( (x1 + x2 + 1) / 2 );
+ break;
+
+ case 2:
+ case 5:
+ /* Drop-out Control Rule #4 */
+
+ /* The spec is not very clear regarding rule #4. It */
+ /* presents a method that is way too costly to implement */
+ /* while the general idea seems to get rid of `stubs'. */
+ /* */
+ /* Here, we only get rid of stubs recognized if: */
+ /* */
+ /* upper stub: */
+ /* */
+ /* - P_Left and P_Right are in the same contour */
+ /* - P_Right is the successor of P_Left in that contour */
+ /* - y is the top of P_Left and P_Right */
+ /* */
+ /* lower stub: */
+ /* */
+ /* - P_Left and P_Right are in the same contour */
+ /* - P_Left is the successor of P_Right in that contour */
+ /* - y is the bottom of P_Left */
+ /* */
+
+ /* FIXXXME: uncommenting this line solves the disappearing */
+ /* bit problem in the `7' of verdana 10pts, but */
+ /* makes a new one in the `C' of arial 14pts */
+
+#if 0
+ if ( x2 - x1 < ras.precision_half )
+#endif
+ {
+ /* upper stub test */
+ if ( left->next == right && left->height <= 0 )
+ return;
+
+ /* lower stub test */
+ if ( right->next == left && left->start == y )
+ return;
+ }
+
+ /* check that the rightmost pixel isn't set */
+
+ e1 = TRUNC( e1 );
+
+ c1 = (Short)( e1 >> 3 );
+ f1 = (Short)( e1 & 7 );
+
+ if ( e1 >= 0 && e1 < ras.bWidth &&
+ ras.bTarget[ras.traceOfs + c1] & ( 0x80 >> f1 ) )
+ return;
+
+ if ( ras.dropOutControl == 2 )
+ e1 = e2;
+ else
+ e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+
+ break;
+
+ default:
+ return; /* unsupported mode */
+ }
+ }
+ else
+ return;
+ }
+
+ e1 = TRUNC( e1 );
+
+ if ( e1 >= 0 && e1 < ras.bWidth )
+ {
+ c1 = (Short)( e1 >> 3 );
+ f1 = (Short)( e1 & 7 );
+
+ if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1;
+ if ( ras.gray_max_x < c1 ) ras.gray_max_x = c1;
+
+ ras.bTarget[ras.traceOfs + c1] |= (char)( 0x80 >> f1 );
+ }
+ }
+
+
+ static void
+ Vertical_Sweep_Step( RAS_ARG )
+ {
+ ras.traceOfs += ras.traceIncr;
+ }
+
+
+ /***********************************************************************/
+ /* */
+ /* Horizontal Sweep Procedure Set */
+ /* */
+ /* These four routines are used during the horizontal black/white */
+ /* sweep phase by the generic Draw_Sweep() function. */
+ /* */
+ /***********************************************************************/
+
+ static void
+ Horizontal_Sweep_Init( RAS_ARGS Short* min,
+ Short* max )
+ {
+ /* nothing, really */
+ FT_UNUSED( raster );
+ FT_UNUSED( min );
+ FT_UNUSED( max );
+ }
+
+
+ static void
+ Horizontal_Sweep_Span( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right )
+ {
+ Long e1, e2;
+ PByte bits;
+ Byte f1;
+
+ FT_UNUSED( left );
+ FT_UNUSED( right );
+
+
+ if ( x2 - x1 < ras.precision )
+ {
+ e1 = CEILING( x1 );
+ e2 = FLOOR ( x2 );
+
+ if ( e1 == e2 )
+ {
+ bits = ras.bTarget + ( y >> 3 );
+ f1 = (Byte)( 0x80 >> ( y & 7 ) );
+
+ e1 = TRUNC( e1 );
+
+ if ( e1 >= 0 && e1 < ras.target.rows )
+ {
+ PByte p;
+
+
+ p = bits - e1*ras.target.pitch;
+ if ( ras.target.pitch > 0 )
+ p += ( ras.target.rows - 1 ) * ras.target.pitch;
+
+ p[0] |= f1;
+ }
+ }
+ }
+ }
+
+
+ static void
+ Horizontal_Sweep_Drop( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right )
+ {
+ Long e1, e2;
+ PByte bits;
+ Byte f1;
+
+
+ /* During the horizontal sweep, we only take care of drop-outs */
+
+ e1 = CEILING( x1 );
+ e2 = FLOOR ( x2 );
+
+ if ( e1 > e2 )
+ {
+ if ( e1 == e2 + ras.precision )
+ {
+ switch ( ras.dropOutControl )
+ {
+ case 1:
+ e1 = e2;
+ break;
+
+ case 4:
+ e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+ break;
+
+ case 2:
+ case 5:
+
+ /* Drop-out Control Rule #4 */
+
+ /* The spec is not very clear regarding rule #4. It */
+ /* presents a method that is way too costly to implement */
+ /* while the general idea seems to get rid of `stubs'. */
+ /* */
+
+ /* rightmost stub test */
+ if ( left->next == right && left->height <= 0 )
+ return;
+
+ /* leftmost stub test */
+ if ( right->next == left && left->start == y )
+ return;
+
+ /* check that the rightmost pixel isn't set */
+
+ e1 = TRUNC( e1 );
+
+ bits = ras.bTarget + ( y >> 3 );
+ f1 = (Byte)( 0x80 >> ( y & 7 ) );
+
+ bits -= e1 * ras.target.pitch;
+ if ( ras.target.pitch > 0 )
+ bits += ( ras.target.rows - 1 ) * ras.target.pitch;
+
+ if ( e1 >= 0 &&
+ e1 < ras.target.rows &&
+ *bits & f1 )
+ return;
+
+ if ( ras.dropOutControl == 2 )
+ e1 = e2;
+ else
+ e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+
+ break;
+
+ default:
+ return; /* unsupported mode */
+ }
+ }
+ else
+ return;
+ }
+
+ bits = ras.bTarget + ( y >> 3 );
+ f1 = (Byte)( 0x80 >> ( y & 7 ) );
+
+ e1 = TRUNC( e1 );
+
+ if ( e1 >= 0 && e1 < ras.target.rows )
+ {
+ bits -= e1 * ras.target.pitch;
+ if ( ras.target.pitch > 0 )
+ bits += ( ras.target.rows - 1 ) * ras.target.pitch;
+
+ bits[0] |= f1;
+ }
+ }
+
+
+ static void
+ Horizontal_Sweep_Step( RAS_ARG )
+ {
+ /* Nothing, really */
+ FT_UNUSED( raster );
+ }
+
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+
+ /*************************************************************************/
+ /* */
+ /* Vertical Gray Sweep Procedure Set */
+ /* */
+ /* These two routines are used during the vertical gray-levels sweep */
+ /* phase by the generic Draw_Sweep() function. */
+ /* */
+ /* NOTES */
+ /* */
+ /* - The target pixmap's width *must* be a multiple of 4. */
+ /* */
+ /* - You have to use the function Vertical_Sweep_Span() for the gray */
+ /* span call. */
+ /* */
+ /*************************************************************************/
+
+ static void
+ Vertical_Gray_Sweep_Init( RAS_ARGS Short* min,
+ Short* max )
+ {
+ Long pitch, byte_len;
+
+
+ *min = *min & -2;
+ *max = ( *max + 3 ) & -2;
+
+ ras.traceOfs = 0;
+ pitch = ras.target.pitch;
+ byte_len = -pitch;
+ ras.traceIncr = (Short)byte_len;
+ ras.traceG = ( *min / 2 ) * byte_len;
+
+ if ( pitch > 0 )
+ {
+ ras.traceG += ( ras.target.rows - 1 ) * pitch;
+ byte_len = -byte_len;
+ }
+
+ ras.gray_min_x = (Short)byte_len;
+ ras.gray_max_x = -(Short)byte_len;
+ }
+
+
+ static void
+ Vertical_Gray_Sweep_Step( RAS_ARG )
+ {
+ Int c1, c2;
+ PByte pix, bit, bit2;
+ Int* count = ras.count_table;
+ Byte* grays;
+
+
+ ras.traceOfs += ras.gray_width;
+
+ if ( ras.traceOfs > ras.gray_width )
+ {
+ pix = ras.gTarget + ras.traceG + ras.gray_min_x * 4;
+ grays = ras.grays;
+
+ if ( ras.gray_max_x >= 0 )
+ {
+ Long last_pixel = ras.target.width - 1;
+ Int last_cell = last_pixel >> 2;
+ Int last_bit = last_pixel & 3;
+ Bool over = 0;
+
+
+ if ( ras.gray_max_x >= last_cell && last_bit != 3 )
+ {
+ ras.gray_max_x = last_cell - 1;
+ over = 1;
+ }
+
+ if ( ras.gray_min_x < 0 )
+ ras.gray_min_x = 0;
+
+ bit = ras.bTarget + ras.gray_min_x;
+ bit2 = bit + ras.gray_width;
+
+ c1 = ras.gray_max_x - ras.gray_min_x;
+
+ while ( c1 >= 0 )
+ {
+ c2 = count[*bit] + count[*bit2];
+
+ if ( c2 )
+ {
+ pix[0] = grays[(c2 >> 12) & 0x000F];
+ pix[1] = grays[(c2 >> 8 ) & 0x000F];
+ pix[2] = grays[(c2 >> 4 ) & 0x000F];
+ pix[3] = grays[ c2 & 0x000F];
+
+ *bit = 0;
+ *bit2 = 0;
+ }
+
+ bit++;
+ bit2++;
+ pix += 4;
+ c1--;
+ }
+
+ if ( over )
+ {
+ c2 = count[*bit] + count[*bit2];
+ if ( c2 )
+ {
+ switch ( last_bit )
+ {
+ case 2:
+ pix[2] = grays[(c2 >> 4 ) & 0x000F];
+ case 1:
+ pix[1] = grays[(c2 >> 8 ) & 0x000F];
+ default:
+ pix[0] = grays[(c2 >> 12) & 0x000F];
+ }
+
+ *bit = 0;
+ *bit2 = 0;
+ }
+ }
+ }
+
+ ras.traceOfs = 0;
+ ras.traceG += ras.traceIncr;
+
+ ras.gray_min_x = 32000;
+ ras.gray_max_x = -32000;
+ }
+ }
+
+
+ static void
+ Horizontal_Gray_Sweep_Span( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right )
+ {
+ /* nothing, really */
+ FT_UNUSED( raster );
+ FT_UNUSED( y );
+ FT_UNUSED( x1 );
+ FT_UNUSED( x2 );
+ FT_UNUSED( left );
+ FT_UNUSED( right );
+ }
+
+
+ static void
+ Horizontal_Gray_Sweep_Drop( RAS_ARGS Short y,
+ FT_F26Dot6 x1,
+ FT_F26Dot6 x2,
+ PProfile left,
+ PProfile right )
+ {
+ Long e1, e2;
+ PByte pixel;
+ Byte color;
+
+
+ /* During the horizontal sweep, we only take care of drop-outs */
+ e1 = CEILING( x1 );
+ e2 = FLOOR ( x2 );
+
+ if ( e1 > e2 )
+ {
+ if ( e1 == e2 + ras.precision )
+ {
+ switch ( ras.dropOutControl )
+ {
+ case 1:
+ e1 = e2;
+ break;
+
+ case 4:
+ e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+ break;
+
+ case 2:
+ case 5:
+
+ /* Drop-out Control Rule #4 */
+
+ /* The spec is not very clear regarding rule #4. It */
+ /* presents a method that is way too costly to implement */
+ /* while the general idea seems to get rid of `stubs'. */
+ /* */
+
+ /* rightmost stub test */
+ if ( left->next == right && left->height <= 0 )
+ return;
+
+ /* leftmost stub test */
+ if ( right->next == left && left->start == y )
+ return;
+
+ if ( ras.dropOutControl == 2 )
+ e1 = e2;
+ else
+ e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+
+ break;
+
+ default:
+ return; /* unsupported mode */
+ }
+ }
+ else
+ return;
+ }
+
+ if ( e1 >= 0 )
+ {
+ if ( x2 - x1 >= ras.precision_half )
+ color = ras.grays[2];
+ else
+ color = ras.grays[1];
+
+ e1 = TRUNC( e1 ) / 2;
+ if ( e1 < ras.target.rows )
+ {
+ pixel = ras.gTarget - e1 * ras.target.pitch + y / 2;
+ if ( ras.target.pitch > 0 )
+ pixel += ( ras.target.rows - 1 ) * ras.target.pitch;
+
+ if ( pixel[0] == ras.grays[0] )
+ pixel[0] = color;
+ }
+ }
+ }
+
+
+#endif /* FT_RASTER_OPTION_ANTI_ALIASING */
+
+
+ /*************************************************************************/
+ /* */
+ /* Generic Sweep Drawing routine */
+ /* */
+ /*************************************************************************/
+
+ static Bool
+ Draw_Sweep( RAS_ARG )
+ {
+ Short y, y_change, y_height;
+
+ PProfile P, Q, P_Left, P_Right;
+
+ Short min_Y, max_Y, top, bottom, dropouts;
+
+ Long x1, x2, xs, e1, e2;
+
+ TProfileList wait;
+ TProfileList draw_left, draw_right;
+
+
+ /* Init empty linked lists */
+
+ Init_Linked( &wait );
+
+ Init_Linked( &draw_left );
+ Init_Linked( &draw_right );
+
+ /* first, compute min and max Y */
+
+ P = ras.fProfile;
+ max_Y = (Short)TRUNC( ras.minY );
+ min_Y = (Short)TRUNC( ras.maxY );
+
+ while ( P )
+ {
+ Q = P->link;
+
+ bottom = (Short)P->start;
+ top = (Short)( P->start + P->height - 1 );
+
+ if ( min_Y > bottom ) min_Y = bottom;
+ if ( max_Y < top ) max_Y = top;
+
+ P->X = 0;
+ InsNew( &wait, P );
+
+ P = Q;
+ }
+
+ /* Check the Y-turns */
+ if ( ras.numTurns == 0 )
+ {
+ ras.error = Raster_Err_Invalid;
+ return FAILURE;
+ }
+
+ /* Now inits the sweep */
+
+ ras.Proc_Sweep_Init( RAS_VARS &min_Y, &max_Y );
+
+ /* Then compute the distance of each profile from min_Y */
+
+ P = wait;
+
+ while ( P )
+ {
+ P->countL = (UShort)( P->start - min_Y );
+ P = P->link;
+ }
+
+ /* Let's go */
+
+ y = min_Y;
+ y_height = 0;
+
+ if ( ras.numTurns > 0 &&
+ ras.sizeBuff[-ras.numTurns] == min_Y )
+ ras.numTurns--;
+
+ while ( ras.numTurns > 0 )
+ {
+ /* look in the wait list for new activations */
+
+ P = wait;
+
+ while ( P )
+ {
+ Q = P->link;
+ P->countL -= y_height;
+ if ( P->countL == 0 )
+ {
+ DelOld( &wait, P );
+
+ switch ( P->flow )
+ {
+ case Flow_Up:
+ InsNew( &draw_left, P );
+ break;
+
+ case Flow_Down:
+ InsNew( &draw_right, P );
+ break;
+ }
+ }
+
+ P = Q;
+ }
+
+ /* Sort the drawing lists */
+
+ Sort( &draw_left );
+ Sort( &draw_right );
+
+ y_change = (Short)ras.sizeBuff[-ras.numTurns--];
+ y_height = (Short)( y_change - y );
+
+ while ( y < y_change )
+ {
+ /* Let's trace */
+
+ dropouts = 0;
+
+ P_Left = draw_left;
+ P_Right = draw_right;
+
+ while ( P_Left )
+ {
+ x1 = P_Left ->X;
+ x2 = P_Right->X;
+
+ if ( x1 > x2 )
+ {
+ xs = x1;
+ x1 = x2;
+ x2 = xs;
+ }
+
+ if ( x2 - x1 <= ras.precision )
+ {
+ e1 = FLOOR( x1 );
+ e2 = CEILING( x2 );
+
+ if ( ras.dropOutControl != 0 &&
+ ( e1 > e2 || e2 == e1 + ras.precision ) )
+ {
+ /* a drop out was detected */
+
+ P_Left ->X = x1;
+ P_Right->X = x2;
+
+ /* mark profile for drop-out processing */
+ P_Left->countL = 1;
+ dropouts++;
+
+ goto Skip_To_Next;
+ }
+ }
+
+ ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right );
+
+ Skip_To_Next:
+
+ P_Left = P_Left->link;
+ P_Right = P_Right->link;
+ }
+
+ /* now perform the dropouts _after_ the span drawing -- */
+ /* drop-outs processing has been moved out of the loop */
+ /* for performance tuning */
+ if ( dropouts > 0 )
+ goto Scan_DropOuts;
+
+ Next_Line:
+
+ ras.Proc_Sweep_Step( RAS_VAR );
+
+ y++;
+
+ if ( y < y_change )
+ {
+ Sort( &draw_left );
+ Sort( &draw_right );
+ }
+ }
+
+ /* Now finalize the profiles that needs it */
+
+ P = draw_left;
+ while ( P )
+ {
+ Q = P->link;
+ if ( P->height == 0 )
+ DelOld( &draw_left, P );
+ P = Q;
+ }
+
+ P = draw_right;
+ while ( P )
+ {
+ Q = P->link;
+ if ( P->height == 0 )
+ DelOld( &draw_right, P );
+ P = Q;
+ }
+ }
+
+ /* for gray-scaling, flushes the bitmap scanline cache */
+ while ( y <= max_Y )
+ {
+ ras.Proc_Sweep_Step( RAS_VAR );
+ y++;
+ }
+
+ return SUCCESS;
+
+ Scan_DropOuts:
+
+ P_Left = draw_left;
+ P_Right = draw_right;
+
+ while ( P_Left )
+ {
+ if ( P_Left->countL )
+ {
+ P_Left->countL = 0;
+#if 0
+ dropouts--; /* -- this is useful when debugging only */
+#endif
+ ras.Proc_Sweep_Drop( RAS_VARS y,
+ P_Left->X,
+ P_Right->X,
+ P_Left,
+ P_Right );
+ }
+
+ P_Left = P_Left->link;
+ P_Right = P_Right->link;
+ }
+
+ goto Next_Line;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Render_Single_Pass */
+ /* */
+ /* <Description> */
+ /* Performs one sweep with sub-banding. */
+ /* */
+ /* <Input> */
+ /* flipped :: If set, flip the direction of the outline. */
+ /* */
+ /* <Return> */
+ /* Renderer error code. */
+ /* */
+ static int
+ Render_Single_Pass( RAS_ARGS Bool flipped )
+ {
+ Short i, j, k;
+
+
+ while ( ras.band_top >= 0 )
+ {
+ ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision;
+ ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision;
+
+ ras.top = ras.buff;
+
+ ras.error = Raster_Err_None;
+
+ if ( Convert_Glyph( RAS_VARS flipped ) )
+ {
+ if ( ras.error != Raster_Err_Overflow )
+ return FAILURE;
+
+ ras.error = Raster_Err_None;
+
+ /* sub-banding */
+
+#ifdef DEBUG_RASTER
+ ClearBand( RAS_VARS TRUNC( ras.minY ), TRUNC( ras.maxY ) );
+#endif
+
+ i = ras.band_stack[ras.band_top].y_min;
+ j = ras.band_stack[ras.band_top].y_max;
+
+ k = (Short)( ( i + j ) / 2 );
+
+ if ( ras.band_top >= 7 || k < i )
+ {
+ ras.band_top = 0;
+ ras.error = Raster_Err_Invalid;
+
+ return ras.error;
+ }
+
+ ras.band_stack[ras.band_top + 1].y_min = k;
+ ras.band_stack[ras.band_top + 1].y_max = j;
+
+ ras.band_stack[ras.band_top].y_max = (Short)( k - 1 );
+
+ ras.band_top++;
+ }
+ else
+ {
+ if ( ras.fProfile )
+ if ( Draw_Sweep( RAS_VAR ) )
+ return ras.error;
+ ras.band_top--;
+ }
+ }
+
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Render_Glyph */
+ /* */
+ /* <Description> */
+ /* Renders a glyph in a bitmap. Sub-banding if needed. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ Render_Glyph( RAS_ARG )
+ {
+ FT_Error error;
+
+
+ Set_High_Precision( RAS_VARS ras.outline.flags &
+ ft_outline_high_precision );
+ ras.scale_shift = ras.precision_shift;
+ ras.dropOutControl = 2;
+ ras.second_pass = (FT_Byte)( !( ras.outline.flags &
+ ft_outline_single_pass ) );
+
+ /* Vertical Sweep */
+ ras.Proc_Sweep_Init = Vertical_Sweep_Init;
+ ras.Proc_Sweep_Span = Vertical_Sweep_Span;
+ ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
+ ras.Proc_Sweep_Step = Vertical_Sweep_Step;
+
+ ras.band_top = 0;
+ ras.band_stack[0].y_min = 0;
+ ras.band_stack[0].y_max = (short)( ras.target.rows - 1 );
+
+ ras.bWidth = (unsigned short)ras.target.width;
+ ras.bTarget = (Byte*)ras.target.buffer;
+
+ if ( ( error = Render_Single_Pass( RAS_VARS 0 ) ) != 0 )
+ return error;
+
+ /* Horizontal Sweep */
+ if ( ras.second_pass && ras.dropOutControl != 0 )
+ {
+ ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
+ ras.Proc_Sweep_Span = Horizontal_Sweep_Span;
+ ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop;
+ ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
+
+ ras.band_top = 0;
+ ras.band_stack[0].y_min = 0;
+ ras.band_stack[0].y_max = (short)( ras.target.width - 1 );
+
+ if ( ( error = Render_Single_Pass( RAS_VARS 1 ) ) != 0 )
+ return error;
+ }
+
+ return Raster_Err_Ok;
+ }
+
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Render_Gray_Glyph */
+ /* */
+ /* <Description> */
+ /* Renders a glyph with grayscaling. Sub-banding if needed. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ Render_Gray_Glyph( RAS_ARG )
+ {
+ Long pixel_width;
+ FT_Error error;
+
+
+ Set_High_Precision( RAS_VARS ras.outline.flags &
+ ft_outline_high_precision );
+ ras.scale_shift = ras.precision_shift + 1;
+ ras.dropOutControl = 2;
+ ras.second_pass = !( ras.outline.flags & ft_outline_single_pass );
+
+ /* Vertical Sweep */
+
+ ras.band_top = 0;
+ ras.band_stack[0].y_min = 0;
+ ras.band_stack[0].y_max = 2 * ras.target.rows - 1;
+
+ ras.bWidth = ras.gray_width;
+ pixel_width = 2 * ( ( ras.target.width + 3 ) >> 2 );
+
+ if ( ras.bWidth > pixel_width )
+ ras.bWidth = pixel_width;
+
+ ras.bWidth = ras.bWidth * 8;
+ ras.bTarget = (Byte*)ras.gray_lines;
+ ras.gTarget = (Byte*)ras.target.buffer;
+
+ ras.Proc_Sweep_Init = Vertical_Gray_Sweep_Init;
+ ras.Proc_Sweep_Span = Vertical_Sweep_Span;
+ ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
+ ras.Proc_Sweep_Step = Vertical_Gray_Sweep_Step;
+
+ error = Render_Single_Pass( RAS_VARS 0 );
+ if ( error )
+ return error;
+
+ /* Horizontal Sweep */
+ if ( ras.second_pass && ras.dropOutControl != 0 )
+ {
+ ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
+ ras.Proc_Sweep_Span = Horizontal_Gray_Sweep_Span;
+ ras.Proc_Sweep_Drop = Horizontal_Gray_Sweep_Drop;
+ ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
+
+ ras.band_top = 0;
+ ras.band_stack[0].y_min = 0;
+ ras.band_stack[0].y_max = ras.target.width * 2 - 1;
+
+ error = Render_Single_Pass( RAS_VARS 1 );
+ if ( error )
+ return error;
+ }
+
+ return Raster_Err_Ok;
+ }
+
+#else /* FT_RASTER_OPTION_ANTI_ALIASING */
+
+ FT_LOCAL_DEF
+ FT_Error Render_Gray_Glyph( RAS_ARG )
+ {
+ FT_UNUSED_RASTER;
+
+ return Raster_Err_Cannot_Render_Glyph;
+ }
+
+#endif /* FT_RASTER_OPTION_ANTI_ALIASING */
+
+
+ static void
+ ft_black_init( TRaster_Instance* raster )
+ {
+ FT_UInt n;
+ FT_ULong c;
+
+
+ /* setup count table */
+ for ( n = 0; n < 256; n++ )
+ {
+ c = ( n & 0x55 ) + ( ( n & 0xAA ) >> 1 );
+
+ c = ( ( c << 6 ) & 0x3000 ) |
+ ( ( c << 4 ) & 0x0300 ) |
+ ( ( c << 2 ) & 0x0030 ) |
+ (c & 0x0003 );
+
+ raster->count_table[n] = c;
+ }
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+ /* set default 5-levels gray palette */
+ for ( n = 0; n < 5; n++ )
+ raster->grays[n] = n * 255 / 4;
+
+ raster->gray_width = RASTER_GRAY_LINES / 2;
+
+#endif
+ }
+
+
+ /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/
+ /**** a static object. *****/
+
+
+#ifdef _STANDALONE_
+
+
+ static int
+ ft_black_new( void* memory,
+ FT_Raster *araster )
+ {
+ static FT_RasterRec_ the_raster;
+
+
+ *araster = &the_raster;
+ memset( &the_raster, sizeof ( the_raster ), 0 );
+ ft_black_init( &the_raster );
+
+ return 0;
+ }
+
+
+ static void
+ ft_black_done( FT_Raster raster )
+ {
+ /* nothing */
+ raster->init = 0;
+ }
+
+
+#else /* _STANDALONE_ */
+
+
+ static int
+ ft_black_new( FT_Memory memory,
+ TRaster_Instance** araster )
+ {
+ FT_Error error;
+ TRaster_Instance* raster;
+
+
+ *araster = 0;
+ if ( !ALLOC( raster, sizeof ( *raster ) ) )
+ {
+ raster->memory = memory;
+ ft_black_init( raster );
+
+ *araster = raster;
+ }
+
+ return error;
+ }
+
+
+ static void
+ ft_black_done( TRaster_Instance* raster )
+ {
+ FT_Memory memory = (FT_Memory)raster->memory;
+ FREE( raster );
+ }
+
+
+#endif /* _STANDALONE_ */
+
+
+ static void
+ ft_black_reset( TRaster_Instance* raster,
+ const char* pool_base,
+ long pool_size )
+ {
+ if ( raster && pool_base && pool_size >= 4096 )
+ {
+ /* save the pool */
+ raster->buff = (PLong)pool_base;
+ raster->sizeBuff = raster->buff + pool_size / sizeof ( Long );
+ }
+ }
+
+
+ static void
+ ft_black_set_mode( TRaster_Instance* raster,
+ unsigned long mode,
+ const char* palette )
+ {
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+ if ( mode == FT_MAKE_TAG( 'p', 'a', 'l', '5' ) )
+ {
+ /* set 5-levels gray palette */
+ raster->grays[0] = palette[0];
+ raster->grays[1] = palette[1];
+ raster->grays[2] = palette[2];
+ raster->grays[3] = palette[3];
+ raster->grays[4] = palette[4];
+ }
+
+#else
+
+ FT_UNUSED( raster );
+ FT_UNUSED( mode );
+ FT_UNUSED( palette );
+
+#endif
+ }
+
+
+ static int
+ ft_black_render( TRaster_Instance* raster,
+ FT_Raster_Params* params )
+ {
+ FT_Outline* outline = (FT_Outline*)params->source;
+ FT_Bitmap* target_map = params->target;
+
+
+ if ( !raster || !raster->buff || !raster->sizeBuff )
+ return Raster_Err_Not_Ini;
+
+ /* return immediately if the outline is empty */
+ if ( outline->n_points == 0 || outline->n_contours <= 0 )
+ return Raster_Err_None;
+
+ if ( !outline || !outline->contours || !outline->points )
+ return Raster_Err_Invalid;
+
+ if ( outline->n_points != outline->contours[outline->n_contours - 1] + 1 )
+ return Raster_Err_Invalid;
+
+ /* this version of the raster does not support direct rendering, sorry */
+ if ( params->flags & ft_raster_flag_direct )
+ return Raster_Err_Unsupported;
+
+ if ( !target_map || !target_map->buffer )
+ return Raster_Err_Invalid;
+
+ ras.outline = *outline;
+ ras.target = *target_map;
+
+ return ( ( params->flags & ft_raster_flag_aa )
+ ? Render_Gray_Glyph( raster )
+ : Render_Glyph( raster ) );
+ }
+
+
+ const FT_Raster_Funcs ft_standard_raster =
+ {
+ ft_glyph_format_outline,
+ (FT_Raster_New_Func) ft_black_new,
+ (FT_Raster_Reset_Func) ft_black_reset,
+ (FT_Raster_Set_Mode_Func)ft_black_set_mode,
+ (FT_Raster_Render_Func) ft_black_render,
+ (FT_Raster_Done_Func) ft_black_done
+ };
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftrend1.c */
+/* */
+/* The FreeType glyph rasterizer interface (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_OUTLINE_H
+#include "ftrend1.h"
+#include "ftraster.h"
+
+#include "rasterrs.h"
+
+
+ /* initialize renderer -- init its raster */
+ static FT_Error
+ ft_raster1_init( FT_Renderer render )
+ {
+ FT_Library library = FT_MODULE_LIBRARY( render );
+
+
+ render->clazz->raster_class->raster_reset( render->raster,
+ library->raster_pool,
+ library->raster_pool_size );
+
+ return Raster_Err_Ok;
+ }
+
+
+ /* set render-specific mode */
+ static FT_Error
+ ft_raster1_set_mode( FT_Renderer render,
+ FT_ULong mode_tag,
+ FT_Pointer data )
+ {
+ /* we simply pass it to the raster */
+ return render->clazz->raster_class->raster_set_mode( render->raster,
+ mode_tag,
+ data );
+ }
+
+
+ /* transform a given glyph image */
+ static FT_Error
+ ft_raster1_transform( FT_Renderer render,
+ FT_GlyphSlot slot,
+ FT_Matrix* matrix,
+ FT_Vector* delta )
+ {
+ FT_Error error = Raster_Err_Ok;
+
+
+ if ( slot->format != render->glyph_format )
+ {
+ error = Raster_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ if ( matrix )
+ FT_Outline_Transform( &slot->outline, matrix );
+
+ if ( delta )
+ FT_Outline_Translate( &slot->outline, delta->x, delta->y );
+
+ Exit:
+ return error;
+ }
+
+
+ /* return the glyph's control box */
+ static void
+ ft_raster1_get_cbox( FT_Renderer render,
+ FT_GlyphSlot slot,
+ FT_BBox* cbox )
+ {
+ MEM_Set( cbox, 0, sizeof ( *cbox ) );
+
+ if ( slot->format == render->glyph_format )
+ FT_Outline_Get_CBox( &slot->outline, cbox );
+ }
+
+
+ /* convert a slot's glyph image into a bitmap */
+ static FT_Error
+ ft_raster1_render( FT_Renderer render,
+ FT_GlyphSlot slot,
+ FT_UInt mode,
+ FT_Vector* origin )
+ {
+ FT_Error error;
+ FT_Outline* outline;
+ FT_BBox cbox;
+ FT_UInt width, height, pitch;
+ FT_Bitmap* bitmap;
+ FT_Memory memory;
+
+ FT_Raster_Params params;
+
+
+ /* check glyph image format */
+ if ( slot->format != render->glyph_format )
+ {
+ error = Raster_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ /* check rendering mode */
+ if ( mode != ft_render_mode_mono )
+ {
+ /* raster1 is only capable of producing monochrome bitmaps */
+ if ( render->clazz == &ft_raster1_renderer_class )
+ return Raster_Err_Cannot_Render_Glyph;
+ }
+ else
+ {
+ /* raster5 is only capable of producing 5-gray-levels bitmaps */
+ if ( render->clazz == &ft_raster5_renderer_class )
+ return Raster_Err_Cannot_Render_Glyph;
+ }
+
+ outline = &slot->outline;
+
+ /* translate the outline to the new origin if needed */
+ if ( origin )
+ FT_Outline_Translate( outline, origin->x, origin->y );
+
+ /* compute the control box, and grid fit it */
+ FT_Outline_Get_CBox( outline, &cbox );
+
+ cbox.xMin &= -64;
+ cbox.yMin &= -64;
+ cbox.xMax = ( cbox.xMax + 63 ) & -64;
+ cbox.yMax = ( cbox.yMax + 63 ) & -64;
+
+ width = ( cbox.xMax - cbox.xMin ) >> 6;
+ height = ( cbox.yMax - cbox.yMin ) >> 6;
+ bitmap = &slot->bitmap;
+ memory = render->root.memory;
+
+ /* release old bitmap buffer */
+ if ( slot->flags & ft_glyph_own_bitmap )
+ {
+ FREE( bitmap->buffer );
+ slot->flags &= ~ft_glyph_own_bitmap;
+ }
+
+ /* allocate new one, depends on pixel format */
+ if ( !( mode & ft_render_mode_mono ) )
+ {
+ /* we pad to 32 bits, only for backwards compatibility with FT 1.x */
+ pitch = ( width + 3 ) & -4;
+ bitmap->pixel_mode = ft_pixel_mode_grays;
+ bitmap->num_grays = 256;
+ }
+ else
+ {
+ pitch = ( width + 7 ) >> 3;
+ bitmap->pixel_mode = ft_pixel_mode_mono;
+ }
+
+ bitmap->width = width;
+ bitmap->rows = height;
+ bitmap->pitch = pitch;
+
+ if ( ALLOC( bitmap->buffer, (FT_ULong)pitch * height ) )
+ goto Exit;
+
+ slot->flags |= ft_glyph_own_bitmap;
+
+ /* translate outline to render it into the bitmap */
+ FT_Outline_Translate( outline, -cbox.xMin, -cbox.yMin );
+
+ /* set up parameters */
+ params.target = bitmap;
+ params.source = outline;
+ params.flags = 0;
+
+ if ( bitmap->pixel_mode == ft_pixel_mode_grays )
+ params.flags |= ft_raster_flag_aa;
+
+ /* render outline into the bitmap */
+ error = render->raster_render( render->raster, ¶ms );
+ if ( error )
+ goto Exit;
+
+ slot->format = ft_glyph_format_bitmap;
+ slot->bitmap_left = cbox.xMin >> 6;
+ slot->bitmap_top = cbox.yMax >> 6;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Renderer_Class ft_raster1_renderer_class =
+ {
+ {
+ ft_module_renderer,
+ sizeof( FT_RendererRec ),
+
+ "raster1",
+ 0x10000L,
+ 0x20000L,
+
+ 0, /* module specific interface */
+
+ (FT_Module_Constructor)ft_raster1_init,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) 0
+ },
+
+ ft_glyph_format_outline,
+
+ (FTRenderer_render) ft_raster1_render,
+ (FTRenderer_transform)ft_raster1_transform,
+ (FTRenderer_getCBox) ft_raster1_get_cbox,
+ (FTRenderer_setMode) ft_raster1_set_mode,
+
+ (FT_Raster_Funcs*) &ft_standard_raster
+ };
+
+
+ /* This renderer is _NOT_ part of the default modules; you will need */
+ /* to register it by hand in your application. It should only be */
+ /* used for backwards-compatibility with FT 1.x anyway. */
+ /* */
+ FT_CALLBACK_TABLE_DEF
+ const FT_Renderer_Class ft_raster5_renderer_class =
+ {
+ {
+ ft_module_renderer,
+ sizeof( FT_RendererRec ),
+
+ "raster5",
+ 0x10000L,
+ 0x20000L,
+
+ 0, /* module specific interface */
+
+ (FT_Module_Constructor)ft_raster1_init,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) 0
+ },
+
+ ft_glyph_format_outline,
+
+ (FTRenderer_render) ft_raster1_render,
+ (FTRenderer_transform)ft_raster1_transform,
+ (FTRenderer_getCBox) ft_raster1_get_cbox,
+ (FTRenderer_setMode) ft_raster1_set_mode,
+
+ (FT_Raster_Funcs*) &ft_standard_raster
+ };
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftsmooth.c */
+/* */
+/* Anti-aliasing renderer interface (body). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_OUTLINE_H
+#include "ftsmooth.h"
+#include "ftgrays.h"
+
+#include "ftsmerrs.h"
+
+
+ /* initialize renderer -- init its raster */
+ static FT_Error
+ ft_smooth_init( FT_Renderer render )
+ {
+ FT_Library library = FT_MODULE_LIBRARY( render );
+
+
+ render->clazz->raster_class->raster_reset( render->raster,
+ library->raster_pool,
+ library->raster_pool_size );
+
+ return 0;
+ }
+
+
+ /* sets render-specific mode */
+ static FT_Error
+ ft_smooth_set_mode( FT_Renderer render,
+ FT_ULong mode_tag,
+ FT_Pointer data )
+ {
+ /* we simply pass it to the raster */
+ return render->clazz->raster_class->raster_set_mode( render->raster,
+ mode_tag,
+ data );
+ }
+
+ /* transform a given glyph image */
+ static FT_Error
+ ft_smooth_transform( FT_Renderer render,
+ FT_GlyphSlot slot,
+ FT_Matrix* matrix,
+ FT_Vector* delta )
+ {
+ FT_Error error = Smooth_Err_Ok;
+
+
+ if ( slot->format != render->glyph_format )
+ {
+ error = Smooth_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ if ( matrix )
+ FT_Outline_Transform( &slot->outline, matrix );
+
+ if ( delta )
+ FT_Outline_Translate( &slot->outline, delta->x, delta->y );
+
+ Exit:
+ return error;
+ }
+
+
+ /* return the glyph's control box */
+ static void
+ ft_smooth_get_cbox( FT_Renderer render,
+ FT_GlyphSlot slot,
+ FT_BBox* cbox )
+ {
+ MEM_Set( cbox, 0, sizeof ( *cbox ) );
+
+ if ( slot->format == render->glyph_format )
+ FT_Outline_Get_CBox( &slot->outline, cbox );
+ }
+
+
+ /* convert a slot's glyph image into a bitmap */
+ static FT_Error
+ ft_smooth_render( FT_Renderer render,
+ FT_GlyphSlot slot,
+ FT_UInt mode,
+ FT_Vector* origin )
+ {
+ FT_Error error;
+ FT_Outline* outline;
+ FT_BBox cbox;
+ FT_UInt width, height, pitch;
+ FT_Bitmap* bitmap;
+ FT_Memory memory;
+
+ FT_Raster_Params params;
+
+
+ /* check glyph image format */
+ if ( slot->format != render->glyph_format )
+ {
+ error = Smooth_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ /* check mode */
+ if ( mode != ft_render_mode_normal )
+ return Smooth_Err_Cannot_Render_Glyph;
+
+ outline = &slot->outline;
+
+ /* translate the outline to the new origin if needed */
+ if ( origin )
+ FT_Outline_Translate( outline, origin->x, origin->y );
+
+ /* compute the control box, and grid fit it */
+ FT_Outline_Get_CBox( outline, &cbox );
+
+ cbox.xMin &= -64;
+ cbox.yMin &= -64;
+ cbox.xMax = ( cbox.xMax + 63 ) & -64;
+ cbox.yMax = ( cbox.yMax + 63 ) & -64;
+
+ width = ( cbox.xMax - cbox.xMin ) >> 6;
+ height = ( cbox.yMax - cbox.yMin ) >> 6;
+ bitmap = &slot->bitmap;
+ memory = render->root.memory;
+
+ /* release old bitmap buffer */
+ if ( slot->flags & ft_glyph_own_bitmap )
+ {
+ FREE( bitmap->buffer );
+ slot->flags &= ~ft_glyph_own_bitmap;
+ }
+
+ /* allocate new one, depends on pixel format */
+ pitch = width;
+ bitmap->pixel_mode = ft_pixel_mode_grays;
+ bitmap->num_grays = 256;
+ bitmap->width = width;
+ bitmap->rows = height;
+ bitmap->pitch = pitch;
+
+ if ( ALLOC( bitmap->buffer, (FT_ULong)pitch * height ) )
+ goto Exit;
+
+ slot->flags |= ft_glyph_own_bitmap;
+
+ /* translate outline to render it into the bitmap */
+ FT_Outline_Translate( outline, -cbox.xMin, -cbox.yMin );
+
+ /* set up parameters */
+ params.target = bitmap;
+ params.source = outline;
+ params.flags = ft_raster_flag_aa;
+
+ /* render outline into the bitmap */
+ error = render->raster_render( render->raster, ¶ms );
+ if ( error )
+ goto Exit;
+
+ slot->format = ft_glyph_format_bitmap;
+ slot->bitmap_left = cbox.xMin >> 6;
+ slot->bitmap_top = cbox.yMax >> 6;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Renderer_Class ft_smooth_renderer_class =
+ {
+ {
+ ft_module_renderer,
+ sizeof( FT_RendererRec ),
+
+ "smooth",
+ 0x10000L,
+ 0x20000L,
+
+ 0, /* module specific interface */
+
+ (FT_Module_Constructor)ft_smooth_init,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) 0
+ },
+
+ ft_glyph_format_outline,
+
+ (FTRenderer_render) ft_smooth_render,
+ (FTRenderer_transform)ft_smooth_transform,
+ (FTRenderer_getCBox) ft_smooth_get_cbox,
+ (FTRenderer_setMode) ft_smooth_set_mode,
+
+ (FT_Raster_Funcs*) &ft_grays_raster
+ };
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftstream.c */
+/* */
+/* I/O stream support (body). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_DEBUG_H
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_stream
+
+
+ FT_BASE_DEF( void )
+ FT_New_Memory_Stream( FT_Library library,
+ FT_Byte* base,
+ FT_ULong size,
+ FT_Stream stream )
+ {
+ stream->memory = library->memory;
+ stream->base = base;
+ stream->size = size;
+ stream->pos = 0;
+ stream->cursor = 0;
+ stream->read = 0;
+ stream->close = 0;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Seek_Stream( FT_Stream stream,
+ FT_ULong pos )
+ {
+ FT_Error error;
+
+
+ stream->pos = pos;
+
+ if ( stream->read )
+ {
+ if ( stream->read( stream, pos, 0, 0 ) )
+ {
+ FT_ERROR(( "FT_Seek_Stream:" ));
+ FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ pos, stream->size ));
+
+ error = FT_Err_Invalid_Stream_Operation;
+ }
+ else
+ error = FT_Err_Ok;
+ }
+ /* note that seeking to the first position after the file is valid */
+ else if ( pos > stream->size )
+ {
+ FT_ERROR(( "FT_Seek_Stream:" ));
+ FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ pos, stream->size ));
+
+ error = FT_Err_Invalid_Stream_Operation;
+ }
+
+ else
+ error = FT_Err_Ok;
+
+ return error;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Skip_Stream( FT_Stream stream,
+ FT_Long distance )
+ {
+ return FT_Seek_Stream( stream, (FT_ULong)( stream->pos + distance ) );
+ }
+
+
+ FT_BASE_DEF( FT_Long )
+ FT_Stream_Pos( FT_Stream stream )
+ {
+ return stream->pos;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Read_Stream( FT_Stream stream,
+ FT_Byte* buffer,
+ FT_ULong count )
+ {
+ return FT_Read_Stream_At( stream, stream->pos, buffer, count );
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Read_Stream_At( FT_Stream stream,
+ FT_ULong pos,
+ FT_Byte* buffer,
+ FT_ULong count )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_ULong read_bytes;
+
+
+ if ( pos >= stream->size )
+ {
+ FT_ERROR(( "FT_Read_Stream_At:" ));
+ FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ pos, stream->size ));
+
+ return FT_Err_Invalid_Stream_Operation;
+ }
+
+ if ( stream->read )
+ read_bytes = stream->read( stream, pos, buffer, count );
+ else
+ {
+ read_bytes = stream->size - pos;
+ if ( read_bytes > count )
+ read_bytes = count;
+
+ MEM_Copy( buffer, stream->base + pos, read_bytes );
+ }
+
+ stream->pos = pos + read_bytes;
+
+ if ( read_bytes < count )
+ {
+ FT_ERROR(( "FT_Read_Stream_At:" ));
+ FT_ERROR(( " invalid read; expected %lu bytes, got %lu\n",
+ count, read_bytes ));
+
+ error = FT_Err_Invalid_Stream_Operation;
+ }
+
+ return error;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Extract_Frame( FT_Stream stream,
+ FT_ULong count,
+ FT_Byte** pbytes )
+ {
+ FT_Error error;
+
+
+ error = FT_Access_Frame( stream, count );
+ if ( !error )
+ {
+ *pbytes = (FT_Byte*)stream->cursor;
+
+ /* equivalent to FT_Forget_Frame(), with no memory block release */
+ stream->cursor = 0;
+ stream->limit = 0;
+ }
+
+ return error;
+ }
+
+
+ FT_BASE_DEF( void )
+ FT_Release_Frame( FT_Stream stream,
+ FT_Byte** pbytes )
+ {
+ if ( stream->read )
+ {
+ FT_Memory memory = stream->memory;
+
+
+ FREE( *pbytes );
+ }
+ *pbytes = 0;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Access_Frame( FT_Stream stream,
+ FT_ULong count )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_ULong read_bytes;
+
+
+ /* check for nested frame access */
+ FT_Assert( stream && stream->cursor == 0 );
+
+ if ( stream->read )
+ {
+ /* allocate the frame in memory */
+ FT_Memory memory = stream->memory;
+
+
+ if ( ALLOC( stream->base, count ) )
+ goto Exit;
+
+ /* read it */
+ read_bytes = stream->read( stream, stream->pos,
+ stream->base, count );
+ if ( read_bytes < count )
+ {
+ FT_ERROR(( "FT_Access_Frame:" ));
+ FT_ERROR(( " invalid read; expected %lu bytes, got %lu\n",
+ count, read_bytes ));
+
+ FREE( stream->base );
+ error = FT_Err_Invalid_Stream_Operation;
+ }
+ stream->cursor = stream->base;
+ stream->limit = stream->cursor + count;
+ stream->pos += read_bytes;
+ }
+ else
+ {
+ /* check current and new position */
+ if ( stream->pos >= stream->size ||
+ stream->pos + count > stream->size )
+ {
+ FT_ERROR(( "FT_Access_Frame:" ));
+ FT_ERROR(( " invalid i/o; pos = 0x%lx, count = %lu, size = 0x%lx\n",
+ stream->pos, count, stream->size ));
+
+ error = FT_Err_Invalid_Stream_Operation;
+ goto Exit;
+ }
+
+ /* set cursor */
+ stream->cursor = stream->base + stream->pos;
+ stream->limit = stream->cursor + count;
+ stream->pos += count;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_BASE_DEF( void )
+ FT_Forget_Frame( FT_Stream stream )
+ {
+ /* IMPORTANT: The assertion stream->cursor != 0 was removed, given */
+ /* that it is possible to access a frame of length 0 in */
+ /* some weird fonts (usually, when accessing an array of */
+ /* 0 records, like in some strange kern tables). */
+ /* */
+ /* In this case, the loader code handles the 0-length table */
+ /* gracefully; however, stream.cursor is really set to 0 by the */
+ /* FT_Access_Frame() call, and this is not an error. */
+ /* */
+ FT_Assert( stream );
+
+ if ( stream->read )
+ {
+ FT_Memory memory = stream->memory;
+
+
+ FREE( stream->base );
+ }
+ stream->cursor = 0;
+ stream->limit = 0;
+ }
+
+
+ FT_BASE_DEF( FT_Char )
+ FT_Get_Char( FT_Stream stream )
+ {
+ FT_Char result;
+
+
+ FT_Assert( stream && stream->cursor );
+
+ result = 0;
+ if ( stream->cursor < stream->limit )
+ result = *stream->cursor++;
+
+ return result;
+ }
+
+
+ FT_BASE_DEF( FT_Short )
+ FT_Get_Short( FT_Stream stream )
+ {
+ FT_Byte* p;
+ FT_Short result;
+
+
+ FT_Assert( stream && stream->cursor );
+
+ result = 0;
+ p = stream->cursor;
+ if ( p + 1 < stream->limit )
+ result = NEXT_Short( p );
+ stream->cursor = p;
+
+ return result;
+ }
+
+
+ FT_BASE_DEF( FT_Short )
+ FT_Get_ShortLE( FT_Stream stream )
+ {
+ FT_Byte* p;
+ FT_Short result;
+
+
+ FT_Assert( stream && stream->cursor );
+
+ result = 0;
+ p = stream->cursor;
+ if ( p + 1 < stream->limit )
+ result = NEXT_ShortLE( p );
+ stream->cursor = p;
+
+ return result;
+ }
+
+
+ FT_BASE_DEF( FT_Long )
+ FT_Get_Offset( FT_Stream stream )
+ {
+ FT_Byte* p;
+ FT_Long result;
+
+
+ FT_Assert( stream && stream->cursor );
+
+ result = 0;
+ p = stream->cursor;
+ if ( p + 2 < stream->limit )
+ result = NEXT_Offset( p );
+ stream->cursor = p;
+ return result;
+ }
+
+
+ FT_BASE_DEF( FT_Long )
+ FT_Get_Long( FT_Stream stream )
+ {
+ FT_Byte* p;
+ FT_Long result;
+
+
+ FT_Assert( stream && stream->cursor );
+
+ result = 0;
+ p = stream->cursor;
+ if ( p + 3 < stream->limit )
+ result = NEXT_Long( p );
+ stream->cursor = p;
+ return result;
+ }
+
+
+ FT_BASE_DEF( FT_Long )
+ FT_Get_LongLE( FT_Stream stream )
+ {
+ FT_Byte* p;
+ FT_Long result;
+
+
+ FT_Assert( stream && stream->cursor );
+
+ result = 0;
+ p = stream->cursor;
+ if ( p + 3 < stream->limit )
+ result = NEXT_LongLE( p );
+ stream->cursor = p;
+ return result;
+ }
+
+
+ FT_BASE_DEF( FT_Char )
+ FT_Read_Char( FT_Stream stream,
+ FT_Error* error )
+ {
+ FT_Byte result = 0;
+
+
+ FT_Assert( stream );
+
+ *error = FT_Err_Ok;
+
+ if ( stream->read )
+ {
+ if ( stream->read( stream, stream->pos, &result, 1L ) != 1L )
+ goto Fail;
+ }
+ else
+ {
+ if ( stream->pos < stream->size )
+ result = stream->base[stream->pos];
+ else
+ goto Fail;
+ }
+ stream->pos++;
+
+ return result;
+
+ Fail:
+ *error = FT_Err_Invalid_Stream_Operation;
+ FT_ERROR(( "FT_Read_Char:" ));
+ FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ stream->pos, stream->size ));
+
+ return 0;
+ }
+
+
+ FT_BASE_DEF( FT_Short )
+ FT_Read_Short( FT_Stream stream,
+ FT_Error* error )
+ {
+ FT_Byte reads[2];
+ FT_Byte* p = 0;
+ FT_Short result = 0;
+
+
+ FT_Assert( stream );
+
+ *error = FT_Err_Ok;
+
+ if ( stream->pos + 1 < stream->size )
+ {
+ if ( stream->read )
+ {
+ if ( stream->read( stream, stream->pos, reads, 2L ) != 2L )
+ goto Fail;
+
+ p = reads;
+ }
+ else
+ {
+ p = stream->base + stream->pos;
+ }
+
+ if ( p )
+ result = NEXT_Short( p );
+ }
+ else
+ goto Fail;
+
+ stream->pos += 2;
+
+ return result;
+
+ Fail:
+ *error = FT_Err_Invalid_Stream_Operation;
+ FT_ERROR(( "FT_Read_Short:" ));
+ FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ stream->pos, stream->size ));
+
+ return 0;
+ }
+
+
+ FT_BASE_DEF( FT_Short )
+ FT_Read_ShortLE( FT_Stream stream,
+ FT_Error* error )
+ {
+ FT_Byte reads[2];
+ FT_Byte* p = 0;
+ FT_Short result = 0;
+
+
+ FT_Assert( stream );
+
+ *error = FT_Err_Ok;
+
+ if ( stream->pos + 1 < stream->size )
+ {
+ if ( stream->read )
+ {
+ if ( stream->read( stream, stream->pos, reads, 2L ) != 2L )
+ goto Fail;
+
+ p = reads;
+ }
+ else
+ {
+ p = stream->base + stream->pos;
+ }
+
+ if ( p )
+ result = NEXT_ShortLE( p );
+ }
+ else
+ goto Fail;
+
+ stream->pos += 2;
+
+ return result;
+
+ Fail:
+ *error = FT_Err_Invalid_Stream_Operation;
+ FT_ERROR(( "FT_Read_Short:" ));
+ FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ stream->pos, stream->size ));
+
+ return 0;
+ }
+
+
+ FT_BASE_DEF( FT_Long )
+ FT_Read_Offset( FT_Stream stream,
+ FT_Error* error )
+ {
+ FT_Byte reads[3];
+ FT_Byte* p = 0;
+ FT_Long result = 0;
+
+
+ FT_Assert( stream );
+
+ *error = FT_Err_Ok;
+
+ if ( stream->pos + 2 < stream->size )
+ {
+ if ( stream->read )
+ {
+ if (stream->read( stream, stream->pos, reads, 3L ) != 3L )
+ goto Fail;
+
+ p = reads;
+ }
+ else
+ {
+ p = stream->base + stream->pos;
+ }
+
+ if ( p )
+ result = NEXT_Offset( p );
+ }
+ else
+ goto Fail;
+
+ stream->pos += 3;
+
+ return result;
+
+ Fail:
+ *error = FT_Err_Invalid_Stream_Operation;
+ FT_ERROR(( "FT_Read_Offset:" ));
+ FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ stream->pos, stream->size ));
+
+ return 0;
+ }
+
+
+ FT_BASE_DEF( FT_Long )
+ FT_Read_Long( FT_Stream stream,
+ FT_Error* error )
+ {
+ FT_Byte reads[4];
+ FT_Byte* p = 0;
+ FT_Long result = 0;
+
+
+ FT_Assert( stream );
+
+ *error = FT_Err_Ok;
+
+ if ( stream->pos + 3 < stream->size )
+ {
+ if ( stream->read )
+ {
+ if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
+ goto Fail;
+
+ p = reads;
+ }
+ else
+ {
+ p = stream->base + stream->pos;
+ }
+
+ if ( p )
+ result = NEXT_Long( p );
+ }
+ else
+ goto Fail;
+
+ stream->pos += 4;
+
+ return result;
+
+ Fail:
+ FT_ERROR(( "FT_Read_Long:" ));
+ FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ stream->pos, stream->size ));
+ *error = FT_Err_Invalid_Stream_Operation;
+
+ return 0;
+ }
+
+
+ FT_BASE_DEF( FT_Long )
+ FT_Read_LongLE( FT_Stream stream,
+ FT_Error* error )
+ {
+ FT_Byte reads[4];
+ FT_Byte* p = 0;
+ FT_Long result = 0;
+
+
+ FT_Assert( stream );
+
+ *error = FT_Err_Ok;
+
+ if ( stream->pos + 3 < stream->size )
+ {
+ if ( stream->read )
+ {
+ if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
+ goto Fail;
+
+ p = reads;
+ }
+ else
+ {
+ p = stream->base + stream->pos;
+ }
+
+ if ( p )
+ result = NEXT_LongLE( p );
+ }
+ else
+ goto Fail;
+
+ stream->pos += 4;
+
+ return result;
+
+ Fail:
+ FT_ERROR(( "FT_Read_Long:" ));
+ FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ stream->pos, stream->size ));
+ *error = FT_Err_Invalid_Stream_Operation;
+
+ return 0;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Read_Fields( FT_Stream stream,
+ const FT_Frame_Field* fields,
+ void* structure )
+ {
+ FT_Error error;
+ FT_Bool frame_accessed = 0;
+ FT_Byte* cursor = stream->cursor;
+
+
+ if ( !fields || !stream )
+ return FT_Err_Invalid_Argument;
+
+ error = FT_Err_Ok;
+ do
+ {
+ FT_ULong value;
+ FT_Int sign_shift;
+ FT_Byte* p;
+
+
+ switch ( fields->value )
+ {
+ case ft_frame_start: /* access a new frame */
+ error = FT_Access_Frame( stream, fields->offset );
+ if ( error )
+ goto Exit;
+
+ frame_accessed = 1;
+ cursor = stream->cursor;
+ fields++;
+ continue; /* loop! */
+
+ case ft_frame_bytes: /* read a byte sequence */
+ case ft_frame_skip: /* skip some bytes */
+ {
+ FT_UInt len = fields->size;
+
+
+ if ( cursor + len > stream->limit )
+ {
+ error = FT_Err_Invalid_Stream_Operation;
+ goto Exit;
+ }
+
+ if ( fields->value == ft_frame_bytes )
+ {
+ p = (FT_Byte*)structure + fields->offset;
+ MEM_Copy( p, cursor, len );
+ }
+ cursor += len;
+ fields++;
+ continue;
+ }
+
+ case ft_frame_byte:
+ case ft_frame_schar: /* read a single byte */
+ value = NEXT_Byte(cursor);
+ sign_shift = 24;
+ break;
+
+ case ft_frame_short_be:
+ case ft_frame_ushort_be: /* read a 2-byte big-endian short */
+ value = NEXT_UShort(cursor);
+ sign_shift = 16;
+ break;
+
+ case ft_frame_short_le:
+ case ft_frame_ushort_le: /* read a 2-byte little-endian short */
+ value = NEXT_UShortLE(cursor);
+ sign_shift = 16;
+ break;
+
+ case ft_frame_long_be:
+ case ft_frame_ulong_be: /* read a 4-byte big-endian long */
+ value = NEXT_ULong(cursor);
+ sign_shift = 0;
+ break;
+
+ case ft_frame_long_le:
+ case ft_frame_ulong_le: /* read a 4-byte little-endian long */
+ value = NEXT_ULongLE(cursor);
+ sign_shift = 0;
+ break;
+
+ case ft_frame_off3_be:
+ case ft_frame_uoff3_be: /* read a 3-byte big-endian long */
+ value = NEXT_UOffset(cursor);
+ sign_shift = 8;
+ break;
+
+ case ft_frame_off3_le:
+ case ft_frame_uoff3_le: /* read a 3-byte little-endian long */
+ value = NEXT_UOffsetLE(cursor);
+ sign_shift = 8;
+ break;
+
+ default:
+ /* otherwise, exit the loop */
+ stream->cursor = cursor;
+ goto Exit;
+ }
+
+ /* now, compute the signed value is necessary */
+ if ( fields->value & FT_FRAME_OP_SIGNED )
+ value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift );
+
+ /* finally, store the value in the object */
+
+ p = (FT_Byte*)structure + fields->offset;
+ switch ( fields->size )
+ {
+ case 1:
+ *(FT_Byte*)p = (FT_Byte)value;
+ break;
+
+ case 2:
+ *(FT_UShort*)p = (FT_UShort)value;
+ break;
+
+ case 4:
+ *(FT_UInt32*)p = (FT_UInt32)value;
+ break;
+
+ default: /* for 64-bit systems */
+ *(FT_ULong*)p = (FT_ULong)value;
+ }
+
+ /* go to next field */
+ fields++;
+ }
+ while ( 1 );
+
+ Exit:
+ /* close the frame if it was opened by this read */
+ if ( frame_accessed )
+ FT_Forget_Frame( stream );
+
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftsynth.c */
+/* */
+/* FreeType synthesizing code for emboldening and slanting (body). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_CALC_H
+#include FT_OUTLINE_H
+#include FT_SYNTHESIS_H
+
+
+#define FT_BOLD_THRESHOLD 0x0100
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** EXPERIMENTAL OBLIQUING SUPPORT ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_Oblique( FT_GlyphSlot original,
+ FT_Outline* outline,
+ FT_Pos* advance )
+ {
+ FT_Matrix transform;
+
+ FT_UNUSED( original );
+ /* we don't touch the advance width */
+ FT_UNUSED( advance );
+
+
+
+ /* For italic, simply apply a shear transform, with an angle */
+ /* of about 12 degrees. */
+
+ transform.xx = 0x10000L;
+ transform.yx = 0x00000L;
+
+ transform.xy = 0x06000L;
+ transform.yy = 0x10000L;
+
+ FT_Outline_Transform( outline, &transform );
+
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** EXPERIMENTAL EMBOLDENING/OUTLINING SUPPORT ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* Compute the norm of a vector */
+
+#ifdef FT_CONFIG_OPTION_OLD_CALCS
+
+ static FT_Pos
+ ft_norm( FT_Vector* vec )
+ {
+ FT_Int64 t1, t2;
+
+
+ MUL_64( vec->x, vec->x, t1 );
+ MUL_64( vec->y, vec->y, t2 );
+ ADD_64( t1, t2, t1 );
+
+ return (FT_Pos)SQRT_64( t1 );
+ }
+
+#else /* FT_CONFIG_OPTION_OLD_CALCS */
+
+ static FT_Pos
+ ft_norm( FT_Vector* vec )
+ {
+ FT_F26Dot6 u, v, d;
+ FT_Int shift;
+ FT_ULong H, L, L2, hi, lo, med;
+
+
+ u = vec->x; if ( u < 0 ) u = -u;
+ v = vec->y; if ( v < 0 ) v = -v;
+
+ if ( u < v )
+ {
+ d = u;
+ u = v;
+ v = d;
+ }
+
+ /* check that we are not trying to normalize zero! */
+ if ( u == 0 )
+ return 0;
+
+ /* compute (u*u + v*v) on 64 bits with two 32-bit registers [H:L] */
+ hi = (FT_ULong)u >> 16;
+ lo = (FT_ULong)u & 0xFFFF;
+ med = hi * lo;
+
+ H = hi * hi + ( med >> 15 );
+ med <<= 17;
+ L = lo * lo + med;
+ if ( L < med )
+ H++;
+
+ hi = (FT_ULong)v >> 16;
+ lo = (FT_ULong)v & 0xFFFF;
+ med = hi * lo;
+
+ H += hi * hi + ( med >> 15 );
+ med <<= 17;
+ L2 = lo * lo + med;
+ if ( L2 < med )
+ H++;
+
+ L += L2;
+ if ( L < L2 )
+ H++;
+
+ /* if the value is smaller than 32 bits */
+ shift = 0;
+ if ( H == 0 )
+ {
+ while ( ( L & 0xC0000000UL ) == 0 )
+ {
+ L <<= 2;
+ shift++;
+ }
+ return ( FT_Sqrt32( L ) >> shift );
+ }
+ else
+ {
+ while ( H )
+ {
+ L = ( L >> 2 ) | ( H << 30 );
+ H >>= 2;
+ shift++;
+ }
+ return ( FT_Sqrt32( L ) << shift );
+ }
+ }
+
+#endif /* FT_CONFIG_OPTION_OLD_CALCS */
+
+
+ static int
+ ft_test_extrema( FT_Outline* outline,
+ int n )
+ {
+ FT_Vector *prev, *cur, *next;
+ FT_Pos product;
+ FT_Int c, first, last;
+
+
+ /* we need to compute the `previous' and `next' point */
+ /* for these extrema. */
+ cur = outline->points + n;
+ prev = cur - 1;
+ next = cur + 1;
+
+ first = 0;
+ for ( c = 0; c < outline->n_contours; c++ )
+ {
+ last = outline->contours[c];
+
+ if ( n == first )
+ prev = outline->points + last;
+
+ if ( n == last )
+ next = outline->points + first;
+
+ first = last + 1;
+ }
+
+ product = FT_MulDiv( cur->x - prev->x, /* in.x */
+ next->y - cur->y, /* out.y */
+ 0x40 )
+ -
+ FT_MulDiv( cur->y - prev->y, /* in.y */
+ next->x - cur->x, /* out.x */
+ 0x40 );
+
+ if ( product )
+ product = product > 0 ? 1 : -1;
+
+ return product;
+ }
+
+
+ /* Compute the orientation of path filling. It differs between TrueType */
+ /* and Type1 formats. We could use the `ft_outline_reverse_fill' flag, */
+ /* but it is better to re-compute it directly (it seems that this flag */
+ /* isn't correctly set for some weird composite glyphs currently). */
+ /* */
+ /* We do this by computing bounding box points, and computing their */
+ /* curvature. */
+ /* */
+ /* The function returns either 1 or -1. */
+ /* */
+ static int
+ ft_get_orientation( FT_Outline* outline )
+ {
+ FT_BBox box;
+ FT_BBox indices;
+ int n, last;
+
+
+ indices.xMin = -1;
+ indices.yMin = -1;
+ indices.xMax = -1;
+ indices.yMax = -1;
+
+ box.xMin = box.yMin = 32767;
+ box.xMax = box.yMax = -32768;
+
+ /* is it empty ? */
+ if ( outline->n_contours < 1 )
+ return 1;
+
+ last = outline->contours[outline->n_contours - 1];
+
+ for ( n = 0; n <= last; n++ )
+ {
+ FT_Pos x, y;
+
+
+ x = outline->points[n].x;
+ if ( x < box.xMin )
+ {
+ box.xMin = x;
+ indices.xMin = n;
+ }
+ if ( x > box.xMax )
+ {
+ box.xMax = x;
+ indices.xMax = n;
+ }
+
+ y = outline->points[n].y;
+ if ( y < box.yMin )
+ {
+ box.yMin = y;
+ indices.yMin = n;
+ }
+ if ( y > box.yMax )
+ {
+ box.yMax = y;
+ indices.yMax = n;
+ }
+ }
+
+ /* test orientation of the xmin */
+ n = ft_test_extrema( outline, indices.xMin );
+ if ( n )
+ goto Exit;
+
+ n = ft_test_extrema( outline, indices.yMin );
+ if ( n )
+ goto Exit;
+
+ n = ft_test_extrema( outline, indices.xMax );
+ if ( n )
+ goto Exit;
+
+ n = ft_test_extrema( outline, indices.yMax );
+ if ( !n )
+ n = 1;
+
+ Exit:
+ return n;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_Embolden( FT_GlyphSlot original,
+ FT_Outline* outline,
+ FT_Pos* advance )
+ {
+ FT_Vector u, v;
+ FT_Vector* points;
+ FT_Vector cur, prev, next;
+ FT_Pos distance;
+ FT_Face face = FT_SLOT_FACE( original );
+ int c, n, first, orientation;
+
+ FT_UNUSED( advance );
+
+
+ /* compute control distance */
+ distance = FT_MulFix( face->units_per_EM / 60,
+ face->size->metrics.y_scale );
+
+ orientation = ft_get_orientation( &original->outline );
+
+ points = original->outline.points;
+
+ first = 0;
+ for ( c = 0; c < outline->n_contours; c++ )
+ {
+ int last = outline->contours[c];
+
+
+ prev = points[last];
+
+ for ( n = first; n <= last; n++ )
+ {
+ FT_Pos norm, delta, d;
+ FT_Vector in, out;
+
+
+ cur = points[n];
+ if ( n < last ) next = points[n + 1];
+ else next = points[first];
+
+ /* compute the in and out vectors */
+ in.x = cur.x - prev.x;
+ in.y = cur.y - prev.y;
+
+ out.x = next.x - cur.x;
+ out.y = next.y - cur.y;
+
+ /* compute U and V */
+ norm = ft_norm( &in );
+ u.x = orientation * FT_DivFix( in.y, norm );
+ u.y = orientation * -FT_DivFix( in.x, norm );
+
+ norm = ft_norm( &out );
+ v.x = orientation * FT_DivFix( out.y, norm );
+ v.y = orientation * -FT_DivFix( out.x, norm );
+
+ d = distance;
+
+ if ( ( outline->tags[n] & FT_Curve_Tag_On ) == 0 )
+ d *= 2;
+
+ /* Check discriminant for parallel vectors */
+ delta = FT_MulFix( u.x, v.y ) - FT_MulFix( u.y, v.x );
+ if ( delta > FT_BOLD_THRESHOLD || delta < -FT_BOLD_THRESHOLD )
+ {
+ /* Move point -- compute A and B */
+ FT_Pos x, y, A, B;
+
+
+ A = d + FT_MulFix( cur.x, u.x ) + FT_MulFix( cur.y, u.y );
+ B = d + FT_MulFix( cur.x, v.x ) + FT_MulFix( cur.y, v.y );
+
+ x = FT_MulFix( A, v.y ) - FT_MulFix( B, u.y );
+ y = FT_MulFix( B, u.x ) - FT_MulFix( A, v.x );
+
+ outline->points[n].x = distance + FT_DivFix( x, delta );
+ outline->points[n].y = distance + FT_DivFix( y, delta );
+ }
+ else
+ {
+ /* Vectors are nearly parallel */
+ FT_Pos x, y;
+
+
+ x = distance + cur.x + FT_MulFix( d, u.x + v.x ) / 2;
+ y = distance + cur.y + FT_MulFix( d, u.y + v.y ) / 2;
+
+ outline->points[n].x = x;
+ outline->points[n].y = y;
+ }
+
+ prev = cur;
+ }
+
+ first = last + 1;
+ }
+
+ if ( advance )
+ *advance = ( *advance + distance * 4 ) & -64;
+
+ return 0;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftsystem.c */
+/* */
+/* ANSI-specific FreeType low-level system interface (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* This file contains the default interface used by FreeType to access */
+ /* low-level, i.e. memory management, i/o access as well as thread */
+ /* synchronisation. It can be replaced by user-specific routines if */
+ /* necessary. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_SYSTEM_H
+#include FT_ERRORS_H
+#include FT_TYPES_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* MEMORY MANAGEMENT INTERFACE */
+ /* */
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* It is not necessary to do any error checking for the */
+ /* allocation-related functions. This will be done by the higher level */
+ /* routines like FT_Alloc() or FT_Realloc(). */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ft_alloc */
+ /* */
+ /* <Description> */
+ /* The memory allocation function. */
+ /* */
+ /* <Input> */
+ /* memory :: A pointer to the memory object. */
+ /* */
+ /* size :: The requested size in bytes. */
+ /* */
+ /* <Return> */
+ /* The address of newly allocated block. */
+ /* */
+ FT_CALLBACK_DEF( void* )
+ ft_alloc( FT_Memory memory,
+ long size )
+ {
+ FT_UNUSED( memory );
+
+ return malloc( size );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ft_realloc */
+ /* */
+ /* <Description> */
+ /* The memory reallocation function. */
+ /* */
+ /* <Input> */
+ /* memory :: A pointer to the memory object. */
+ /* */
+ /* cur_size :: The current size of the allocated memory block. */
+ /* */
+ /* new_size :: The newly requested size in bytes. */
+ /* */
+ /* block :: The current address of the block in memory. */
+ /* */
+ /* <Return> */
+ /* The address of the reallocated memory block. */
+ /* */
+ FT_CALLBACK_DEF( void* )
+ ft_realloc( FT_Memory memory,
+ long cur_size,
+ long new_size,
+ void* block )
+ {
+ FT_UNUSED( memory );
+ FT_UNUSED( cur_size );
+
+ return realloc( block, new_size );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ft_free */
+ /* */
+ /* <Description> */
+ /* The memory release function. */
+ /* */
+ /* <Input> */
+ /* memory :: A pointer to the memory object. */
+ /* */
+ /* block :: The address of block in memory to be freed. */
+ /* */
+ FT_CALLBACK_DEF( void )
+ ft_free( FT_Memory memory,
+ void* block )
+ {
+ FT_UNUSED( memory );
+
+ free( block );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* RESOURCE MANAGEMENT INTERFACE */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_io
+
+ /* We use the macro STREAM_FILE for convenience to extract the */
+ /* system-specific stream handle from a given FreeType stream object */
+#define STREAM_FILE( stream ) ( (FILE*)stream->descriptor.pointer )
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ft_close_stream */
+ /* */
+ /* <Description> */
+ /* The function to close a stream. */
+ /* */
+ /* <Input> */
+ /* stream :: A pointer to the stream object. */
+ /* */
+ FT_CALLBACK_DEF( void )
+ ft_close_stream( FT_Stream stream )
+ {
+ fclose( STREAM_FILE( stream ) );
+
+ stream->descriptor.pointer = NULL;
+ stream->size = 0;
+ stream->base = 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* ft_io_stream */
+ /* */
+ /* <Description> */
+ /* The function to open a stream. */
+ /* */
+ /* <Input> */
+ /* stream :: A pointer to the stream object. */
+ /* */
+ /* offset :: The position in the data stream to start reading. */
+ /* */
+ /* buffer :: The address of buffer to store the read data. */
+ /* */
+ /* count :: The number of bytes to read from the stream. */
+ /* */
+ /* <Return> */
+ /* The number of bytes actually read. */
+ /* */
+ FT_CALLBACK_DEF( unsigned long )
+ ft_io_stream( FT_Stream stream,
+ unsigned long offset,
+ unsigned char* buffer,
+ unsigned long count )
+ {
+ FILE* file;
+
+
+ file = STREAM_FILE( stream );
+
+ fseek( file, offset, SEEK_SET );
+
+ return (unsigned long)fread( buffer, 1, count, file );
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_New_Stream( const char* filepathname,
+ FT_Stream astream )
+ {
+ FILE* file;
+
+
+ if ( !astream )
+ return FT_Err_Invalid_Stream_Handle;
+
+ file = fopen( filepathname, "rb" );
+ if ( !file )
+ {
+ FT_ERROR(( "FT_New_Stream:" ));
+ FT_ERROR(( " could not open `%s'\n", filepathname ));
+
+ return FT_Err_Cannot_Open_Resource;
+ }
+
+ fseek( file, 0, SEEK_END );
+ astream->size = ftell( file );
+ fseek( file, 0, SEEK_SET );
+
+ astream->descriptor.pointer = file;
+ astream->pathname.pointer = (char*)filepathname;
+ astream->pos = 0;
+
+ astream->read = ft_io_stream;
+ astream->close = ft_close_stream;
+
+ FT_TRACE1(( "FT_New_Stream:" ));
+ FT_TRACE1(( " opened `%s' (%d bytes) successfully\n",
+ filepathname, astream->size ));
+
+ return FT_Err_Ok;
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_EXPORT_DEF( FT_Memory )
+ FT_New_Memory( void )
+ {
+ FT_Memory memory;
+
+
+ memory = (FT_Memory)malloc( sizeof ( *memory ) );
+ if ( memory )
+ {
+ memory->user = 0;
+ memory->alloc = ft_alloc;
+ memory->realloc = ft_realloc;
+ memory->free = ft_free;
+ }
+
+ return memory;
+ }
+
+
+ /* documentation is in ftobjs.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Done_Memory( FT_Memory memory )
+ {
+ memory->free( memory, memory );
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* fttrigon.c */
+/* */
+/* FreeType trigonometric functions (body). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_TRIGONOMETRY_H
+
+
+ /* the following is 0.2715717684432231 * 2^30 */
+#define FT_TRIG_COSCALE 0x11616E8EUL
+
+ /* 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] =
+ {
+ 4157273L, 2949120L, 1740967L, 919879L, 466945L, 234379L, 117304L,
+ 58666L, 29335L, 14668L, 7334L, 3667L, 1833L, 917L, 458L, 229L, 115L,
+ 57L, 29L, 14L, 7L, 4L, 2L, 1L
+ };
+
+ /* the Cordic shrink factor, multiplied by 2^32 */
+#define FT_TRIG_SCALE 1166391785UL /* 0x4585BA38UL */
+
+
+#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 ) + 0x100000000UL;
+ 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 += 0x10000UL;
+
+ 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;
+ }
+
+
+ /* documentation is in fttrigon.h */
+
+ 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;
+ }
+
+
+ /* documentation is in fttrigon.h */
+
+ FT_EXPORT_DEF( FT_Fixed )
+ FT_Sin( FT_Angle angle )
+ {
+ return FT_Cos( FT_ANGLE_PI2 - angle );
+ }
+
+
+ /* documentation is in fttrigon.h */
+
+ 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 );
+ }
+
+
+ /* documentation is in fttrigon.h */
+
+ 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;
+ }
+
+
+ /* documentation is in fttrigon.h */
+
+ 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;
+ }
+
+
+ /* documentation is in fttrigon.h */
+
+ 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;
+ }
+ }
+ }
+
+
+ /* documentation is in fttrigon.h */
+
+ 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 );
+ }
+
+
+ /* documentation is in fttrigon.h */
+
+ 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;
+ }
+
+
+/* END */
--- /dev/null
+## Process this file with automake to produce Makefile.in
+
+noinst_HEADERS = \
+ ahangles.h ahoptim.h cffparse.h cidriver.h ftrend1.h psauxerr.h sfdriver.h t1gload.h tterrors.h ttsbit.h \
+ aherrors.h ahtypes.h cfftoken.h cidtoken.h ftsmerrs.h psauxmod.h sferrors.h t1load.h ttgload.h winfnt.h \
+ ahglobal.h cffdrivr.h ciderrs.h fnterrs.h ftsmooth.h psmodule.h sfobjs.h t1objs.h ttinterp.h \
+ ahglyph.h cfferrs.h cidgload.h ft2build.h pcf.h psnamerr.h t1afm.h t1parse.h ttload.h \
+ ahhint.h cffgload.h cidload.h ftcerror.h pcfdriver.h psobjs.h t1decode.h t1tokens.h ttobjs.h \
+ ahloader.h cffload.h cidobjs.h ftgrays.h pcferror.h pstables.h t1driver.h ttcmap.h ttpload.h \
+ ahmodule.h cffobjs.h cidparse.h ftraster.h pcfutil.h rasterrs.h t1errors.h ttdriver.h ttpost.h
--- /dev/null
+/***************************************************************************/
+/* */
+/* ahangles.h */
+/* */
+/* A routine used to compute vector angles with limited accuracy */
+/* and very high speed (specification). */
+/* */
+/* Copyright 2000-2001 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AHANGLES_H__
+#define __AHANGLES_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include "ahtypes.h"
+
+
+FT_BEGIN_HEADER
+
+
+ /* PI expressed in ah_angles -- we don't really need an important */
+ /* precision, so 256 should be enough */
+#define AH_PI 256
+#define AH_2PI ( AH_PI * 2 )
+#define AH_HALF_PI ( AH_PI / 2 )
+#define AH_2PIMASK ( AH_2PI - 1 )
+
+ /* the number of bits used to express an arc tangent; */
+ /* see the structure of the lookup table */
+#define AH_ATAN_BITS 8
+
+ extern
+ const AH_Angle ah_arctan[1L << AH_ATAN_BITS];
+
+
+ FT_LOCAL AH_Angle
+ ah_angle( FT_Vector* v );
+
+
+FT_END_HEADER
+
+#endif /* __AHANGLES_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* aherrors.h */
+/* */
+/* Autohinter error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the Autohinter error enumeration */
+ /* constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __AHERRORS_H__
+#define __AHERRORS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX AH_Err_
+#define FT_ERR_BASE FT_Mod_Err_Autohint
+
+#include FT_ERRORS_H
+
+#endif /* __AHERRORS_H__ */
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ahglobal.h */
+/* */
+/* Routines used to compute global metrics automatically */
+/* (specification). */
+/* */
+/* Copyright 2000-2001 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AHGLOBAL_H__
+#define __AHGLOBAL_H__
+
+
+#include <ft2build.h>
+#include "ahtypes.h"
+#include FT_INTERNAL_OBJECTS_H
+
+
+FT_BEGIN_HEADER
+
+
+#define AH_IS_TOP_BLUE( b ) ( (b) == ah_blue_capital_top || \
+ (b) == ah_blue_small_top )
+
+
+ /* compute global metrics automatically */
+ FT_LOCAL
+ FT_Error ah_hinter_compute_globals( AH_Hinter* hinter );
+
+
+FT_END_HEADER
+
+#endif /* __AHGLOBAL_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ahglyph.h */
+/* */
+/* Routines used to load and analyze a given glyph before hinting */
+/* (specification). */
+/* */
+/* Copyright 2000-2001 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AHGLYPH_H__
+#define __AHGLYPH_H__
+
+
+#include <ft2build.h>
+#include "ahtypes.h"
+
+
+FT_BEGIN_HEADER
+
+
+ typedef enum AH_UV_
+ {
+ ah_uv_fxy,
+ ah_uv_fyx,
+ ah_uv_oxy,
+ ah_uv_oyx,
+ ah_uv_ox,
+ ah_uv_oy,
+ ah_uv_yx,
+ ah_uv_xy /* should always be last! */
+
+ } AH_UV;
+
+
+ FT_LOCAL void
+ ah_setup_uv( AH_Outline* outline,
+ AH_UV source );
+
+
+ /* AH_Outline functions - they should be typically called in this order */
+
+ FT_LOCAL FT_Error
+ ah_outline_new( FT_Memory memory,
+ AH_Outline** aoutline );
+
+ FT_LOCAL FT_Error
+ ah_outline_load( AH_Outline* outline,
+ FT_Face face );
+
+ FT_LOCAL void
+ ah_outline_compute_segments( AH_Outline* outline );
+
+ FT_LOCAL void
+ ah_outline_link_segments( AH_Outline* outline );
+
+ FT_LOCAL void
+ ah_outline_detect_features( AH_Outline* outline );
+
+ FT_LOCAL void
+ ah_outline_compute_blue_edges( AH_Outline* outline,
+ AH_Face_Globals* globals );
+
+ FT_LOCAL void
+ ah_outline_scale_blue_edges( AH_Outline* outline,
+ AH_Face_Globals* globals );
+
+ FT_LOCAL void
+ ah_outline_save( AH_Outline* outline,
+ AH_Loader* loader );
+
+ FT_LOCAL void
+ ah_outline_done( AH_Outline* outline );
+
+
+FT_END_HEADER
+
+#endif /* __AHGLYPH_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ahhint.h */
+/* */
+/* Glyph hinter (declaration). */
+/* */
+/* Copyright 2000-2001 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AHHINT_H__
+#define __AHHINT_H__
+
+
+#include <ft2build.h>
+#include "ahglobal.h"
+
+
+FT_BEGIN_HEADER
+
+
+#define AH_HINT_DEFAULT 0
+#define AH_HINT_NO_ALIGNMENT 1
+#define AH_HINT_NO_HORZ_EDGES 0x20000L
+#define AH_HINT_NO_VERT_EDGES 0x40000L
+
+
+ /* create a new empty hinter object */
+ FT_LOCAL FT_Error
+ ah_hinter_new( FT_Library library,
+ AH_Hinter** ahinter );
+
+ /* Load a hinted glyph in the hinter */
+ FT_LOCAL FT_Error
+ ah_hinter_load_glyph( AH_Hinter* hinter,
+ FT_GlyphSlot slot,
+ FT_Size size,
+ FT_UInt glyph_index,
+ FT_Int load_flags );
+
+ /* finalize a hinter object */
+ FT_LOCAL void
+ ah_hinter_done( AH_Hinter* hinter );
+
+ FT_LOCAL void
+ ah_hinter_done_face_globals( AH_Face_Globals* globals );
+
+ FT_LOCAL void
+ ah_hinter_get_global_hints( AH_Hinter* hinter,
+ FT_Face face,
+ void** global_hints,
+ long* global_len );
+
+ FT_LOCAL void
+ ah_hinter_done_global_hints( AH_Hinter* hinter,
+ void* global_hints );
+
+
+FT_END_HEADER
+
+#endif /* __AHHINT_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ahloader.h */
+/* */
+/* Glyph loader for the auto-hinting module (declaration only). */
+/* */
+/* Copyright 2000-2001 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This defines the AH_GlyphLoader type in two different ways: */
+ /* */
+ /* - If the module is compiled within FreeType 2, the type is simply a */
+ /* typedef to FT_GlyphLoader. */
+ /* */
+ /* - If the module is compiled as a standalone object, AH_GlyphLoader */
+ /* has its own implementation. */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef __AHLOADER_H__
+#define __AHLOADER_H__
+
+
+#include <ft2build.h>
+
+
+FT_BEGIN_HEADER
+
+
+#ifdef _STANDALONE_
+
+ typedef struct AH_GlyphLoad_
+ {
+ FT_Outline outline; /* outline */
+ FT_UInt num_subglyphs; /* number of subglyphs */
+ FT_SubGlyph* subglyphs; /* subglyphs */
+ FT_Vector* extra_points; /* extra points table */
+
+ } AH_GlyphLoad;
+
+
+ struct AH_GlyphLoader_
+ {
+ FT_Memory memory;
+ FT_UInt max_points;
+ FT_UInt max_contours;
+ FT_UInt max_subglyphs;
+ FT_Bool use_extra;
+
+ AH_GlyphLoad base;
+ AH_GlyphLoad current;
+
+ void* other; /* for possible future extensions */
+ };
+
+
+ FT_LOCAL FT_Error
+ AH_GlyphLoader_New( FT_Memory memory,
+ AH_GlyphLoader** aloader );
+
+ FT_LOCAL FT_Error
+ AH_GlyphLoader_Create_Extra( AH_GlyphLoader* loader );
+
+ FT_LOCAL void
+ AH_GlyphLoader_Done( AH_GlyphLoader* loader );
+
+ FT_LOCAL void
+ AH_GlyphLoader_Reset( AH_GlyphLoader* loader );
+
+ FT_LOCAL void
+ AH_GlyphLoader_Rewind( AH_GlyphLoader* loader );
+
+ FT_LOCAL FT_Error
+ AH_GlyphLoader_Check_Points( AH_GlyphLoader* loader,
+ FT_UInt n_points,
+ FT_UInt n_contours );
+
+ FT_LOCAL FT_Error
+ AH_GlyphLoader_Check_Subglyphs( AH_GlyphLoader* loader,
+ FT_UInt n_subs );
+
+ FT_LOCAL void
+ AH_GlyphLoader_Prepare( AH_GlyphLoader* loader );
+
+ FT_LOCAL void
+ AH_GlyphLoader_Add( AH_GlyphLoader* loader );
+
+ FT_LOCAL FT_Error
+ AH_GlyphLoader_Copy_Points( AH_GlyphLoader* target,
+ FT_GlyphLoader* source );
+
+#else /* _STANDALONE */
+
+#include FT_INTERNAL_OBJECTS_H
+
+ #define AH_Load FT_GlyphLoad
+ #define AH_Loader FT_GlyphLoader
+
+ #define ah_loader_new FT_GlyphLoader_New
+ #define ah_loader_done FT_GlyphLoader_Done
+ #define ah_loader_reset FT_GlyphLoader_Reset
+ #define ah_loader_rewind FT_GlyphLoader_Rewind
+ #define ah_loader_create_extra FT_GlyphLoader_Create_Extra
+ #define ah_loader_check_points FT_GlyphLoader_Check_Points
+ #define ah_loader_check_subglyphs FT_GlyphLoader_Check_Subglyphs
+ #define ah_loader_prepare FT_GlyphLoader_Prepare
+ #define ah_loader_add FT_GlyphLoader_Add
+ #define ah_loader_copy_points FT_GlyphLoader_Copy_Points
+
+#endif /* _STANDALONE_ */
+
+
+FT_END_HEADER
+
+#endif /* __AHLOADER_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ahmodule.h */
+/* */
+/* Auto-hinting module (declaration). */
+/* */
+/* Copyright 2000-2001 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AHMODULE_H__
+#define __AHMODULE_H__
+
+
+#include <ft2build.h>
+#include FT_MODULE_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_CALLBACK_TABLE
+ const FT_Module_Class autohint_module_class;
+
+
+FT_END_HEADER
+
+#endif /* __AHMODULE_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ahoptim.h */
+/* */
+/* FreeType auto hinting outline optimization (declaration). */
+/* */
+/* Copyright 2000-2001 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AHOPTIM_H__
+#define __AHOPTIM_H__
+
+
+#include <ft2build.h>
+#include "ahtypes.h"
+
+
+FT_BEGIN_HEADER
+
+
+ /* the maximal number of stem configurations to record */
+ /* during optimization */
+#define AH_MAX_CONFIGS 8
+
+
+ typedef struct AH_Stem_
+ {
+ FT_Pos pos; /* current position */
+ FT_Pos velocity; /* current velocity */
+ FT_Pos force; /* sum of current forces */
+ FT_Pos width; /* normalized width */
+
+ FT_Pos min_pos; /* minimum grid position */
+ FT_Pos max_pos; /* maximum grid position */
+
+ AH_Edge* edge1; /* left/bottom edge */
+ AH_Edge* edge2; /* right/top edge */
+
+ FT_Pos opos; /* original position */
+ FT_Pos owidth; /* original width */
+
+ FT_Pos min_coord; /* minimum coordinate */
+ FT_Pos max_coord; /* maximum coordinate */
+
+ } AH_Stem;
+
+
+ /* A spring between two stems */
+ typedef struct AH_Spring_
+ {
+ AH_Stem* stem1;
+ AH_Stem* stem2;
+ FT_Pos owidth; /* original width */
+ FT_Pos tension; /* current tension */
+
+ } AH_Spring;
+
+
+ /* A configuration records the position of each stem at a given time */
+ /* as well as the associated distortion */
+ typedef struct AH_Configuration_
+ {
+ FT_Pos* positions;
+ FT_Long distortion;
+
+ } AH_Configuration;
+
+
+ typedef struct AH_Optimizer_
+ {
+ FT_Memory memory;
+ AH_Outline* outline;
+
+ FT_Int num_hstems;
+ AH_Stem* horz_stems;
+
+ FT_Int num_vstems;
+ AH_Stem* vert_stems;
+
+ FT_Int num_hsprings;
+ FT_Int num_vsprings;
+ AH_Spring* horz_springs;
+ AH_Spring* vert_springs;
+
+ FT_Int num_configs;
+ AH_Configuration configs[AH_MAX_CONFIGS];
+ FT_Pos* positions;
+
+ /* during each pass, use these instead */
+ FT_Int num_stems;
+ AH_Stem* stems;
+
+ FT_Int num_springs;
+ AH_Spring* springs;
+ FT_Bool vertical;
+
+ FT_Fixed tension_scale;
+ FT_Pos tension_threshold;
+
+ } AH_Optimizer;
+
+
+ /* loads the outline into the optimizer */
+ int
+ AH_Optimizer_Init( AH_Optimizer* optimizer,
+ AH_Outline* outline,
+ FT_Memory memory );
+
+
+ /* compute optimal outline */
+ void
+ AH_Optimizer_Compute( AH_Optimizer* optimizer );
+
+
+ /* release the optimization data */
+ void
+ AH_Optimizer_Done( AH_Optimizer* optimizer );
+
+
+FT_END_HEADER
+
+#endif /* __AHOPTIM_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ahtypes.h */
+/* */
+/* General types and definitions for the auto-hint module */
+/* (specification only). */
+/* */
+/* Copyright 2000-2001 Catharon Productions Inc. */
+/* Author: David Turner */
+/* */
+/* This file is part of the Catharon Typography Project and shall only */
+/* be used, modified, and distributed under the terms of the Catharon */
+/* Open Source License that should come with this file under the name */
+/* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/* Note that this license is compatible with the FreeType license. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AHTYPES_H__
+#define __AHTYPES_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include "ahloader.h"
+
+
+#define xxAH_DEBUG
+
+
+#ifdef AH_DEBUG
+
+#include <stdio.h>
+#define AH_LOG( x ) printf ## x
+
+#else
+
+#define AH_LOG( x ) do ; while ( 0 ) /* nothing */
+
+#endif /* AH_DEBUG */
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** COMPILE-TIME BUILD OPTIONS ****/
+ /**** ****/
+ /**** Toggle these configuration macros to experiment with `features' ****/
+ /**** of the auto-hinter. ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* If this option is defined, only strong interpolation will be used to */
+ /* place the points between edges. Otherwise, `smooth' points are */
+ /* detected and later hinted through weak interpolation to correct some */
+ /* unpleasant artefacts. */
+ /* */
+#undef AH_OPTION_NO_WEAK_INTERPOLATION
+
+
+ /*************************************************************************/
+ /* */
+ /* If this option is defined, only weak interpolation will be used to */
+ /* place the points between edges. Otherwise, `strong' points are */
+ /* detected and later hinted through strong interpolation to correct */
+ /* some unpleasant artefacts. */
+ /* */
+#undef AH_OPTION_NO_STRONG_INTERPOLATION
+
+
+ /*************************************************************************/
+ /* */
+ /* Undefine this macro if you don't want to hint the metrics. There is */
+ /* no reason to do this (at least for non-CJK scripts), except for */
+ /* experimentation. */
+ /* */
+#define AH_HINT_METRICS
+
+
+ /*************************************************************************/
+ /* */
+ /* Define this macro if you do not want to insert extra edges at a */
+ /* glyph's x and y extremum (if there isn't one already available). */
+ /* This helps to reduce a number of artefacts and allows hinting of */
+ /* metrics. */
+ /* */
+#undef AH_OPTION_NO_EXTREMUM_EDGES
+
+
+ /* don't touch for now */
+#define AH_MAX_WIDTHS 12
+#define AH_MAX_HEIGHTS 12
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** TYPE DEFINITIONS ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* see agangles.h */
+ typedef FT_Int AH_Angle;
+
+
+ /* hint flags */
+#define ah_flah_none 0
+
+ /* bezier control points flags */
+#define ah_flah_conic 1
+#define ah_flah_cubic 2
+#define ah_flah_control ( ah_flah_conic | ah_flah_cubic )
+
+ /* extrema flags */
+#define ah_flah_extrema_x 4
+#define ah_flah_extrema_y 8
+
+ /* roundness */
+#define ah_flah_round_x 16
+#define ah_flah_round_y 32
+
+ /* touched */
+#define ah_flah_touch_x 64
+#define ah_flah_touch_y 128
+
+ /* weak interpolation */
+#define ah_flah_weak_interpolation 256
+
+ typedef FT_Int AH_Flags;
+
+
+ /* edge hint flags */
+#define ah_edge_normal 0
+#define ah_edge_round 1
+#define ah_edge_serif 2
+#define ah_edge_done 4
+
+ typedef FT_Int AH_Edge_Flags;
+
+
+ /* hint directions -- the values are computed so that two vectors are */
+ /* in opposite directions iff `dir1+dir2 == 0' */
+#define ah_dir_none 4
+#define ah_dir_right 1
+#define ah_dir_left -1
+#define ah_dir_up 2
+#define ah_dir_down -2
+
+ typedef FT_Int AH_Direction;
+
+
+ typedef struct AH_Point AH_Point;
+ typedef struct AH_Segment AH_Segment;
+ typedef struct AH_Edge AH_Edge;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* AH_Point */
+ /* */
+ /* <Description> */
+ /* A structure used to model an outline point to the AH_Outline type. */
+ /* */
+ /* <Fields> */
+ /* flags :: The current point hint flags. */
+ /* */
+ /* ox, oy :: The current original scaled coordinates. */
+ /* */
+ /* fx, fy :: The current coordinates in font units. */
+ /* */
+ /* x, y :: The current hinter coordinates. */
+ /* */
+ /* u, v :: Point coordinates -- meaning varies with context. */
+ /* */
+ /* in_dir :: The direction of the inwards vector (prev->point). */
+ /* */
+ /* out_dir :: The direction of the outwards vector (point->next). */
+ /* */
+ /* in_angle :: The angle of the inwards vector. */
+ /* */
+ /* out_angle :: The angle of the outwards vector. */
+ /* */
+ /* next :: The next point in same contour. */
+ /* */
+ /* prev :: The previous point in same contour. */
+ /* */
+ struct AH_Point
+ {
+ AH_Flags flags; /* point flags used by hinter */
+ FT_Pos ox, oy;
+ FT_Pos fx, fy;
+ FT_Pos x, y;
+ FT_Pos u, v;
+
+ AH_Direction in_dir; /* direction of inwards vector */
+ AH_Direction out_dir; /* direction of outwards vector */
+
+ AH_Angle in_angle;
+ AH_Angle out_angle;
+
+ AH_Point* next; /* next point in contour */
+ AH_Point* prev; /* previous point in contour */
+ };
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* AH_Segment */
+ /* */
+ /* <Description> */
+ /* A structure used to describe an edge segment to the auto-hinter. */
+ /* A segment is simply a sequence of successive points located on the */
+ /* same horizontal or vertical `position', in a given direction. */
+ /* */
+ /* <Fields> */
+ /* flags :: The segment edge flags (straight, rounded, etc.). */
+ /* */
+ /* dir :: The segment direction. */
+ /* */
+ /* first :: The first point in the segment. */
+ /* */
+ /* last :: The last point in the segment. */
+ /* */
+ /* contour :: A pointer to the first point of the segment's */
+ /* contour. */
+ /* */
+ /* pos :: The segment position in font units. */
+ /* */
+ /* size :: The segment size. */
+ /* */
+ /* edge :: The edge of the current segment. */
+ /* */
+ /* edge_next :: The next segment on the same edge. */
+ /* */
+ /* link :: The pairing segment for this edge. */
+ /* */
+ /* serif :: The primary segment for serifs. */
+ /* */
+ /* num_linked :: The number of other segments that link to this one. */
+ /* */
+ /* score :: Used to score the segment when selecting them. */
+ /* */
+ struct AH_Segment
+ {
+ AH_Edge_Flags flags;
+ AH_Direction dir;
+
+ AH_Point* first; /* first point in edge segment */
+ AH_Point* last; /* last point in edge segment */
+ AH_Point** contour; /* ptr to first point of segment's contour */
+
+ FT_Pos pos; /* position of segment */
+ FT_Pos min_coord; /* minimum coordinate of segment */
+ FT_Pos max_coord; /* maximum coordinate of segment */
+
+ AH_Edge* edge;
+ AH_Segment* edge_next;
+
+ AH_Segment* link; /* link segment */
+ AH_Segment* serif; /* primary segment for serifs */
+ FT_Pos num_linked; /* number of linked segments */
+ FT_Int score;
+ };
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* AH_Edge */
+ /* */
+ /* <Description> */
+ /* A structure used to describe an edge, which really is a horizontal */
+ /* or vertical coordinate to be hinted depending on the segments */
+ /* located on it. */
+ /* */
+ /* <Fields> */
+ /* flags :: The segment edge flags (straight, rounded, etc.). */
+ /* */
+ /* dir :: The main segment direction on this edge. */
+ /* */
+ /* first :: The first edge segment. */
+ /* */
+ /* last :: The last edge segment. */
+ /* */
+ /* fpos :: The original edge position in font units. */
+ /* */
+ /* opos :: The original scaled edge position. */
+ /* */
+ /* pos :: The hinted edge position. */
+ /* */
+ /* link :: The linked edge. */
+ /* */
+ /* serif :: The serif edge. */
+ /* */
+ /* num_paired :: The number of other edges that pair to this one. */
+ /* */
+ /* score :: Used to score the edge when selecting them. */
+ /* */
+ /* blue_edge :: Indicate the blue zone edge this edge is related to. */
+ /* Only set for some of the horizontal edges in a Latin */
+ /* font. */
+ /* */
+ struct AH_Edge
+ {
+ AH_Edge_Flags flags;
+ AH_Direction dir;
+
+ AH_Segment* first;
+ AH_Segment* last;
+
+ FT_Pos fpos;
+ FT_Pos opos;
+ FT_Pos pos;
+
+ AH_Edge* link;
+ AH_Edge* serif;
+ FT_Int num_linked;
+
+ FT_Int score;
+ FT_Pos* blue_edge;
+ };
+
+
+ /* an outline as seen by the hinter */
+ typedef struct AH_Outline_
+ {
+ FT_Memory memory;
+
+ AH_Direction vert_major_dir; /* vertical major direction */
+ AH_Direction horz_major_dir; /* horizontal major direction */
+
+ FT_Fixed x_scale;
+ FT_Fixed y_scale;
+ FT_Pos edge_distance_threshold;
+
+ FT_Int max_points;
+ FT_Int num_points;
+ AH_Point* points;
+
+ FT_Int max_contours;
+ FT_Int num_contours;
+ AH_Point** contours;
+
+ FT_Int num_hedges;
+ AH_Edge* horz_edges;
+
+ FT_Int num_vedges;
+ AH_Edge* vert_edges;
+
+ FT_Int num_hsegments;
+ AH_Segment* horz_segments;
+
+ FT_Int num_vsegments;
+ AH_Segment* vert_segments;
+
+ } AH_Outline;
+
+
+#define ah_blue_capital_top 0 /* THEZOCQS */
+#define ah_blue_capital_bottom ( ah_blue_capital_top + 1 ) /* HEZLOCUS */
+#define ah_blue_small_top ( ah_blue_capital_bottom + 1 ) /* xzroesc */
+#define ah_blue_small_bottom ( ah_blue_small_top + 1 ) /* xzroesc */
+#define ah_blue_small_minor ( ah_blue_small_bottom + 1 ) /* pqgjy */
+#define ah_blue_max ( ah_blue_small_minor + 1 )
+
+ typedef FT_Int AH_Blue;
+
+
+#define ah_hinter_monochrome 1
+#define ah_hinter_optimize 2
+
+ typedef FT_Int AH_Hinter_Flags;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* AH_Globals */
+ /* */
+ /* <Description> */
+ /* Holds the global metrics for a given font face (be it in design */
+ /* units or scaled pixel values). */
+ /* */
+ /* <Fields> */
+ /* num_widths :: The number of widths. */
+ /* */
+ /* num_heights :: The number of heights. */
+ /* */
+ /* widths :: Snap widths, including standard one. */
+ /* */
+ /* heights :: Snap height, including standard one. */
+ /* */
+ /* blue_refs :: The reference positions of blue zones. */
+ /* */
+ /* blue_shoots :: The overshoot positions of blue zones. */
+ /* */
+ typedef struct AH_Globals_
+ {
+ FT_Int num_widths;
+ FT_Int num_heights;
+
+ FT_Pos widths [AH_MAX_WIDTHS];
+ FT_Pos heights[AH_MAX_HEIGHTS];
+
+ FT_Pos blue_refs [ah_blue_max];
+ FT_Pos blue_shoots[ah_blue_max];
+
+ } AH_Globals;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* AH_Face_Globals */
+ /* */
+ /* <Description> */
+ /* Holds the complete global metrics for a given font face (i.e., the */
+ /* design units version + a scaled version + the current scales */
+ /* used). */
+ /* */
+ /* <Fields> */
+ /* face :: A handle to the source face object */
+ /* */
+ /* design :: The globals in font design units. */
+ /* */
+ /* scaled :: Scaled globals in sub-pixel values. */
+ /* */
+ /* x_scale :: The current horizontal scale. */
+ /* */
+ /* y_scale :: The current vertical scale. */
+ /* */
+ typedef struct AH_Face_Globals_
+ {
+ FT_Face face;
+ AH_Globals design;
+ AH_Globals scaled;
+ FT_Fixed x_scale;
+ FT_Fixed y_scale;
+ FT_Bool control_overshoot;
+
+ } AH_Face_Globals;
+
+
+ typedef struct AH_Hinter
+ {
+ FT_Memory memory;
+ AH_Hinter_Flags flags;
+
+ FT_Int algorithm;
+ FT_Face face;
+
+ AH_Face_Globals* globals;
+
+ AH_Outline* glyph;
+
+ AH_Loader* loader;
+ FT_Vector pp1;
+ FT_Vector pp2;
+
+ FT_Bool transformed;
+ FT_Vector trans_delta;
+ FT_Matrix trans_matrix;
+
+ FT_Bool disable_horz_edges;
+ FT_Bool disable_vert_edges;
+ } AH_Hinter;
+
+
+FT_END_HEADER
+
+#endif /* __AHTYPES_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cffdrivr.h */
+/* */
+/* High-level OpenType driver interface (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CFFDRIVER_H__
+#define __CFFDRIVER_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_CALLBACK_TABLE
+ const FT_Driver_Class cff_driver_class;
+
+
+FT_END_HEADER
+
+#endif /* __CFFDRIVER_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cfferrs.h */
+/* */
+/* CFF error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the CFF error enumeration constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __CFFERRS_H__
+#define __CFFERRS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX CFF_Err_
+#define FT_ERR_BASE FT_Mod_Err_CFF
+
+
+#include FT_ERRORS_H
+
+#endif /* __CFFERRS_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cffgload.h */
+/* */
+/* OpenType Glyph Loader (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CFFGLOAD_H__
+#define __CFFGLOAD_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include "cffobjs.h"
+
+
+FT_BEGIN_HEADER
+
+
+#define CFF_MAX_OPERANDS 48
+#define CFF_MAX_SUBRS_CALLS 32
+
+
+ /*************************************************************************/
+ /* */
+ /* <Structure> */
+ /* CFF_Builder */
+ /* */
+ /* <Description> */
+ /* A structure used during glyph loading to store its outline. */
+ /* */
+ /* <Fields> */
+ /* memory :: The current memory object. */
+ /* */
+ /* face :: The current face object. */
+ /* */
+ /* glyph :: The current glyph slot. */
+ /* */
+ /* current :: The current glyph outline. */
+ /* */
+ /* base :: The base glyph outline. */
+ /* */
+ /* max_points :: maximum points in builder outline */
+ /* */
+ /* max_contours :: Maximal number of contours in builder outline. */
+ /* */
+ /* last :: The last point position. */
+ /* */
+ /* scale_x :: The horizontal scale (FUnits to sub-pixels). */
+ /* */
+ /* scale_y :: The vertical scale (FUnits to sub-pixels). */
+ /* */
+ /* pos_x :: The horizontal translation (if composite glyph). */
+ /* */
+ /* pos_y :: The vertical translation (if composite glyph). */
+ /* */
+ /* left_bearing :: The left side bearing point. */
+ /* */
+ /* advance :: The horizontal advance vector. */
+ /* */
+ /* bbox :: Unused. */
+ /* */
+ /* path_begun :: A flag which indicates that a new path has begun. */
+ /* */
+ /* load_points :: If this flag is not set, no points are loaded. */
+ /* */
+ /* no_recurse :: Set but not used. */
+ /* */
+ /* error :: An error code that is only used to report memory */
+ /* allocation problems. */
+ /* */
+ /* metrics_only :: A boolean indicating that we only want to compute */
+ /* the metrics of a given glyph, not load all of its */
+ /* points. */
+ /* */
+ typedef struct CFF_Builder_
+ {
+ FT_Memory memory;
+ TT_Face face;
+ CFF_GlyphSlot glyph;
+ FT_GlyphLoader* loader;
+ FT_Outline* base;
+ FT_Outline* current;
+
+ FT_Vector last;
+
+ FT_Fixed scale_x;
+ FT_Fixed scale_y;
+
+ FT_Pos pos_x;
+ FT_Pos pos_y;
+
+ FT_Vector left_bearing;
+ FT_Vector advance;
+
+ FT_BBox bbox; /* bounding box */
+ FT_Bool path_begun;
+ FT_Bool load_points;
+ FT_Bool no_recurse;
+
+ FT_Error error; /* only used for memory errors */
+ FT_Bool metrics_only;
+
+ } CFF_Builder;
+
+
+ /* execution context charstring zone */
+
+ typedef struct CFF_Decoder_Zone_
+ {
+ FT_Byte* base;
+ FT_Byte* limit;
+ FT_Byte* cursor;
+
+ } CFF_Decoder_Zone;
+
+
+ typedef struct CFF_Decoder_
+ {
+ CFF_Builder builder;
+ CFF_Font* cff;
+
+ FT_Fixed stack[CFF_MAX_OPERANDS + 1];
+ FT_Fixed* top;
+
+ CFF_Decoder_Zone zones[CFF_MAX_SUBRS_CALLS + 1];
+ CFF_Decoder_Zone* zone;
+
+ FT_Int flex_state;
+ FT_Int num_flex_vectors;
+ FT_Vector flex_vectors[7];
+
+ FT_Pos glyph_width;
+ FT_Pos nominal_width;
+
+ FT_Bool read_width;
+ FT_Int num_hints;
+ FT_Fixed* buildchar;
+ FT_Int len_buildchar;
+
+ FT_UInt num_locals;
+ FT_UInt num_globals;
+
+ FT_Int locals_bias;
+ FT_Int globals_bias;
+
+ FT_Byte** locals;
+ FT_Byte** globals;
+
+ FT_Byte** glyph_names; /* for pure CFF fonts only */
+ FT_UInt num_glyphs; /* number of glyphs in font */
+
+ } CFF_Decoder;
+
+
+ FT_LOCAL void
+ CFF_Init_Decoder( CFF_Decoder* decoder,
+ TT_Face face,
+ CFF_Size size,
+ CFF_GlyphSlot slot );
+
+ FT_LOCAL void
+ CFF_Prepare_Decoder( CFF_Decoder* decoder,
+ FT_UInt glyph_index );
+
+#if 0 /* unused until we support pure CFF fonts */
+
+ /* Compute the maximum advance width of a font through quick parsing */
+ FT_LOCAL FT_Error
+ CFF_Compute_Max_Advance( TT_Face face,
+ FT_Int* max_advance );
+
+#endif /* 0 */
+
+ FT_LOCAL FT_Error
+ CFF_Parse_CharStrings( CFF_Decoder* decoder,
+ FT_Byte* charstring_base,
+ FT_Int charstring_len );
+
+ FT_LOCAL FT_Error
+ CFF_Load_Glyph( CFF_GlyphSlot glyph,
+ CFF_Size size,
+ FT_Int glyph_index,
+ FT_Int load_flags );
+
+
+FT_END_HEADER
+
+#endif /* __CFFGLOAD_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cffload.h */
+/* */
+/* OpenType & CFF data/program tables loader (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CFFLOAD_H__
+#define __CFFLOAD_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_CFF_TYPES_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+
+FT_BEGIN_HEADER
+
+ const FT_UShort cff_isoadobe_charset[229] =
+ {
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 64,
+ 65,
+ 66,
+ 67,
+ 68,
+ 69,
+ 70,
+ 71,
+ 72,
+ 73,
+ 74,
+ 75,
+ 76,
+ 77,
+ 78,
+ 79,
+ 80,
+ 81,
+ 82,
+ 83,
+ 84,
+ 85,
+ 86,
+ 87,
+ 88,
+ 89,
+ 90,
+ 91,
+ 92,
+ 93,
+ 94,
+ 95,
+ 96,
+ 97,
+ 98,
+ 99,
+ 100,
+ 101,
+ 102,
+ 103,
+ 104,
+ 105,
+ 106,
+ 107,
+ 108,
+ 109,
+ 110,
+ 111,
+ 112,
+ 113,
+ 114,
+ 115,
+ 116,
+ 117,
+ 118,
+ 119,
+ 120,
+ 121,
+ 122,
+ 123,
+ 124,
+ 125,
+ 126,
+ 127,
+ 128,
+ 129,
+ 130,
+ 131,
+ 132,
+ 133,
+ 134,
+ 135,
+ 136,
+ 137,
+ 138,
+ 139,
+ 140,
+ 141,
+ 142,
+ 143,
+ 144,
+ 145,
+ 146,
+ 147,
+ 148,
+ 149,
+ 150,
+ 151,
+ 152,
+ 153,
+ 154,
+ 155,
+ 156,
+ 157,
+ 158,
+ 159,
+ 160,
+ 161,
+ 162,
+ 163,
+ 164,
+ 165,
+ 166,
+ 167,
+ 168,
+ 169,
+ 170,
+ 171,
+ 172,
+ 173,
+ 174,
+ 175,
+ 176,
+ 177,
+ 178,
+ 179,
+ 180,
+ 181,
+ 182,
+ 183,
+ 184,
+ 185,
+ 186,
+ 187,
+ 188,
+ 189,
+ 190,
+ 191,
+ 192,
+ 193,
+ 194,
+ 195,
+ 196,
+ 197,
+ 198,
+ 199,
+ 200,
+ 201,
+ 202,
+ 203,
+ 204,
+ 205,
+ 206,
+ 207,
+ 208,
+ 209,
+ 210,
+ 211,
+ 212,
+ 213,
+ 214,
+ 215,
+ 216,
+ 217,
+ 218,
+ 219,
+ 220,
+ 221,
+ 222,
+ 223,
+ 224,
+ 225,
+ 226,
+ 227,
+ 228
+ };
+
+ const FT_UShort cff_expert_charset[166] =
+ {
+ 0,
+ 1,
+ 229,
+ 230,
+ 231,
+ 232,
+ 233,
+ 234,
+ 235,
+ 236,
+ 237,
+ 238,
+ 13,
+ 14,
+ 15,
+ 99,
+ 239,
+ 240,
+ 241,
+ 242,
+ 243,
+ 244,
+ 245,
+ 246,
+ 247,
+ 248,
+ 27,
+ 28,
+ 249,
+ 250,
+ 251,
+ 252,
+ 253,
+ 254,
+ 255,
+ 256,
+ 257,
+ 258,
+ 259,
+ 260,
+ 261,
+ 262,
+ 263,
+ 264,
+ 265,
+ 266,
+ 109,
+ 110,
+ 267,
+ 268,
+ 269,
+ 270,
+ 271,
+ 272,
+ 273,
+ 274,
+ 275,
+ 276,
+ 277,
+ 278,
+ 279,
+ 280,
+ 281,
+ 282,
+ 283,
+ 284,
+ 285,
+ 286,
+ 287,
+ 288,
+ 289,
+ 290,
+ 291,
+ 292,
+ 293,
+ 294,
+ 295,
+ 296,
+ 297,
+ 298,
+ 299,
+ 300,
+ 301,
+ 302,
+ 303,
+ 304,
+ 305,
+ 306,
+ 307,
+ 308,
+ 309,
+ 310,
+ 311,
+ 312,
+ 313,
+ 314,
+ 315,
+ 316,
+ 317,
+ 318,
+ 158,
+ 155,
+ 163,
+ 319,
+ 320,
+ 321,
+ 322,
+ 323,
+ 324,
+ 325,
+ 326,
+ 150,
+ 164,
+ 169,
+ 327,
+ 328,
+ 329,
+ 330,
+ 331,
+ 332,
+ 333,
+ 334,
+ 335,
+ 336,
+ 337,
+ 338,
+ 339,
+ 340,
+ 341,
+ 342,
+ 343,
+ 344,
+ 345,
+ 346,
+ 347,
+ 348,
+ 349,
+ 350,
+ 351,
+ 352,
+ 353,
+ 354,
+ 355,
+ 356,
+ 357,
+ 358,
+ 359,
+ 360,
+ 361,
+ 362,
+ 363,
+ 364,
+ 365,
+ 366,
+ 367,
+ 368,
+ 369,
+ 370,
+ 371,
+ 372,
+ 373,
+ 374,
+ 375,
+ 376,
+ 377,
+ 378
+ };
+
+ const FT_UShort cff_expertsubset_charset[87] =
+ {
+ 0,
+ 1,
+ 231,
+ 232,
+ 235,
+ 236,
+ 237,
+ 238,
+ 13,
+ 14,
+ 15,
+ 99,
+ 239,
+ 240,
+ 241,
+ 242,
+ 243,
+ 244,
+ 245,
+ 246,
+ 247,
+ 248,
+ 27,
+ 28,
+ 249,
+ 250,
+ 251,
+ 253,
+ 254,
+ 255,
+ 256,
+ 257,
+ 258,
+ 259,
+ 260,
+ 261,
+ 262,
+ 263,
+ 264,
+ 265,
+ 266,
+ 109,
+ 110,
+ 267,
+ 268,
+ 269,
+ 270,
+ 272,
+ 300,
+ 301,
+ 302,
+ 305,
+ 314,
+ 315,
+ 158,
+ 155,
+ 163,
+ 320,
+ 321,
+ 322,
+ 323,
+ 324,
+ 325,
+ 326,
+ 150,
+ 164,
+ 169,
+ 327,
+ 328,
+ 329,
+ 330,
+ 331,
+ 332,
+ 333,
+ 334,
+ 335,
+ 336,
+ 337,
+ 338,
+ 339,
+ 340,
+ 341,
+ 342,
+ 343,
+ 344,
+ 345,
+ 346
+ };
+
+ const FT_UShort cff_standard_encoding[256] =
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 64,
+ 65,
+ 66,
+ 67,
+ 68,
+ 69,
+ 70,
+ 71,
+ 72,
+ 73,
+ 74,
+ 75,
+ 76,
+ 77,
+ 78,
+ 79,
+ 80,
+ 81,
+ 82,
+ 83,
+ 84,
+ 85,
+ 86,
+ 87,
+ 88,
+ 89,
+ 90,
+ 91,
+ 92,
+ 93,
+ 94,
+ 95,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 96,
+ 97,
+ 98,
+ 99,
+ 100,
+ 101,
+ 102,
+ 103,
+ 104,
+ 105,
+ 106,
+ 107,
+ 108,
+ 109,
+ 110,
+ 0,
+ 111,
+ 112,
+ 113,
+ 114,
+ 0,
+ 115,
+ 116,
+ 117,
+ 118,
+ 119,
+ 120,
+ 121,
+ 122,
+ 0,
+ 123,
+ 0,
+ 124,
+ 125,
+ 126,
+ 127,
+ 128,
+ 129,
+ 130,
+ 131,
+ 0,
+ 132,
+ 133,
+ 0,
+ 134,
+ 135,
+ 136,
+ 137,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 138,
+ 0,
+ 139,
+ 0,
+ 0,
+ 0,
+ 0,
+ 140,
+ 141,
+ 142,
+ 143,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 144,
+ 0,
+ 0,
+ 0,
+ 145,
+ 0,
+ 0,
+ 146,
+ 147,
+ 148,
+ 149,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ const FT_UShort cff_expert_encoding[256] =
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 229,
+ 230,
+ 0,
+ 231,
+ 232,
+ 233,
+ 234,
+ 235,
+ 236,
+ 237,
+ 238,
+ 13,
+ 14,
+ 15,
+ 99,
+ 239,
+ 240,
+ 241,
+ 242,
+ 243,
+ 244,
+ 245,
+ 246,
+ 247,
+ 248,
+ 27,
+ 28,
+ 249,
+ 250,
+ 251,
+ 252,
+ 0,
+ 253,
+ 254,
+ 255,
+ 256,
+ 257,
+ 0,
+ 0,
+ 0,
+ 258,
+ 0,
+ 0,
+ 259,
+ 260,
+ 261,
+ 262,
+ 0,
+ 0,
+ 263,
+ 264,
+ 265,
+ 0,
+ 266,
+ 109,
+ 110,
+ 267,
+ 268,
+ 269,
+ 0,
+ 270,
+ 271,
+ 272,
+ 273,
+ 274,
+ 275,
+ 276,
+ 277,
+ 278,
+ 279,
+ 280,
+ 281,
+ 282,
+ 283,
+ 284,
+ 285,
+ 286,
+ 287,
+ 288,
+ 289,
+ 290,
+ 291,
+ 292,
+ 293,
+ 294,
+ 295,
+ 296,
+ 297,
+ 298,
+ 299,
+ 300,
+ 301,
+ 302,
+ 303,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 304,
+ 305,
+ 306,
+ 0,
+ 0,
+ 307,
+ 308,
+ 309,
+ 310,
+ 311,
+ 0,
+ 312,
+ 0,
+ 0,
+ 312,
+ 0,
+ 0,
+ 314,
+ 315,
+ 0,
+ 0,
+ 316,
+ 317,
+ 318,
+ 0,
+ 0,
+ 0,
+ 158,
+ 155,
+ 163,
+ 319,
+ 320,
+ 321,
+ 322,
+ 323,
+ 324,
+ 325,
+ 0,
+ 0,
+ 326,
+ 150,
+ 164,
+ 169,
+ 327,
+ 328,
+ 329,
+ 330,
+ 331,
+ 332,
+ 333,
+ 334,
+ 335,
+ 336,
+ 337,
+ 338,
+ 339,
+ 340,
+ 341,
+ 342,
+ 343,
+ 344,
+ 345,
+ 346,
+ 347,
+ 348,
+ 349,
+ 350,
+ 351,
+ 352,
+ 353,
+ 354,
+ 355,
+ 356,
+ 357,
+ 358,
+ 359,
+ 360,
+ 361,
+ 362,
+ 363,
+ 364,
+ 365,
+ 366,
+ 367,
+ 368,
+ 369,
+ 370,
+ 371,
+ 372,
+ 373,
+ 374,
+ 375,
+ 376,
+ 377,
+ 378
+ };
+
+
+ FT_LOCAL FT_String*
+ CFF_Get_Name( CFF_Index* index,
+ FT_UInt element );
+
+ FT_LOCAL FT_String*
+ CFF_Get_String( CFF_Index* index,
+ FT_UInt sid,
+ PSNames_Interface* interface );
+
+
+ FT_LOCAL FT_Error
+ CFF_Access_Element( CFF_Index* index,
+ FT_UInt element,
+ FT_Byte** pbytes,
+ FT_ULong* pbyte_len );
+
+ FT_LOCAL void
+ CFF_Forget_Element( CFF_Index* index,
+ FT_Byte** pbytes );
+
+
+ FT_LOCAL FT_Error
+ CFF_Load_Font( FT_Stream stream,
+ FT_Int face_index,
+ CFF_Font* font );
+
+ FT_LOCAL void
+ CFF_Done_Font( CFF_Font* font );
+
+
+ FT_LOCAL FT_Byte
+ CFF_Get_FD( CFF_FD_Select* select,
+ FT_UInt glyph_index );
+
+
+FT_END_HEADER
+
+#endif /* __CFFLOAD_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cffobjs.h */
+/* */
+/* OpenType objects manager (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CFFOBJS_H__
+#define __CFFOBJS_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_CFF_TYPES_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* CFF_Driver */
+ /* */
+ /* <Description> */
+ /* A handle to an OpenType driver object. */
+ /* */
+ typedef struct CFF_DriverRec_* CFF_Driver;
+
+ typedef TT_Face CFF_Face;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* CFF_Size */
+ /* */
+ /* <Description> */
+ /* A handle to an OpenType size object. */
+ /* */
+ typedef FT_Size CFF_Size;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* CFF_GlyphSlot */
+ /* */
+ /* <Description> */
+ /* A handle to an OpenType glyph slot object. */
+ /* */
+ typedef struct CFF_GlyphSlotRec_
+ {
+ FT_GlyphSlotRec root;
+
+ FT_Bool hint;
+ FT_Bool scaled;
+
+ FT_Fixed x_scale;
+ FT_Fixed y_scale;
+
+ } CFF_GlyphSlotRec, *CFF_GlyphSlot;
+
+
+
+ /*************************************************************************/
+ /* */
+ /* Subglyph transformation record. */
+ /* */
+ typedef struct CFF_Transform_
+ {
+ FT_Fixed xx, xy; /* transformation matrix coefficients */
+ FT_Fixed yx, yy;
+ FT_F26Dot6 ox, oy; /* offsets */
+
+ } CFF_Transform;
+
+
+ /* this is only used in the case of a pure CFF font with no charmap */
+ typedef struct CFF_CharMapRec_
+ {
+ TT_CharMapRec root;
+ PS_Unicodes unicodes;
+
+ } CFF_CharMapRec, *CFF_CharMap;
+
+
+ /***********************************************************************/
+ /* */
+ /* TrueType driver class. */
+ /* */
+ typedef struct CFF_DriverRec_
+ {
+ FT_DriverRec root;
+ void* extension_component;
+
+ } CFF_DriverRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* Face functions */
+ /* */
+ FT_LOCAL FT_Error
+ CFF_Init_Face( FT_Stream stream,
+ CFF_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params );
+
+ FT_LOCAL void
+ CFF_Done_Face( CFF_Face face );
+
+
+ /*************************************************************************/
+ /* */
+ /* Driver functions */
+ /* */
+ FT_LOCAL FT_Error
+ CFF_Init_Driver( CFF_Driver driver );
+
+ FT_LOCAL void
+ CFF_Done_Driver( CFF_Driver driver );
+
+
+FT_END_HEADER
+
+#endif /* __CFFOBJS_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cffparse.h */
+/* */
+/* CFF token stream parser (specification) */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CFF_PARSE_H__
+#define __CFF_PARSE_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_CFF_TYPES_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+FT_BEGIN_HEADER
+
+
+#define CFF_MAX_STACK_DEPTH 96
+
+#define CFF_CODE_TOPDICT 0x1000
+#define CFF_CODE_PRIVATE 0x2000
+
+
+ typedef struct CFF_Parser_
+ {
+ FT_Byte* start;
+ FT_Byte* limit;
+ FT_Byte* cursor;
+
+ FT_Byte* stack[CFF_MAX_STACK_DEPTH + 1];
+ FT_Byte** top;
+
+ FT_UInt object_code;
+ void* object;
+
+ } CFF_Parser;
+
+
+ FT_LOCAL void
+ CFF_Parser_Init( CFF_Parser* parser,
+ FT_UInt code,
+ void* object );
+
+ FT_LOCAL FT_Error
+ CFF_Parser_Run( CFF_Parser* parser,
+ FT_Byte* start,
+ FT_Byte* limit );
+
+
+FT_END_HEADER
+
+
+#endif /* __CFF_PARSE_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cfftoken.h */
+/* */
+/* CFF token definitions */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE CFF_Font_Dict
+
+#undef CFFCODE
+#define CFFCODE CFFCODE_TOPDICT
+
+ CFF_FIELD_STRING ( 0, version )
+ CFF_FIELD_STRING ( 1, notice )
+ CFF_FIELD_STRING ( 0x100, copyright )
+ CFF_FIELD_STRING ( 2, full_name )
+ CFF_FIELD_STRING ( 3, family_name )
+ CFF_FIELD_STRING ( 4, weight )
+ CFF_FIELD_BOOL ( 0x101, is_fixed_pitch )
+ CFF_FIELD_FIXED ( 0x102, italic_angle )
+ CFF_FIELD_NUM ( 0x103, underline_position )
+ CFF_FIELD_NUM ( 0x104, underline_thickness )
+ CFF_FIELD_NUM ( 0x105, paint_type )
+ CFF_FIELD_NUM ( 0x106, charstring_type )
+ CFF_FIELD_CALLBACK( 0x107, font_matrix )
+ CFF_FIELD_NUM ( 13, unique_id )
+ CFF_FIELD_CALLBACK( 5, font_bbox )
+ CFF_FIELD_NUM ( 0x108, stroke_width )
+ CFF_FIELD_NUM ( 15, charset_offset )
+ CFF_FIELD_NUM ( 16, encoding_offset )
+ CFF_FIELD_NUM ( 17, charstrings_offset )
+ CFF_FIELD_CALLBACK( 18, private_dict )
+ CFF_FIELD_NUM ( 0x114, synthetic_base )
+ CFF_FIELD_STRING ( 0x115, postscript )
+ CFF_FIELD_STRING ( 0x116, base_font_name )
+
+#if 0
+ CFF_FIELD_DELTA ( 0x117, base_font_blend, 16 )
+ CFF_FIELD_CALLBACK( 0x118, multiple_master )
+ CFF_FIELD_CALLBACK( 0x119, blend_axit_types )
+#endif
+
+ CFF_FIELD_CALLBACK( 0x11E, cid_ros )
+ CFF_FIELD_NUM ( 0x11F, cid_font_version )
+ CFF_FIELD_NUM ( 0x120, cid_font_revision )
+ CFF_FIELD_NUM ( 0x121, cid_font_type )
+ CFF_FIELD_NUM ( 0x122, cid_count )
+ CFF_FIELD_NUM ( 0x123, cid_uid_base )
+ CFF_FIELD_NUM ( 0x124, cid_fd_array_offset )
+ CFF_FIELD_NUM ( 0x125, cid_fd_select_offset )
+ CFF_FIELD_STRING ( 0x126, cid_font_name )
+
+#if 0
+ CFF_FIELD_NUM ( 0x127, chameleon )
+#endif
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE CFF_Private
+#undef CFFCODE
+#define CFFCODE CFFCODE_PRIVATE
+
+ CFF_FIELD_DELTA( 6, blue_values, 14 )
+ CFF_FIELD_DELTA( 7, other_blues, 10 )
+ CFF_FIELD_DELTA( 8, family_blues, 14 )
+ CFF_FIELD_DELTA( 9, family_other_blues, 10 )
+ CFF_FIELD_FIXED( 0x109, blue_scale )
+ CFF_FIELD_NUM ( 0x10A, blue_shift )
+ CFF_FIELD_NUM ( 0x10B, blue_fuzz )
+ CFF_FIELD_NUM ( 10, standard_width )
+ CFF_FIELD_NUM ( 11, standard_height )
+ CFF_FIELD_DELTA( 0x10C, snap_widths, 13 )
+ CFF_FIELD_DELTA( 0x10D, snap_heights, 13 )
+ CFF_FIELD_BOOL ( 0x10E, force_bold )
+ CFF_FIELD_FIXED( 0x10F, force_bold_threshold )
+ CFF_FIELD_NUM ( 0x110, lenIV )
+ CFF_FIELD_NUM ( 0x111, language_group )
+ CFF_FIELD_FIXED( 0x112, expansion_factor )
+ CFF_FIELD_NUM ( 0x113, initial_random_seed )
+ CFF_FIELD_NUM ( 19, local_subrs_offset )
+ CFF_FIELD_NUM ( 20, default_width )
+ CFF_FIELD_NUM ( 21, nominal_width )
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ciderrs.h */
+/* */
+/* CID error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the CID error enumeration constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __CIDERRS_H__
+#define __CIDERRS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX CID_Err_
+#define FT_ERR_BASE FT_Mod_Err_CID
+
+#include FT_ERRORS_H
+
+#endif /* __CIDERRS_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cidgload.h */
+/* */
+/* OpenType Glyph Loader (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CIDGLOAD_H__
+#define __CIDGLOAD_H__
+
+
+#include <ft2build.h>
+#include "cidobjs.h"
+
+
+FT_BEGIN_HEADER
+
+
+#if 0
+
+ /* Compute the maximum advance width of a font through quick parsing */
+ FT_LOCAL FT_Error
+ CID_Compute_Max_Advance( CID_Face face,
+ FT_Int* max_advance );
+
+#endif /* 0 */
+
+ FT_LOCAL FT_Error
+ CID_Load_Glyph( CID_GlyphSlot glyph,
+ CID_Size size,
+ FT_Int glyph_index,
+ FT_Int load_flags );
+
+
+FT_END_HEADER
+
+#endif /* __CIDGLOAD_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cidload.h */
+/* */
+/* CID-keyed Type1 font loader (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CIDLOAD_H__
+#define __CIDLOAD_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_STREAM_H
+#include "cidparse.h"
+
+
+FT_BEGIN_HEADER
+
+
+ typedef struct CID_Loader_
+ {
+ CID_Parser parser; /* parser used to read the stream */
+ FT_Int num_chars; /* number of characters in encoding */
+
+ } CID_Loader;
+
+
+ FT_LOCAL FT_Long
+ cid_get_offset( FT_Byte** start,
+ FT_Byte offsize );
+
+ FT_LOCAL void
+ cid_decrypt( FT_Byte* buffer,
+ FT_Offset length,
+ FT_UShort seed );
+
+ FT_LOCAL FT_Error
+ CID_Open_Face( CID_Face face );
+
+
+FT_END_HEADER
+
+#endif /* __CIDLOAD_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cidobjs.h */
+/* */
+/* CID objects manager (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CIDOBJS_H__
+#define __CIDOBJS_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_CONFIG_CONFIG_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+ /* The following structures must be defined by the hinter */
+ typedef struct CID_Size_Hints_ CID_Size_Hints;
+ typedef struct CID_Glyph_Hints_ CID_Glyph_Hints;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* CID_Driver */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 driver object. */
+ /* */
+ typedef struct CID_DriverRec_* CID_Driver;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* CID_Size */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 size object. */
+ /* */
+ typedef struct CID_SizeRec_* CID_Size;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* CID_GlyphSlot */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 glyph slot object. */
+ /* */
+ typedef struct CID_GlyphSlotRec_* CID_GlyphSlot;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* CID_CharMap */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 character mapping object. */
+ /* */
+ /* <Note> */
+ /* The Type 1 format doesn't use a charmap but an encoding table. */
+ /* The driver is responsible for making up charmap objects */
+ /* corresponding to these tables. */
+ /* */
+ typedef struct CID_CharMapRec_* CID_CharMap;
+
+
+ /*************************************************************************/
+ /* */
+ /* HERE BEGINS THE TYPE 1 SPECIFIC STUFF */
+ /* */
+ /*************************************************************************/
+
+
+ typedef struct CID_SizeRec_
+ {
+ FT_SizeRec root;
+ FT_Bool valid;
+
+ } CID_SizeRec;
+
+
+ typedef struct CID_GlyphSlotRec_
+ {
+ FT_GlyphSlotRec root;
+
+ FT_Bool hint;
+ FT_Bool scaled;
+
+ FT_Fixed x_scale;
+ FT_Fixed y_scale;
+
+ } CID_GlyphSlotRec;
+
+
+ FT_LOCAL FT_Error
+ CID_Init_Face( FT_Stream stream,
+ CID_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params );
+
+ FT_LOCAL void
+ CID_Done_Face( CID_Face face );
+
+
+ FT_LOCAL FT_Error
+ CID_Init_Driver( CID_Driver driver );
+
+ FT_LOCAL void
+ CID_Done_Driver( CID_Driver driver );
+
+
+FT_END_HEADER
+
+#endif /* __CIDOBJS_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cidparse.h */
+/* */
+/* CID-keyed Type1 parser (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CIDPARSE_H__
+#define __CIDPARSE_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_TYPE1_TYPES_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* CID_Parser */
+ /* */
+ /* <Description> */
+ /* A CID_Parser is an object used to parse a Type 1 fonts very */
+ /* quickly. */
+ /* */
+ /* <Fields> */
+ /* root :: the root T1_Parser fields */
+ /* */
+ /* stream :: The current input stream. */
+ /* */
+ /* postscript :: A pointer to the data to be parsed. */
+ /* */
+ /* postscript_len :: The length of the data to be parsed. */
+ /* */
+ /* data_offset :: The start position of the binary data (i.e., the */
+ /* end of the data to be parsed. */
+ /* */
+ /* cid :: A structure which holds the information about */
+ /* the current font. */
+ /* */
+ /* num_dict :: The number of font dictionaries. */
+ /* */
+ typedef struct CID_Parser_
+ {
+ T1_Parser root;
+ FT_Stream stream;
+
+ FT_Byte* postscript;
+ FT_Int postscript_len;
+
+ FT_ULong data_offset;
+
+ CID_Info* cid;
+ FT_Int num_dict;
+
+ } CID_Parser;
+
+
+ FT_LOCAL FT_Error
+ CID_New_Parser( CID_Parser* parser,
+ FT_Stream stream,
+ FT_Memory memory,
+ PSAux_Interface* psaux );
+
+ FT_LOCAL void
+ CID_Done_Parser( CID_Parser* parser );
+
+
+ /*************************************************************************/
+ /* */
+ /* PARSING ROUTINES */
+ /* */
+ /*************************************************************************/
+
+#define CID_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root )
+#define CID_Skip_Alpha( p ) (p)->root.funcs.skip_alpha ( &(p)->root )
+
+#define CID_ToInt( p ) (p)->root.funcs.to_int( &(p)->root )
+#define CID_ToFixed( p, t ) (p)->root.funcs.to_fixed( &(p)->root, t )
+
+#define CID_ToCoordArray( p, m, c ) \
+ (p)->root.funcs.to_coord_array( &(p)->root, m, c )
+#define CID_ToFixedArray( p, m, f, t ) \
+ (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t )
+#define CID_ToToken( p, t ) \
+ (p)->root.funcs.to_token( &(p)->root, t )
+#define CID_ToTokenArray( p, t, m, c ) \
+ (p)->root.funcs.to_token_array( &(p)->root, t, m, c )
+
+#define CID_Load_Field( p, f, o ) \
+ (p)->root.funcs.load_field( &(p)->root, f, o, 0, 0 )
+#define CID_Load_Field_Table( p, f, o ) \
+ (p)->root.funcs.load_field_table( &(p)->root, f, o, 0, 0 )
+
+
+FT_END_HEADER
+
+#endif /* __CIDPARSE_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cidriver.h */
+/* */
+/* High-level CID driver interface (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CIDRIVER_H__
+#define __CIDRIVER_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_CALLBACK_TABLE
+ const FT_Driver_Class t1cid_driver_class;
+
+
+FT_END_HEADER
+
+#endif /* __CIDRIVER_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cidtoken.h */
+/* */
+/* CID token definitions (specification only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE CID_Info
+#undef T1CODE
+#define T1CODE t1_field_cid_info
+
+ T1_FIELD_STRING( "CIDFontName", cid_font_name )
+ T1_FIELD_NUM ( "CIDFontVersion", cid_version )
+ T1_FIELD_NUM ( "CIDFontType", cid_font_type )
+ T1_FIELD_STRING( "Registry", registry )
+ T1_FIELD_STRING( "Ordering", ordering )
+ T1_FIELD_NUM ( "Supplement", supplement )
+ T1_FIELD_NUM ( "UIDBase", uid_base )
+ T1_FIELD_NUM ( "CIDMapOffset", cidmap_offset )
+ T1_FIELD_NUM ( "FDBytes", fd_bytes )
+ T1_FIELD_NUM ( "GDBytes", gd_bytes )
+ T1_FIELD_NUM ( "CIDCount", cid_count )
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE T1_FontInfo
+#undef T1CODE
+#define T1CODE t1_field_font_info
+
+ T1_FIELD_STRING( "version", version )
+ T1_FIELD_STRING( "Notice", notice )
+ T1_FIELD_STRING( "FullName", full_name )
+ T1_FIELD_STRING( "FamilyName", family_name )
+ T1_FIELD_STRING( "Weight", weight )
+ T1_FIELD_FIXED ( "ItalicAngle", italic_angle )
+ T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch )
+ T1_FIELD_NUM ( "UnderlinePosition", underline_position )
+ T1_FIELD_NUM ( "UnderlineThickness", underline_thickness )
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE CID_FontDict
+#undef T1CODE
+#define T1CODE t1_field_font_dict
+
+ T1_FIELD_NUM ( "PaintType", paint_type )
+ T1_FIELD_NUM ( "FontType", font_type )
+ T1_FIELD_NUM ( "SubrMapOffset", subrmap_offset )
+ T1_FIELD_NUM ( "SDBytes", sd_bytes )
+ T1_FIELD_NUM ( "SubrCount", num_subrs )
+ T1_FIELD_NUM ( "lenBuildCharArray", len_buildchar )
+ T1_FIELD_FIXED( "ForceBoldThreshold", forcebold_threshold )
+ T1_FIELD_FIXED( "ExpansionFactor", expansion_factor )
+ T1_FIELD_NUM ( "StrokeWidth", stroke_width )
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE T1_Private
+#undef T1CODE
+#define T1CODE t1_field_private
+
+ T1_FIELD_NUM ( "UniqueID", unique_id )
+ T1_FIELD_NUM ( "lenIV", lenIV )
+ T1_FIELD_NUM ( "LanguageGroup", language_group )
+ T1_FIELD_NUM ( "password", password )
+
+ T1_FIELD_FIXED ( "BlueScale", blue_scale )
+ T1_FIELD_NUM ( "BlueShift", blue_shift )
+ T1_FIELD_NUM ( "BlueFuzz", blue_fuzz )
+
+ T1_FIELD_NUM_TABLE ( "BlueValues", blue_values, 14 )
+ T1_FIELD_NUM_TABLE ( "OtherBlues", other_blues, 10 )
+ T1_FIELD_NUM_TABLE ( "FamilyBlues", family_blues, 14 )
+ T1_FIELD_NUM_TABLE ( "FamilyOtherBlues", family_other_blues, 10 )
+
+ T1_FIELD_NUM_TABLE2( "StdHW", standard_width, 1 )
+ T1_FIELD_NUM_TABLE2( "StdVW", standard_height, 1 )
+ T1_FIELD_NUM_TABLE2( "MinFeature", min_feature, 2 )
+
+ T1_FIELD_NUM_TABLE ( "StemSnapH", snap_widths, 12 )
+ T1_FIELD_NUM_TABLE ( "StemSnapV", snap_heights, 12 )
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* fnterrs.h */
+/* */
+/* Win FNT/FON error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the Windows FNT/FON error enumeration */
+ /* constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __FNTERRS_H__
+#define __FNTERRS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX FNT_Err_
+#define FT_ERR_BASE FT_Mod_Err_Winfonts
+
+#include FT_ERRORS_H
+
+#endif /* __FNTERRS_H__ */
+
+
+/* END */
--- /dev/null
+## Process this file with automake to produce Makefile.in
+
+noinst_HEADERS = \
+ freetype.h ftchapters.h ftimage.h ftmm.h ftoutln.h ftsnames.h fttrigon.h ttnameid.h \
+ ftbbox.h fterrors.h ftlist.h ftmoderr.h ftrender.h ftsynth.h fttypes.h tttables.h \
+ ftcache.h ftglyph.h ftmac.h ftmodule.h ftsizes.h ftsystem.h t1tables.h tttags.h
--- /dev/null
+## Process this file with automake to produce Makefile.in
+
+noinst_HEADERS = ftcchunk.h ftcglyph.h ftcimage.h ftcmanag.h ftcsbits.h ftlru.h
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftcchunk.h */
+/* */
+/* FreeType chunk cache (specification). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* Important: The functions defined in this file are only used to */
+ /* implement an abstract chunk cache class. You need to */
+ /* provide additional logic to implement a complete cache. */
+ /* For example, see `ftcmetrx.h' and `ftcmetrx.c' which */
+ /* implement a glyph metrics cache based on this code. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********* *********/
+ /********* WARNING, THIS IS BETA CODE. *********/
+ /********* *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#ifndef __FTCCHUNK_H__
+#define __FTCCHUNK_H__
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_MANAGER_H
+
+
+FT_BEGIN_HEADER
+
+
+ /* maximum number of chunk sets in a given chunk cache */
+#define FTC_MAX_CHUNK_SETS 16
+
+
+ typedef struct FTC_ChunkNodeRec_* FTC_ChunkNode;
+ typedef struct FTC_ChunkSetRec_* FTC_ChunkSet;
+ typedef struct FTC_Chunk_CacheRec_* FTC_Chunk_Cache;
+
+ typedef struct FTC_ChunkNodeRec_
+ {
+ FTC_CacheNodeRec root;
+ FTC_ChunkSet cset;
+ FT_UShort cset_index;
+ FT_UShort num_elements;
+ FT_Byte* elements;
+
+ } FTC_ChunkNodeRec;
+
+
+#define FTC_CHUNKNODE_TO_LRUNODE( x ) ((FT_ListNode)( x ))
+#define FTC_LRUNODE_TO_CHUNKNODE( x ) ((FTC_ChunkNode)( x ))
+
+
+ /*************************************************************************/
+ /* */
+ /* chunk set methods */
+ /* */
+
+ /* used to set "element_max", "element_count" and "element_size" */
+ typedef FT_Error
+ (*FTC_ChunkSet_SizesFunc)( FTC_ChunkSet cset,
+ FT_Pointer type );
+
+ typedef FT_Error
+ (*FTC_ChunkSet_InitFunc)( FTC_ChunkSet cset,
+ FT_Pointer type );
+
+ typedef void
+ (*FTC_ChunkSet_DoneFunc)( FTC_ChunkSet cset );
+
+ typedef FT_Bool
+ (*FTC_ChunkSet_CompareFunc)( FTC_ChunkSet cset,
+ FT_Pointer type );
+
+
+ typedef FT_Error
+ (*FTC_ChunkSet_NewNodeFunc)( FTC_ChunkSet cset,
+ FT_UInt index,
+ FTC_ChunkNode* anode );
+
+ typedef void
+ (*FTC_ChunkSet_DestroyNodeFunc)( FTC_ChunkNode node );
+
+ typedef FT_ULong
+ (*FTC_ChunkSet_SizeNodeFunc)( FTC_ChunkNode node );
+
+
+ typedef struct FTC_ChunkSet_Class_
+ {
+ FT_UInt cset_byte_size;
+
+ FTC_ChunkSet_InitFunc init;
+ FTC_ChunkSet_DoneFunc done;
+ FTC_ChunkSet_CompareFunc compare;
+ FTC_ChunkSet_SizesFunc sizes;
+
+ FTC_ChunkSet_NewNodeFunc new_node;
+ FTC_ChunkSet_SizeNodeFunc size_node;
+ FTC_ChunkSet_DestroyNodeFunc destroy_node;
+
+ } FTC_ChunkSet_Class;
+
+
+ typedef struct FTC_ChunkSetRec_
+ {
+ FTC_Chunk_Cache cache;
+ FTC_Manager manager;
+ FT_Memory memory;
+ FTC_ChunkSet_Class* clazz;
+ FT_UInt cset_index; /* index in parent cache */
+
+ FT_UInt element_max; /* maximum number of elements */
+ FT_UInt element_size; /* element size in bytes */
+ FT_UInt element_count; /* number of elements per chunk */
+
+ FT_UInt num_chunks;
+ FTC_ChunkNode* chunks;
+
+ } FTC_ChunkSetRec;
+
+
+ /* the abstract chunk cache class */
+ typedef struct FTC_Chunk_Cache_Class_
+ {
+ FTC_Cache_Class root;
+ FTC_ChunkSet_Class* cset_class;
+
+ } FTC_Chunk_Cache_Class;
+
+
+ /* the abstract chunk cache object */
+ typedef struct FTC_Chunk_CacheRec_
+ {
+ FTC_CacheRec root;
+ FT_Lru csets_lru; /* static chunk set lru list */
+ FTC_ChunkSet last_cset; /* small cache :-) */
+ FTC_ChunkSet_CompareFunc compare; /* useful shortcut */
+
+ } FTC_Chunk_CacheRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* These functions are exported so that they can be called from */
+ /* user-provided cache classes; otherwise, they are really part of the */
+ /* cache sub-system internals. */
+ /* */
+
+ FT_EXPORT( FT_Error )
+ FTC_ChunkNode_Init( FTC_ChunkNode node,
+ FTC_ChunkSet cset,
+ FT_UInt index,
+ FT_Bool alloc );
+
+#define FTC_ChunkNode_Ref( n ) \
+ FTC_CACHENODE_TO_DATA_P( &(n)->root )->ref_count++
+
+#define FTC_ChunkNode_Unref( n ) \
+ FTC_CACHENODE_TO_DATA_P( &(n)->root )->ref_count--
+
+
+ /* chunk set objects */
+
+ FT_EXPORT( void )
+ FTC_ChunkNode_Destroy( FTC_ChunkNode node );
+
+
+ FT_EXPORT( FT_Error )
+ FTC_ChunkSet_New( FTC_Chunk_Cache cache,
+ FT_Pointer type,
+ FTC_ChunkSet *aset );
+
+
+ FT_EXPORT( FT_Error )
+ FTC_ChunkSet_Lookup_Node( FTC_ChunkSet cset,
+ FT_UInt glyph_index,
+ FTC_ChunkNode* anode,
+ FT_UInt *anindex );
+
+
+ /* chunk cache objects */
+
+ FT_EXPORT( FT_Error )
+ FTC_Chunk_Cache_Init( FTC_Chunk_Cache cache );
+
+ FT_EXPORT( void )
+ FTC_Chunk_Cache_Done( FTC_Chunk_Cache cache );
+
+ FT_EXPORT( FT_Error )
+ FTC_Chunk_Cache_Lookup( FTC_Chunk_Cache cache,
+ FT_Pointer type,
+ FT_UInt gindex,
+ FTC_ChunkNode *anode,
+ FT_UInt *aindex );
+
+
+FT_END_HEADER
+
+#endif /* __FTCCHUNK_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftcglyph.h */
+/* */
+/* FreeType abstract glyph cache (specification). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* Important: The functions defined in this file are only used to */
+ /* implement an abstract glyph cache class. You need to */
+ /* provide additional logic to implement a complete cache. */
+ /* For example, see `ftcimage.h' and `ftcimage.c' which */
+ /* implement a FT_Glyph cache based on this code. */
+ /* */
+ /* NOTE: For now, each glyph set is implemented as a static hash table. */
+ /* It would be interesting to experiment with dynamic hashes to */
+ /* see whether this improves performance or not (I don't know why */
+ /* but something tells me it won't). */
+ /* */
+ /* In all cases, this change should not affect any derived glyph */
+ /* cache class. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********* *********/
+ /********* WARNING, THIS IS BETA CODE. *********/
+ /********* *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#ifndef __FTCGLYPH_H__
+#define __FTCGLYPH_H__
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_MANAGER_H
+
+#include <stddef.h>
+
+
+FT_BEGIN_HEADER
+
+
+ /* maximum number of glyph sets per glyph cache; must be < 256 */
+#define FTC_MAX_GLYPH_SETS 16
+#define FTC_GSET_HASH_SIZE_DEFAULT 64
+
+
+ typedef struct FTC_GlyphSetRec_* FTC_GlyphSet;
+ typedef struct FTC_GlyphNodeRec_* FTC_GlyphNode;
+ typedef struct FTC_Glyph_CacheRec_* FTC_Glyph_Cache;
+
+ typedef struct FTC_GlyphNodeRec_
+ {
+ FTC_CacheNodeRec root;
+ FTC_GlyphNode gset_next; /* next in glyph set's bucket list */
+ FT_UShort glyph_index;
+ FT_UShort gset_index;
+
+ } FTC_GlyphNodeRec;
+
+
+#define FTC_GLYPHNODE( x ) ( (FTC_GlyphNode)( x ) )
+#define FTC_GLYPHNODE_TO_LRUNODE( n ) ( (FT_ListNode)( n ) )
+#define FTC_LRUNODE_TO_GLYPHNODE( n ) ( (FTC_GlyphNode)( n ) )
+
+
+ /*************************************************************************/
+ /* */
+ /* Glyph set methods. */
+ /* */
+
+ typedef FT_Error
+ (*FTC_GlyphSet_InitFunc)( FTC_GlyphSet gset,
+ FT_Pointer type );
+
+ typedef void
+ (*FTC_GlyphSet_DoneFunc)( FTC_GlyphSet gset );
+
+ typedef FT_Bool
+ (*FTC_GlyphSet_CompareFunc)( FTC_GlyphSet gset,
+ FT_Pointer type );
+
+
+ typedef FT_Error
+ (*FTC_GlyphSet_NewNodeFunc)( FTC_GlyphSet gset,
+ FT_UInt gindex,
+ FTC_GlyphNode* anode );
+
+ typedef void
+ (*FTC_GlyphSet_DestroyNodeFunc)( FTC_GlyphNode node,
+ FTC_GlyphSet gset );
+
+ typedef FT_ULong
+ (*FTC_GlyphSet_SizeNodeFunc)( FTC_GlyphNode node,
+ FTC_GlyphSet gset );
+
+
+ typedef struct FTC_GlyphSet_Class_
+ {
+ FT_UInt gset_byte_size;
+
+ FTC_GlyphSet_InitFunc init;
+ FTC_GlyphSet_DoneFunc done;
+ FTC_GlyphSet_CompareFunc compare;
+
+ FTC_GlyphSet_NewNodeFunc new_node;
+ FTC_GlyphSet_SizeNodeFunc size_node;
+ FTC_GlyphSet_DestroyNodeFunc destroy_node;
+
+ } FTC_GlyphSet_Class;
+
+
+ typedef struct FTC_GlyphSetRec_
+ {
+ FTC_Glyph_Cache cache;
+ FTC_Manager manager;
+ FT_Memory memory;
+ FTC_GlyphSet_Class* clazz;
+ FT_UInt hash_size;
+ FTC_GlyphNode* buckets;
+ FT_UInt gset_index; /* index in parent cache */
+
+ } FTC_GlyphSetRec;
+
+
+ /* the abstract glyph cache class */
+ typedef struct FTC_Glyph_Cache_Class_
+ {
+ FTC_Cache_Class root;
+ FTC_GlyphSet_Class* gset_class;
+
+ } FTC_Glyph_Cache_Class;
+
+
+ /* the abstract glyph cache object */
+ typedef struct FTC_Glyph_CacheRec_
+ {
+ FTC_CacheRec root;
+ FT_Lru gsets_lru; /* static sets lru list */
+ FTC_GlyphSet last_gset; /* small cache :-) */
+ FTC_GlyphSet_CompareFunc compare; /* useful shortcut */
+
+ } FTC_Glyph_CacheRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* These functions are exported so that they can be called from */
+ /* user-provided cache classes; otherwise, they are really part of the */
+ /* cache sub-system internals. */
+ /* */
+
+ FT_EXPORT( void )
+ FTC_GlyphNode_Init( FTC_GlyphNode node,
+ FTC_GlyphSet gset,
+ FT_UInt gindex );
+
+#define FTC_GlyphNode_Ref( n ) \
+ FTC_CACHENODE_TO_DATA_P( &(n)->root )->ref_count++
+
+#define FTC_GlyphNode_Unref( n ) \
+ FTC_CACHENODE_TO_DATA_P( &(n)->root )->ref_count--
+
+
+ FT_EXPORT( void )
+ FTC_GlyphNode_Destroy( FTC_GlyphNode node,
+ FTC_Glyph_Cache cache );
+
+ FT_EXPORT( FT_Error )
+ FTC_Glyph_Cache_Init( FTC_Glyph_Cache cache );
+
+ FT_EXPORT( void )
+ FTC_Glyph_Cache_Done( FTC_Glyph_Cache cache );
+
+
+ FT_EXPORT( FT_Error )
+ FTC_GlyphSet_New( FTC_Glyph_Cache cache,
+ FT_Pointer type,
+ FTC_GlyphSet *aset );
+
+ FT_EXPORT( FT_Error )
+ FTC_GlyphSet_Lookup_Node( FTC_GlyphSet gset,
+ FT_UInt glyph_index,
+ FTC_GlyphNode *anode );
+
+ FT_EXPORT( FT_Error )
+ FTC_Glyph_Cache_Lookup( FTC_Glyph_Cache cache,
+ FT_Pointer type,
+ FT_UInt gindex,
+ FTC_GlyphNode *anode );
+
+
+FT_END_HEADER
+
+#endif /* __FTCGLYPH_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftcimage.h */
+/* */
+/* FreeType Image cache (body). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* Each image cache really manages FT_Glyph objects. */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef __FTCIMAGE_H__
+#define __FTCIMAGE_H__
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_INTERNAL_GLYPH_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* cache_subsystem */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** IMAGE CACHE OBJECT *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#define FTC_IMAGE_FORMAT( x ) ( (x) & 7 )
+
+
+#define ftc_image_format_bitmap 0
+#define ftc_image_format_outline 1
+
+#define ftc_image_flag_monochrome 16
+#define ftc_image_flag_unhinted 32
+#define ftc_image_flag_autohinted 64
+#define ftc_image_flag_unscaled 128
+#define ftc_image_flag_no_sbits 256
+
+ /* monochrome bitmap */
+#define ftc_image_mono ftc_image_format_bitmap | \
+ ftc_image_flag_monochrome
+ /* anti-aliased bitmap */
+#define ftc_image_grays ftc_image_format_bitmap
+ /* scaled outline */
+#define ftc_image_outline ftc_image_format_outline
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FTC_Image_Desc */
+ /* */
+ /* <Description> */
+ /* A simple structure used to describe a given glyph image category. */
+ /* */
+ /* <Fields> */
+ /* size :: An FTC_SizeRec used to describe the glyph's face & */
+ /* size. */
+ /* */
+ /* image_type :: The glyph image's type. */
+ /* */
+ typedef struct FTC_Image_Desc_
+ {
+ FTC_FontRec font;
+ FT_UInt image_type;
+
+ } FTC_Image_Desc;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FTC_Image_Cache */
+ /* */
+ /* <Description> */
+ /* A handle to an glyph image cache object. They are designed to */
+ /* hold many distinct glyph images, while not exceeding a certain */
+ /* memory threshold. */
+ /* */
+ typedef struct FTC_Image_CacheRec_* FTC_Image_Cache;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_Image_Cache_New */
+ /* */
+ /* <Description> */
+ /* Creates a new glyph image cache. */
+ /* */
+ /* <Input> */
+ /* manager :: The parent manager for the image cache. */
+ /* */
+ /* <Output> */
+ /* acache :: A handle to the new glyph image cache object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FTC_Image_Cache_New( FTC_Manager manager,
+ FTC_Image_Cache *acache );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_Image_Cache_Lookup */
+ /* */
+ /* <Description> */
+ /* Retrieves a given glyph image from a glyph image cache. */
+ /* */
+ /* <Input> */
+ /* cache :: A handle to the source glyph image cache. */
+ /* */
+ /* desc :: A pointer to a glyph image descriptor. */
+ /* */
+ /* gindex :: The glyph index to retrieve. */
+ /* */
+ /* <Output> */
+ /* aglyph :: The corresponding FT_Glyph object. 0 in case of */
+ /* failure. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The returned glyph is owned and managed by the glyph image cache. */
+ /* Never try to transform or discard it manually! You can however */
+ /* create a copy with FT_Glyph_Copy() and modify the new one. */
+ /* */
+ /* Because the glyph image cache limits the total amount of memory */
+ /* taken by the glyphs it holds, the returned glyph might disappear */
+ /* on a later invocation of this function! It's a cache after all... */
+ /* */
+ FT_EXPORT( FT_Error )
+ FTC_Image_Cache_Lookup( FTC_Image_Cache cache,
+ FTC_Image_Desc* desc,
+ FT_UInt gindex,
+ FT_Glyph *aglyph );
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FTCIMAGE_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftcmanag.h */
+/* */
+/* FreeType Cache Manager (specification). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* A cache manager is in charge of the following: */
+ /* */
+ /* - Maintain a mapping between generic FTC_FaceIDs and live FT_Face */
+ /* objects. The mapping itself is performed through a user-provided */
+ /* callback. However, the manager maintains a small cache of FT_Face */
+ /* & FT_Size objects in order to speed up things considerably. */
+ /* */
+ /* - Manage one or more cache objects. Each cache is in charge of */
+ /* holding a varying number of `cache nodes'. Each cache node */
+ /* represents a minimal amount of individually accessible cached */
+ /* data. For example, a cache node can be an FT_Glyph image */
+ /* containing a vector outline, or some glyph metrics, or anything */
+ /* else. */
+ /* */
+ /* Each cache node has a certain size in bytes that is added to the */
+ /* total amount of `cache memory' within the manager. */
+ /* */
+ /* All cache nodes are located in a global LRU list, where the oldest */
+ /* node is at the tail of the list. */
+ /* */
+ /* Each node belongs to a single cache, and includes a reference */
+ /* count to avoid destroying it (due to caching). */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********* *********/
+ /********* WARNING, THIS IS BETA CODE. *********/
+ /********* *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#ifndef __FTCMANAG_H__
+#define __FTCMANAG_H__
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_INTERNAL_LRU_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* cache_subsystem */
+ /* */
+ /*************************************************************************/
+
+
+#define FTC_MAX_FACES_DEFAULT 2
+#define FTC_MAX_SIZES_DEFAULT 4
+#define FTC_MAX_BYTES_DEFAULT 200000L /* 200kByte by default! */
+
+ /* maximum number of caches registered in a single manager */
+#define FTC_MAX_CACHES 16
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FTC_ManagerRec */
+ /* */
+ /* <Description> */
+ /* The cache manager structure. */
+ /* */
+ /* <Fields> */
+ /* library :: A handle to a FreeType library instance. */
+ /* */
+ /* faces_lru :: The lru list of FT_Face objects in the cache. */
+ /* */
+ /* sizes_lru :: The lru list of FT_Size objects in the cache. */
+ /* */
+ /* max_bytes :: The maximum number of bytes to be allocated in the */
+ /* cache. This is only related to the byte size of */
+ /* the nodes cached by the manager. */
+ /* */
+ /* num_bytes :: The current number of bytes allocated in the */
+ /* cache. Only related to the byte size of cached */
+ /* nodes. */
+ /* */
+ /* num_nodes :: The current number of nodes in the manager. */
+ /* */
+ /* global_lru :: The global lru list of all cache nodes. */
+ /* */
+ /* caches :: A table of installed/registered cache objects. */
+ /* */
+ /* request_data :: User-provided data passed to the requester. */
+ /* */
+ /* request_face :: User-provided function used to implement a mapping */
+ /* between abstract FTC_FaceIDs and real FT_Face */
+ /* objects. */
+ /* */
+ typedef struct FTC_ManagerRec_
+ {
+ FT_Library library;
+ FT_Lru faces_lru;
+ FT_Lru sizes_lru;
+
+ FT_ULong max_bytes;
+ FT_ULong num_bytes;
+ FT_UInt num_nodes;
+ FT_ListRec global_lru;
+ FTC_Cache caches[FTC_MAX_CACHES];
+
+ FT_Pointer request_data;
+ FTC_Face_Requester request_face;
+
+ } FTC_ManagerRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_Manager_Compress */
+ /* */
+ /* <Description> */
+ /* This function is used to check the state of the cache manager if */
+ /* its `num_bytes' field is greater than its `max_bytes' field. It */
+ /* will flush as many old cache nodes as possible (ignoring cache */
+ /* nodes with a non-zero reference count). */
+ /* */
+ /* <InOut> */
+ /* manager :: A handle to the cache manager. */
+ /* */
+ /* <Note> */
+ /* Client applications should not call this function directly. It is */
+ /* normally invoked by specific cache implementations. */
+ /* */
+ /* The reason this function is exported is to allow client-specific */
+ /* cache classes. */
+ /* */
+ FT_EXPORT( void )
+ FTC_Manager_Compress( FTC_Manager manager );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CACHE NODE DEFINITIONS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* Each cache controls one or more cache nodes. Each node is part of */
+ /* the global_lru list of the manager. Its `data' field however is used */
+ /* as a reference count for now. */
+ /* */
+ /* A node can be anything, depending on the type of information held by */
+ /* the cache. It can be an individual glyph image, a set of bitmaps */
+ /* glyphs for a given size, some metrics, etc. */
+ /* */
+
+ typedef FT_ListNodeRec FTC_CacheNodeRec;
+ typedef FTC_CacheNodeRec* FTC_CacheNode;
+
+
+ /* the field `cachenode.data' is typecast to this type */
+ typedef struct FTC_CacheNode_Data_
+ {
+ FT_UShort cache_index;
+ FT_Short ref_count;
+
+ } FTC_CacheNode_Data;
+
+
+ /* return a pointer to FTC_CacheNode_Data contained in a */
+ /* CacheNode's `data' field */
+#define FTC_CACHENODE_TO_DATA_P( n ) \
+ ( (FTC_CacheNode_Data*)&(n)->data )
+
+#define FTC_LIST_TO_CACHENODE( n ) ( (FTC_CacheNode)(n) )
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FTC_CacheNode_SizeFunc */
+ /* */
+ /* <Description> */
+ /* A function used to compute the total size in bytes of a given */
+ /* cache node. It is used by the cache manager to compute the number */
+ /* of old nodes to flush when the cache is full. */
+ /* */
+ /* <Input> */
+ /* node :: A handle to the target cache node. */
+ /* */
+ /* cache_data :: A generic pointer passed to the destructor. */
+ /* */
+ /* <Return> */
+ /* The size of a given cache node in bytes. */
+ /* */
+ typedef FT_ULong
+ (*FTC_CacheNode_SizeFunc)( FTC_CacheNode node,
+ FT_Pointer cache_data );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FTC_CacheNode_DestroyFunc */
+ /* */
+ /* <Description> */
+ /* A function used to destroy a given cache node. It is called by */
+ /* the manager when the cache is full and old nodes need to be */
+ /* flushed out. */
+ /* */
+ /* <Input> */
+ /* node :: A handle to the target cache node. */
+ /* */
+ /* cache_data :: A generic pointer passed to the destructor. */
+ /* */
+ typedef void
+ (*FTC_CacheNode_DestroyFunc)( FTC_CacheNode node,
+ FT_Pointer cache_data );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FTC_CacheNode_Class */
+ /* */
+ /* <Description> */
+ /* A very simple structure used to describe a cache node's class to */
+ /* the cache manager. */
+ /* */
+ /* <Fields> */
+ /* size_node :: A function used to size the node. */
+ /* */
+ /* destroy_node :: A function used to destroy the node. */
+ /* */
+ /* <Note> */
+ /* The cache node class doesn't include a `new_node' function because */
+ /* the cache manager never allocates cache node directly; it */
+ /* delegates this task to its cache objects. */
+ /* */
+ typedef struct FTC_CacheNode_Class_
+ {
+ FTC_CacheNode_SizeFunc size_node;
+ FTC_CacheNode_DestroyFunc destroy_node;
+
+ } FTC_CacheNode_Class;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CACHE DEFINITIONS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FTC_Cache_InitFunc */
+ /* */
+ /* <Description> */
+ /* A function used to initialize a given cache object. */
+ /* */
+ /* <Input> */
+ /* cache :: A handle to the new cache. */
+ /* */
+ typedef FT_Error
+ (*FTC_Cache_InitFunc)( FTC_Cache cache );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FTC_Cache_DoneFunc */
+ /* */
+ /* <Description> */
+ /* A function to finalize a given cache object. */
+ /* */
+ /* <Input> */
+ /* cache :: A handle to the target cache. */
+ /* */
+ typedef void
+ (*FTC_Cache_DoneFunc)( FTC_Cache cache );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FTC_Cache_Class */
+ /* */
+ /* <Description> */
+ /* A structure used to describe a given cache object class to the */
+ /* cache manager. */
+ /* */
+ /* <Fields> */
+ /* cache_byte_size :: The size of the cache object in bytes. */
+ /* */
+ /* init_cache :: The cache object initializer. */
+ /* */
+ /* done_cache :: The cache object finalizer. */
+ /* */
+ struct FTC_Cache_Class_
+ {
+ FT_UInt cache_byte_size;
+ FTC_Cache_InitFunc init_cache;
+ FTC_Cache_DoneFunc done_cache;
+ };
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FTC_CacheRec */
+ /* */
+ /* <Description> */
+ /* A structure used to describe an abstract cache object. */
+ /* */
+ /* <Fields> */
+ /* manager :: A handle to the parent cache manager. */
+ /* */
+ /* memory :: A handle to the memory manager. */
+ /* */
+ /* clazz :: A pointer to the cache class. */
+ /* */
+ /* node_clazz :: A pointer to the cache's node class. */
+ /* */
+ /* cache_index :: An index of the cache in the manager's table. */
+ /* */
+ /* cache_data :: Data passed to the cache node */
+ /* constructor/finalizer. */
+ /* */
+ typedef struct FTC_CacheRec_
+ {
+ FTC_Manager manager;
+ FT_Memory memory;
+ FTC_Cache_Class* clazz;
+ FTC_CacheNode_Class* node_clazz;
+
+ FT_UInt cache_index; /* in manager's table */
+ FT_Pointer cache_data; /* passed to cache node methods */
+
+ } FTC_CacheRec;
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FTCMANAG_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftcsbits.h */
+/* */
+/* A small-bitmap cache (specification). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTCSBITS_H__
+#define __FTCSBITS_H__
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_INTERNAL_CHUNK_H
+#include FT_CACHE_IMAGE_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* cache_subsystem */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FTC_SBit */
+ /* */
+ /* <Description> */
+ /* A handle to a small bitmap descriptor. See the FTC_SBitRec */
+ /* structure for details. */
+ /* */
+ typedef struct FTC_SBitRec_* FTC_SBit;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FTC_SBit_Cache */
+ /* */
+ /* <Description> */
+ /* A handle to a small bitmap cache. These are special cache objects */
+ /* used to store small glyph bitmaps (and anti-aliased pixmaps) in a */
+ /* much more efficient way than the traditional glyph image cache */
+ /* implemented by FTC_Image_Cache. */
+ /* */
+ typedef struct FTC_SBit_CacheRec_* FTC_SBit_Cache;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FTC_SBitRec */
+ /* */
+ /* <Description> */
+ /* A very compact structure used to describe a small glyph bitmap. */
+ /* */
+ /* <Fields> */
+ /* width :: The bitmap width in pixels. */
+ /* */
+ /* height :: The bitmap height in pixels. */
+ /* */
+ /* left :: The horizontal distance from the pen position to the */
+ /* left bitmap border (a.k.a. `left side bearing', or */
+ /* `lsb'). */
+ /* */
+ /* top :: The vertical distance from the pen position (on the */
+ /* baseline) to the upper bitmap border (a.k.a. `top side */
+ /* bearing'). The distance is positive for upwards */
+ /* Y coordinates. */
+ /* */
+ /* format :: The format of the glyph bitmap (monochrome or gray). */
+ /* */
+ /* pitch :: The number of bytes per bitmap line. May be positive */
+ /* or negative. */
+ /* */
+ /* xadvance :: The horizontal advance width in pixels. */
+ /* */
+ /* yadvance :: The vertical advance height in pixels. */
+ /* */
+ /* buffer :: A pointer to the bitmap pixels. */
+ /* */
+ typedef struct FTC_SBitRec_
+ {
+ FT_Byte width;
+ FT_Byte height;
+ FT_Char left;
+ FT_Char top;
+
+ FT_Byte format;
+ FT_Char pitch;
+ FT_Char xadvance;
+ FT_Char yadvance;
+
+ FT_Byte* buffer;
+
+ } FTC_SBitRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_SBit_Cache_New */
+ /* */
+ /* <Description> */
+ /* Creates a new cache to store small glyph bitmaps. */
+ /* */
+ /* <Input> */
+ /* manager :: A handle to the source cache manager. */
+ /* */
+ /* <Output> */
+ /* acache :: A handle to the new sbit cache. NULL in case of error. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FTC_SBit_Cache_New( FTC_Manager manager,
+ FTC_SBit_Cache *acache );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_SBit_Cache_Lookup */
+ /* */
+ /* <Description> */
+ /* Looks up a given small glyph bitmap in a given sbit cache. */
+ /* */
+ /* <Input> */
+ /* cache :: A handle to the source sbit cache. */
+ /* desc :: A pointer to the glyph image descriptor. */
+ /* gindex :: The glyph index. */
+ /* */
+ /* <Output> */
+ /* sbit :: A handle to a small bitmap descriptor. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The small bitmap descriptor and its bit buffer are owned by the */
+ /* cache and should never be freed by the application. They might */
+ /* as well disappear from memory on the next cache lookup, so don't */
+ /* treat them as persistent data. */
+ /* */
+ /* The descriptor's `buffer' field is set to 0 to indicate a missing */
+ /* glyph bitmap. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FTC_SBit_Cache_Lookup( FTC_SBit_Cache cache,
+ FTC_Image_Desc* desc,
+ FT_UInt gindex,
+ FTC_SBit *sbit );
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FTCSBITS_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftlru.h */
+/* */
+/* Simple LRU list-cache (specification). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* An LRU is a list that cannot hold more than a certain number of */
+ /* elements (`max_elements'). All elements on the list are sorted in */
+ /* least-recently-used order, i.e., the `oldest' element is at the tail */
+ /* of the list. */
+ /* */
+ /* When doing a lookup (either through `Lookup()' or `Lookup_Node()'), */
+ /* the list is searched for an element with the corresponding key. If */
+ /* it is found, the element is moved to the head of the list and is */
+ /* returned. */
+ /* */
+ /* If no corresponding element is found, the lookup routine will try to */
+ /* obtain a new element with the relevant key. If the list is already */
+ /* full, the oldest element from the list is discarded and replaced by a */
+ /* new one; a new element is added to the list otherwise. */
+ /* */
+ /* Note that it is possible to pre-allocate the element list nodes. */
+ /* This is handy if `max_elements' is sufficiently small, as it saves */
+ /* allocations/releases during the lookup process. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********* *********/
+ /********* WARNING, THIS IS BETA CODE. *********/
+ /********* *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#ifndef __FTLRU_H__
+#define __FTLRU_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+
+FT_BEGIN_HEADER
+
+
+ /* generic key type */
+ typedef FT_Pointer FT_LruKey;
+
+
+ /* an lru node -- root.data points to the element */
+ typedef struct FT_LruNodeRec_
+ {
+ FT_ListNodeRec root;
+ FT_LruKey key;
+
+ } FT_LruNodeRec, *FT_LruNode;
+
+
+ /* forward declaration */
+ typedef struct FT_LruRec_* FT_Lru;
+
+
+ /* LRU class */
+ typedef struct FT_Lru_Class_
+ {
+ FT_UInt lru_size; /* object size in bytes */
+
+ /* this method is used to initialize a new list element node */
+ FT_Error
+ (*init_element)( FT_Lru lru,
+ FT_LruNode node );
+
+ /* this method is used to finalize a given list element node */
+ void
+ (*done_element)( FT_Lru lru,
+ FT_LruNode node );
+
+ /* If defined, this method is called when the list if full */
+ /* during the lookup process -- it is used to change the contents */
+ /* of a list element node, instead of calling `done_element()', */
+ /* then `init_element'. Set it to 0 for default behaviour. */
+ FT_Error
+ (*flush_element)( FT_Lru lru,
+ FT_LruNode node,
+ FT_LruKey new_key );
+
+ /* If defined, this method is used to compare a list element node */
+ /* with a given key during a lookup. If set to 0, the `key' */
+ /* fields will be directly compared instead. */
+ FT_Bool
+ (*compare_element)( FT_LruNode node,
+ FT_LruKey key );
+
+ } FT_Lru_Class;
+
+
+ /* A selector is used to indicate whether a given list element node */
+ /* is part of a selection for FT_Lru_Remove_Selection(). The function */
+ /* must return true (i.e., non-null) to indicate that the node is part */
+ /* of it. */
+ typedef FT_Bool
+ (*FT_Lru_Selector)( FT_Lru lru,
+ FT_LruNode node,
+ FT_Pointer data );
+
+
+ typedef struct FT_LruRec_
+ {
+ FT_Lru_Class* clazz;
+ FT_UInt max_elements;
+ FT_UInt num_elements;
+ FT_ListRec elements;
+ FT_Memory memory;
+ FT_Pointer user_data;
+
+ /* the following fields are only meaningful for static lru containers */
+ FT_ListRec free_nodes;
+ FT_LruNode nodes;
+
+ } FT_LruRec;
+
+
+ FT_EXPORT( FT_Error )
+ FT_Lru_New( const FT_Lru_Class* clazz,
+ FT_UInt max_elements,
+ FT_Pointer user_data,
+ FT_Memory memory,
+ FT_Bool pre_alloc,
+ FT_Lru *anlru );
+
+ FT_EXPORT( void )
+ FT_Lru_Reset( FT_Lru lru );
+
+ FT_EXPORT( void )
+ FT_Lru_Done ( FT_Lru lru );
+
+ FT_EXPORT( FT_Error )
+ FT_Lru_Lookup_Node( FT_Lru lru,
+ FT_LruKey key,
+ FT_LruNode *anode );
+
+ FT_EXPORT( FT_Error )
+ FT_Lru_Lookup( FT_Lru lru,
+ FT_LruKey key,
+ FT_Pointer *anobject );
+
+ FT_EXPORT( void )
+ FT_Lru_Remove_Node( FT_Lru lru,
+ FT_LruNode node );
+
+ FT_EXPORT( void )
+ FT_Lru_Remove_Selection( FT_Lru lru,
+ FT_Lru_Selector selector,
+ FT_Pointer data );
+
+
+FT_END_HEADER
+
+#endif /* __FTLRU_H__ */
+
+
+/* END */
--- /dev/null
+## Process this file with automake to produce Makefile.in
+
+noinst_HEADERS = ftconfig.h ftheader.h ftmodule.h ftoption.h
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftconfig.h */
+/* */
+/* ANSI-specific configuration file (specification only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This header file contains a number of macro definitions that are used */
+ /* by the rest of the engine. Most of the macros here are automatically */
+ /* determined at compile time, and you should not need to change it to */
+ /* port FreeType, except to compile the library with a non-ANSI */
+ /* compiler. */
+ /* */
+ /* Note however that if some specific modifications are needed, we */
+ /* advise you to place a modified copy in your build directory. */
+ /* */
+ /* The build directory is usually `freetype/builds/<system>', and */
+ /* contains system-specific files that are always included first when */
+ /* building the library. */
+ /* */
+ /* This ANSI version should stay in `include/freetype/config'. */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef __FTCONFIG_H__
+#define __FTCONFIG_H__
+
+#include <ft2build.h>
+#include FT_CONFIG_OPTIONS_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* PLATFORM-SPECIFIC CONFIGURATION MACROS */
+ /* */
+ /* These macros can be toggled to suit a specific system. The current */
+ /* ones are defaults used to compile FreeType in an ANSI C environment */
+ /* (16bit compilers are also supported). Copy this file to your own */
+ /* `freetype/builds/<system>' directory, and edit it to port the engine. */
+ /* */
+ /*************************************************************************/
+
+
+ /* We use <limits.h> values to know the sizes of the types. */
+#include <limits.h>
+
+ /* The number of bytes in an `int' type. */
+#if UINT_MAX == 0xFFFFFFFFUL
+#define FT_SIZEOF_INT 4
+#elif UINT_MAX == 0xFFFFU
+#define FT_SIZEOF_INT 2
+#elif UINT_MAX > 0xFFFFFFFFU && UINT_MAX == 0xFFFFFFFFFFFFFFFFU
+#define FT_SIZEOF_INT 8
+#else
+#error "Unsupported number of bytes in `int' type!"
+#endif
+
+ /* The number of bytes in a `long' type. */
+#if ULONG_MAX == 0xFFFFFFFFUL
+#define FT_SIZEOF_LONG 4
+#elif ULONG_MAX > 0xFFFFFFFFU && ULONG_MAX == 0xFFFFFFFFFFFFFFFFU
+#define FT_SIZEOF_LONG 8
+#else
+#error "Unsupported number of bytes in `long' type!"
+#endif
+
+
+ /* Preferred alignment of data */
+#define FT_ALIGNMENT 8
+
+
+ /* UNUSED is a macro used to indicate that a given parameter is not used */
+ /* -- this is only used to get rid of unpleasant compiler warnings */
+#ifndef FT_UNUSED
+#define FT_UNUSED( arg ) ( (arg) = (arg) )
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* AUTOMATIC CONFIGURATION MACROS */
+ /* */
+ /* These macros are computed from the ones defined above. Don't touch */
+ /* their definition, unless you know precisely what you are doing. No */
+ /* porter should need to mess with them. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* IntN types */
+ /* */
+ /* Used to guarantee the size of some specific integers. */
+ /* */
+ typedef signed short FT_Int16;
+ typedef unsigned short FT_UInt16;
+
+#if FT_SIZEOF_INT == 4
+
+ typedef signed int FT_Int32;
+ typedef unsigned int FT_UInt32;
+
+#elif FT_SIZEOF_LONG == 4
+
+ typedef signed long FT_Int32;
+ typedef unsigned long FT_UInt32;
+
+#else
+#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 */
+#if FT_SIZEOF_LONG == 8
+
+ /* FT_LONG64 must be defined if a 64-bit type is available */
+#define FT_LONG64
+#define FT_INT64 long
+
+#elif defined( _MSC_VER ) /* Visual C++ (and Intel C++) */
+
+ /* this compiler provides the __int64 type */
+#define FT_LONG64
+#define FT_INT64 __int64
+
+#elif defined( __BORLANDC__ ) /* Borland C++ */
+
+ /* XXXX: We should probably check the value of __BORLANDC__ in order */
+ /* to test the compiler version. */
+
+ /* this compiler provides the __int64 type */
+#define FT_LONG64
+#define FT_INT64 __int64
+
+#elif defined( __WATCOMC__ ) /* Watcom C++ */
+
+ /* Watcom doesn't provide 64-bit data types */
+
+#elif defined( __MWKS__ ) /* Metrowerks CodeWarrior */
+
+ /* I don't know if it provides 64-bit data types, any suggestion */
+ /* is welcome. */
+
+#elif defined( __GNUC__ )
+
+ /* GCC provides the "long long" type */
+#define FT_LONG64
+#define FT_INT64 long long int
+
+#endif /* !FT_LONG64 */
+
+
+ /*************************************************************************/
+ /* */
+ /* A 64-bit data type will create compilation problems if you compile */
+ /* in strict ANSI mode. To avoid them, we disable their use if */
+ /* __STDC__ is defined. You can however ignore this rule by */
+ /* defining the FT_CONFIG_OPTION_FORCE_INT64 configuration macro. */
+ /* */
+#if defined( FT_LONG64 ) && !defined( FT_CONFIG_OPTION_FORCE_INT64 )
+
+#ifdef __STDC__
+
+ /* undefine the 64-bit macros in strict ANSI compilation mode */
+#undef FT_LONG64
+#undef FT_INT64
+
+#endif /* __STDC__ */
+
+#endif /* FT_LONG64 && !FT_CONFIG_OPTION_FORCE_INT64 */
+
+
+#ifdef FT_MAKE_OPTION_SINGLE_OBJECT
+
+#define FT_LOCAL static
+#define FT_LOCAL_DEF static
+
+#else
+
+#ifdef __cplusplus
+#define FT_LOCAL extern "C"
+#define FT_LOCAL_DEF extern "C"
+#else
+#define FT_LOCAL extern
+#define FT_LOCAL_DEF extern
+#endif
+
+#endif /* FT_MAKE_OPTION_SINGLE_OBJECT */
+
+
+#ifndef FT_BASE
+
+#ifdef __cplusplus
+#define FT_BASE( x ) extern "C" x
+#else
+#define FT_BASE( x ) extern x
+#endif
+
+#endif /* !FT_BASE */
+
+
+#ifndef FT_BASE_DEF
+
+#ifdef __cplusplus
+#define FT_BASE_DEF( x ) extern "C" x
+#else
+#define FT_BASE_DEF( x ) extern x
+#endif
+
+#endif /* !FT_BASE_DEF */
+
+
+#ifndef FT_EXPORT
+
+#ifdef __cplusplus
+#define FT_EXPORT( x ) extern "C" x
+#else
+#define FT_EXPORT( x ) extern x
+#endif
+
+#endif /* !FT_EXPORT */
+
+
+#ifndef FT_EXPORT_DEF
+
+#ifdef __cplusplus
+#define FT_EXPORT_DEF( x ) extern "C" x
+#else
+#define FT_EXPORT_DEF( x ) extern x
+#endif
+
+#endif /* !FT_EXPORT_DEF */
+
+
+#ifndef FT_EXPORT_VAR
+
+#ifdef __cplusplus
+#define FT_EXPORT_VAR( x ) extern "C" x
+#else
+#define FT_EXPORT_VAR( x ) extern x
+#endif
+
+#endif /* !FT_EXPORT_VAR */
+
+ /* The following macros are needed to compile the library with a */
+ /* C++ compiler and with 16bit compilers. */
+ /* */
+
+ /* This is special. Within C++, you must specify `extern "C"' for */
+ /* functions which are used via function pointers, and you also */
+ /* must do that for structures which contain function pointers to */
+ /* assure C linkage -- it's not possible to have (local) anonymous */
+ /* functions which are accessed by (global) function pointers. */
+ /* */
+ /* */
+ /* FT_CALLBACK_DEF is used to _define_ a callback function. */
+ /* */
+ /* FT_CALLBACK_TABLE is used to _declare_ a constant variable that */
+ /* contains pointers to callback functions. */
+ /* */
+ /* FT_CALLBACK_TABLE_DEF is used to _define_ a constant variable */
+ /* that contains pointers to callback functions. */
+ /* */
+ /* */
+ /* Some 16bit compilers have to redefine these macros to insert */
+ /* the infamous `_cdecl' or `__fastcall' declarations. */
+ /* */
+#ifndef FT_CALLBACK_DEF
+#ifdef __cplusplus
+#define FT_CALLBACK_DEF( x ) extern "C" x
+#else
+#define FT_CALLBACK_DEF( x ) static x
+#endif
+#endif /* FT_CALLBACK_DEF */
+
+#ifndef FT_CALLBACK_TABLE
+#ifdef __cplusplus
+#define FT_CALLBACK_TABLE extern "C"
+#define FT_CALLBACK_TABLE_DEF extern "C"
+#else
+#define FT_CALLBACK_TABLE extern
+#define FT_CALLBACK_TABLE_DEF /* nothing */
+#endif
+#endif /* FT_CALLBACK_TABLE */
+
+
+FT_END_HEADER
+
+
+#endif /* __FTCONFIG_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftheader.h */
+/* */
+/* Build macros of the FreeType 2 library. */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+#ifndef __FT_HEADER_H__
+#define __FT_HEADER_H__
+
+ /*************************************************************************/
+ /* */
+ /* <Macro> */
+ /* FT_BEGIN_HEADER */
+ /* */
+ /* <Description> */
+ /* This macro is used in association with @FT_END_HEADER in header */
+ /* files to ensure that the declarations within are properly */
+ /* encapsulated in an `extern "C" { .. }' block when included from a */
+ /* C++ compiler. */
+ /* */
+#ifdef __cplusplus
+#define FT_BEGIN_HEADER extern "C" {
+#else
+#define FT_BEGIN_HEADER /* nothing */
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* <Macro> */
+ /* FT_END_HEADER */
+ /* */
+ /* <Description> */
+ /* This macro is used in association with @FT_BEGIN_HEADER in header */
+ /* files to ensure that the declarations within are properly */
+ /* encapsulated in an `extern "C" { .. }' block when included from a */
+ /* C++ compiler. */
+ /* */
+#ifdef __cplusplus
+#define FT_END_HEADER }
+#else
+#define FT_END_HEADER /* nothing */
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* Aliases for the FreeType 2 public and configuration files. */
+ /* */
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* header_file_macros */
+ /* */
+ /* <Title> */
+ /* Header File Macros */
+ /* */
+ /* <Abstract> */
+ /* Macro definitions used to #include specific header files. */
+ /* */
+ /* <Description> */
+ /* The following macros are defined to the name of specific */
+ /* FreeType 2 header files. They can be used directly in #include */
+ /* statements as in: */
+ /* */
+ /* { */
+ /* #include FT_FREETYPE_H */
+ /* #include FT_MULTIPLE_MASTERS_H */
+ /* #include FT_GLYPH_H */
+ /* } */
+ /* */
+ /* There are several reasons why we are now using macros to name */
+ /* public header files. The first one is that such macros are not */
+ /* limited to the infamous 8.3 naming rule required by DOS (and */
+ /* `FT_MULTIPLE_MASTERS_H' is a lot more meaningful than `ftmm.h'). */
+ /* */
+ /* The second reason is that is allows for more flexibility in the */
+ /* way FreeType 2 is installed on a given system. */
+ /* */
+ /*************************************************************************/
+
+ /* configuration files */
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_CONFIG_CONFIG_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* FreeType 2 configuration data. */
+ /* */
+#ifndef FT_CONFIG_CONFIG_H
+#define FT_CONFIG_CONFIG_H <freetype/config/ftconfig.h>
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_CONFIG_OPTIONS_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* FreeType 2 project-specific configuration options. */
+ /* */
+#ifndef FT_CONFIG_OPTIONS_H
+#define FT_CONFIG_OPTIONS_H <freetype/config/ftoption.h>
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_CONFIG_MODULES_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the list of FreeType 2 modules that are statically linked to new */
+ /* library instances in @FT_Init_FreeType. */
+ /* */
+#ifndef FT_CONFIG_MODULES_H
+#define FT_CONFIG_MODULES_H <freetype/config/ftmodule.h>
+#endif
+
+ /* public headers */
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_FREETYPE_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the base FreeType 2 API. */
+ /* */
+#define FT_FREETYPE_H <freetype/freetype.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_ERRORS_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the list of FreeType 2 error codes (and messages). */
+ /* */
+ /* It is included by @FT_FREETYPE_H. */
+ /* */
+#define FT_ERRORS_H <freetype/fterrors.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_MODULE_ERRORS_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the list of FreeType 2 module error offsets (and messages). */
+ /* */
+#define FT_MODULE_ERRORS_H <freetype/ftmoderr.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_SYSTEM_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the FreeType 2 interface to low-level operations (i.e. memory */
+ /* management and stream i/o). */
+ /* */
+ /* It is included by @FT_FREETYPE_H. */
+ /* */
+#define FT_SYSTEM_H <freetype/ftsystem.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_IMAGE_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* types definitions related to glyph images (i.e. bitmaps, outlines, */
+ /* scan-converter parameters). */
+ /* */
+ /* It is included by @FT_FREETYPE_H. */
+ /* */
+#define FT_IMAGE_H <freetype/ftimage.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_TYPES_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the basic data types defined by FreeType 2. */
+ /* */
+ /* It is included by @FT_FREETYPE_H. */
+ /* */
+#define FT_TYPES_H <freetype/fttypes.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_LIST_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the list management API of FreeType 2. */
+ /* */
+ /* (Most applications will never need to include this file.) */
+ /* */
+#define FT_LIST_H <freetype/ftlist.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_OUTLINE_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the scalable outline management API of FreeType 2. */
+ /* */
+#define FT_OUTLINE_H <freetype/ftoutln.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_SIZES_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the API used to manage multiple @FT_Size objects per face. */
+ /* */
+#define FT_SIZES_H <freetype/ftsizes.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_MODULE_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the module management API of FreeType 2. */
+ /* */
+#define FT_MODULE_H <freetype/ftmodule.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_RENDER_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the renderer module management API of FreeType 2. */
+ /* */
+#define FT_RENDER_H <freetype/ftrender.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_TYPE1_TABLES_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the types and API specific to the Type 1 format. */
+ /* */
+#define FT_TYPE1_TABLES_H <freetype/t1tables.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_TRUETYPE_IDS_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the enumeration values used to identify name strings, languages, */
+ /* encodings, etc. This file really contains a _large_ set of */
+ /* constant macro definitions, taken from the TrueType and OpenType */
+ /* specifications. */
+ /* */
+#define FT_TRUETYPE_IDS_H <freetype/ttnameid.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_TRUETYPE_TABLES_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the types and API specific to the TrueType (as well as OpenType) */
+ /* format. */
+ /* */
+#define FT_TRUETYPE_TABLES_H <freetype/tttables.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_TRUETYPE_TAGS_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the definitions of TrueType 4-byte `tags' used to identify blocks */
+ /* in SFNT-based font formats (i.e. TrueType and OpenType). */
+ /* */
+#define FT_TRUETYPE_TAGS_H <freetype/tttags.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_GLYPH_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the API of the optional glyph management component. */
+ /* */
+#define FT_GLYPH_H <freetype/ftglyph.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_BBOX_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the API of the optional exact bounding box computation routines. */
+ /* */
+#define FT_BBOX_H <freetype/ftbbox.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_BEZIER_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* a small useful API to handle bezier arcs. Note that you _must_ */
+ /* include FT_FREETYPE_H or FT_IMAGE_H before this header. */
+ /* */
+#define FT_BEZIER_H <freetype/ftbezier.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_CACHE_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the API of the optional FreeType 2 cache sub-system. */
+ /* */
+#define FT_CACHE_H <freetype/ftcache.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_CACHE_IMAGE_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the `glyph image' API of the FreeType 2 cache sub-system. */
+ /* */
+ /* It is used to define a cache for @FT_Glyph elements. You can also */
+ /* see the API defined in @FT_CACHE_SMALL_BITMAPS_H if you only need */
+ /* to store small glyph bitmaps, as it will use less memory. */
+ /* */
+#define FT_CACHE_IMAGE_H <freetype/cache/ftcimage.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_CACHE_SMALL_BITMAPS_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the `small bitmaps' API of the FreeType 2 cache sub-system. */
+ /* */
+ /* It is used to define a cache for small glyph bitmaps in a */
+ /* relatively memory-efficient way. You can also use the API defined */
+ /* in @FT_CACHE_IMAGE_H if you want to cache arbitrary glyph images, */
+ /* including scalable outlines. */
+ /* */
+#define FT_CACHE_SMALL_BITMAPS_H <freetype/cache/ftcsbits.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_MAC_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the Macintosh-specific FreeType 2 API. The latter is used to */
+ /* access fonts embedded in resource forks. */
+ /* */
+ /* This header file must be explicitly included by client */
+ /* applications compiled on the Mac (note that the base API still */
+ /* works though). */
+ /* */
+#define FT_MAC_H <freetype/ftmac.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_MULTIPLE_MASTERS_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the optional multiple-masters management API of FreeType 2. */
+ /* */
+#define FT_MULTIPLE_MASTERS_H <freetype/ftmm.h>
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: */
+ /* FT_SFNT_NAMES_H */
+ /* */
+ /* @description: */
+ /* A macro used in #include statements to name the file containing */
+ /* the optional FreeType 2 API used to access embedded `name' strings */
+ /* in SFNT-based font formats (i.e. TrueType and OpenType). */
+ /* */
+#define FT_SFNT_NAMES_H <freetype/ftsnames.h>
+
+ /* */
+
+#define FT_TRIGONOMETRY_H <freetype/fttrigon.h>
+#define FT_SYNTHESIS_H <freetype/ftsynth.h>
+
+#define FT_CACHE_MANAGER_H <freetype/cache/ftcmanag.h>
+
+#define FT_CACHE_INTERNAL_LRU_H <freetype/cache/ftlru.h>
+#define FT_CACHE_INTERNAL_GLYPH_H <freetype/cache/ftcglyph.h>
+#define FT_CACHE_INTERNAL_CHUNK_H <freetype/cache/ftcchunk.h>
+
+ /* now include internal headers definitions from <freetype/internal/...> */
+
+#define FT_INTERNAL_INTERNAL_H <freetype/internal/internal.h>
+#include FT_INTERNAL_INTERNAL_H
+
+
+#endif /* __FT2_BUILD_H__ */
+
+
+/* END */
--- /dev/null
+FT_USE_MODULE(autohint_module_class)
+FT_USE_MODULE(cff_driver_class)
+FT_USE_MODULE(t1cid_driver_class)
+FT_USE_MODULE(pcf_driver_class)
+FT_USE_MODULE(psaux_module_class)
+FT_USE_MODULE(psnames_module_class)
+FT_USE_MODULE(ft_raster1_renderer_class)
+FT_USE_MODULE(sfnt_module_class)
+FT_USE_MODULE(ft_smooth_renderer_class)
+FT_USE_MODULE(tt_driver_class)
+FT_USE_MODULE(t1_driver_class)
+FT_USE_MODULE(winfnt_driver_class)
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftoption.h */
+/* */
+/* User-selectable configuration macros (specification only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTOPTION_H__
+#define __FTOPTION_H__
+
+
+#include <ft2build.h>
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* USER-SELECTABLE CONFIGURATION MACROS */
+ /* */
+ /* These macros can be toggled by developers to enable or disable */
+ /* certain aspects of FreeType. This is a default file, where all major */
+ /* options are enabled. */
+ /* */
+ /* Note that if some modifications are required for your build, we */
+ /* advise you to put a modified copy of this file in your build */
+ /* directory, rather than modifying it in-place. */
+ /* */
+ /* The build directory is normally `freetype/builds/<system>' and */
+ /* contains build or system-specific files that are included in */
+ /* priority when building the library. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** G E N E R A L F R E E T Y P E 2 C O N F I G U R A T I O N ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* Convenience functions support */
+ /* */
+ /* Some functions of the FreeType 2 API are provided as a convenience */
+ /* for client applications and developers. However, they are not */
+ /* required to build and run the library itself. */
+ /* */
+ /* By defining this configuration macro, you'll disable the */
+ /* compilation of these functions at build time. This can be useful */
+ /* to reduce the library's code size when you don't need any of */
+ /* these functions. */
+ /* */
+ /* All convenience functions are declared as such in their */
+ /* documentation. */
+ /* */
+#undef FT_CONFIG_OPTION_NO_CONVENIENCE_FUNCS
+
+
+ /*************************************************************************/
+ /* */
+ /* Module errors */
+ /* */
+ /* If this macro is set (which is _not_ the default), the higher byte */
+ /* of an error code gives the module in which the error has occurred, */
+ /* while the lower byte is the real error code. */
+ /* */
+ /* Setting this macro makes sense for debugging purposes only, since */
+ /* it would break source compatibility of certain programs that use */
+ /* FreeType 2. */
+ /* */
+ /* More details can be found in the files ftmoderr.h and fterrors.h. */
+ /* */
+#undef FT_CONFIG_OPTION_USE_MODULE_ERRORS
+
+
+ /*************************************************************************/
+ /* */
+ /* Alternate Glyph Image Format support */
+ /* */
+ /* By default, the glyph images returned by the FreeType glyph loader */
+ /* can either be a pixmap or a vectorial outline defined through */
+ /* Bezier control points. When defining the following configuration */
+ /* macro, some font drivers will be able to register alternate */
+ /* glyph image formats. */
+ /* */
+ /* Unset this macro if you are sure that you will never use a font */
+ /* driver with an alternate glyph format; this will reduce the size of */
+ /* the base layer code. */
+ /* */
+ /* Note that a few Type 1 fonts, as well as Windows `vector' fonts */
+ /* use a vector `plotter' format that isn't supported when this */
+ /* macro is undefined. */
+ /* */
+#define FT_CONFIG_OPTION_ALTERNATE_GLYPH_FORMATS
+
+
+ /*************************************************************************/
+ /* */
+ /* Glyph Postscript Names handling */
+ /* */
+ /* By default, FreeType 2 is compiled with the `PSNames' module. This */
+ /* This module is in charge of converting a glyph name string into a */
+ /* Unicode value, or return a Macintosh standard glyph name for the */
+ /* use with the TrueType `post' table. */
+ /* */
+ /* Undefine this macro if you do not want `PSNames' compiled in your */
+ /* build of FreeType. This has the following effects: */
+ /* */
+ /* - The TrueType driver will provide its own set of glyph names, */
+ /* if you build it to support postscript names in the TrueType */
+ /* `post' table. */
+ /* */
+ /* - The Type 1 driver will not be able to synthetize a Unicode */
+ /* charmap out of the glyphs found in the fonts. */
+ /* */
+ /* You would normally undefine this configuration macro when building */
+ /* a version of FreeType that doesn't contain a Type 1 or CFF driver. */
+ /* */
+#define FT_CONFIG_OPTION_POSTSCRIPT_NAMES
+
+
+ /*************************************************************************/
+ /* */
+ /* Postscript Names to Unicode Values support */
+ /* */
+ /* By default, FreeType 2 is built with the `PSNames' module compiled */
+ /* in. Among other things, the module is used to convert a glyph name */
+ /* into a Unicode value. This is especially useful in order to */
+ /* synthetize on the fly a Unicode charmap from the CFF/Type 1 driver */
+ /* through a big table named the `Adobe Glyph List' (AGL). */
+ /* */
+ /* Undefine this macro if you do not want the Adobe Glyph List */
+ /* compiled in your `PSNames' module. The Type 1 driver will not be */
+ /* able to synthetize a Unicode charmap out of the glyphs found in the */
+ /* fonts. */
+ /* */
+#define FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
+
+
+ /*************************************************************************/
+ /* */
+ /* Many compilers provide a non-ANSI 64-bit data type that can be used */
+ /* by FreeType to speed up some computations. However, this will create */
+ /* some problems when compiling the library in strict ANSI mode. */
+ /* */
+ /* For this reason, the use of 64-bit ints is normally disabled when */
+ /* the __STDC__ macro is defined. You can however disable this by */
+ /* defining here the macro FT_CONFIG_OPTION_FORCE_INT64. */
+ /* */
+ /* For most compilers, this will only create compilation warnings */
+ /* when building the library. */
+ /* */
+ /* ObNote: The compiler-specific 64-bit integers are detected in the */
+ /* file "ftconfig.h" either statically, or through Autoconf */
+ /* on platforms that support it. */
+ /* */
+#define FT_CONFIG_OPTION_FORCE_INT64
+
+
+ /*************************************************************************/
+ /* */
+ /* DLL export compilation */
+ /* */
+ /* When compiling FreeType as a DLL, some systems/compilers need a */
+ /* special keyword in front OR after the return type of function */
+ /* declarations. */
+ /* */
+ /* Two macros are used within the FreeType source code to define */
+ /* exported library functions: FT_EXPORT and FT_EXPORT_DEF. */
+ /* */
+ /* FT_EXPORT( return_type ) */
+ /* */
+ /* is used in a function declaration, as in */
+ /* */
+ /* FT_EXPORT( FT_Error ) */
+ /* FT_Init_FreeType( FT_Library* alibrary ); */
+ /* */
+ /* */
+ /* FT_EXPORT_DEF( return_type ) */
+ /* */
+ /* is used in a function definition, as in */
+ /* */
+ /* FT_EXPORT_DEF( FT_Error ) */
+ /* FT_Init_FreeType( FT_Library* alibrary ) */
+ /* { */
+ /* ... some code ... */
+ /* return FT_Err_Ok; */
+ /* } */
+ /* */
+ /* You can provide your own implementation of FT_EXPORT and */
+ /* FT_EXPORT_DEF here if you want. If you leave them undefined, they */
+ /* will be later automatically defined as `extern return_type' to */
+ /* allow normal compilation. */
+ /* */
+#undef FT_EXPORT
+#undef FT_EXPORT_DEF
+
+
+ /*************************************************************************/
+ /* */
+ /* Debug level */
+ /* */
+ /* FreeType can be compiled in debug or trace mode. In debug mode, */
+ /* errors are reported through the `ftdebug' component. In trace */
+ /* mode, additional messages are sent to the standard output during */
+ /* execution. */
+ /* */
+ /* Define FT_DEBUG_LEVEL_ERROR to build the library in debug mode. */
+ /* Define FT_DEBUG_LEVEL_TRACE to build it in trace mode. */
+ /* */
+ /* Don't define any of these macros to compile in `release' mode! */
+ /* */
+/* #define FT_DEBUG_LEVEL_ERROR */
+/* #define FT_DEBUG_LEVEL_TRACE */
+
+
+ /*************************************************************************/
+ /* */
+ /* 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. */
+ /* */
+ /* This must be greater than 4kByte. */
+ /* */
+#define FT_RENDER_POOL_SIZE 32768L
+
+
+ /*************************************************************************/
+ /* */
+ /* FT_MAX_MODULES */
+ /* */
+ /* The maximum number of modules that can be registered in a single */
+ /* FreeType library object. 16 is the default. */
+ /* */
+#define FT_MAX_MODULES 16
+
+
+ /*************************************************************************/
+ /* */
+ /* FT_MAX_EXTENSIONS */
+ /* */
+ /* The maximum number of extensions that can be registered in a single */
+ /* font driver. 8 is the default. */
+ /* */
+ /* If you don't know what this means, you certainly do not need to */
+ /* change this value. */
+ /* */
+#define FT_MAX_EXTENSIONS 8
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** S F N T D R I V E R C O N F I G U R A T I O N ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* Define TT_CONFIG_OPTION_EMBEDDED_BITMAPS if you want to support */
+ /* embedded bitmaps in all formats using the SFNT module (namely */
+ /* TrueType & OpenType). */
+ /* */
+#define TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+
+ /*************************************************************************/
+ /* */
+ /* Define TT_CONFIG_OPTION_POSTSCRIPT_NAMES if you want to be able to */
+ /* load and enumerate the glyph Postscript names in a TrueType or */
+ /* OpenType file. */
+ /* */
+ /* Note that when you do not compile the `PSNames' module by undefining */
+ /* the above FT_CONFIG_OPTION_POSTSCRIPT_NAMES, the `sfnt' module will */
+ /* contain additional code used to read the PS Names table from a font. */
+ /* */
+ /* (By default, the module uses `PSNames' to extract glyph names.) */
+ /* */
+#define TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+
+
+ /*************************************************************************/
+ /* */
+ /* Define TT_CONFIG_OPTION_SFNT_NAMES if your applications need to */
+ /* access the internal name table in a SFNT-based format like TrueType */
+ /* or OpenType. The name table contains various strings used to */
+ /* describe the font, like family name, copyright, version, etc. It */
+ /* does not contain any glyph name though. */
+ /* */
+ /* Accessing SFNT names is done through the functions declared in */
+ /* `freetype/ftnames.h'. */
+ /* */
+#define TT_CONFIG_OPTION_SFNT_NAMES
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** T R U E T Y P E D R I V E R C O N F I G U R A T I O N ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* Define TT_CONFIG_OPTION_BYTECODE_INTERPRETER if you want to compile */
+ /* a bytecode interpreter in the TrueType driver. Note that there are */
+ /* important patent issues related to the use of the interpreter. */
+ /* */
+ /* 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_INTERPRETER_SWITCH to compile the TrueType */
+ /* bytecode interpreter with a huge switch statement, rather than a call */
+ /* table. This results in smaller and faster code for a number of */
+ /* architectures. */
+ /* */
+ /* Note however that on some compiler/processor combinations, undefining */
+ /* this macro will generate faster, though larger, code. */
+ /* */
+#define TT_CONFIG_OPTION_INTERPRETER_SWITCH
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** T Y P E 1 D R I V E R C O N F I G U R A T I O N ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* T1_MAX_DICT_DEPTH is the maximal depth of nest dictionaries and */
+ /* arrays in the Type 1 stream (see t1load.c). A minimum of 4 is */
+ /* required. */
+ /* */
+#define T1_MAX_DICT_DEPTH 5
+
+
+ /*************************************************************************/
+ /* */
+ /* T1_MAX_SUBRS_CALLS details the maximum number of nested sub-routine */
+ /* calls during glyph loading. */
+ /* */
+#define T1_MAX_SUBRS_CALLS 16
+
+
+ /*************************************************************************/
+ /* */
+ /* T1_MAX_CHARSTRING_OPERANDS is the charstring stack's capacity. A */
+ /* minimum of 16 is required. */
+ /* */
+ /* The Chinese font MingTiEG-Medium (CNS 11643 character set) needs 256. */
+ /* */
+#define T1_MAX_CHARSTRINGS_OPERANDS 256
+
+
+ /*************************************************************************/
+ /* */
+ /* Define T1_CONFIG_OPTION_DISABLE_HINTER if you want to generate a */
+ /* driver with no hinter. This can be useful to debug the parser. */
+ /* */
+#undef T1_CONFIG_OPTION_DISABLE_HINTER
+
+
+ /*************************************************************************/
+ /* */
+ /* Define this configuration macro if you want to prevent the */
+ /* compilation of `t1afm', which is in charge of reading Type 1 AFM */
+ /* files into an existing face. Note that if set, the T1 driver will be */
+ /* unable to produce kerning distances. */
+ /* */
+#undef T1_CONFIG_OPTION_NO_AFM
+
+
+ /*************************************************************************/
+ /* */
+ /* Define this configuration macro if you want to prevent the */
+ /* compilation of the Multiple Masters font support in the Type 1 */
+ /* driver. */
+ /* */
+#undef T1_CONFIG_OPTION_NO_MM_SUPPORT
+
+
+FT_END_HEADER
+
+
+#endif /* __FTOPTION_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* freetype.h */
+/* */
+/* FreeType high-level API and common types (specification only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FREETYPE_H__
+#define __FREETYPE_H__
+
+
+ /*************************************************************************/
+ /* */
+ /* The `raster' component duplicates some of the declarations in */
+ /* freetype.h for stand-alone use if _FREETYPE_ isn't defined. */
+ /* */
+
+
+ /*************************************************************************/
+ /* */
+ /* The FREETYPE_MAJOR and FREETYPE_MINOR macros are used to version the */
+ /* new FreeType design, which is able to host several kinds of font */
+ /* drivers. It starts at 2.0. */
+ /* */
+#define FREETYPE_MAJOR 2
+#define FREETYPE_MINOR 0
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include FT_ERRORS_H
+#include FT_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /* */
+ /* B A S I C T Y P E S */
+ /* */
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* base_interface */
+ /* */
+ /* <Title> */
+ /* Base Interface */
+ /* */
+ /* <Abstract> */
+ /* The FreeType 2 base font interface. */
+ /* */
+ /* <Description> */
+ /* This section describes the public high-level API of FreeType 2. */
+ /* */
+ /* <Order> */
+ /* FT_Library */
+ /* FT_Face */
+ /* FT_Size */
+ /* FT_GlyphSlot */
+ /* FT_CharMap */
+ /* FT_Encoding */
+ /* */
+ /* FT_FaceRec */
+ /* */
+ /* FT_FACE_FLAG_SCALABLE */
+ /* FT_FACE_FLAG_FIXED_SIZES */
+ /* FT_FACE_FLAG_FIXED_WIDTH */
+ /* FT_FACE_FLAG_HORIZONTAL */
+ /* FT_FACE_FLAG_VERTICAL */
+ /* FT_FACE_FLAG_SFNT */
+ /* FT_FACE_FLAG_KERNING */
+ /* FT_FACE_FLAG_MULTIPLE_MASTERS */
+ /* FT_FACE_FLAG_GLYPH_NAMES */
+ /* FT_FACE_FLAG_EXTERNAL_STREAM */
+ /* FT_FACE_FLAG_FAST_GLYPHS */
+ /* */
+ /* FT_STYLE_FLAG_BOLD */
+ /* FT_STYLE_FLAG_ITALIC */
+ /* */
+ /* FT_SizeRec */
+ /* FT_Size_Metrics */
+ /* */
+ /* FT_GlyphSlotRec */
+ /* FT_Glyph_Metrics */
+ /* FT_SubGlyph */
+ /* */
+ /* FT_Bitmap_Size */
+ /* */
+ /* FT_Init_FreeType */
+ /* FT_Done_FreeType */
+ /* */
+ /* FT_New_Face */
+ /* FT_Done_Face */
+ /* FT_New_Memory_Face */
+ /* FT_Open_Face */
+ /* FT_Open_Args */
+ /* FT_Open_Flags */
+ /* FT_Parameter */
+ /* FT_Attach_File */
+ /* FT_Attach_Stream */
+ /* */
+ /* FT_Set_Char_Size */
+ /* FT_Set_Pixel_Sizes */
+ /* FT_Set_Transform */
+ /* FT_Load_Glyph */
+ /* FT_Get_Char_Index */
+ /* FT_Get_Name_Index */
+ /* FT_Load_Char */
+ /* */
+ /* FT_LOAD_DEFAULT */
+ /* FT_LOAD_RENDER */
+ /* FT_LOAD_MONOCHROME */
+ /* FT_LOAD_LINEAR_DESIGN */
+ /* FT_LOAD_NO_SCALE */
+ /* FT_LOAD_NO_HINTING */
+ /* FT_LOAD_NO_BITMAP */
+ /* FT_LOAD_CROP_BITMAP */
+ /* */
+ /* FT_LOAD_VERTICAL_LAYOUT */
+ /* FT_LOAD_IGNORE_TRANSFORM */
+ /* FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH */
+ /* FT_LOAD_FORCE_AUTOHINT */
+ /* FT_LOAD_NO_RECURSE */
+ /* FT_LOAD_PEDANTIC */
+ /* */
+ /* FT_Render_Glyph */
+ /* FT_Render_Mode */
+ /* FT_Get_Kerning */
+ /* FT_Kerning_Mode */
+ /* FT_Get_Glyph_Name */
+ /* */
+ /* FT_CharMapRec */
+ /* FT_Select_Charmap */
+ /* FT_Set_Charmap */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Glyph_Metrics */
+ /* */
+ /* <Description> */
+ /* A structure used to model the metrics of a single glyph. Note */
+ /* that values are expressed in 26.6 fractional pixel format or in */
+ /* font units, depending on context. */
+ /* */
+ /* <Fields> */
+ /* width :: The glyph's width. */
+ /* */
+ /* height :: The glyph's height. */
+ /* */
+ /* horiBearingX :: Horizontal left side bearing. */
+ /* */
+ /* horiBearingY :: Horizontal top side bearing. */
+ /* */
+ /* horiAdvance :: Horizontal advance width. */
+ /* */
+ /* vertBearingX :: Vertical left side bearing. */
+ /* */
+ /* vertBearingY :: Vertical top side bearing. */
+ /* */
+ /* vertAdvance :: Vertical advance height. */
+ /* */
+ typedef struct FT_Glyph_Metrics_
+ {
+ FT_Pos width; /* glyph width */
+ FT_Pos height; /* glyph height */
+
+ FT_Pos horiBearingX; /* left side bearing in horizontal layouts */
+ FT_Pos horiBearingY; /* top side bearing in horizontal layouts */
+ FT_Pos horiAdvance; /* advance width for horizontal layout */
+
+ FT_Pos vertBearingX; /* left side bearing in vertical layouts */
+ FT_Pos vertBearingY; /* top side bearing in vertical layouts */
+ FT_Pos vertAdvance; /* advance height for vertical layout */
+
+ } FT_Glyph_Metrics;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Bitmap_Size */
+ /* */
+ /* <Description> */
+ /* An extremely simple structure used to model the size of a bitmap */
+ /* strike (i.e., a bitmap instance of the font for a given */
+ /* resolution) in a fixed-size font face. This is used for the */
+ /* `available_sizes' field of the FT_Face_Properties structure. */
+ /* */
+ /* <Fields> */
+ /* height :: The character height in pixels. */
+ /* */
+ /* width :: The character width in pixels. */
+ /* */
+ typedef struct FT_Bitmap_Size_
+ {
+ FT_Short height;
+ FT_Short width;
+
+ } FT_Bitmap_Size;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /* */
+ /* O B J E C T C L A S S E S */
+ /* */
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Library */
+ /* */
+ /* <Description> */
+ /* A handle to a FreeType library instance. Each `library' is */
+ /* completely independent from the others; it is the `root' of a set */
+ /* of objects like fonts, faces, sizes, etc. */
+ /* */
+ /* It also embeds a system object (see FT_System), as well as a */
+ /* scan-line converter object (see FT_Raster). */
+ /* */
+ /* <Note> */
+ /* Library objects are created through FT_Init_FreeType(). */
+ /* */
+ typedef struct FT_LibraryRec_ *FT_Library;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Module */
+ /* */
+ /* <Description> */
+ /* A handle to a given FreeType module object. Each module can be a */
+ /* font driver, a renderer, or anything else that provides services */
+ /* to the formers. */
+ /* */
+ typedef struct FT_ModuleRec_* FT_Module;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Driver */
+ /* */
+ /* <Description> */
+ /* A handle to a given FreeType font driver object. Each font driver */
+ /* is able to create faces, sizes, glyph slots, and charmaps from the */
+ /* resources whose format it supports. */
+ /* */
+ /* A driver can support either bitmap, graymap, or scalable font */
+ /* formats. */
+ /* */
+ typedef struct FT_DriverRec_* FT_Driver;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Renderer */
+ /* */
+ /* <Description> */
+ /* A handle to a given FreeType renderer. A renderer is in charge of */
+ /* converting a glyph image to a bitmap, when necessary. Each */
+ /* supports a given glyph image format, and one or more target */
+ /* surface depths. */
+ /* */
+ typedef struct FT_RendererRec_* FT_Renderer;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Face */
+ /* */
+ /* <Description> */
+ /* A handle to a given driver face object. A face object contains */
+ /* all the instance and glyph independent data of a font file */
+ /* typeface. */
+ /* */
+ /* A face object is created from a resource object through the */
+ /* new_face() method of a given driver. */
+ /* */
+ typedef struct FT_FaceRec_* FT_Face;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Size */
+ /* */
+ /* <Description> */
+ /* A handle to a given driver size object. Such an object models the */
+ /* _resolution_ AND _size_ dependent state of a given driver face */
+ /* size. */
+ /* */
+ /* A size object is always created from a given face object. It is */
+ /* discarded automatically by its parent face. */
+ /* */
+ typedef struct FT_SizeRec_* FT_Size;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_GlyphSlot */
+ /* */
+ /* <Description> */
+ /* A handle to a given `glyph slot'. A slot is a container where it */
+ /* is possible to load any of the glyphs contained within its parent */
+ /* face. */
+ /* */
+ /* A glyph slot is created from a given face object. It is discarded */
+ /* automatically by its parent face. */
+ /* */
+ typedef struct FT_GlyphSlotRec_* FT_GlyphSlot;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_CharMap */
+ /* */
+ /* <Description> */
+ /* A handle to a given character map. A charmap is used to translate */
+ /* character codes in a given encoding into glyph indexes for its */
+ /* parent's face. Some font formats may provide several charmaps per */
+ /* font. */
+ /* */
+ /* A charmap is created from a given face object. It is discarded */
+ /* automatically by its parent face. */
+ /* */
+ typedef struct FT_CharMapRec_* FT_CharMap;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Macro> */
+ /* FT_ENC_TAG */
+ /* */
+ /* <Description> */
+ /* This macro converts four letter tags into an unsigned long. */
+ /* */
+#ifndef FT_ENC_TAG
+#define FT_ENC_TAG( value, _x1, _x2, _x3, _x4 ) \
+ value = ( ( (unsigned long)_x1 << 24 ) | \
+ ( (unsigned long)_x2 << 16 ) | \
+ ( (unsigned long)_x3 << 8 ) | \
+ (unsigned long)_x4 )
+#endif /* FT_ENC_TAG */
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_Encoding */
+ /* */
+ /* <Description> */
+ /* An enumeration used to specify encodings supported by charmaps. */
+ /* Used in the FT_Select_Charmap() API function. */
+ /* */
+ /* <Note> */
+ /* Because of 32-bit charcodes defined in Unicode (i.e., surrogates), */
+ /* all character codes must be expressed as FT_Longs. */
+ /* */
+ /* Other encodings might be defined in the future. */
+ /* */
+ typedef enum FT_Encoding_
+ {
+ FT_ENC_TAG( ft_encoding_none, 0, 0, 0, 0 ),
+
+ FT_ENC_TAG( ft_encoding_symbol, 's', 'y', 'm', 'b' ),
+ FT_ENC_TAG( ft_encoding_unicode, 'u', 'n', 'i', 'c' ),
+ FT_ENC_TAG( ft_encoding_latin_2, 'l', 'a', 't', '2' ),
+ FT_ENC_TAG( ft_encoding_sjis, 's', 'j', 'i', 's' ),
+ FT_ENC_TAG( ft_encoding_gb2312, 'g', 'b', ' ', ' ' ),
+ FT_ENC_TAG( ft_encoding_big5, 'b', 'i', 'g', '5' ),
+ FT_ENC_TAG( ft_encoding_wansung, 'w', 'a', 'n', 's' ),
+ FT_ENC_TAG( ft_encoding_johab, 'j', 'o', 'h', 'a' ),
+
+ FT_ENC_TAG( ft_encoding_adobe_standard, 'A', 'D', 'O', 'B' ),
+ FT_ENC_TAG( ft_encoding_adobe_expert, 'A', 'D', 'B', 'E' ),
+ FT_ENC_TAG( ft_encoding_adobe_custom, 'A', 'D', 'B', 'C' ),
+
+ FT_ENC_TAG( ft_encoding_apple_roman, 'a', 'r', 'm', 'n' )
+
+ } FT_Encoding;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_CharMapRec */
+ /* */
+ /* <Description> */
+ /* The base charmap class. */
+ /* */
+ /* <Fields> */
+ /* face :: A handle to the parent face object. */
+ /* */
+ /* encoding :: A tag which identifies the charmap. Use this with */
+ /* FT_Select_Charmap(). */
+ /* */
+ /* platform_id :: An ID number describing the platform for the */
+ /* following encoding ID. This comes directly from */
+ /* the TrueType specification and should be emulated */
+ /* for other formats. */
+ /* */
+ /* encoding_id :: A platform specific encoding number. This also */
+ /* comes from the TrueType specification and should be */
+ /* emulated similarly. */
+ /* */
+ /* <Note> */
+ /* We STRONGLY recommmend emulating a Unicode charmap for drivers */
+ /* that do not support TrueType or OpenType. */
+ /* */
+ typedef struct FT_CharMapRec_
+ {
+ FT_Face face;
+ FT_Encoding encoding;
+ FT_UShort platform_id;
+ FT_UShort encoding_id;
+
+ } FT_CharMapRec;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /* */
+ /* B A S E O B J E C T C L A S S E S */
+ /* */
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Face_Internal */
+ /* */
+ /* <Description> */
+ /* An opaque handle to an FT_Face_InternalRec structure, used to */
+ /* model private data of a given FT_Face object. */
+ /* */
+ /* This field might change between releases of FreeType 2 and are */
+ /* not generally available to client applications. */
+ /* */
+ typedef struct FT_Face_InternalRec_* FT_Face_Internal;
+
+
+ /*************************************************************************/
+ /* */
+ /* FreeType base face class */
+ /* */
+ /* <Struct> */
+ /* FT_FaceRec */
+ /* */
+ /* <Description> */
+ /* FreeType root face class structure. A face object models the */
+ /* resolution and point-size independent data found in a font file. */
+ /* */
+ /* <Fields> */
+ /* num_faces :: In the case where the face is located in a */
+ /* collection (i.e., a resource which embeds */
+ /* several faces), this is the total number of */
+ /* faces found in the resource. 1 by default. */
+ /* */
+ /* face_index :: The index of the face in its resource. */
+ /* Usually, this is 0 for all normal font */
+ /* formats. It can be more in the case of */
+ /* collections (which embed several fonts in a */
+ /* single resource/file). */
+ /* */
+ /* face_flags :: A set of bit flags that give important */
+ /* information about the face; see the */
+ /* FT_FACE_FLAG_XXX macros for details. */
+ /* */
+ /* style_flags :: A set of bit flags indicating the style of */
+ /* the face (i.e., italic, bold, underline, */
+ /* etc). */
+ /* */
+ /* num_glyphs :: The total number of glyphs in the face. */
+ /* */
+ /* family_name :: The face's family name. This is an ASCII */
+ /* string, usually in English, which describes */
+ /* the typeface's family (like `Times New */
+ /* Roman', `Bodoni', `Garamond', etc). This */
+ /* is a least common denominator used to list */
+ /* fonts. Some formats (TrueType & OpenType) */
+ /* provide localized and Unicode versions of */
+ /* this string. Applications should use the */
+ /* format specific interface to access them. */
+ /* */
+ /* style_name :: The face's style name. This is an ASCII */
+ /* string, usually in English, which describes */
+ /* the typeface's style (like `Italic', */
+ /* `Bold', `Condensed', etc). Not all font */
+ /* formats provide a style name, so this field */
+ /* is optional, and can be set to NULL. As */
+ /* for `family_name', some formats provide */
+ /* localized/Unicode versions of this string. */
+ /* Applications should use the format specific */
+ /* interface to access them. */
+ /* */
+ /* num_fixed_sizes :: The number of fixed sizes available in this */
+ /* face. This should be set to 0 for scalable */
+ /* fonts, unless its resource includes a */
+ /* complete set of glyphs (called a `strike') */
+ /* for the specified size. */
+ /* */
+ /* available_sizes :: An array of sizes specifying the available */
+ /* bitmap/graymap sizes that are contained in */
+ /* in the font resource. Should be set to */
+ /* NULL if the field `num_fixed_sizes' is set */
+ /* to 0. */
+ /* */
+ /* num_charmaps :: The total number of character maps in the */
+ /* face. */
+ /* */
+ /* charmaps :: A table of pointers to the face's charmaps. */
+ /* Used to scan the list of available charmaps */
+ /* -- this table might change after a call to */
+ /* FT_Attach_File/Stream (e.g. when used to */
+ /* hook an additional encoding/CMap to the */
+ /* face object). */
+ /* */
+ /* generic :: A field reserved for client uses. See the */
+ /* FT_Generic type description. */
+ /* */
+ /* bbox :: The font bounding box. Coordinates are */
+ /* expressed in font units (see units_per_EM). */
+ /* The box is large enough to contain any */
+ /* glyph from the font. Thus, bbox.yMax can */
+ /* be seen as the `maximal ascender', */
+ /* bbox.yMin as the `minimal descender', and */
+ /* the maximal glyph width is given by */
+ /* `bbox.xMax-bbox.xMin' (not to be confused */
+ /* with the maximal _advance_width_). Only */
+ /* relevant for scalable formats. */
+ /* */
+ /* units_per_EM :: The number of font units per EM square for */
+ /* this face. This is typically 2048 for */
+ /* TrueType fonts, 1000 for Type1 fonts, and */
+ /* should be set to the (unrealistic) value 1 */
+ /* for fixed-sizes fonts. Only relevant for */
+ /* scalable formats. */
+ /* */
+ /* ascender :: The face's ascender is the vertical */
+ /* distance from the baseline to the topmost */
+ /* point of any glyph in the face. This */
+ /* field's value is positive, expressed in */
+ /* font units. Some font designs use a value */
+ /* different from `bbox.yMax'. Only relevant */
+ /* for scalable formats. */
+ /* */
+ /* descender :: The face's descender is the vertical */
+ /* distance from the baseline to the */
+ /* bottommost point of any glyph in the face. */
+ /* This field's value is positive, expressed */
+ /* in font units. Some font designs use a */
+ /* value different from `-bbox.yMin'. Only */
+ /* relevant for scalable formats. */
+ /* */
+ /* height :: The face's height is the vertical distance */
+ /* from one baseline to the next when writing */
+ /* several lines of text. Its value is always */
+ /* positive, expressed in font units. The */
+ /* value can be computed as */
+ /* `ascender+descender+line_gap' where the */
+ /* value of `line_gap' is also called */
+ /* `external leading'. Only relevant for */
+ /* scalable formats. */
+ /* */
+ /* max_advance_width :: The maximal advance width, in font units, */
+ /* for all glyphs in this face. This can be */
+ /* used to make word wrapping computations */
+ /* faster. Only relevant for scalable */
+ /* formats. */
+ /* */
+ /* max_advance_height :: The maximal advance height, in font units, */
+ /* for all glyphs in this face. This is only */
+ /* relevant for vertical layouts, and should */
+ /* be set to the `height' for fonts that do */
+ /* not provide vertical metrics. Only */
+ /* relevant for scalable formats. */
+ /* */
+ /* underline_position :: The position, in font units, of the */
+ /* underline line for this face. It's the */
+ /* center of the underlining stem. Only */
+ /* relevant for scalable formats. */
+ /* */
+ /* underline_thickness :: The thickness, in font units, of the */
+ /* underline for this face. Only relevant for */
+ /* scalable formats. */
+ /* */
+ /* driver :: A handle to the face's parent driver */
+ /* object. */
+ /* */
+ /* memory :: A handle to the face's parent memory */
+ /* object. Used for the allocation of */
+ /* subsequent objects. */
+ /* */
+ /* stream :: A handle to the face's stream. */
+ /* */
+ /* glyph :: The face's associated glyph slot(s). This */
+ /* object is created automatically with a new */
+ /* face object. However, certain kinds of */
+ /* applications (mainly tools like converters) */
+ /* can need more than one slot to ease their */
+ /* task. */
+ /* */
+ /* sizes_list :: The list of child sizes for this face. */
+ /* */
+ /* internal :: A pointer to internal fields of the face */
+ /* object. These fields can change freely */
+ /* between releases of FreeType and are not */
+ /* publicly available. */
+ /* */
+ typedef struct FT_FaceRec_
+ {
+ FT_Long num_faces;
+ FT_Long face_index;
+
+ FT_Long face_flags;
+ FT_Long style_flags;
+
+ FT_Long num_glyphs;
+
+ FT_String* family_name;
+ FT_String* style_name;
+
+ FT_Int num_fixed_sizes;
+ FT_Bitmap_Size* available_sizes;
+
+ FT_Int num_charmaps;
+ FT_CharMap* charmaps;
+
+ FT_Generic generic;
+
+ /*# the following are only relevant to scalable outlines */
+ FT_BBox bbox;
+
+ FT_UShort units_per_EM;
+ FT_Short ascender;
+ FT_Short descender;
+ FT_Short height;
+
+ FT_Short max_advance_width;
+ FT_Short max_advance_height;
+
+ FT_Short underline_position;
+ FT_Short underline_thickness;
+
+ FT_GlyphSlot glyph;
+ FT_Size size;
+ FT_CharMap charmap;
+
+ /*@private begin */
+
+ FT_Driver driver;
+ FT_Memory memory;
+ FT_Stream stream;
+
+ FT_ListRec sizes_list;
+
+ FT_Generic autohint;
+ void* extensions;
+
+ FT_Face_Internal internal;
+
+ /*@private end */
+
+ } FT_FaceRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_FACE_FLAG_SCALABLE */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used to indicate that a given face provides */
+ /* vectorial outlines (i.e., TrueType or Type1). This doesn't */
+ /* prevent embedding of bitmap strikes though, i.e., a given face can */
+ /* have both this bit set, and a `num_fixed_sizes' property > 0. */
+ /* */
+#define FT_FACE_FLAG_SCALABLE 1
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_FACE_FLAG_FIXED_SIZES */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used to indicate that a given face contains */
+ /* `fixed sizes', i.e., bitmap strikes for some given pixel sizes. */
+ /* See the `num_fixed_sizes' and `available_sizes' face properties */
+ /* for more information. */
+ /* */
+#define FT_FACE_FLAG_FIXED_SIZES 2
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_FACE_FLAG_FIXED_WIDTH */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used to indicate that a given face contains */
+ /* fixed-width characters (like Courier, Lucida, MonoType, etc.). */
+ /* */
+#define FT_FACE_FLAG_FIXED_WIDTH 4
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_FACE_FLAG_SFNT */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used to indicate that a given face uses the */
+ /* `sfnt' storage fomat. For now, this means TrueType or OpenType. */
+ /* */
+#define FT_FACE_FLAG_SFNT 8
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_FACE_FLAG_HORIZONTAL */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used to indicate that a given face contains */
+ /* horizontal glyph metrics. This should be set for all common */
+ /* formats, but who knows. */
+ /* */
+#define FT_FACE_FLAG_HORIZONTAL 0x10
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_FACE_FLAG_VERTICAL */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used to indicate that a given face contains */
+ /* vertical glyph metrics. If not set, the glyph loader will */
+ /* synthetize vertical metrics itself to help display vertical text */
+ /* correctly. */
+ /* */
+#define FT_FACE_FLAG_VERTICAL 0x20
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_FACE_FLAG_KERNING */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used to indicate that a given face contains */
+ /* kerning information. When set, this information can be retrieved */
+ /* through the function FT_Get_Kerning(). Note that when unset, this */
+ /* function will always return the kerning vector (0,0). */
+ /* */
+#define FT_FACE_FLAG_KERNING 0x40
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_FACE_FLAG_FAST_GLYPHS */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used to indicate that the glyphs in a given */
+ /* font can be retrieved very quickly, and that a glyph cache is thus */
+ /* not necessary for any of its child size objects. */
+ /* */
+ /* This flag should really be set for fixed-size formats like FNT, */
+ /* where each glyph bitmap is available directly in binary form */
+ /* without any kind of compression. */
+ /* */
+#define FT_FACE_FLAG_FAST_GLYPHS 0x80
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_FACE_FLAG_MULTIPLE_MASTERS */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used to indicate that the font contains */
+ /* multiple masters and is capable of interpolating between them. */
+ /* */
+#define FT_FACE_FLAG_MULTIPLE_MASTERS 0x100
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_FACE_FLAG_GLYPH_NAMES */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used to indicate that the font contains */
+ /* glyph names that can be retrieved through FT_Get_Glyph_Name(). */
+ /* */
+#define FT_FACE_FLAG_GLYPH_NAMES 0x200
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_FACE_FLAG_EXTERNAL_STREAM */
+ /* */
+ /* <Description> */
+ /* This bit field is used internally by FreeType to indicate that */
+ /* a face's stream was provided by the client application and should */
+ /* not be destroyed by FT_Done_Face(). */
+ /* */
+#define FT_FACE_FLAG_EXTERNAL_STREAM 0x4000
+
+
+ /* */
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: FT_HAS_HORIZONTAL (face) */
+ /* */
+ /* @description: */
+ /* A macro that returns true whenever a face object contains */
+ /* horizontal metrics (this is true for all font formats though). */
+ /* */
+ /* @also: */
+ /* @FT_HAS_VERTICAL can be used to check for vertical metrics. */
+ /* */
+#define FT_HAS_HORIZONTAL( face ) \
+ ( face->face_flags & FT_FACE_FLAG_HORIZONTAL )
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: FT_HAS_VERTICAL (face) */
+ /* */
+ /* @description: */
+ /* A macro that returns true whenever a face object contains vertical */
+ /* metrics. */
+ /* */
+#define FT_HAS_VERTICAL( face ) \
+ ( face->face_flags & FT_FACE_FLAG_VERTICAL )
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: FT_HAS_KERNING (face) */
+ /* */
+ /* @description: */
+ /* A macro that returns true whenever a face object contains kerning */
+ /* data that can be accessed with @FT_Get_Kerning. */
+ /* */
+#define FT_HAS_KERNING( face ) \
+ ( face->face_flags & FT_FACE_FLAG_KERNING )
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: FT_IS_SCALABLE (face) */
+ /* */
+ /* @description: */
+ /* A macro that returns true whenever a face object contains a */
+ /* scalable font face (true for TrueType, Type 1, CID, and */
+ /* OpenType/CFF font formats. */
+ /* */
+#define FT_IS_SCALABLE( face ) \
+ ( face->face_flags & FT_FACE_FLAG_SCALABLE )
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: FT_IS_SFNT (face) */
+ /* */
+ /* @description: */
+ /* A macro that returns true whenever a face object contains a font */
+ /* whose format is based on the SFNT storage scheme. This usually */
+ /* means: TrueType fonts, OpenType fonts, as well as SFNT-based */
+ /* embedded bitmap fonts. */
+ /* */
+ /* If this macro is true, all functions defined in @FT_SFNT_NAMES_H */
+ /* and @FT_TRUETYPE_TABLES_H are available. */
+ /* */
+#define FT_IS_SFNT( face ) \
+ ( face->face_flags & FT_FACE_FLAG_SFNT )
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: FT_IS_FIXED_WIDTH (face) */
+ /* */
+ /* @description: */
+ /* A macro that returns true whenever a face object contains a font */
+ /* face that contains fixed-width (or "monospace", "fixed-pitch", */
+ /* etc.) glyphs. */
+ /* */
+#define FT_IS_FIXED_WIDTH( face ) \
+ ( face->face_flags & FT_FACE_FLAG_FIXED_WIDTH )
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: FT_IS_FIXED_SIZES (face) */
+ /* */
+ /* @description: */
+ /* A macro that returns true whenever a face object contains some */
+ /* embedded bitmaps. See the `fixed_sizes' field of the @FT_FaceRec */
+ /* structure. */
+ /* */
+#define FT_HAS_FIXED_SIZES( face ) \
+ ( face->face_flags & FT_FACE_FLAG_FIXED_SIZES )
+
+
+ /* */
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: FT_HAS_FAST_GLYPHS (face) */
+ /* */
+ /* @description: */
+ /* XXX */
+ /* */
+#define FT_HAS_FAST_GLYPHS( face ) \
+ ( face->face_flags & FT_FACE_FLAG_FAST_GLYPHS )
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: FT_HAS_GLYPH_NAMES (face) */
+ /* */
+ /* @description: */
+ /* A macro that returns true whenever a face object contains some */
+ /* glyph names that can be accessed through @FT_Get_Glyph_Names. */
+ /* */
+#define FT_HAS_GLYPH_NAMES( face ) \
+ ( face->face_flags & FT_FACE_FLAG_GLYPH_NAMES )
+
+
+ /*************************************************************************/
+ /* */
+ /* @macro: FT_HAS_MULTIPLE_MASTERS (face) */
+ /* */
+ /* @description: */
+ /* A macro that returns true whenever a face object contains some */
+ /* multiple masters. The functions provided by */
+ /* @FT_MULTIPLE_MASTERS_H are then available to choose the exact */
+ /* design you want. */
+ /* */
+#define FT_HAS_MULTIPLE_MASTERS( face ) \
+ ( face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS )
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_STYLE_FLAG_ITALIC */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used to indicate that a given face is */
+ /* italicized. */
+ /* */
+#define FT_STYLE_FLAG_ITALIC 1
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_STYLE_FLAG_BOLD */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used to indicate that a given face is */
+ /* emboldened. */
+ /* */
+#define FT_STYLE_FLAG_BOLD 2
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Size_Internal */
+ /* */
+ /* <Description> */
+ /* An opaque handle to an FT_Size_InternalRec structure, used to */
+ /* model private data of a given FT_Size object. */
+ /* */
+ typedef struct FT_Size_InternalRec_* FT_Size_Internal;
+
+
+ /*************************************************************************/
+ /* */
+ /* FreeType base size metrics */
+ /* */
+ /* <Struct> */
+ /* FT_Size_Metrics */
+ /* */
+ /* <Description> */
+ /* The size metrics structure returned scaled important distances for */
+ /* a given size object. */
+ /* */
+ /* <Fields> */
+ /* x_ppem :: The character width, expressed in integer pixels. */
+ /* This is the width of the EM square expressed in */
+ /* pixels, hence the term `ppem' (pixels per EM). */
+ /* */
+ /* y_ppem :: The character height, expressed in integer pixels. */
+ /* This is the height of the EM square expressed in */
+ /* pixels, hence the term `ppem' (pixels per EM). */
+ /* */
+ /* x_scale :: A simple 16.16 fixed point format coefficient used */
+ /* to scale horizontal distances expressed in font */
+ /* units to fractional (26.6) pixel coordinates. */
+ /* */
+ /* y_scale :: A simple 16.16 fixed point format coefficient used */
+ /* to scale vertical distances expressed in font */
+ /* units to fractional (26.6) pixel coordinates. */
+ /* */
+ /* ascender :: The ascender, expressed in 26.6 fixed point */
+ /* pixels. Always positive. */
+ /* */
+ /* descender :: The descender, expressed in 26.6 fixed point */
+ /* pixels. Always positive. */
+ /* */
+ /* height :: The text height, expressed in 26.6 fixed point */
+ /* pixels. Always positive. */
+ /* */
+ /* max_advance :: Maximum horizontal advance, expressed in 26.6 */
+ /* fixed point pixels. Always positive. */
+ /* */
+ /* <Note> */
+ /* The values of `ascender', `descender', and `height' are only the */
+ /* scaled versions of `face->ascender', `face->descender', and */
+ /* `face->height'. */
+ /* */
+ /* Unfortunately, due to glyph hinting, these values might not be */
+ /* exact for certain fonts, they thus must be treated as unreliable */
+ /* with an error margin of at least one pixel! */
+ /* */
+ /* Indeed, the only way to get the exact pixel ascender and descender */
+ /* is to render _all_ glyphs. As this would be a definite */
+ /* performance hit, it is up to client applications to perform such */
+ /* computations. */
+ /* */
+ typedef struct FT_Size_Metrics_
+ {
+ FT_UShort x_ppem; /* horizontal pixels per EM */
+ FT_UShort y_ppem; /* vertical pixels per EM */
+
+ FT_Fixed x_scale; /* two scales used to convert font units */
+ FT_Fixed y_scale; /* to 26.6 frac. pixel coordinates.. */
+
+ FT_Pos ascender; /* ascender in 26.6 frac. pixels */
+ FT_Pos descender; /* descender in 26.6 frac. pixels */
+ FT_Pos height; /* text height in 26.6 frac. pixels */
+ FT_Pos max_advance; /* max horizontal advance, in 26.6 pixels */
+
+ } FT_Size_Metrics;
+
+
+ /*************************************************************************/
+ /* */
+ /* FreeType base size class */
+ /* */
+ /* <Struct> */
+ /* FT_SizeRec */
+ /* */
+ /* <Description> */
+ /* FreeType root size class structure. A size object models the */
+ /* resolution and pointsize dependent data of a given face. */
+ /* */
+ /* <Fields> */
+ /* face :: Handle to the parent face object. */
+ /* */
+ /* generic :: A typeless pointer, which is unused by the FreeType */
+ /* library or any of its drivers. It can be used by */
+ /* client applications to link their own data to each size */
+ /* object. */
+ /* */
+ /* metrics :: Metrics for this size object. This field is read-only. */
+ /* */
+ typedef struct FT_SizeRec_
+ {
+ FT_Face face; /* parent face object */
+ FT_Generic generic; /* generic pointer for client uses */
+ FT_Size_Metrics metrics; /* size metrics */
+ FT_Size_Internal internal;
+
+ } FT_SizeRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_SubGlyph */
+ /* */
+ /* <Description> */
+ /* The subglyph structure is an internal object used to describe */
+ /* subglyphs (for example, in the case of composites). */
+ /* */
+ /* <Note> */
+ /* The subglyph implementation is not part of the high-level API, */
+ /* hence the forward structure declaration. */
+ /* */
+ typedef struct FT_SubGlyph_ FT_SubGlyph;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Slot_Internal */
+ /* */
+ /* <Description> */
+ /* An opaque handle to an FT_Slot_InternalRec structure, used to */
+ /* model private data of a given FT_GlyphSlot object. */
+ /* */
+ typedef struct FT_Slot_InternalRec_* FT_Slot_Internal;
+
+
+ /*************************************************************************/
+ /* */
+ /* FreeType Glyph Slot base class */
+ /* */
+ /* <Struct> */
+ /* FT_GlyphSlotRec */
+ /* */
+ /* <Description> */
+ /* FreeType root glyph slot class structure. A glyph slot is a */
+ /* container where individual glyphs can be loaded, be they */
+ /* vectorial or bitmap/graymaps. */
+ /* */
+ /* <Fields> */
+ /* library :: A handle to the FreeType library instance */
+ /* this slot belongs to. */
+ /* */
+ /* face :: A handle to the parent face object. */
+ /* */
+ /* next :: In some cases (like some font tools), several */
+ /* glyph slots per face object can be a good */
+ /* thing. As this is rare, the glyph slots are */
+ /* listed through a direct, single-linked list */
+ /* using its `next' field. */
+ /* */
+ /* generic :: A typeless pointer which is unused by the */
+ /* FreeType library or any of its drivers. It */
+ /* can be used by client applications to link */
+ /* their own data to each glyph slot object. */
+ /* */
+ /* metrics :: The metrics of the last loaded glyph in the */
+ /* slot. The returned values depend on the last */
+ /* load flags (see the FT_Load_Glyph() API */
+ /* function) and can be expressed either in 26.6 */
+ /* fractional pixels or font units. */
+ /* */
+ /* Note that even when the glyph image is */
+ /* transformed, the metrics are not. */
+ /* */
+ /* linearHoriAdvance :: For scalable formats only, this field holds */
+ /* the linearly scaled horizontal advance width */
+ /* for the glyph (i.e. the scaled and unhinted */
+ /* value of the hori advance). This can be */
+ /* important to perform correct WYSIWYG layout. */
+ /* */
+ /* Note that this value is expressed by default */
+ /* in 16.16 pixels. However, when the glyph is */
+ /* loaded with the FT_LOAD_LINEAR_DESIGN flag, */
+ /* this field contains simply the value of the */
+ /* advance in original font units. */
+ /* */
+ /* linearVertAdvance :: For scalable formats only, this field holds */
+ /* the linearly scaled vertical advance height */
+ /* for the glyph. See linearHoriAdvance for */
+ /* comments. */
+ /* */
+ /* advance :: This is the transformed advance width for the */
+ /* glyph. */
+ /* */
+ /* format :: This field indicates the format of the image */
+ /* contained in the glyph slot. Typically */
+ /* ft_glyph_format_bitmap, */
+ /* ft_glyph_format_outline, and */
+ /* ft_glyph_format_composite, but others are */
+ /* possible. */
+ /* */
+ /* bitmap :: This field is used as a bitmap descriptor */
+ /* when the slot format is */
+ /* ft_glyph_format_bitmap. Note that the */
+ /* address and content of the bitmap buffer can */
+ /* change between calls of FT_Load_Glyph() and a */
+ /* few other functions. */
+ /* */
+ /* bitmap_left :: This is the bitmap's left bearing expressed */
+ /* in integer pixels. Of course, this is only */
+ /* valid if the format is */
+ /* ft_glyph_format_bitmap. */
+ /* */
+ /* bitmap_top :: This is the bitmap's top bearing expressed in */
+ /* integer pixels. Remember that this is the */
+ /* distance from the baseline to the top-most */
+ /* glyph scanline, upwards y-coordinates being */
+ /* *positive*. */
+ /* */
+ /* outline :: The outline descriptor for the current glyph */
+ /* image if its format is */
+ /* ft_glyph_bitmap_outline. */
+ /* */
+ /* num_subglyphs :: The number of subglyphs in a composite glyph. */
+ /* This format is only valid for the composite */
+ /* glyph format, that should normally only be */
+ /* loaded with the FT_LOAD_NO_RECURSE flag. */
+ /* */
+ /* subglyphs :: An array of subglyph descriptors for */
+ /* composite glyphs. There are `num_subglyphs' */
+ /* elements in there. */
+ /* */
+ /* control_data :: Certain font drivers can also return the */
+ /* control data for a given glyph image (e.g. */
+ /* TrueType bytecode, Type 1 charstrings, etc.). */
+ /* This field is a pointer to such data. */
+ /* */
+ /* control_len :: This is the length in bytes of the control */
+ /* data. */
+ /* */
+ /* other :: Really wicked formats can use this pointer to */
+ /* present their own glyph image to client apps. */
+ /* Note that the app will need to know about the */
+ /* image format. */
+ /* */
+ /* <Note> */
+ /* If @FT_Load_Glyph() is called with default flags (see */
+ /* @FT_LOAD_DEFAULT ) the glyph image is loaded in the glyph slot in */
+ /* its native format (e.g. a vectorial outline for TrueType and */
+ /* Type 1 formats). */
+ /* */
+ /* This image can later be converted into a bitmap by calling */
+ /* FT_Render_Glyph(). This function finds the current renderer for */
+ /* the native image's format then invokes it. */
+ /* */
+ /* The renderer is in charge of transforming the native image through */
+ /* the slot's face transformation fields, then convert it into a */
+ /* bitmap that is returned in `slot->bitmap'. */
+ /* */
+ /* Note that `slot->bitmap_left' and `slot->bitmap_top' are also used */
+ /* to specify the position of the bitmap relative to the current pen */
+ /* position (e.g. coordinates [0,0] on the baseline). Of course, */
+ /* `slot->format' is also changed to `ft_glyph_format_bitmap' . */
+ /* */
+ typedef struct FT_GlyphSlotRec_
+ {
+ FT_Library library;
+ FT_Face face;
+ FT_GlyphSlot next;
+ FT_UInt flags;
+ FT_Generic generic;
+
+ FT_Glyph_Metrics metrics;
+ FT_Fixed linearHoriAdvance;
+ FT_Fixed linearVertAdvance;
+ FT_Vector advance;
+
+ FT_Glyph_Format format;
+
+ FT_Bitmap bitmap;
+ FT_Int bitmap_left;
+ FT_Int bitmap_top;
+
+ FT_Outline outline;
+
+ FT_UInt num_subglyphs;
+ FT_SubGlyph* subglyphs;
+
+ void* control_data;
+ long control_len;
+
+ void* other;
+
+ FT_Slot_Internal internal;
+
+ } FT_GlyphSlotRec;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /* */
+ /* F U N C T I O N S */
+ /* */
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Init_FreeType */
+ /* */
+ /* <Description> */
+ /* Initializes a new FreeType library object. The set of drivers */
+ /* that are registered by this function is determined at build time. */
+ /* */
+ /* <Output> */
+ /* alibrary :: A handle to a new library object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Init_FreeType( FT_Library *alibrary );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Done_FreeType */
+ /* */
+ /* <Description> */
+ /* Destroys a given FreeType library object and all of its childs, */
+ /* including resources, drivers, faces, sizes, etc. */
+ /* */
+ /* <Input> */
+ /* library :: A handle to the target library object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Done_FreeType( FT_Library library );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_Open_Flags */
+ /* */
+ /* <Description> */
+ /* An enumeration used to list the bit flags used within the */
+ /* `flags' field of the @FT_Open_Args structure. */
+ /* */
+ /* <Fields> */
+ /* ft_open_memory :: This is a memory-based stream. */
+ /* */
+ /* ft_open_stream :: Copy the stream from the `stream' field. */
+ /* */
+ /* ft_open_pathname :: Create a new input stream from a C pathname. */
+ /* */
+ /* ft_open_driver :: Use the `driver' field. */
+ /* */
+ /* ft_open_params :: Use the `num_params' & `params' field. */
+ /* */
+ /* <Note> */
+ /* The `ft_open_memory', `ft_open_stream', and `ft_open_pathname' */
+ /* flags are mutually exclusive. */
+ /* */
+ typedef enum
+ {
+ ft_open_memory = 1,
+ ft_open_stream = 2,
+ ft_open_pathname = 4,
+ ft_open_driver = 8,
+ ft_open_params = 16
+
+ } FT_Open_Flags;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Parameter */
+ /* */
+ /* <Description> */
+ /* A simple structure used to pass more or less generic parameters */
+ /* to FT_Open_Face(). */
+ /* */
+ /* <Fields> */
+ /* tag :: A 4-byte identification tag. */
+ /* */
+ /* data :: A pointer to the parameter data. */
+ /* */
+ /* <Note> */
+ /* The id and function of parameters are driver-specific. */
+ /* */
+ typedef struct FT_Parameter_
+ {
+ FT_ULong tag;
+ FT_Pointer data;
+
+ } FT_Parameter;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Open_Args */
+ /* */
+ /* <Description> */
+ /* A structure used to indicate how to open a new font file/stream. */
+ /* A pointer to such a structure can be used as a parameter for the */
+ /* functions @FT_Open_Face() & @FT_Attach_Stream(). */
+ /* */
+ /* <Fields> */
+ /* flags :: A set of bit flags indicating how to use the */
+ /* structure. */
+ /* */
+ /* memory_base :: The first byte of the file in memory. */
+ /* */
+ /* memory_size :: The size in bytes of the file in memory. */
+ /* */
+ /* pathname :: A pointer to an 8-bit file pathname. */
+ /* */
+ /* stream :: A handle to a source stream object. */
+ /* */
+ /* driver :: This field is exclusively used by FT_Open_Face(); */
+ /* it simply specifies the font driver to use to open */
+ /* the face. If set to 0, FreeType will try to load */
+ /* the face with each one of the drivers in its list. */
+ /* */
+ /* num_params :: The number of extra parameters. */
+ /* */
+ /* params :: Extra parameters passed to the font driver when */
+ /* opening a new face. */
+ /* */
+ /* <Note> */
+ /* The stream type is determined by the contents of `flags' which */
+ /* are tested in the following order by @FT_Open_Face: */
+ /* */
+ /* If the `ft_open_memory' bit is set, assume that this is a */
+ /* memory file of `memory_size' bytes,located at `memory_address'. */
+ /* */
+ /* Otherwise, if the `ft_open_stream' bit is set, assume that a */
+ /* custom input stream `stream' is used. */
+ /* */
+ /* Otherwise, if the `ft_open_pathname' bit is set, assume that this */
+ /* is a normal file and use `pathname' to open it. */
+ /* */
+ /* If the `ft_open_driver' bit is set, @FT_Open_Face() will only */
+ /* try to open the file with the driver whose handler is in `driver'. */
+ /* */
+ /* If the `ft_open_params' bit is set, the parameters given by */
+ /* `num_params' and `params' will be used. They are ignored */
+ /* otherwise. */
+ /* */
+ typedef struct FT_Open_Args_
+ {
+ FT_Open_Flags flags;
+ const FT_Byte* memory_base;
+ FT_Long memory_size;
+ FT_String* pathname;
+ FT_Stream stream;
+ FT_Module driver;
+ FT_Int num_params;
+ FT_Parameter* params;
+
+ } FT_Open_Args;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_New_Face */
+ /* */
+ /* <Description> */
+ /* Creates a new face object from a given resource and typeface index */
+ /* using a pathname to the font file. */
+ /* */
+ /* <InOut> */
+ /* library :: A handle to the library resource. */
+ /* */
+ /* <Input> */
+ /* pathname :: A path to the font file. */
+ /* */
+ /* face_index :: The index of the face within the resource. The */
+ /* first face has index 0. */
+ /* <Output> */
+ /* aface :: A handle to a new face object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Unlike FreeType 1.x, this function automatically creates a glyph */
+ /* slot for the face object which can be accessed directly through */
+ /* `face->glyph'. */
+ /* */
+ /* FT_New_Face() can be used to determine and/or check the font */
+ /* format of a given font resource. If the `face_index' field is */
+ /* negative, the function will _not_ return any face handle in */
+ /* `aface'. Its return value should be 0 if the font format is */
+ /* recognized, or non-zero otherwise. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_New_Face( FT_Library library,
+ const char* filepathname,
+ FT_Long face_index,
+ FT_Face *aface );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_New_Memory_Face */
+ /* */
+ /* <Description> */
+ /* Creates a new face object from a given resource and typeface index */
+ /* using a font file already loaded into memory. */
+ /* */
+ /* <InOut> */
+ /* library :: A handle to the library resource. */
+ /* */
+ /* <Input> */
+ /* file_base :: A pointer to the beginning of the font data. */
+ /* */
+ /* file_size :: The size of the memory chunk used by the font data. */
+ /* */
+ /* face_index :: The index of the face within the resource. The */
+ /* first face has index 0. */
+ /* <Output> */
+ /* aface :: A handle to a new face object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The font data bytes are used _directly_ by the @FT_Face object. */
+ /* This means that they are not copied, and that the client is */
+ /* responsible for releasing/destroying them _after_ the */
+ /* corresponding call to @FT_Done_Face . */
+ /* */
+ /* Unlike FreeType 1.x, this function automatically creates a glyph */
+ /* slot for the face object which can be accessed directly through */
+ /* `face->glyph'. */
+ /* */
+ /* FT_New_Memory_Face() can be used to determine and/or check the */
+ /* font format of a given font resource. If the `face_index' field */
+ /* is negative, the function will _not_ return any face handle in */
+ /* `aface'. Its return value should be 0 if the font format is */
+ /* recognized, or non-zero otherwise. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_New_Memory_Face( FT_Library library,
+ const FT_Byte* file_base,
+ FT_Long file_size,
+ FT_Long face_index,
+ FT_Face *aface );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Open_Face */
+ /* */
+ /* <Description> */
+ /* Opens a face object from a given resource and typeface index using */
+ /* an `FT_Open_Args' structure. If the face object doesn't exist, it */
+ /* will be created. */
+ /* */
+ /* <InOut> */
+ /* library :: A handle to the library resource. */
+ /* */
+ /* <Input> */
+ /* args :: A pointer to an `FT_Open_Args' structure which must */
+ /* be filled by the caller. */
+ /* */
+ /* face_index :: The index of the face within the resource. The */
+ /* first face has index 0. */
+ /* <Output> */
+ /* aface :: A handle to a new face object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Unlike FreeType 1.x, this function automatically creates a glyph */
+ /* slot for the face object which can be accessed directly through */
+ /* `face->glyph'. */
+ /* */
+ /* FT_Open_Face() can be used to determine and/or check the font */
+ /* format of a given font resource. If the `face_index' field is */
+ /* negative, the function will _not_ return any face handle in */
+ /* `*face'. Its return value should be 0 if the font format is */
+ /* recognized, or non-zero otherwise. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Open_Face( FT_Library library,
+ FT_Open_Args* args,
+ FT_Long face_index,
+ FT_Face *aface );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Attach_File */
+ /* */
+ /* <Description> */
+ /* `Attaches' a given font file to an existing face. This is usually */
+ /* to read additional information for a single face object. For */
+ /* example, it is used to read the AFM files that come with Type 1 */
+ /* fonts in order to add kerning data and other metrics. */
+ /* */
+ /* <InOut> */
+ /* face :: The target face object. */
+ /* */
+ /* <Input> */
+ /* filepathname :: An 8-bit pathname naming the `metrics' file. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* If your font file is in memory, or if you want to provide your */
+ /* own input stream object, use FT_Attach_Stream(). */
+ /* */
+ /* The meaning of the `attach' action (i.e., what really happens when */
+ /* the new file is read) is not fixed by FreeType itself. It really */
+ /* depends on the font format (and thus the font driver). */
+ /* */
+ /* Client applications are expected to know what they are doing */
+ /* when invoking this function. Most drivers simply do not implement */
+ /* file attachments. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Attach_File( FT_Face face,
+ const char* filepathname );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Attach_Stream */
+ /* */
+ /* <Description> */
+ /* This function is similar to FT_Attach_File() with the exception */
+ /* that it reads the attachment from an arbitrary stream. */
+ /* */
+ /* <InOut> */
+ /* face :: The target face object. */
+ /* */
+ /* <Input> */
+ /* parameters :: A pointer to an FT_Open_Args structure used to */
+ /* describe the input stream to FreeType. */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The meaning of the `attach' (i.e. what really happens when the */
+ /* new file is read) is not fixed by FreeType itself. It really */
+ /* depends on the font format (and thus the font driver). */
+ /* */
+ /* Client applications are expected to know what they are doing */
+ /* when invoking this function. Most drivers simply do not implement */
+ /* file attachments. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Attach_Stream( FT_Face face,
+ FT_Open_Args* parameters );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Done_Face */
+ /* */
+ /* <Description> */
+ /* Discards a given face object, as well as all of its child slots */
+ /* and sizes. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to a target face object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Done_Face( FT_Face face );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Set_Char_Size */
+ /* */
+ /* <Description> */
+ /* Sets the character dimensions of a given face object. The */
+ /* `char_width' and `char_height' values are used for the width and */
+ /* height, respectively, expressed in 26.6 fractional points. */
+ /* */
+ /* If the horizontal or vertical resolution values are zero, a */
+ /* default value of 72dpi is used. Similarly, if one of the */
+ /* character dimensions is zero, its value is set equal to the other. */
+ /* */
+ /* <InOut> */
+ /* size :: A handle to a target size object. */
+ /* */
+ /* <Input> */
+ /* char_width :: The character width, in 26.6 fractional points. */
+ /* */
+ /* char_height :: The character height, in 26.6 fractional */
+ /* points. */
+ /* */
+ /* horz_resolution :: The horizontal resolution. */
+ /* */
+ /* vert_resolution :: The vertical resolution. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* When dealing with fixed-size faces (i.e., non-scalable formats), */
+ /* use the function FT_Set_Pixel_Sizes(). */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Set_Char_Size( FT_Face face,
+ FT_F26Dot6 char_width,
+ FT_F26Dot6 char_height,
+ FT_UInt horz_resolution,
+ FT_UInt vert_resolution );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Set_Pixel_Sizes */
+ /* */
+ /* <Description> */
+ /* Sets the character dimensions of a given face object. The width */
+ /* and height are expressed in integer pixels. */
+ /* */
+ /* If one of the character dimensions is zero, its value is set equal */
+ /* to the other. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* <Input> */
+ /* pixel_width :: The character width, in integer pixels. */
+ /* */
+ /* pixel_height :: The character height, in integer pixels. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* */
+ /* <Note> */
+ /* The values of `pixel_width' and `pixel_height' correspond to the */
+ /* pixel values of the _typographic_ character size, which are NOT */
+ /* necessarily the same as the dimensions of the glyph `bitmap */
+ /* cells'. */
+ /* */
+ /* The `character size' is really the size of an abstract square */
+ /* called the `EM', used to design the font. However, depending */
+ /* on the font design, glyphs will be smaller or greater than the */
+ /* EM. */
+ /* */
+ /* This means that setting the pixel size to, say, 8x8 doesn't */
+ /* guarantee in any way that you will get glyph bitmaps that all fit */
+ /* within an 8x8 cell (sometimes even far from it). */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Set_Pixel_Sizes( FT_Face face,
+ FT_UInt pixel_width,
+ FT_UInt pixel_height );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Load_Glyph */
+ /* */
+ /* <Description> */
+ /* A function used to load a single glyph within a given glyph slot, */
+ /* for a given size. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the target face object where the glyph */
+ /* will be loaded. */
+ /* */
+ /* <Input> */
+ /* glyph_index :: The index of the glyph in the font file. */
+ /* */
+ /* load_flags :: A flag indicating what to load for this glyph. The */
+ /* FT_LOAD_XXX constants can be used to control the */
+ /* glyph loading process (e.g., whether the outline */
+ /* should be scaled, whether to load bitmaps or not, */
+ /* whether to hint the outline, etc). */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* If the glyph image is not a bitmap, and if the bit flag */
+ /* FT_LOAD_IGNORE_TRANSFORM is unset, the glyph image will be */
+ /* transformed with the information passed to a previous call to */
+ /* FT_Set_Transform(). */
+ /* */
+ /* Note that this also transforms the `face.glyph.advance' field, but */
+ /* *not* the values in `face.glyph.metrics'. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Load_Glyph( FT_Face face,
+ FT_UInt glyph_index,
+ FT_Int load_flags );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Load_Char */
+ /* */
+ /* <Description> */
+ /* A function used to load a single glyph within a given glyph slot, */
+ /* for a given size, according to its character code. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to a target face object where the glyph */
+ /* will be loaded. */
+ /* */
+ /* <Input> */
+ /* char_code :: The glyph's character code, according to the */
+ /* current charmap used in the face. */
+ /* */
+ /* load_flags :: A flag indicating what to load for this glyph. The */
+ /* FT_LOAD_XXX constants can be used to control the */
+ /* glyph loading process (e.g., whether the outline */
+ /* should be scaled, whether to load bitmaps or not, */
+ /* whether to hint the outline, etc). */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* If the face has no current charmap, or if the character code */
+ /* is not defined in the charmap, this function will return an */
+ /* error. */
+ /* */
+ /* If the glyph image is not a bitmap, and if the bit flag */
+ /* FT_LOAD_IGNORE_TRANSFORM is unset, the glyph image will be */
+ /* transformed with the information passed to a previous call to */
+ /* FT_Set_Transform(). */
+ /* */
+ /* Note that this also transforms the `face.glyph.advance' field, but */
+ /* *not* the values in `face.glyph.metrics'. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Load_Char( FT_Face face,
+ FT_ULong char_code,
+ FT_Int load_flags );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_LOAD_NO_SCALE */
+ /* */
+ /* <Description> */
+ /* A bit field constant, used with FT_Load_Glyph() to indicate that */
+ /* the vector outline being loaded should not be scaled to 26.6 */
+ /* fractional pixels, but kept in notional units. */
+ /* */
+#define FT_LOAD_NO_SCALE 1
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_LOAD_NO_HINTING */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used with FT_Load_Glyph() to indicate that */
+ /* the vector outline being loaded should not be fitted to the pixel */
+ /* grid but simply scaled to 26.6 fractional pixels. */
+ /* */
+ /* This flag is ignored if FT_LOAD_NO_SCALE is set. */
+ /* */
+#define FT_LOAD_NO_HINTING 2
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_LOAD_RENDER */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used with FT_Load_Glyph() to indicate that */
+ /* the function should load the glyph and immediately convert it into */
+ /* a bitmap, if necessary, by calling FT_Render_Glyph(). */
+ /* */
+ /* Note that by default, FT_Load_Glyph() loads the glyph image in its */
+ /* native format. */
+ /* */
+#define FT_LOAD_RENDER 4
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_LOAD_NO_BITMAP */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used with FT_Load_Glyph() to indicate that */
+ /* the function should not load the bitmap or pixmap of a given */
+ /* glyph. This is useful when you do not want to load the embedded */
+ /* bitmaps of scalable formats, as the native glyph image will be */
+ /* loaded, and can then be rendered through FT_Render_Glyph(). */
+ /* */
+#define FT_LOAD_NO_BITMAP 8
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_LOAD_VERTICAL_LAYOUT */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used with FT_Load_Glyph() to indicate that */
+ /* the glyph image should be prepared for vertical layout. This */
+ /* basically means that `face.glyph.advance' will correspond to the */
+ /* vertical advance height (instead of the default horizontal */
+ /* advance width), and that the glyph image will translated to match */
+ /* the vertical bearings positions. */
+ /* */
+#define FT_LOAD_VERTICAL_LAYOUT 16
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_LOAD_FORCE_AUTOHINT */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used with FT_Load_Glyph() to indicate that */
+ /* the function should try to auto-hint the glyphs, even if a driver */
+ /* specific hinter is available. */
+ /* */
+#define FT_LOAD_FORCE_AUTOHINT 32
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_LOAD_CROP_BITMAP */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used with FT_Load_Glyph() to indicate that */
+ /* the font driver should try to crop the bitmap (i.e. remove all */
+ /* space around its black bits) when loading it. For now, this */
+ /* really only works with embedded bitmaps in TrueType fonts. */
+ /* */
+#define FT_LOAD_CROP_BITMAP 64
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_LOAD_PEDANTIC */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used with FT_Load_Glyph() to indicate that */
+ /* the glyph loader should perform a pedantic bytecode */
+ /* interpretation. Many popular fonts come with broken glyph */
+ /* programs. When this flag is set, loading them will return an */
+ /* error. Otherwise, errors are ignored by the loader, sometimes */
+ /* resulting in ugly glyphs. */
+ /* */
+#define FT_LOAD_PEDANTIC 128
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used with FT_Load_Glyph() to indicate that */
+ /* the glyph loader should ignore the global advance width defined */
+ /* in the font. As far as we know, this is only used by the */
+ /* X-TrueType font server, in order to deal correctly with the */
+ /* incorrect metrics contained in DynaLab's TrueType CJK fonts. */
+ /* */
+#define FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH 512
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_LOAD_NO_RECURSE */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used with FT_Load_Glyph() to indicate that */
+ /* the glyph loader should not load composite glyph recursively. */
+ /* Rather, when a composite glyph is encountered, it should set */
+ /* the values of `num_subglyphs' and `subglyphs', as well as set */
+ /* `face->glyph.format' to ft_glyph_format_composite. */
+ /* */
+ /* This is for use by the auto-hinter and possibly other tools. */
+ /* For nearly all applications, this flags should be left unset */
+ /* when invoking FT_Load_Glyph(). */
+ /* */
+ /* Note that the flag forces the load of unscaled glyphs. */
+ /* */
+#define FT_LOAD_NO_RECURSE 1024
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_LOAD_IGNORE_TRANSFORM */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used with FT_Load_Glyph() to indicate that */
+ /* the glyph loader should not try to transform the loaded glyph */
+ /* image. */
+ /* */
+#define FT_LOAD_IGNORE_TRANSFORM 2048
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_LOAD_MONOCHROME */
+ /* */
+ /* <Description> */
+ /* Only used with FT_LOAD_RENDER set, it indicates that the returned */
+ /* glyph image should be 1-bit monochrome. This really tells the */
+ /* glyph loader to use `ft_render_mode_mono' when calling */
+ /* FT_Render_Glyph(). */
+ /* */
+#define FT_LOAD_MONOCHROME 4096
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_LOAD_LINEAR_DESIGN */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used with FT_Load_Glyph() to indicate that */
+ /* the function should return the linearly scaled metrics expressed */
+ /* in original font units, instead of the default 16.16 pixel values. */
+ /* */
+#define FT_LOAD_LINEAR_DESIGN 8192
+
+
+ /*************************************************************************/
+ /* */
+ /* <Constant> */
+ /* FT_LOAD_DEFAULT */
+ /* */
+ /* <Description> */
+ /* A bit-field constant, used with FT_Load_Glyph() to indicate that */
+ /* the function should try to load the glyph normally, i.e., */
+ /* embedded bitmaps are favored over outlines, vectors are always */
+ /* scaled and grid-fitted. */
+ /* */
+#define FT_LOAD_DEFAULT 0
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Set_Transform */
+ /* */
+ /* <Description> */
+ /* A function used to set the transformation that is applied to glyph */
+ /* images just before they are converted to bitmaps in a glyph slot */
+ /* when FT_Render_Glyph() is called. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* <Input> */
+ /* matrix :: A pointer to the transformation's 2x2 matrix. Use 0 for */
+ /* the identity matrix. */
+ /* delta :: A pointer to the translation vector. Use 0 for the null */
+ /* vector. */
+ /* */
+ /* <Note> */
+ /* The transformation is only applied to scalable image formats after */
+ /* the glyph has been loaded. It means that hinting is unaltered by */
+ /* the transformation and is performed on the character size given in */
+ /* the last call to FT_Set_Char_Sizes() or FT_Set_Pixel_Sizes(). */
+ /* */
+ FT_EXPORT( void )
+ FT_Set_Transform( FT_Face face,
+ FT_Matrix* matrix,
+ FT_Vector* delta );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_Render_Mode */
+ /* */
+ /* <Description> */
+ /* An enumeration type that lists the render modes supported by the */
+ /* FreeType 2 renderer(s). A renderer is in charge of converting a */
+ /* glyph image into a bitmap. */
+ /* */
+ /* <Fields> */
+ /* ft_render_mode_normal :: This is the default render mode; it */
+ /* corresponds to 8-bit anti-aliased */
+ /* bitmaps, using 256 levels of gray. */
+ /* */
+ /* ft_render_mode_mono :: This render mode is used to produce 1-bit */
+ /* monochrome bitmaps. */
+ /* */
+ /* <Note> */
+ /* There is no render mode to produce 8-bit `monochrome' bitmaps -- */
+ /* you have to make the conversion yourself if you need such things */
+ /* (besides, FreeType is not a graphics library). */
+ /* */
+ /* More modes might appear later for specific display modes (e.g. TV, */
+ /* LCDs, etc.). They will be supported through the simple addition */
+ /* of a renderer module, with no changes to the rest of the engine. */
+ /* */
+ typedef enum FT_Render_Mode_
+ {
+ ft_render_mode_normal = 0,
+ ft_render_mode_mono = 1
+
+ } FT_Render_Mode;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Render_Glyph */
+ /* */
+ /* <Description> */
+ /* Converts a given glyph image to a bitmap. It does so by */
+ /* inspecting the glyph image format, find the relevant renderer, and */
+ /* invoke it. */
+ /* */
+ /* <InOut> */
+ /* slot :: A handle to the glyph slot containing the image to */
+ /* convert. */
+ /* */
+ /* <Input> */
+ /* render_mode :: This is the render mode used to render the glyph */
+ /* image into a bitmap. See FT_Render_Mode for a list */
+ /* of possible values. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Render_Glyph( FT_GlyphSlot slot,
+ FT_UInt render_mode );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_Kerning_Mode */
+ /* */
+ /* <Description> */
+ /* An enumeration used to specify which kerning values to return in */
+ /* FT_Get_Kerning(). */
+ /* */
+ /* <Fields> */
+ /* ft_kerning_default :: Return scaled and grid-fitted kerning */
+ /* distances (value is 0). */
+ /* */
+ /* ft_kerning_unfitted :: Return scaled but un-grid-fitted kerning */
+ /* distances. */
+ /* */
+ /* ft_kerning_unscaled :: Return the kerning vector in original font */
+ /* units. */
+ /* */
+ typedef enum FT_Kerning_Mode_
+ {
+ ft_kerning_default = 0,
+ ft_kerning_unfitted,
+ ft_kerning_unscaled
+
+ } FT_Kerning_Mode;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Kerning */
+ /* */
+ /* <Description> */
+ /* Returns the kerning vector between two glyphs of a same face. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to a source face object. */
+ /* */
+ /* left_glyph :: The index of the left glyph in the kern pair. */
+ /* */
+ /* right_glyph :: The index of the right glyph in the kern pair. */
+ /* */
+ /* kern_mode :: See FT_Kerning_Mode() for more information. */
+ /* Determines the scale/dimension of the returned */
+ /* kerning vector. */
+ /* */
+ /* <Output> */
+ /* akerning :: The kerning vector. This is in font units for */
+ /* scalable formats, and in pixels for fixed-sizes */
+ /* formats. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Only horizontal layouts (left-to-right & right-to-left) are */
+ /* supported by this method. Other layouts, or more sophisticated */
+ /* kernings, are out of the scope of this API function -- they can be */
+ /* implemented through format-specific interfaces. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Get_Kerning( FT_Face face,
+ FT_UInt left_glyph,
+ FT_UInt right_glyph,
+ FT_UInt kern_mode,
+ FT_Vector *akerning );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Glyph_Name */
+ /* */
+ /* <Description> */
+ /* Retrieves the ASCII name of a given glyph in a face. This only */
+ /* works for those faces where FT_HAS_GLYPH_NAME(face) returns true. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to a source face object. */
+ /* */
+ /* glyph_index :: The glyph index. */
+ /* */
+ /* buffer_max :: The maximal number of bytes available in the */
+ /* buffer. */
+ /* */
+ /* <Output> */
+ /* buffer :: A pointer to a target buffer where the name will be */
+ /* copied to. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* An error is returned if the face doesn't provide glyph names or if */
+ /* the glyph index is invalid. In all cases of failure, the first */
+ /* byte of `buffer' will be set to 0 to indicate an empty name. */
+ /* */
+ /* The glyph name is truncated to fit within the buffer if it is too */
+ /* long. The returned string is always zero-terminated. */
+ /* */
+ /* This function is not compiled within the library if the config */
+ /* macro FT_CONFIG_OPTION_NO_GLYPH_NAMES is defined in */
+ /* `include/freetype/config/ftoptions.h' */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Get_Glyph_Name( FT_Face face,
+ FT_UInt glyph_index,
+ FT_Pointer buffer,
+ FT_UInt buffer_max );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Postscript_Name */
+ /* */
+ /* <Description> */
+ /* Retrieves the ASCII Postscript name of a given face, when */
+ /* available. This should only work with Postscript and TrueType */
+ /* fonts.. */
+ /* */
+ /* <Input> */
+ /* face :: handle to source face object. */
+ /* */
+ /* <Return> */
+ /* pointer to face's Postscript name. NULL when un-available */
+ /* */
+ /* <Note> */
+ /* The returned pointer is owned by the face and will be destroyed */
+ /* with it. */
+ /* */
+ FT_EXPORT( const char* )
+ FT_Get_Postscript_Name( FT_Face face );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Select_Charmap */
+ /* */
+ /* <Description> */
+ /* Selects a given charmap by its encoding tag (as listed in */
+ /* `freetype.h'). */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* <Input> */
+ /* encoding :: A handle to the selected charmap. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* This function will return an error if no charmap in the face */
+ /* corresponds to the encoding queried here. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Select_Charmap( FT_Face face,
+ FT_Encoding encoding );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Set_Charmap */
+ /* */
+ /* <Description> */
+ /* Selects a given charmap for character code to glyph index */
+ /* decoding. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* <Input> */
+ /* charmap :: A handle to the selected charmap. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* This function will return an error if the charmap is not part of */
+ /* the face (i.e., if it is not listed in the face->charmaps[] */
+ /* table). */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Set_Charmap( FT_Face face,
+ FT_CharMap charmap );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Char_Index */
+ /* */
+ /* <Description> */
+ /* Returns the glyph index of a given character code. This function */
+ /* uses a charmap object to do the translation. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* charcode :: The character code. */
+ /* */
+ /* <Return> */
+ /* The glyph index. 0 means `undefined character code'. */
+ /* */
+ FT_EXPORT( FT_UInt )
+ FT_Get_Char_Index( FT_Face face,
+ FT_ULong charcode );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Name_Index */
+ /* */
+ /* <Description> */
+ /* Returns the glyph index of a given glyph name. This function uses */
+ /* driver specific objects to do the translation. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* glyph_name :: The glyph name. */
+ /* */
+ /* <Return> */
+ /* The glyph index. 0 means `undefined character code'. */
+ /* */
+ FT_EXPORT( FT_UInt )
+ FT_Get_Name_Index( FT_Face face,
+ FT_String* glyph_name );
+
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* computations */
+ /* */
+ /* <Title> */
+ /* Computations */
+ /* */
+ /* <Abstract> */
+ /* Crunching fixed numbers and vectors */
+ /* */
+ /* <Description> */
+ /* This section contains various functions used to perform */
+ /* computations on 16.16 fixed-float numbers or 2d vectors. */
+ /* */
+ /* <Order> */
+ /* FT_MulDiv */
+ /* FT_MulFix */
+ /* FT_DivFix */
+ /* FT_RoundFix */
+ /* FT_CeilFix */
+ /* FT_FloorFix */
+ /* FT_Vector_Transform */
+ /* FT_Matrix_Multiply */
+ /* FT_Matrix_Invert */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_MulDiv */
+ /* */
+ /* <Description> */
+ /* A very simple function used to perform the computation `(a*b)/c' */
+ /* with maximal accuracy (it uses a 64-bit intermediate integer */
+ /* whenever necessary). */
+ /* */
+ /* This function isn't necessarily as fast as some processor specific */
+ /* operations, but is at least completely portable. */
+ /* */
+ /* <Input> */
+ /* a :: The first multiplier. */
+ /* b :: The second multiplier. */
+ /* c :: The divisor. */
+ /* */
+ /* <Return> */
+ /* The result of `(a*b)/c'. This function never traps when trying to */
+ /* divide by zero; it simply returns `MaxInt' or `MinInt' depending */
+ /* on the signs of `a' and `b'. */
+ /* */
+ FT_EXPORT( FT_Long )
+ FT_MulDiv( FT_Long a,
+ FT_Long b,
+ FT_Long c );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_MulFix */
+ /* */
+ /* <Description> */
+ /* A very simple function used to perform the computation */
+ /* `(a*b)/0x10000' with maximal accuracy. Most of the time this is */
+ /* used to multiply a given value by a 16.16 fixed float factor. */
+ /* */
+ /* <Input> */
+ /* a :: The first multiplier. */
+ /* b :: The second multiplier. Use a 16.16 factor here whenever */
+ /* possible (see note below). */
+ /* */
+ /* <Return> */
+ /* The result of `(a*b)/0x10000'. */
+ /* */
+ /* <Note> */
+ /* This function has been optimized for the case where the absolute */
+ /* value of `a' is less than 2048, and `b' is a 16.16 scaling factor. */
+ /* As this happens mainly when scaling from notional units to */
+ /* fractional pixels in FreeType, it resulted in noticeable speed */
+ /* improvements between versions 2.x and 1.x. */
+ /* */
+ /* As a conclusion, always try to place a 16.16 factor as the */
+ /* _second_ argument of this function; this can make a great */
+ /* difference. */
+ /* */
+ FT_EXPORT( FT_Long )
+ FT_MulFix( FT_Long a,
+ FT_Long b );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_DivFix */
+ /* */
+ /* <Description> */
+ /* A very simple function used to perform the computation */
+ /* `(a*0x10000)/b' with maximal accuracy. Most of the time, this is */
+ /* used to divide a given value by a 16.16 fixed float factor. */
+ /* */
+ /* <Input> */
+ /* a :: The first multiplier. */
+ /* b :: The second multiplier. Use a 16.16 factor here whenever */
+ /* possible (see note below). */
+ /* */
+ /* <Return> */
+ /* The result of `(a*0x10000)/b'. */
+ /* */
+ /* <Note> */
+ /* The optimization for FT_DivFix() is simple: If (a << 16) fits in */
+ /* 32 bits, then the division is computed directly. Otherwise, we */
+ /* use a specialized version of the old FT_MulDiv64(). */
+ /* */
+ FT_EXPORT( FT_Long )
+ FT_DivFix( FT_Long a,
+ FT_Long b );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_RoundFix */
+ /* */
+ /* <Description> */
+ /* A very simple function used to round a 16.16 fixed number. */
+ /* */
+ /* <Input> */
+ /* a :: The number to be rounded. */
+ /* */
+ /* <Return> */
+ /* The result of `(a + 0x8000) & -0x10000'. */
+ /* */
+ FT_EXPORT( FT_Fixed )
+ FT_RoundFix( FT_Fixed a );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_CeilFix */
+ /* */
+ /* <Description> */
+ /* A very simple function used to compute the ceiling function of a */
+ /* 16.16 fixed number. */
+ /* */
+ /* <Input> */
+ /* a :: The number for which the ceiling function is to be computed. */
+ /* */
+ /* <Return> */
+ /* The result of `(a + 0x10000 - 1) & -0x10000'. */
+ /* */
+ FT_EXPORT( FT_Fixed )
+ FT_CeilFix( FT_Fixed a );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_FloorFix */
+ /* */
+ /* <Description> */
+ /* A very simple function used to compute the floor function of a */
+ /* 16.16 fixed number. */
+ /* */
+ /* <Input> */
+ /* a :: The number for which the floor function is to be computed. */
+ /* */
+ /* <Return> */
+ /* The result of `a & -0x10000'. */
+ /* */
+ FT_EXPORT( FT_Fixed )
+ FT_FloorFix( FT_Fixed a );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Vector_Transform */
+ /* */
+ /* <Description> */
+ /* Transforms a single vector through a 2x2 matrix. */
+ /* */
+ /* <InOut> */
+ /* vector :: The target vector to transform. */
+ /* */
+ /* <Input> */
+ /* matrix :: A pointer to the source 2x2 matrix. */
+ /* */
+ /* <Note> */
+ /* The result is undefined if either `vector' or `matrix' is invalid. */
+ /* */
+ FT_EXPORT( void )
+ FT_Vector_Transform( FT_Vector* vec,
+ FT_Matrix* matrix );
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FREETYPE_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftbbox.h */
+/* */
+/* FreeType exact bbox computation (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This component has a _single_ role: to compute exact outline bounding */
+ /* boxes. */
+ /* */
+ /* It is separated from the rest of the engine for various technical */
+ /* reasons. It may well be integrated in `ftoutln' later. */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef __FTBBOX_H__
+#define __FTBBOX_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* outline_processing */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Get_BBox */
+ /* */
+ /* <Description> */
+ /* Computes the exact bounding box of an outline. This is slower */
+ /* than computing the control box. However, it uses an advanced */
+ /* algorithm which returns _very_ quickly when the two boxes */
+ /* coincide. Otherwise, the outline Bezier arcs are walked over to */
+ /* extract their extrema. */
+ /* */
+ /* <Input> */
+ /* outline :: A pointer to the source outline. */
+ /* */
+ /* <Output> */
+ /* abbox :: The outline's exact bounding box. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Outline_Get_BBox( FT_Outline* outline,
+ FT_BBox *abbox );
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FTBBOX_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftcache.h */
+/* */
+/* FreeType Cache subsystem. */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********* *********/
+ /********* WARNING, THIS IS BETA CODE. *********/
+ /********* *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#ifndef __FTCACHE_H__
+#define __FTCACHE_H__
+
+
+#include <ft2build.h>
+#include FT_GLYPH_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* cache_subsystem */
+ /* */
+ /* <Title> */
+ /* Cache Sub-System */
+ /* */
+ /* <Abstract> */
+ /* How to cache face, size, and glyph data with FreeType 2. */
+ /* */
+ /* <Description> */
+ /* This section describes the FreeType 2 cache sub-system which is */
+ /* stile in beta. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** BASIC TYPE DEFINITIONS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FTC_FaceID */
+ /* */
+ /* <Description> */
+ /* A generic pointer type that is used to identity face objects. The */
+ /* contents of such objects is application-dependent. */
+ /* */
+ typedef FT_Pointer FTC_FaceID;
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FTC_Face_Requester */
+ /* */
+ /* <Description> */
+ /* A callback function provided by client applications. It is used */
+ /* to translate a given FTC_FaceID into a new valid FT_Face object. */
+ /* */
+ /* <Input> */
+ /* face_id :: The face ID to resolve. */
+ /* */
+ /* library :: A handle to a FreeType library object. */
+ /* */
+ /* data :: Application-provided request data. */
+ /* */
+ /* <Output> */
+ /* aface :: A new FT_Face handle. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The face requester should not perform funny things on the returned */
+ /* face object, like creating a new FT_Size for it, or setting a */
+ /* transformation through FT_Set_Transform()! */
+ /* */
+ typedef FT_Error
+ (*FTC_Face_Requester)( FTC_FaceID face_id,
+ FT_Library library,
+ FT_Pointer request_data,
+ FT_Face* aface );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FTC_FontRec */
+ /* */
+ /* <Description> */
+ /* A simple structure used to describe a given `font' to the cache */
+ /* manager. Note that a `font' is the combination of a given face */
+ /* with a given character size. */
+ /* */
+ /* <Fields> */
+ /* face_id :: The ID of the face to use. */
+ /* */
+ /* pix_width :: The character width in integer pixels. */
+ /* */
+ /* pix_height :: The character height in integer pixels. */
+ /* */
+ typedef struct FTC_FontRec_
+ {
+ FTC_FaceID face_id;
+ FT_UShort pix_width;
+ FT_UShort pix_height;
+
+ } FTC_FontRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FTC_Font */
+ /* */
+ /* <Description> */
+ /* A simple handle to a FTC_FontRec structure. */
+ /* */
+ typedef FTC_FontRec* FTC_Font;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** CACHE MANAGER OBJECT *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FTC_Manager */
+ /* */
+ /* <Description> */
+ /* This object is used to cache one or more FT_Face objects, along */
+ /* with corresponding FT_Size objects. */
+ /* */
+ typedef struct FTC_ManagerRec_* FTC_Manager;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_Manager_New */
+ /* */
+ /* <Description> */
+ /* Creates a new cache manager. */
+ /* */
+ /* <Input> */
+ /* library :: The parent FreeType library handle to use. */
+ /* */
+ /* max_faces :: Maximum number of faces to keep alive in manager. */
+ /* Use 0 for defaults. */
+ /* */
+ /* max_sizes :: Maximum number of sizes to keep alive in manager. */
+ /* Use 0 for defaults. */
+ /* */
+ /* max_bytes :: Maximum number of bytes to use for cached data. */
+ /* Use 0 for defaults. */
+ /* */
+ /* requester :: An application-provided callback used to translate */
+ /* face IDs into real FT_Face objects. */
+ /* */
+ /* req_data :: A generic pointer that is passed to the requester */
+ /* each time it is called (see FTC_Face_Requester) */
+ /* */
+ /* <Output> */
+ /* amanager :: A handle to a new manager object. 0 in case of */
+ /* failure. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FTC_Manager_New( FT_Library library,
+ FT_UInt max_faces,
+ FT_UInt max_sizes,
+ FT_ULong max_bytes,
+ FTC_Face_Requester requester,
+ FT_Pointer req_data,
+ FTC_Manager *amanager );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_Manager_Reset */
+ /* */
+ /* <Description> */
+ /* Empties a given cache manager. This simply gets rid of all the */
+ /* currently cached FT_Face & FT_Size objects within the manager. */
+ /* */
+ /* <InOut> */
+ /* manager :: A handle to the manager. */
+ /* */
+ FT_EXPORT( void )
+ FTC_Manager_Reset( FTC_Manager manager );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_Manager_Done */
+ /* */
+ /* <Description> */
+ /* Destroys a given manager after emptying it. */
+ /* */
+ /* <Input> */
+ /* manager :: A handle to the target cache manager object. */
+ /* */
+ FT_EXPORT( void )
+ FTC_Manager_Done( FTC_Manager manager );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_Manager_Lookup_Face */
+ /* */
+ /* <Description> */
+ /* Retrieves the FT_Face object that corresponds to a given face ID */
+ /* through a cache manager. */
+ /* */
+ /* <Input> */
+ /* manager :: A handle to the cache manager. */
+ /* */
+ /* face_id :: The ID of the face object. */
+ /* */
+ /* <Output> */
+ /* aface :: A handle to the face object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The returned FT_Face object is always owned by the manager. You */
+ /* should never try to discard it yourself. */
+ /* */
+ /* The FT_Face object doesn't necessarily have a current size object */
+ /* (i.e., face->size can be 0). If you need a specific `font size', */
+ /* use FTC_Manager_Lookup_Size() instead. */
+ /* */
+ /* Never change the face's transformation matrix (i.e., never call */
+ /* the FT_Set_Transform() function) on a returned face! If you need */
+ /* to transform glyphs, do it yourself after glyph loading. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FTC_Manager_Lookup_Face( FTC_Manager manager,
+ FTC_FaceID face_id,
+ FT_Face *aface );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FTC_Manager_Lookup_Size */
+ /* */
+ /* <Description> */
+ /* Retrieves the FT_Face & FT_Size objects that correspond to a given */
+ /* FTC_SizeID. */
+ /* */
+ /* <Input> */
+ /* manager :: A handle to the cache manager. */
+ /* */
+ /* size_id :: The ID of the `font size' to use. */
+ /* */
+ /* <Output> */
+ /* aface :: A pointer to the handle of the face object. Set it to */
+ /* zero if you don't need it. */
+ /* */
+ /* asize :: A pointer to the handle of the size object. Set it to */
+ /* zero if you don't need it. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The returned FT_Face object is always owned by the manager. You */
+ /* should never try to discard it yourself. */
+ /* */
+ /* Never change the face's transformation matrix (i.e., never call */
+ /* the FT_Set_Transform() function) on a returned face! If you need */
+ /* to transform glyphs, do it yourself after glyph loading. */
+ /* */
+ /* Similarly, the returned FT_Size object is always owned by the */
+ /* manager. You should never try to discard it, and never change its */
+ /* settings with FT_Set_Pixel_Sizes() or FT_Set_Char_Size()! */
+ /* */
+ /* The returned size object is the face's current size, which means */
+ /* that you can call FT_Load_Glyph() with the face if you need to. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FTC_Manager_Lookup_Size( FTC_Manager manager,
+ FTC_Font font,
+ FT_Face *aface,
+ FT_Size *asize );
+
+
+ /* a cache class is used to describe a unique cache type to the manager */
+ typedef struct FTC_Cache_Class_ FTC_Cache_Class;
+ typedef struct FTC_CacheRec_* FTC_Cache;
+
+
+ /* this must be used internally for the moment */
+ FT_EXPORT( FT_Error )
+ FTC_Manager_Register_Cache( FTC_Manager manager,
+ FTC_Cache_Class* clazz,
+ FTC_Cache *acache );
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FTCACHE_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* <Chapter> */
+/* core_api */
+/* */
+/* <Title> */
+/* Core API */
+/* */
+/* <Sections> */
+/* basic_types */
+/* base_interface */
+/* glyph_management */
+/* mac_specific */
+/* multiple_masters */
+/* truetype_tables */
+/* type1_tables */
+/* sfnt_names */
+/* sizes_management */
+/* module_management */
+/* system_interface */
+/* header_file_macros */
+/* */
+/***************************************************************************/
+
+
+/***************************************************************************/
+/* */
+/* <Chapter> */
+/* cache_subsystem */
+/* */
+/* <Title> */
+/* Cache Sub-System */
+/* */
+/* <Sections> */
+/* cache_subsystem */
+/* */
+/***************************************************************************/
+
+
+/***************************************************************************/
+/* */
+/* <Chapter> */
+/* support_api */
+/* */
+/* <Title> */
+/* Support API */
+/* */
+/* <Sections> */
+/* computations */
+/* list_processing */
+/* outline_processing */
+/* raster */
+/* */
+/***************************************************************************/
+
--- /dev/null
+/***************************************************************************/
+/* */
+/* fterrors.h */
+/* */
+/* FreeType error codes (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This special header file is used to define the FT2 enumeration */
+ /* constants. It can also be used to generate error message strings */
+ /* with a small macro trick explained below. */
+ /* */
+ /* I - Error Formats */
+ /* ----------------- */
+ /* */
+ /* Since release 2.1, the error constants have changed. The lower */
+ /* byte of the error value gives the "generic" error code, while the */
+ /* higher byte indicates in which module the error occured. */
+ /* */
+ /* You can use the macro FT_ERROR_BASE(x) macro to extract the generic */
+ /* error code from an FT_Error value. */
+ /* */
+ /* The configuration macro FT_CONFIG_OPTION_USE_MODULE_ERRORS can be */
+ /* undefined in ftoption.h in order to make the higher byte always */
+ /* zero, in case you need to be compatible with previous versions of */
+ /* FreeType 2. */
+ /* */
+ /* */
+ /* II - Error Message strings */
+ /* -------------------------- */
+ /* */
+ /* The error definitions below are made through special macros that */
+ /* allow client applications to build a table of error message strings */
+ /* if they need it. The strings are not included in a normal build of */
+ /* FreeType 2 to save space (most client applications do not use */
+ /* them). */
+ /* */
+ /* To do so, you have to define the following macros before including */
+ /* this file: */
+ /* */
+ /* FT_ERROR_START_LIST :: */
+ /* This macro is called before anything else to define the start of */
+ /* the error list. It is followed by several FT_ERROR_DEF calls */
+ /* (see below). */
+ /* */
+ /* FT_ERROR_DEF( e, v, s ) :: */
+ /* This macro is called to define one single error. */
+ /* `e' is the error code identifier (e.g. FT_Err_Invalid_Argument). */
+ /* `v' is the error numerical value. */
+ /* `s' is the corresponding error string. */
+ /* */
+ /* FT_ERROR_END_LIST :: */
+ /* This macro ends the list. */
+ /* */
+ /* Additionally, you have to undefine __FTERRORS_H__ before #including */
+ /* this file. */
+ /* */
+ /* Here is a simple example: */
+ /* */
+ /* { */
+ /* #undef __FTERRORS_H__ */
+ /* #define FT_ERRORDEF( e, v, s ) { e, s }, */
+ /* #define FT_ERROR_START_LIST { */
+ /* #define FT_ERROR_END_LIST { 0, 0 } }; */
+ /* */
+ /* const struct */
+ /* { */
+ /* int err_code; */
+ /* const char* err_msg */
+ /* } ft_errors[] = */
+ /* */
+ /* #include FT_ERRORS_H */
+ /* } */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef __FTERRORS_H__
+#define __FTERRORS_H__
+
+
+ /* include module base error codes */
+#include FT_MODULE_ERRORS_H
+
+
+ /*******************************************************************/
+ /*******************************************************************/
+ /***** *****/
+ /***** SETUP MACROS *****/
+ /***** *****/
+ /*******************************************************************/
+ /*******************************************************************/
+
+
+#undef FT_NEED_EXTERN_C
+#define FT_ERR_XCAT( x, y ) x ## y
+#define FT_ERR_CAT( x, y ) FT_ERR_XCAT( x, y )
+
+
+ /* FT_ERR_PREFIX is used as a prefix for error identifiers. */
+ /* By default, we use `FT_Err_'. */
+ /* */
+#ifndef FT_ERR_PREFIX
+#define FT_ERR_PREFIX FT_Err_
+#endif
+
+
+ /* FT_ERR_BASE is used as the base for module-specific errors. */
+ /* */
+#ifdef FT_CONFIG_OPTION_USE_MODULE_ERRORS
+
+#ifndef FT_ERR_BASE
+#define FT_ERR_BASE FT_Mod_Err_Base
+#endif
+
+#else
+
+#undef FT_ERR_BASE
+#define FT_ERR_BASE 0
+
+#endif /* FT_CONFIG_OPTION_USE_MODULE_ERRORS */
+
+
+ /* If FT_ERRORDEF is not defined, we need to define a simple */
+ /* enumeration type. */
+ /* */
+#ifndef FT_ERRORDEF
+
+#define FT_ERRORDEF( e, v, s ) e = v,
+#define FT_ERROR_START_LIST enum {
+#define FT_ERROR_END_LIST FT_ERR_CAT( FT_ERR_PREFIX, Max ) };
+
+#ifdef __cplusplus
+#define FT_NEED_EXTERN_C
+ extern "C" {
+#endif
+
+#endif /* !FT_ERRORDEF */
+
+
+ /* this macro is used to define an error */
+#define FT_ERRORDEF_( e, v, s ) \
+ FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v + FT_ERR_BASE, s )
+
+ /* this is only used for FT_Err_Ok, which must be 0! */
+#define FT_NOERRORDEF_( e, v, s ) \
+ FT_ERRORDEF( FT_ERR_CAT( FT_ERR_PREFIX, e ), v, s )
+
+
+ /*******************************************************************/
+ /*******************************************************************/
+ /***** *****/
+ /***** LIST OF ERROR CODES/MESSAGES *****/
+ /***** *****/
+ /*******************************************************************/
+ /*******************************************************************/
+
+
+#ifdef FT_ERROR_START_LIST
+ FT_ERROR_START_LIST
+#endif
+
+
+ /* generic errors */
+
+ FT_NOERRORDEF_( Ok, 0x00, \
+ "no error" )
+
+ FT_ERRORDEF_( Cannot_Open_Resource, 0x01, \
+ "cannot open resource" )
+ FT_ERRORDEF_( Unknown_File_Format, 0x02, \
+ "unknown file format" )
+ FT_ERRORDEF_( Invalid_File_Format, 0x03, \
+ "broken file" )
+ FT_ERRORDEF_( Invalid_Version, 0x04, \
+ "invalid FreeType version" )
+ FT_ERRORDEF_( Lower_Module_Version, 0x05, \
+ "module version is too low" )
+ FT_ERRORDEF_( Invalid_Argument, 0x06, \
+ "invalid argument" )
+ FT_ERRORDEF_( Unimplemented_Feature, 0x07, \
+ "unimplemented feature" )
+
+ /* glyph/character errors */
+
+ FT_ERRORDEF_( Invalid_Glyph_Index, 0x10, \
+ "invalid glyph index" )
+ FT_ERRORDEF_( Invalid_Character_Code, 0x11, \
+ "invalid character code" )
+ FT_ERRORDEF_( Invalid_Glyph_Format, 0x12, \
+ "unsupported glyph image format" )
+ FT_ERRORDEF_( Cannot_Render_Glyph, 0x13, \
+ "cannot render this glyph format" )
+ FT_ERRORDEF_( Invalid_Outline, 0x14, \
+ "invalid outline" )
+ FT_ERRORDEF_( Invalid_Composite, 0x15, \
+ "invalid composite glyph" )
+ FT_ERRORDEF_( Too_Many_Hints, 0x16, \
+ "too many hints" )
+ FT_ERRORDEF_( Invalid_Pixel_Size, 0x17, \
+ "invalid pixel size" )
+
+ /* handle errors */
+
+ FT_ERRORDEF_( Invalid_Handle, 0x20, \
+ "invalid object handle" )
+ FT_ERRORDEF_( Invalid_Library_Handle, 0x21, \
+ "invalid library handle" )
+ FT_ERRORDEF_( Invalid_Driver_Handle, 0x22, \
+ "invalid module handle" )
+ FT_ERRORDEF_( Invalid_Face_Handle, 0x23, \
+ "invalid face handle" )
+ FT_ERRORDEF_( Invalid_Size_Handle, 0x24, \
+ "invalid size handle" )
+ FT_ERRORDEF_( Invalid_Slot_Handle, 0x25, \
+ "invalid glyph slot handle" )
+ FT_ERRORDEF_( Invalid_CharMap_Handle, 0x26, \
+ "invalid charmap handle" )
+ FT_ERRORDEF_( Invalid_Cache_Handle, 0x27, \
+ "invalid cache manager handle" )
+ FT_ERRORDEF_( Invalid_Stream_Handle, 0x28, \
+ "invalid stream handle" )
+
+ /* driver errors */
+
+ FT_ERRORDEF_( Too_Many_Drivers, 0x30, \
+ "too many modules" )
+ FT_ERRORDEF_( Too_Many_Extensions, 0x31, \
+ "too many extensions" )
+
+ /* memory errors */
+
+ FT_ERRORDEF_( Out_Of_Memory, 0x40, \
+ "out of memory" )
+ FT_ERRORDEF_( Unlisted_Object, 0x41, \
+ "unlisted object" )
+
+ /* stream errors */
+
+ FT_ERRORDEF_( Cannot_Open_Stream, 0x51, \
+ "cannot open stream" )
+ FT_ERRORDEF_( Invalid_Stream_Seek, 0x52, \
+ "invalid stream seek" )
+ FT_ERRORDEF_( Invalid_Stream_Skip, 0x53, \
+ "invalid stream skip" )
+ FT_ERRORDEF_( Invalid_Stream_Read, 0x54, \
+ "invalid stream read" )
+ FT_ERRORDEF_( Invalid_Stream_Operation, 0x55, \
+ "invalid stream operation" )
+ FT_ERRORDEF_( Invalid_Frame_Operation, 0x56, \
+ "invalid frame operation" )
+ FT_ERRORDEF_( Nested_Frame_Access, 0x57, \
+ "nested frame access" )
+ FT_ERRORDEF_( Invalid_Frame_Read, 0x58, \
+ "invalid frame read" )
+
+ /* raster errors */
+
+ FT_ERRORDEF_( Raster_Uninitialized, 0x60, \
+ "raster uninitialized" )
+ FT_ERRORDEF_( Raster_Corrupted, 0x61, \
+ "raster corrupted" )
+ FT_ERRORDEF_( Raster_Overflow, 0x62, \
+ "raster overflow" )
+ FT_ERRORDEF_( Raster_Negative_Height, 0x63, \
+ "negative height while rastering" )
+
+ /* cache errors */
+
+ FT_ERRORDEF_( Too_Many_Caches, 0x70, \
+ "too many registered caches" )
+
+ /* TrueType and SFNT errors */
+
+ FT_ERRORDEF_( Invalid_Opcode, 0x80, \
+ "invalid opcode" )
+ FT_ERRORDEF_( Too_Few_Arguments, 0x81, \
+ "too few arguments" )
+ FT_ERRORDEF_( Stack_Overflow, 0x82, \
+ "stack overflow" )
+ FT_ERRORDEF_( Code_Overflow, 0x83, \
+ "code overflow" )
+ FT_ERRORDEF_( Bad_Argument, 0x84, \
+ "bad argument" )
+ FT_ERRORDEF_( Divide_By_Zero, 0x85, \
+ "division by zero" )
+ FT_ERRORDEF_( Invalid_Reference, 0x86, \
+ "invalid reference" )
+ FT_ERRORDEF_( Debug_OpCode, 0x87, \
+ "found debug opcode" )
+ FT_ERRORDEF_( ENDF_In_Exec_Stream, 0x88, \
+ "found ENDF opcode in execution stream" )
+ FT_ERRORDEF_( Nested_DEFS, 0x89, \
+ "nested DEFS" )
+ FT_ERRORDEF_( Invalid_CodeRange, 0x8A, \
+ "invalid code range" )
+ FT_ERRORDEF_( Execution_Too_Long, 0x8B, \
+ "execution context too long" )
+ FT_ERRORDEF_( Too_Many_Function_Defs, 0x8C, \
+ "too many function definitions" )
+ FT_ERRORDEF_( Too_Many_Instruction_Defs, 0x8D, \
+ "too many instruction definitions" )
+ FT_ERRORDEF_( Table_Missing, 0x8E, \
+ "SFNT font table missing" )
+ FT_ERRORDEF_( Horiz_Header_Missing, 0x8F, \
+ "horizontal header (hhea) table missing" )
+ FT_ERRORDEF_( Locations_Missing, 0x90, \
+ "locations (loca) table missing" )
+ FT_ERRORDEF_( Name_Table_Missing, 0x91, \
+ "name table missing" )
+ FT_ERRORDEF_( CMap_Table_Missing, 0x92, \
+ "character map (cmap) table missing" )
+ FT_ERRORDEF_( Hmtx_Table_Missing, 0x93, \
+ "horizontal metrics (hmtx) table missing" )
+ FT_ERRORDEF_( Post_Table_Missing, 0x94, \
+ "PostScript (post) table missing" )
+ FT_ERRORDEF_( Invalid_Horiz_Metrics, 0x95, \
+ "invalid horizontal metrics" )
+ FT_ERRORDEF_( Invalid_CharMap_Format, 0x96, \
+ "invalid character map (cmap) format" )
+ FT_ERRORDEF_( Invalid_PPem, 0x97, \
+ "invalid ppem value" )
+ FT_ERRORDEF_( Invalid_Vert_Metrics, 0x98, \
+ "invalid vertical metrics" )
+ FT_ERRORDEF_( Could_Not_Find_Context, 0x99, \
+ "could not find context" )
+ FT_ERRORDEF_( Invalid_Post_Table_Format, 0x9A, \
+ "invalid PostScript (post) table format" )
+ FT_ERRORDEF_( Invalid_Post_Table, 0x9B, \
+ "invalid PostScript (post) table" )
+
+ /* CFF, CID, and Type 1 errors */
+
+ FT_ERRORDEF_( Syntax_Error, 0xA0, \
+ "opcode syntax error" )
+ FT_ERRORDEF_( Stack_Underflow, 0xA1, \
+ "argument stack underflow" )
+
+
+#ifdef FT_ERROR_END_LIST
+ FT_ERROR_END_LIST
+#endif
+
+
+ /*******************************************************************/
+ /*******************************************************************/
+ /***** *****/
+ /***** SIMPLE CLEANUP *****/
+ /***** *****/
+ /*******************************************************************/
+ /*******************************************************************/
+
+#ifdef FT_NEED_EXTERN_C
+ }
+#endif
+
+#undef FT_ERROR_START_LIST
+#undef FT_ERROR_END_LIST
+
+#undef FT_ERRORDEF
+#undef FT_ERRORDEF_
+#undef FT_NOERRORDEF_
+
+#undef FT_NEED_EXTERN_C
+#undef FT_ERR_PREFIX
+#undef FT_ERR_BASE
+#undef FT_ERR_CONCAT
+
+#endif /* __FTERRORS_H__ */
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftglyph.h */
+/* */
+/* FreeType convenience functions to handle glyphs (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file contains the definition of several convenience functions */
+ /* that can be used by client applications to easily retrieve glyph */
+ /* bitmaps and outlines from a given face. */
+ /* */
+ /* These functions should be optional if you are writing a font server */
+ /* or text layout engine on top of FreeType. However, they are pretty */
+ /* handy for many other simple uses of the library. */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef __FTGLYPH_H__
+#define __FTGLYPH_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* glyph_management */
+ /* */
+ /* <Title> */
+ /* Glyph Management */
+ /* */
+ /* <Abstract> */
+ /* Generic interface to manage individual glyph data. */
+ /* */
+ /* <Description> */
+ /* This section contains definitions used to manage glyph data */
+ /* through generic FT_Glyph objects. Each of them can contain a */
+ /* bitmap, a vector outline, or even images in other formats. */
+ /* */
+ /*************************************************************************/
+
+
+ /* forward declaration to a private type */
+ typedef struct FT_Glyph_Class_ FT_Glyph_Class;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_GlyphRec */
+ /* */
+ /* <Description> */
+ /* The root glyph structure contains a given glyph image plus its */
+ /* advance width in 16.16 fixed float format. */
+ /* */
+ /* <Fields> */
+ /* library :: A handle to the FreeType library object. */
+ /* */
+ /* clazz :: A pointer to the glyph's class. Private. */
+ /* */
+ /* format :: The format of the glyph's image. */
+ /* */
+ /* advance :: A 16.16 vector that gives the glyph's advance width. */
+ /* */
+ typedef struct FT_GlyphRec_
+ {
+ FT_Library library;
+ const FT_Glyph_Class* clazz;
+ FT_Glyph_Format format;
+ FT_Vector advance;
+
+ } FT_GlyphRec, *FT_Glyph;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_BitmapGlyphRec */
+ /* */
+ /* <Description> */
+ /* A structure used for bitmap glyph images. This really is a */
+ /* `sub-class' of `FT_GlyphRec'. */
+ /* */
+ /* <Fields> */
+ /* root :: The root FT_Glyph fields. */
+ /* */
+ /* left :: The left-side bearing, i.e., the horizontal distance */
+ /* from the current pen position to the left border of the */
+ /* glyph bitmap. */
+ /* */
+ /* top :: The top-side bearing, i.e., the vertical distance from */
+ /* the current pen position to the top border of the glyph */
+ /* bitmap. This distance is positive for upwards-y! */
+ /* */
+ /* bitmap :: A descriptor for the bitmap. */
+ /* */
+ /* <Note> */
+ /* You can typecast FT_Glyph to FT_BitmapGlyph if you have */
+ /* glyph->format == ft_glyph_format_bitmap. This lets you access */
+ /* the bitmap's contents easily. */
+ /* */
+ /* The corresponding pixel buffer is always owned by the BitmapGlyph */
+ /* and is thus created and destroyed with it. */
+ /* */
+ typedef struct FT_BitmapGlyphRec_
+ {
+ FT_GlyphRec root;
+ FT_Int left;
+ FT_Int top;
+ FT_Bitmap bitmap;
+
+ } FT_BitmapGlyphRec, *FT_BitmapGlyph;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_OutlineGlyphRec */
+ /* */
+ /* <Description> */
+ /* A structure used for outline (vectorial) glyph images. This */
+ /* really is a `sub-class' of `FT_GlyphRec'. */
+ /* */
+ /* <Fields> */
+ /* root :: The root FT_Glyph fields. */
+ /* */
+ /* outline :: A descriptor for the outline. */
+ /* */
+ /* <Note> */
+ /* You can typecast FT_Glyph to FT_OutlineGlyph if you have */
+ /* glyph->format == ft_glyph_format_outline. This lets you access */
+ /* the outline's content easily. */
+ /* */
+ /* As the outline is extracted from a glyph slot, its coordinates are */
+ /* expressed normally in 26.6 pixels, unless the flag */
+ /* FT_LOAD_NO_SCALE was used in FT_Load_Glyph() or FT_Load_Char(). */
+ /* */
+ /* The outline's tables are always owned by the object and are */
+ /* destroyed with it. */
+ /* */
+ typedef struct FT_OutlineGlyphRec_
+ {
+ FT_GlyphRec root;
+ FT_Outline outline;
+
+ } FT_OutlineGlyphRec, *FT_OutlineGlyph;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Glyph */
+ /* */
+ /* <Description> */
+ /* A function used to extract a glyph image from a slot. */
+ /* */
+ /* <Input> */
+ /* slot :: A handle to the source glyph slot. */
+ /* */
+ /* <Output> */
+ /* aglyph :: A handle to the glyph object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Get_Glyph( FT_GlyphSlot slot,
+ FT_Glyph *aglyph );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Glyph_Copy */
+ /* */
+ /* <Description> */
+ /* A function used to copy a glyph image. */
+ /* */
+ /* <Input> */
+ /* source :: A handle to the source glyph object. */
+ /* */
+ /* <Output> */
+ /* target :: A handle to the target glyph object. 0 in case of */
+ /* error. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Glyph_Copy( FT_Glyph source,
+ FT_Glyph *target );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Glyph_Transform */
+ /* */
+ /* <Description> */
+ /* Transforms a glyph image if its format is scalable. */
+ /* */
+ /* <InOut> */
+ /* glyph :: A handle to the target glyph object. */
+ /* */
+ /* <Input> */
+ /* matrix :: A pointer to a 2x2 matrix to apply. */
+ /* */
+ /* delta :: A pointer to a 2d vector to apply. Coordinates are */
+ /* expressed in 1/64th of a pixel. */
+ /* */
+ /* <Return> */
+ /* FreeType error code (the glyph format is not scalable if it is */
+ /* not zero). */
+ /* */
+ /* <Note> */
+ /* The 2x2 transformation matrix is also applied to the glyph's */
+ /* advance vector. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Glyph_Transform( FT_Glyph glyph,
+ FT_Matrix* matrix,
+ FT_Vector* delta );
+
+ /* */
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Glyph_Get_CBox */
+ /* */
+ /* <Description> */
+ /* Returns a glyph's `control box'. The control box encloses all the */
+ /* outline's points, including Bezier control points. Though it */
+ /* coincides with the exact bounding box for most glyphs, it can be */
+ /* slightly larger in some situations (like when rotating an outline */
+ /* which contains Bezier outside arcs). */
+ /* */
+ /* Computing the control box is very fast, while getting the bounding */
+ /* box can take much more time as it needs to walk over all segments */
+ /* and arcs in the outline. To get the latter, you can use the */
+ /* `ftbbox' component which is dedicated to this single task. */
+ /* */
+ /* <Input> */
+ /* glyph :: A handle to the source glyph object. */
+ /* */
+ /* mode :: The mode which indicates how to interpret the returned */
+ /* bounding box values. */
+ /* */
+ /* <Output> */
+ /* acbox :: The glyph coordinate bounding box. Coordinates are */
+ /* expressed in 1/64th of pixels if it is grid-fitted. */
+ /* */
+ /* <Note> */
+ /* Coordinates are relative to the glyph origin, using the Y-upwards */
+ /* convention. */
+ /* */
+ /* If the glyph has been loaded with FT_LOAD_NO_SCALE, `bbox_mode' */
+ /* must be set to `ft_glyph_bbox_unscaled' to get unscaled font */
+ /* units. */
+ /* */
+ /* If `bbox_mode' is set to `ft_glyph_bbox_subpixels' the bbox */
+ /* coordinates are returned in 26.6 pixels (i.e. 1/64th of pixels). */
+ /* */
+ /* Note that the maximum coordinates are exclusive, which means that */
+ /* one can compute the width and height of the glyph image (be it in */
+ /* integer or 26.6 pixels) as: */
+ /* */
+ /* width = bbox.xMax - bbox.xMin; */
+ /* height = bbox.yMax - bbox.yMin; */
+ /* */
+ /* Note also that for 26.6 coordinates, if `bbox_mode' is set to */
+ /* `ft_glyph_bbox_gridfit', the coordinates will also be grid-fitted, */
+ /* which corresponds to: */
+ /* */
+ /* bbox.xMin = FLOOR(bbox.xMin); */
+ /* bbox.yMin = FLOOR(bbox.yMin); */
+ /* bbox.xMax = CEILING(bbox.xMax); */
+ /* bbox.yMax = CEILING(bbox.yMax); */
+ /* */
+ /* To get the bbox in pixel coordinates, set `bbox_mode' to */
+ /* `ft_glyph_bbox_truncate'. */
+ /* */
+ /* To get the bbox in grid-fitted pixel coordinates, set `bbox_mode' */
+ /* to `ft_glyph_bbox_pixels'. */
+ /* */
+ /* The default value for `bbox_mode' is `ft_glyph_bbox_pixels'. */
+ /* */
+ enum
+ {
+ ft_glyph_bbox_unscaled = 0, /* return unscaled font units */
+ ft_glyph_bbox_subpixels = 0, /* return unfitted 26.6 coordinates */
+ ft_glyph_bbox_gridfit = 1, /* return grid-fitted 26.6 coordinates */
+ ft_glyph_bbox_truncate = 2, /* return coordinates in integer pixels */
+ ft_glyph_bbox_pixels = 3 /* return grid-fitted pixel coordinates */
+ };
+
+
+ FT_EXPORT( void )
+ FT_Glyph_Get_CBox( FT_Glyph glyph,
+ FT_UInt bbox_mode,
+ FT_BBox *acbox );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Glyph_To_Bitmap */
+ /* */
+ /* <Description> */
+ /* Converts a given glyph object to a bitmap glyph object. */
+ /* */
+ /* <InOut> */
+ /* the_glyph :: A pointer to a handle to the target glyph. */
+ /* */
+ /* <Input> */
+ /* render_mode :: A set of bit flags that describe how the data is */
+ /* */
+ /* */
+ /* origin :: A pointer to a vector used to translate the glyph */
+ /* image before rendering. Can be 0 (if no */
+ /* translation). The origin is expressed in */
+ /* 26.6 pixels. */
+ /* */
+ /* destroy :: A boolean that indicates that the original glyph */
+ /* image should be destroyed by this function. It is */
+ /* never destroyed in case of error. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The glyph image is translated with the `origin' vector before */
+ /* rendering. In case of error, it it translated back to its */
+ /* original position and the glyph is left untouched. */
+ /* */
+ /* The first parameter is a pointer to a FT_Glyph handle, that will */
+ /* be replaced by this function. Typically, you would use (omitting */
+ /* error handling): */
+ /* */
+ /* */
+ /* { */
+ /* FT_Glyph glyph; */
+ /* FT_BitmapGlyph glyph_bitmap; */
+ /* */
+ /* */
+ /* // load glyph */
+ /* error = FT_Load_Char( face, glyph_index, FT_LOAD_DEFAUT ); */
+ /* */
+ /* // extract glyph image */
+ /* error = FT_Get_Glyph( face->glyph, &glyph ); */
+ /* */
+ /* // convert to a bitmap (default render mode + destroy old) */
+ /* if ( glyph->format != ft_glyph_format_bitmap ) */
+ /* { */
+ /* error = FT_Glyph_To_Bitmap( &glyph, ft_render_mode_default, */
+ /* 0, 1 ); */
+ /* if ( error ) // glyph unchanged */
+ /* ... */
+ /* } */
+ /* */
+ /* // access bitmap content by typecasting */
+ /* glyph_bitmap = (FT_BitmapGlyph)glyph; */
+ /* */
+ /* // do funny stuff with it, like blitting/drawing */
+ /* ... */
+ /* */
+ /* // discard glyph image (bitmap or not) */
+ /* FT_Done_Glyph( glyph ); */
+ /* } */
+ /* */
+ /* */
+ /* This function will always fail if the glyph's format isn't */
+ /* scalable. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Glyph_To_Bitmap( FT_Glyph* the_glyph,
+ FT_ULong render_mode,
+ FT_Vector* origin,
+ FT_Bool destroy );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Done_Glyph */
+ /* */
+ /* <Description> */
+ /* Destroys a given glyph. */
+ /* */
+ /* <Input> */
+ /* glyph :: A handle to the target glyph object. */
+ /* */
+ FT_EXPORT( void )
+ FT_Done_Glyph( FT_Glyph glyph );
+
+
+ /* other helpful functions */
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* computations */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Matrix_Multiply */
+ /* */
+ /* <Description> */
+ /* Performs the matrix operation `b = a*b'. */
+ /* */
+ /* <Input> */
+ /* a :: A pointer to matrix `a'. */
+ /* */
+ /* <InOut> */
+ /* b :: A pointer to matrix `b'. */
+ /* */
+ /* <Note> */
+ /* The result is undefined if either `a' or `b' is zero. */
+ /* */
+ FT_EXPORT( void )
+ FT_Matrix_Multiply( FT_Matrix* a,
+ FT_Matrix* b );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Matrix_Invert */
+ /* */
+ /* <Description> */
+ /* Inverts a 2x2 matrix. Returns an error if it can't be inverted. */
+ /* */
+ /* <InOut> */
+ /* matrix :: A pointer to the target matrix. Remains untouched in */
+ /* case of error. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Matrix_Invert( FT_Matrix* matrix );
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FTGLYPH_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftimage.h */
+/* */
+/* FreeType glyph image formats and default raster interface */
+/* (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* Note: A `raster' is simply a scan-line converter, used to render */
+ /* FT_Outlines into FT_Bitmaps. */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef __FTIMAGE_H__
+#define __FTIMAGE_H__
+
+
+#include <ft2build.h>
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* basic_types */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Pos */
+ /* */
+ /* <Description> */
+ /* The type FT_Pos is a 32-bit integer used to store vectorial */
+ /* coordinates. Depending on the context, these can represent */
+ /* distances in integer font units, or 26.6 fixed float pixel */
+ /* coordinates. */
+ /* */
+ typedef signed long FT_Pos;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Vector */
+ /* */
+ /* <Description> */
+ /* A simple structure used to store a 2D vector; coordinates are of */
+ /* the FT_Pos type. */
+ /* */
+ /* <Fields> */
+ /* x :: The horizontal coordinate. */
+ /* y :: The vertical coordinate. */
+ /* */
+ typedef struct FT_Vector_
+ {
+ FT_Pos x;
+ FT_Pos y;
+
+ } FT_Vector;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_BBox */
+ /* */
+ /* <Description> */
+ /* A structure used to hold an outline's bounding box, i.e., the */
+ /* coordinates of its extrema in the horizontal and vertical */
+ /* directions. */
+ /* */
+ /* <Fields> */
+ /* xMin :: The horizontal minimum (left-most). */
+ /* */
+ /* yMin :: The vertical minimum (bottom-most). */
+ /* */
+ /* xMax :: The horizontal maximum (right-most). */
+ /* */
+ /* yMax :: The vertical maximum (top-most). */
+ /* */
+ typedef struct FT_BBox_
+ {
+ FT_Pos xMin, yMin;
+ FT_Pos xMax, yMax;
+
+ } FT_BBox;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_Pixel_Mode */
+ /* */
+ /* <Description> */
+ /* An enumeration type used to describe the format of pixels in a */
+ /* given bitmap. Note that additional formats may be added in the */
+ /* future. */
+ /* */
+ /* <Fields> */
+ /* ft_pixel_mode_mono :: A monochrome bitmap (1 bit/pixel). */
+ /* */
+ /* ft_pixel_mode_grays :: An 8-bit gray-levels bitmap. Note that the */
+ /* total number of gray levels is given in the */
+ /* `num_grays' field of the FT_Bitmap */
+ /* structure. */
+ /* */
+ /* ft_pixel_mode_pal2 :: A 2-bit paletted bitmap. */
+ /* Currently unused by FreeType. */
+ /* */
+ /* ft_pixel_mode_pal4 :: A 4-bit paletted bitmap. */
+ /* Currently unused by FreeType. */
+ /* */
+ /* ft_pixel_mode_pal8 :: An 8-bit paletted bitmap. */
+ /* Currently unused by FreeType. */
+ /* */
+ /* ft_pixel_mode_rgb15 :: A 15-bit RGB bitmap. Uses 5:5:5 encoding. */
+ /* Currently unused by FreeType. */
+ /* */
+ /* ft_pixel_mode_rgb16 :: A 16-bit RGB bitmap. Uses 5:6:5 encoding. */
+ /* Currently unused by FreeType. */
+ /* */
+ /* ft_pixel_mode_rgb24 :: A 24-bit RGB bitmap. */
+ /* Currently unused by FreeType. */
+ /* */
+ /* ft_pixel_mode_rgb32 :: A 32-bit RGB bitmap. */
+ /* Currently unused by FreeType. */
+ /* */
+ /* <Note> */
+ /* Some anti-aliased bitmaps might be embedded in TrueType fonts */
+ /* using formats pal2 or pal4, though no fonts presenting those have */
+ /* been found to date. */
+ /* */
+ typedef enum FT_Pixel_Mode_
+ {
+ ft_pixel_mode_none = 0,
+ ft_pixel_mode_mono,
+ ft_pixel_mode_grays,
+ ft_pixel_mode_pal2,
+ ft_pixel_mode_pal4,
+ ft_pixel_mode_pal8,
+ ft_pixel_mode_rgb15,
+ ft_pixel_mode_rgb16,
+ ft_pixel_mode_rgb24,
+ ft_pixel_mode_rgb32,
+
+ ft_pixel_mode_max /* do not remove */
+
+ } FT_Pixel_Mode;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_Palette_Mode */
+ /* */
+ /* <Description> */
+ /* An enumeration type used to describe the format of a bitmap */
+ /* palette, used with ft_pixel_mode_pal4 and ft_pixel_mode_pal8. */
+ /* */
+ /* <Fields> */
+ /* ft_palette_mode_rgb :: The palette is an array of 3-bytes RGB */
+ /* records. */
+ /* */
+ /* ft_palette_mode_rgba :: The palette is an array of 4-bytes RGBA */
+ /* records. */
+ /* */
+ /* <Note> */
+ /* As ft_pixel_mode_pal2, pal4 and pal8 are currently unused by */
+ /* FreeType, these types are not handled by the library itself. */
+ /* */
+ typedef enum FT_Palette_Mode_
+ {
+ ft_palette_mode_rgb = 0,
+ ft_palette_mode_rgba,
+
+ ft_palettte_mode_max /* do not remove */
+
+ } FT_Palette_Mode;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Bitmap */
+ /* */
+ /* <Description> */
+ /* A structure used to describe a bitmap or pixmap to the raster. */
+ /* Note that we now manage pixmaps of various depths through the */
+ /* `pixel_mode' field. */
+ /* */
+ /* <Fields> */
+ /* rows :: The number of bitmap rows. */
+ /* */
+ /* width :: The number of pixels in bitmap row. */
+ /* */
+ /* pitch :: The pitch's absolute value is the number of bytes */
+ /* taken by one bitmap row, including padding. */
+ /* However, the pitch is positive when the bitmap has */
+ /* a `down' flow, and negative when it has an `up' */
+ /* flow. In all cases, the pitch is an offset to add */
+ /* to a bitmap pointer in order to go down one row. */
+ /* */
+ /* buffer :: A typeless pointer to the bitmap buffer. This */
+ /* value should be aligned on 32-bit boundaries in */
+ /* most cases. */
+ /* */
+ /* num_grays :: This field is only used with */
+ /* `ft_pixel_mode_grays'; it gives the number of gray */
+ /* levels used in the bitmap. */
+ /* */
+ /* pixel_mode :: The pixel_mode, i.e., how pixel bits are stored. */
+ /* */
+ /* palette_mode :: This field is only used with paletted pixel modes; */
+ /* it indicates how the palette is stored. */
+ /* */
+ /* palette :: A typeless pointer to the bitmap palette; only */
+ /* used for paletted pixel modes. */
+ /* */
+ /* <Note> */
+ /* For now, the only pixel mode supported by FreeType are mono and */
+ /* grays. However, drivers might be added in the future to support */
+ /* more `colorful' options. */
+ /* */
+ /* When using pixel modes pal2, pal4 and pal8 with a void `palette' */
+ /* field, a gray pixmap with respectively 4, 16, and 256 levels of */
+ /* gray is assumed. This, in order to be compatible with some */
+ /* embedded bitmap formats defined in the TrueType specification. */
+ /* */
+ /* Note that no font was found presenting such embedded bitmaps, so */
+ /* this is currently completely unhandled by the library. */
+ /* */
+ typedef struct FT_Bitmap_
+ {
+ int rows;
+ int width;
+ int pitch;
+ unsigned char* buffer;
+ short num_grays;
+ char pixel_mode;
+ char palette_mode;
+ void* palette;
+
+ } FT_Bitmap;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* outline_processing */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Outline */
+ /* */
+ /* <Description> */
+ /* This structure is used to describe an outline to the scan-line */
+ /* converter. */
+ /* */
+ /* <Fields> */
+ /* n_contours :: The number of contours in the outline. */
+ /* */
+ /* n_points :: The number of points in the outline. */
+ /* */
+ /* points :: A pointer to an array of `n_points' FT_Vector */
+ /* elements, giving the outline's point coordinates. */
+ /* */
+ /* tags :: A pointer to an array of `n_points' chars, giving */
+ /* each outline point's type. If bit 0 is unset, the */
+ /* point is `off' the curve, i.e. a Bezier control */
+ /* point, while it is `on' when set. */
+ /* */
+ /* Bit 1 is meaningful for `off' points only. If set, */
+ /* it indicates a third-order Bezier arc control point; */
+ /* and a second-order control point if unset. */
+ /* */
+ /* contours :: An array of `n_contours' shorts, giving the end */
+ /* point of each contour within the outline. For */
+ /* example, the first contour is defined by the points */
+ /* `0' to `contours[0]', the second one is defined by */
+ /* the points `contours[0]+1' to `contours[1]', etc. */
+ /* */
+ /* flags :: A set of bit flags used to characterize the outline */
+ /* and give hints to the scan-converter and hinter on */
+ /* how to convert/grid-fit it. See FT_Outline_Flags. */
+ /* */
+ typedef struct FT_Outline_
+ {
+ short n_contours; /* number of contours in glyph */
+ short n_points; /* number of points in the glyph */
+
+ FT_Vector* points; /* the outline's points */
+ char* tags; /* the points flags */
+ short* contours; /* the contour end points */
+
+ int flags; /* outline masks */
+
+ } FT_Outline;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_Outline_Flags */
+ /* */
+ /* <Description> */
+ /* A simple type used to enumerates the flags in an outline's */
+ /* `outline_flags' field. */
+ /* */
+ /* <Fields> */
+ /* ft_outline_owner :: If set, this flag indicates that the */
+ /* outline's field arrays (i.e. */
+ /* `points', `flags' & `contours') are */
+ /* `owned' by the outline object, and */
+ /* should thus be freed when it is */
+ /* destroyed. */
+ /* */
+ /* ft_outline_even_odd_fill :: By default, outlines are filled using */
+ /* the non-zero winding rule. If set to */
+ /* 1, the outline will be filled using */
+ /* the even-odd fill rule (only works */
+ /* with the smooth raster). */
+ /* */
+ /* ft_outline_reverse_fill :: By default, outside contours of an */
+ /* outline are oriented in clock-wise */
+ /* direction, as defined in the TrueType */
+ /* specification. This flag is set if */
+ /* the outline uses the opposite */
+ /* direction (typically for Type 1 */
+ /* fonts). This flag is ignored by the */
+ /* scan-converter. However, it is very */
+ /* important for the auto-hinter. */
+ /* */
+ /* ft_outline_ignore_dropouts :: By default, the scan converter will */
+ /* try to detect drop-outs in an outline */
+ /* and correct the glyph bitmap to */
+ /* ensure consistent shape continuity. */
+ /* If set, this flag hints the scan-line */
+ /* converter to ignore such cases. */
+ /* */
+ /* ft_outline_high_precision :: This flag indicates that the */
+ /* scan-line converter should try to */
+ /* convert this outline to bitmaps with */
+ /* the highest possible quality. It is */
+ /* typically set for small character */
+ /* sizes. Note that this is only a */
+ /* hint, that might be completely */
+ /* ignored by a given scan-converter. */
+ /* */
+ /* ft_outline_single_pass :: This flag is set to force a given */
+ /* scan-converter to only use a single */
+ /* pass over the outline to render a */
+ /* bitmap glyph image. Normally, it is */
+ /* set for very large character sizes. */
+ /* It is only a hint, that might be */
+ /* completely ignored by a given */
+ /* scan-converter. */
+ /* */
+ typedef enum FT_Outline_Flags_
+ {
+ ft_outline_none = 0,
+ ft_outline_owner = 1,
+ ft_outline_even_odd_fill = 2,
+ ft_outline_reverse_fill = 4,
+ ft_outline_ignore_dropouts = 8,
+ ft_outline_high_precision = 256,
+ ft_outline_single_pass = 512
+
+ } FT_Outline_Flags;
+
+ /* */
+
+#define FT_CURVE_TAG( flag ) ( flag & 3 )
+
+#define FT_Curve_Tag_On 1
+#define FT_Curve_Tag_Conic 0
+#define FT_Curve_Tag_Cubic 2
+
+#define FT_Curve_Tag_Touch_X 8 /* reserved for the TrueType hinter */
+#define FT_Curve_Tag_Touch_Y 16 /* reserved for the TrueType hinter */
+
+#define FT_Curve_Tag_Touch_Both ( FT_Curve_Tag_Touch_X | \
+ FT_Curve_Tag_Touch_Y )
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Outline_MoveTo_Func */
+ /* */
+ /* <Description> */
+ /* A function pointer type used to describe the signature of a `move */
+ /* to' function during outline walking/decomposition. */
+ /* */
+ /* A `move to' is emitted to start a new contour in an outline. */
+ /* */
+ /* <Input> */
+ /* to :: A pointer to the target point of the `move to'. */
+ /* */
+ /* user :: A typeless pointer which is passed from the caller of the */
+ /* decomposition function. */
+ /* */
+ /* <Return> */
+ /* Error code. 0 means success. */
+ /* */
+ typedef int
+ (*FT_Outline_MoveTo_Func)( FT_Vector* to,
+ void* user );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Outline_LineTo_Func */
+ /* */
+ /* <Description> */
+ /* A function pointer type used to describe the signature of a `line */
+ /* to' function during outline walking/decomposition. */
+ /* */
+ /* A `line to' is emitted to indicate a segment in the outline. */
+ /* */
+ /* <Input> */
+ /* to :: A pointer to the target point of the `line to'. */
+ /* */
+ /* user :: A typeless pointer which is passed from the caller of the */
+ /* decomposition function. */
+ /* */
+ /* <Return> */
+ /* Error code. 0 means success. */
+ /* */
+ typedef int
+ (*FT_Outline_LineTo_Func)( FT_Vector* to,
+ void* user );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Outline_ConicTo_Func */
+ /* */
+ /* <Description> */
+ /* A function pointer type use to describe the signature of a `conic */
+ /* to' function during outline walking/decomposition. */
+ /* */
+ /* A `conic to' is emitted to indicate a second-order Bezier arc in */
+ /* the outline. */
+ /* */
+ /* <Input> */
+ /* control :: An intermediate control point between the last position */
+ /* and the new target in `to'. */
+ /* */
+ /* to :: A pointer to the target end point of the conic arc. */
+ /* */
+ /* user :: A typeless pointer which is passed from the caller of */
+ /* the decomposition function. */
+ /* */
+ /* <Return> */
+ /* Error code. 0 means success. */
+ /* */
+ typedef int
+ (*FT_Outline_ConicTo_Func)( FT_Vector* control,
+ FT_Vector* to,
+ void* user );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Outline_CubicTo_Func */
+ /* */
+ /* <Description> */
+ /* A function pointer type used to describe the signature of a `cubic */
+ /* to' function during outline walking/decomposition. */
+ /* */
+ /* A `cubic to' is emitted to indicate a third-order Bezier arc. */
+ /* */
+ /* <Input> */
+ /* control1 :: A pointer to the first Bezier control point. */
+ /* */
+ /* control2 :: A pointer to the second Bezier control point. */
+ /* */
+ /* to :: A pointer to the target end point. */
+ /* */
+ /* user :: A typeless pointer which is passed from the caller of */
+ /* the decomposition function. */
+ /* */
+ /* <Return> */
+ /* Error code. 0 means success. */
+ /* */
+ typedef int
+ (*FT_Outline_CubicTo_Func)( FT_Vector* control1,
+ FT_Vector* control2,
+ FT_Vector* to,
+ void* user );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Outline_Funcs */
+ /* */
+ /* <Description> */
+ /* A structure to hold various function pointers used during outline */
+ /* decomposition in order to emit segments, conic, and cubic Beziers, */
+ /* as well as `move to' and `close to' operations. */
+ /* */
+ /* <Fields> */
+ /* move_to :: The `move to' emitter. */
+ /* */
+ /* line_to :: The segment emitter. */
+ /* */
+ /* conic_to :: The second-order Bezier arc emitter. */
+ /* */
+ /* cubic_to :: The third-order Bezier arc emitter. */
+ /* */
+ /* shift :: The shift that is applied to coordinates before they */
+ /* are sent to the emitter. */
+ /* */
+ /* delta :: The delta that is applied to coordinates before they */
+ /* are sent to the emitter, but after the shift. */
+ /* */
+ /* <Note> */
+ /* The point coordinates sent to the emitters are the transformed */
+ /* version of the original coordinates (this is important for high */
+ /* accuracy during scan-conversion). The transformation is simple: */
+ /* */
+ /* x' = (x << shift) - delta */
+ /* y' = (x << shift) - delta */
+ /* */
+ /* Set the value of `shift' and `delta' to 0 to get the original */
+ /* point coordinates. */
+ /* */
+ typedef struct FT_Outline_Funcs_
+ {
+ FT_Outline_MoveTo_Func move_to;
+ FT_Outline_LineTo_Func line_to;
+ FT_Outline_ConicTo_Func conic_to;
+ FT_Outline_CubicTo_Func cubic_to;
+
+ int shift;
+ FT_Pos delta;
+
+ } FT_Outline_Funcs;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* basic_types */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Macro> */
+ /* FT_IMAGE_TAG */
+ /* */
+ /* <Description> */
+ /* This macro converts four letter tags into an unsigned long. */
+ /* */
+#ifndef FT_IMAGE_TAG
+#define FT_IMAGE_TAG( value, _x1, _x2, _x3, _x4 ) \
+ value = ( ( (unsigned long)_x1 << 24 ) | \
+ ( (unsigned long)_x2 << 16 ) | \
+ ( (unsigned long)_x3 << 8 ) | \
+ (unsigned long)_x4 )
+#endif /* FT_IMAGE_TAG */
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_Glyph_Format */
+ /* */
+ /* <Description> */
+ /* An enumeration type used to describe the format of a given glyph */
+ /* image. Note that this version of FreeType only supports two image */
+ /* formats, even though future font drivers will be able to register */
+ /* their own format. */
+ /* */
+ /* <Fields> */
+ /* ft_glyph_format_composite :: The glyph image is a composite of */
+ /* several other images. This glyph */
+ /* format is _only_ used with the */
+ /* FT_LOAD_FLAG_NO_RECURSE flag (XXX: */
+ /* Which is currently unimplemented). */
+ /* */
+ /* ft_glyph_format_bitmap :: The glyph image is a bitmap, and can */
+ /* be described as a FT_Bitmap. */
+ /* */
+ /* ft_glyph_format_outline :: The glyph image is a vectorial image */
+ /* made of bezier control points, and */
+ /* can be described as a FT_Outline. */
+ /* */
+ /* ft_glyph_format_plotter :: The glyph image is a vectorial image */
+ /* made of plotter lines (some T1 fonts */
+ /* like Hershey contain glyph in this */
+ /* format). */
+ /* */
+ typedef enum FT_Glyph_Format_
+ {
+ FT_IMAGE_TAG( ft_glyph_format_none, 0, 0, 0, 0 ),
+
+ FT_IMAGE_TAG( ft_glyph_format_composite, 'c', 'o', 'm', 'p' ),
+ FT_IMAGE_TAG( ft_glyph_format_bitmap, 'b', 'i', 't', 's' ),
+ FT_IMAGE_TAG( ft_glyph_format_outline, 'o', 'u', 't', 'l' ),
+ FT_IMAGE_TAG( ft_glyph_format_plotter, 'p', 'l', 'o', 't' )
+
+ } FT_Glyph_Format;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** R A S T E R D E F I N I T I O N S *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* A raster is a scan converter, in charge of rendering an outline into */
+ /* a a bitmap. This section contains the public API for rasters. */
+ /* */
+ /* Note that in FreeType 2, all rasters are now encapsulated within */
+ /* specific modules called `renderers'. See `freetype/ftrender.h' for */
+ /* more details on renderers. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* Raster */
+ /* */
+ /* <Title> */
+ /* Scanline converter */
+ /* */
+ /* <Abstract> */
+ /* How vectorial outlines are converted into bitmaps and pixmaps. */
+ /* */
+ /* <Description> */
+ /* This section contains technical definitions. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Raster */
+ /* */
+ /* <Description> */
+ /* A handle (pointer) to a raster object. Each object can be used */
+ /* independently to convert an outline into a bitmap or pixmap. */
+ /* */
+ typedef struct FT_RasterRec_* FT_Raster;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Span */
+ /* */
+ /* <Description> */
+ /* A structure used to model a single span of gray (or black) pixels */
+ /* when rendering a monochrome or anti-aliased bitmap. */
+ /* */
+ /* <Fields> */
+ /* x :: The span's horizontal start position. */
+ /* */
+ /* len :: The span's length in pixels. */
+ /* */
+ /* coverage :: The span color/coverage, ranging from 0 (background) */
+ /* to 255 (foreground). Only used for anti-aliased */
+ /* rendering. */
+ /* */
+ /* <Note> */
+ /* This structure is used by the span drawing callback type named */
+ /* FT_Raster_Span_Func(), which takes the y-coordinate of the span as */
+ /* a parameter. */
+ /* */
+ /* The coverage value is always between 0 and 255, even if the number */
+ /* of gray levels have been set through FT_Set_Gray_Levels(). */
+ /* */
+ typedef struct FT_Span_
+ {
+ short x;
+ unsigned short len;
+ unsigned char coverage;
+
+ } FT_Span;
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Raster_Span_Func */
+ /* */
+ /* <Description> */
+ /* A function used as a call-back by the anti-aliased renderer in */
+ /* order to let client applications draw themselves the gray pixel */
+ /* spans on each scan line. */
+ /* */
+ /* <Input> */
+ /* y :: The scanline's y-coordinate. */
+ /* */
+ /* count :: The number of spans to draw on this scanline. */
+ /* */
+ /* spans :: A table of `count' spans to draw on the scanline. */
+ /* */
+ /* user :: User-supplied data that is passed to the callback. */
+ /* */
+ /* <Note> */
+ /* This callback allows client applications to directly render the */
+ /* gray spans of the anti-aliased bitmap to any kind of surfaces. */
+ /* */
+ /* This can be used to write anti-aliased outlines directly to a */
+ /* given background bitmap, and even perform translucency. */
+ /* */
+ /* Note that the `count' field cannot be greater than a fixed value */
+ /* defined by the FT_MAX_GRAY_SPANS configuration macro in */
+ /* ftoption.h. By default, this value is set to 32, which means that */
+ /* if there are more than 32 spans on a given scanline, the callback */
+ /* will be called several times with the same `y' parameter in order */
+ /* to draw all callbacks. */
+ /* */
+ /* Otherwise, the callback is only called once per scan-line, and */
+ /* only for those scanlines that do have `gray' pixels on them. */
+ /* */
+ typedef void
+ (*FT_Raster_Span_Func)( int y,
+ int count,
+ FT_Span* spans,
+ void* user );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Raster_BitTest_Func */
+ /* */
+ /* <Description> */
+ /* A function used as a call-back by the monochrome scan-converter */
+ /* to test whether a given target pixel is already set to the drawing */
+ /* `color'. These tests are crucial to implement drop-out control */
+ /* per-se the TrueType spec. */
+ /* */
+ /* <Input> */
+ /* y :: The pixel's y-coordinate. */
+ /* */
+ /* x :: The pixel's x-coordinate. */
+ /* */
+ /* user :: User-supplied data that is passed to the callback. */
+ /* */
+ /* <Return> */
+ /* 1 if the pixel is `set', 0 otherwise. */
+ /* */
+ typedef int
+ (*FT_Raster_BitTest_Func)( int y,
+ int x,
+ void* user );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Raster_BitSet_Func */
+ /* */
+ /* <Description> */
+ /* A function used as a call-back by the monochrome scan-converter */
+ /* to set an individual target pixel. This is crucial to implement */
+ /* drop-out control according to the TrueType specification. */
+ /* */
+ /* <Input> */
+ /* y :: The pixel's y-coordinate. */
+ /* */
+ /* x :: The pixel's x-coordinate. */
+ /* */
+ /* user :: User-supplied data that is passed to the callback. */
+ /* */
+ /* <Return> */
+ /* 1 if the pixel is `set', 0 otherwise. */
+ /* */
+ typedef void
+ (*FT_Raster_BitSet_Func)( int y,
+ int x,
+ void* user );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* FT_Raster_Flag */
+ /* */
+ /* <Description> */
+ /* An enumeration to list the bit flags as used in the `flags' field */
+ /* of a FT_Raster_Params structure. */
+ /* */
+ /* <Fields> */
+ /* ft_raster_flag_default :: This value is 0. */
+ /* */
+ /* ft_raster_flag_aa :: This flag is set to indicate that an */
+ /* anti-aliased glyph image should be */
+ /* generated. Otherwise, it will be */
+ /* monochrome (1-bit) */
+ /* */
+ /* ft_raster_flag_direct :: This flag is set to indicate direct */
+ /* rendering. In this mode, client */
+ /* applications must provide their own span */
+ /* callback. This lets them directly */
+ /* draw or compose over an existing bitmap. */
+ /* If this bit is not set, the target */
+ /* pixmap's buffer _must_ be zeroed before */
+ /* rendering. */
+ /* */
+ /* Note that for now, direct rendering is */
+ /* only possible with anti-aliased glyphs. */
+ /* */
+ /* ft_raster_flag_clip :: This flag is only used in direct */
+ /* rendering mode. If set, the output will */
+ /* be clipped to a box specified in the */
+ /* "clip_box" field of the FT_Raster_Params */
+ /* structure. */
+ /* */
+ /* Note that by default, the glyph bitmap */
+ /* is clipped to the target pixmap, except */
+ /* in direct rendering mode where all spans */
+ /* are generated if no clipping box is set. */
+ /* */
+ typedef enum
+ {
+ ft_raster_flag_default = 0,
+ ft_raster_flag_aa = 1,
+ ft_raster_flag_direct = 2,
+ ft_raster_flag_clip = 4
+
+ } FT_Raster_Flag;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Raster_Params */
+ /* */
+ /* <Description> */
+ /* A structure to hold the arguments used by a raster's render */
+ /* function. */
+ /* */
+ /* <Fields> */
+ /* target :: The target bitmap. */
+ /* */
+ /* source :: A pointer to the source glyph image (e.g. an */
+ /* FT_Outline). */
+ /* */
+ /* flags :: The rendering flags. */
+ /* */
+ /* gray_spans :: The gray span drawing callback. */
+ /* */
+ /* black_spans :: The black span drawing callback. */
+ /* */
+ /* bit_test :: The bit test callback. */
+ /* */
+ /* bit_set :: The bit set callback. */
+ /* */
+ /* user :: User-supplied data that is passed to each drawing */
+ /* callback. */
+ /* */
+ /* clip_box :: an optional clipping box. It is only used in */
+ /* direct rendering mode */
+ /* */
+ /* <Note> */
+ /* An anti-aliased glyph bitmap is drawn if the ft_raster_flag_aa bit */
+ /* flag is set in the `flags' field, otherwise a monochrome bitmap */
+ /* will be generated. */
+ /* */
+ /* If the ft_raster_flag_direct bit flag is set in `flags', the */
+ /* raster will call the `gray_spans' callback to draw gray pixel */
+ /* spans, in the case of an aa glyph bitmap, it will call */
+ /* `black_spans', and `bit_test' and `bit_set' in the case of a */
+ /* monochrome bitmap. This allows direct composition over a */
+ /* pre-existing bitmap through user-provided callbacks to perform the */
+ /* span drawing/composition. */
+ /* */
+ /* Note that the `bit_test' and `bit_set' callbacks are required when */
+ /* rendering a monochrome bitmap, as they are crucial to implement */
+ /* correct drop-out control as defined in the TrueType specification. */
+ /* */
+ typedef struct FT_Raster_Params_
+ {
+ FT_Bitmap* target;
+ void* source;
+ int flags;
+ FT_Raster_Span_Func gray_spans;
+ FT_Raster_Span_Func black_spans;
+ FT_Raster_BitTest_Func bit_test;
+ FT_Raster_BitSet_Func bit_set;
+ void* user;
+ FT_BBox clip_box;
+
+ } FT_Raster_Params;
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Raster_New_Func */
+ /* */
+ /* <Description> */
+ /* A function used to create a new raster object. */
+ /* */
+ /* <Input> */
+ /* memory :: A handle to the memory allocator. */
+ /* */
+ /* <Output> */
+ /* raster :: A handle to the new raster object. */
+ /* */
+ /* <Return> */
+ /* Error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The `memory' parameter is a typeless pointer in order to avoid */
+ /* un-wanted dependencies on the rest of the FreeType code. In */
+ /* practice, it is a FT_Memory, i.e., a handle to the standard */
+ /* FreeType memory allocator. However, this field can be completely */
+ /* ignored by a given raster implementation. */
+ /* */
+ typedef int
+ (*FT_Raster_New_Func)( void* memory,
+ FT_Raster* raster );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Raster_Done_Func */
+ /* */
+ /* <Description> */
+ /* A function used to destroy a given raster object. */
+ /* */
+ /* <Input> */
+ /* raster :: A handle to the raster object. */
+ /* */
+ typedef void
+ (*FT_Raster_Done_Func)( FT_Raster raster );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Raster_Reset_Func */
+ /* */
+ /* <Description> */
+ /* FreeType provides an area of memory called the `render pool', */
+ /* available to all registered rasters. This pool can be freely used */
+ /* during a given scan-conversion but is shared by all rasters. Its */
+ /* content is thus transient. */
+ /* */
+ /* This function is called each time the render pool changes, or just */
+ /* after a new raster object is created. */
+ /* */
+ /* <Input> */
+ /* raster :: A handle to the new raster object. */
+ /* */
+ /* pool_base :: The address in memory of the render pool. */
+ /* */
+ /* pool_size :: The size in bytes of the render pool. */
+ /* */
+ /* <Note> */
+ /* Rasters can ignore the render pool and rely on dynamic memory */
+ /* allocation if they want to (a handle to the memory allocator is */
+ /* passed to the raster constructor). However, this is not */
+ /* recommended for efficiency purposes. */
+ /* */
+ typedef void
+ (*FT_Raster_Reset_Func)( FT_Raster raster,
+ unsigned char* pool_base,
+ unsigned long pool_size );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Raster_Set_Mode_Func */
+ /* */
+ /* <Description> */
+ /* This function is a generic facility to change modes or attributes */
+ /* in a given raster. This can be used for debugging purposes, or */
+ /* simply to allow implementation-specific `features' in a given */
+ /* raster module. */
+ /* */
+ /* <Input> */
+ /* raster :: A handle to the new raster object. */
+ /* */
+ /* mode :: A 4-byte tag used to name the mode or property. */
+ /* */
+ /* args :: A pointer to the new mode/property to use. */
+ /* */
+ typedef int
+ (*FT_Raster_Set_Mode_Func)( FT_Raster raster,
+ unsigned long mode,
+ void* args );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Raster_Render_Func */
+ /* */
+ /* <Description> */
+ /* Invokes a given raster to scan-convert a given glyph image into a */
+ /* target bitmap. */
+ /* */
+ /* <Input> */
+ /* raster :: A handle to the raster object. */
+ /* */
+ /* params :: A pointer to a FT_Raster_Params structure used to store */
+ /* the rendering parameters. */
+ /* */
+ /* <Return> */
+ /* Error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The exact format of the source image depends on the raster's glyph */
+ /* format defined in its FT_Raster_Funcs structure. It can be an */
+ /* FT_Outline or anything else in order to support a large array of */
+ /* glyph formats. */
+ /* */
+ /* Note also that the render function can fail and return a */
+ /* FT_Err_Unimplemented_Feature error code if the raster used does */
+ /* not support direct composition. */
+ /* */
+ /* XXX: For now, the standard raster doesn't support direct */
+ /* composition but this should change for the final release (see */
+ /* the files demos/src/ftgrays.c and demos/src/ftgrays2.c for */
+ /* examples of distinct implementations which support direct */
+ /* composition). */
+ /* */
+ typedef int
+ (*FT_Raster_Render_Func)( FT_Raster raster,
+ FT_Raster_Params* params );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Raster_Funcs */
+ /* */
+ /* <Description> */
+ /* A structure used to describe a given raster class to the library. */
+ /* */
+ /* <Fields> */
+ /* glyph_format :: The supported glyph format for this raster. */
+ /* */
+ /* raster_new :: The raster constructor. */
+ /* */
+ /* raster_reset :: Used to reset the render pool within the raster. */
+ /* */
+ /* raster_render :: A function to render a glyph into a given bitmap. */
+ /* */
+ /* raster_done :: The raster destructor. */
+ /* */
+ typedef struct FT_Raster_Funcs_
+ {
+ FT_Glyph_Format glyph_format;
+ FT_Raster_New_Func raster_new;
+ FT_Raster_Reset_Func raster_reset;
+ FT_Raster_Set_Mode_Func raster_set_mode;
+ FT_Raster_Render_Func raster_render;
+ FT_Raster_Done_Func raster_done;
+
+ } FT_Raster_Funcs;
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FTIMAGE_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftlist.h */
+/* */
+/* Generic list support for FreeType (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file implements functions relative to list processing. Its */
+ /* data structures are defined in `freetype.h'. */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef __FTLIST_H__
+#define __FTLIST_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* list_processing */
+ /* */
+ /* <Title> */
+ /* List Processing */
+ /* */
+ /* <Abstract> */
+ /* Simple management of lists. */
+ /* */
+ /* <Description> */
+ /* This section contains various definitions related to list */
+ /* processing using doubly-linked nodes. */
+ /* */
+ /* <Order> */
+ /* FT_List */
+ /* FT_ListNode */
+ /* FT_ListRec */
+ /* FT_ListNodeRec */
+ /* */
+ /* FT_List_Add */
+ /* FT_List_Insert */
+ /* FT_List_Find */
+ /* FT_List_Remove */
+ /* FT_List_Up */
+ /* FT_List_Iterate */
+ /* FT_List_Iterator */
+ /* FT_List_Finalize */
+ /* FT_List_Destructor */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_List_Find */
+ /* */
+ /* <Description> */
+ /* Finds the list node for a given listed object. */
+ /* */
+ /* <Input> */
+ /* list :: A pointer to the parent list. */
+ /* data :: The address of the listed object. */
+ /* */
+ /* <Return> */
+ /* List node. NULL if it wasn't found. */
+ /* */
+ FT_EXPORT( FT_ListNode )
+ FT_List_Find( FT_List list,
+ void* data );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_List_Add */
+ /* */
+ /* <Description> */
+ /* Appends an element to the end of a list. */
+ /* */
+ /* <InOut> */
+ /* list :: A pointer to the parent list. */
+ /* node :: The node to append. */
+ /* */
+ FT_EXPORT( void )
+ FT_List_Add( FT_List list,
+ FT_ListNode node );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_List_Insert */
+ /* */
+ /* <Description> */
+ /* Inserts an element at the head of a list. */
+ /* */
+ /* <InOut> */
+ /* list :: A pointer to parent list. */
+ /* node :: The node to insert. */
+ /* */
+ FT_EXPORT( void )
+ FT_List_Insert( FT_List list,
+ FT_ListNode node );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_List_Remove */
+ /* */
+ /* <Description> */
+ /* Removes a node from a list. This function doesn't check whether */
+ /* the node is in the list! */
+ /* */
+ /* <Input> */
+ /* node :: The node to remove. */
+ /* */
+ /* <InOut> */
+ /* list :: A pointer to the parent list. */
+ /* */
+ FT_EXPORT( void )
+ FT_List_Remove( FT_List list,
+ FT_ListNode node );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_List_Up */
+ /* */
+ /* <Description> */
+ /* Moves a node to the head/top of a list. Used to maintain LRU */
+ /* lists. */
+ /* */
+ /* <InOut> */
+ /* list :: A pointer to the parent list. */
+ /* node :: The node to move. */
+ /* */
+ FT_EXPORT( void )
+ FT_List_Up( FT_List list,
+ FT_ListNode node );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_List_Iterator */
+ /* */
+ /* <Description> */
+ /* An FT_List iterator function which is called during a list parse */
+ /* by FT_List_Iterate(). */
+ /* */
+ /* <Input> */
+ /* node :: The current iteration list node. */
+ /* */
+ /* user :: A typeless pointer passed to FT_List_Iterate(). */
+ /* Can be used to point to the iteration's state. */
+ /* */
+ typedef FT_Error
+ (*FT_List_Iterator)( FT_ListNode node,
+ void* user );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_List_Iterate */
+ /* */
+ /* <Description> */
+ /* Parses a list and calls a given iterator function on each element. */
+ /* Note that parsing is stopped as soon as one of the iterator calls */
+ /* returns a non-zero value. */
+ /* */
+ /* <Input> */
+ /* list :: A handle to the list. */
+ /* iterator :: An interator function, called on each node of the */
+ /* list. */
+ /* user :: A user-supplied field which is passed as the second */
+ /* argument to the iterator. */
+ /* */
+ /* <Return> */
+ /* The result (a FreeType error code) of the last iterator call. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_List_Iterate( FT_List list,
+ FT_List_Iterator iterator,
+ void* user );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_List_Destructor */
+ /* */
+ /* <Description> */
+ /* An FT_List iterator function which is called during a list */
+ /* finalization by FT_List_Finalize() to destroy all elements in a */
+ /* given list. */
+ /* */
+ /* <Input> */
+ /* system :: The current system object. */
+ /* */
+ /* data :: The current object to destroy. */
+ /* */
+ /* user :: A typeless pointer passed to FT_List_Iterate(). It can */
+ /* be used to point to the iteration's state. */
+ /* */
+ typedef void
+ (*FT_List_Destructor)( FT_Memory memory,
+ void* data,
+ void* user );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_List_Finalize */
+ /* */
+ /* <Description> */
+ /* Destroys all elements in the list as well as the list itself. */
+ /* */
+ /* <Input> */
+ /* list :: A handle to the list. */
+ /* */
+ /* destroy :: A list destructor that will be applied to each element */
+ /* of the list. */
+ /* */
+ /* memory :: The current memory object which handles deallocation. */
+ /* */
+ /* user :: A user-supplied field which is passed as the last */
+ /* argument to the destructor. */
+ /* */
+ FT_EXPORT( void )
+ FT_List_Finalize( FT_List list,
+ FT_List_Destructor destroy,
+ FT_Memory memory,
+ void* user );
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FTLIST_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftmac.h */
+/* */
+/* Additional Mac-specific API. */
+/* */
+/* Copyright 1996-2001 by */
+/* Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+/***************************************************************************/
+/* */
+/* NOTE: Include this file after <freetype/freetype.h> and after the */
+/* Mac-specific <Types.h> header (or any other Mac header that */
+/* includes <Types.h>); we use Handle type. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FT_MAC_H__
+#define __FT_MAC_H__
+
+
+#include <ft2build.h>
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* mac_specific */
+ /* */
+ /* <Title> */
+ /* Mac-Specific Interface */
+ /* */
+ /* <Abstract> */
+ /* Only available on the Macintosh. */
+ /* */
+ /* <Description> */
+ /* The following definitions are only available if FreeType is */
+ /* compiled on a Macintosh. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_New_Face_From_FOND */
+ /* */
+ /* <Description> */
+ /* Creates a new face object from an FOND resource. */
+ /* */
+ /* <InOut> */
+ /* library :: A handle to the library resource. */
+ /* */
+ /* <Input> */
+ /* fond :: An FOND resource. */
+ /* */
+ /* face_index :: Only supported for the -1 `sanity check' special */
+ /* case. */
+ /* */
+ /* <Output> */
+ /* aface :: A handle to a new face object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Notes> */
+ /* This function can be used to create FT_Face abjects from fonts */
+ /* that are installed in the system like so: */
+ /* */
+ /* { */
+ /* fond = GetResource( 'FOND', fontName ); */
+ /* error = FT_New_Face_From_FOND( library, fond, 0, &face ); */
+ /* } */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_New_Face_From_FOND( FT_Library library,
+ Handle fond,
+ FT_Long face_index,
+ FT_Face *aface );
+
+
+ /* */
+
+
+FT_END_HEADER
+
+
+#endif /* __FT_MAC_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftmm.h */
+/* */
+/* FreeType Multiple Master font interface (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTMM_H__
+#define __FTMM_H__
+
+
+#include <ft2build.h>
+#include FT_TYPE1_TABLES_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* multiple_masters */
+ /* */
+ /* <Title> */
+ /* Multiple Masters */
+ /* */
+ /* <Abstract> */
+ /* How to manage Multiple Masters fonts. */
+ /* */
+ /* <Description> */
+ /* The following types and functions are used to manage Multiple */
+ /* Master fonts, i.e. the selection of specific design instances by */
+ /* setting design axis coordinates. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_MM_Axis */
+ /* */
+ /* <Description> */
+ /* A simple structure used to model a given axis in design space for */
+ /* Multiple Masters fonts. */
+ /* */
+ /* <Fields> */
+ /* name :: The axis's name. */
+ /* */
+ /* minimum :: The axis's minimum design coordinate. */
+ /* */
+ /* maximum :: The axis's maximum design coordinate. */
+ /* */
+ typedef struct FT_MM_Axis_
+ {
+ FT_String* name;
+ FT_Long minimum;
+ FT_Long maximum;
+
+ } FT_MM_Axis;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Multi_Master */
+ /* */
+ /* <Description> */
+ /* A structure used to model the axes and space of a Multiple Masters */
+ /* font. */
+ /* */
+ /* <Fields> */
+ /* num_axis :: Number of axes. Cannot exceed 4. */
+ /* */
+ /* num_designs :: Number of designs; should ne normally 2^num_axis */
+ /* even though the Type 1 specification strangely */
+ /* allows for intermediate designs to be present. This */
+ /* number cannot exceed 16. */
+ /* */
+ /* axis :: A table of axis descriptors. */
+ /* */
+ typedef struct FT_Multi_Master_
+ {
+ FT_UInt num_axis;
+ FT_UInt num_designs;
+ FT_MM_Axis axis[T1_MAX_MM_AXIS];
+
+ } FT_Multi_Master;
+
+ /* */
+
+ typedef FT_Error
+ (*FT_Get_MM_Func)( FT_Face face,
+ FT_Multi_Master* master );
+
+ typedef FT_Error
+ (*FT_Set_MM_Design_Func)( FT_Face face,
+ FT_UInt num_coords,
+ FT_Long* coords );
+
+ typedef FT_Error
+ (*FT_Set_MM_Blend_Func)( FT_Face face,
+ FT_UInt num_coords,
+ FT_Long* coords );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Multi_Master */
+ /* */
+ /* <Description> */
+ /* Retrieves the Multiple Master descriptor of a given font. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face. */
+ /* */
+ /* <Output> */
+ /* amaster :: The Multiple Masters descriptor. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Get_Multi_Master( FT_Face face,
+ FT_Multi_Master *amaster );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Set_MM_Design_Coordinates */
+ /* */
+ /* <Description> */
+ /* For Multiple Masters fonts, choose an interpolated font design */
+ /* through design coordinates. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the source face. */
+ /* */
+ /* <Input> */
+ /* num_coords :: The number of design coordinates (must be equal to */
+ /* the number of axes in the font). */
+ /* */
+ /* coords :: An array of design coordinates. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Set_MM_Design_Coordinates( FT_Face face,
+ FT_UInt num_coords,
+ FT_Long* coords );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Set_MM_Blend_Coordinates */
+ /* */
+ /* <Description> */
+ /* For Multiple Masters fonts, choose an interpolated font design */
+ /* through normalized blend coordinates. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the source face. */
+ /* */
+ /* <Input> */
+ /* num_coords :: The number of design coordinates (must be equal to */
+ /* the number of axes in the font). */
+ /* */
+ /* coords :: The design coordinates array (each element must be */
+ /* between 0 and 1.0). */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Set_MM_Blend_Coordinates( FT_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords );
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FTMM_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftmoderr.h */
+/* */
+/* FreeType module error offsets (specification). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the FreeType module error offsets. */
+ /* */
+ /* The lower byte gives the error code, the higher byte gives the */
+ /* module. The base module has error offset 0. For example, the error */
+ /* `FT_Err_Invalid_File_Format' has value 0x003, the error */
+ /* `TT_Err_Invalid_File_Format' has value 0xB03, the error */
+ /* `T1_Err_Invalid_File_Format' has value 0xC03, etc. */
+ /* */
+ /* Undefine the macro FT_CONFIG_OPTION_USE_MODULE_ERRORS in ftoption.h */
+ /* to make the higher byte always zero (disabling the module error */
+ /* mechanism). */
+ /* */
+ /* It can also be used to create a module error message table easily */
+ /* with something like */
+ /* */
+ /* { */
+ /* #undef __FTMODERR_H__ */
+ /* #define FT_MODERRDEF( e, v, s ) { FT_Mod_Err_ ## e, s }, */
+ /* #define FT_MODERR_START_LIST { */
+ /* #define FT_MODERR_END_LIST { 0, 0 } }; */
+ /* */
+ /* const struct */
+ /* { */
+ /* int mod_err_offset; */
+ /* const char* mod_err_msg */
+ /* } ft_mod_errors[] = */
+ /* */
+ /* #include FT_MODULE_ERRORS_H */
+ /* } */
+ /* */
+ /* To use such a table, all errors must be ANDed with 0xFF00 to remove */
+ /* the error code. */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef __FTMODERR_H__
+#define __FTMODERR_H__
+
+
+ /*******************************************************************/
+ /*******************************************************************/
+ /***** *****/
+ /***** SETUP MACROS *****/
+ /***** *****/
+ /*******************************************************************/
+ /*******************************************************************/
+
+
+#undef FT_NEED_EXTERN_C
+
+#ifndef FT_MODERRDEF
+
+#ifdef FT_CONFIG_OPTION_USE_MODULE_ERRORS
+#define FT_MODERRDEF( e, v, s ) FT_Mod_Err_ ## e = v,
+#else
+#define FT_MODERRDEF( e, v, s ) FT_Mod_Err_ ## e = 0,
+#endif
+
+#define FT_MODERR_START_LIST enum {
+#define FT_MODERR_END_LIST FT_Mod_Err_Max };
+
+#ifdef __cplusplus
+#define FT_NEED_EXTERN_C
+ extern "C" {
+#endif
+
+#endif /* !FT_MODERRDEF */
+
+
+ /*******************************************************************/
+ /*******************************************************************/
+ /***** *****/
+ /***** LIST MODULE ERROR BASES *****/
+ /***** *****/
+ /*******************************************************************/
+ /*******************************************************************/
+
+
+#ifdef FT_MODERR_START_LIST
+ FT_MODERR_START_LIST
+#endif
+
+
+ FT_MODERRDEF( Base, 0x000, "base module" )
+ FT_MODERRDEF( Autohint, 0x100, "autohinter module" )
+ FT_MODERRDEF( Cache, 0x200, "cache module" )
+ FT_MODERRDEF( CFF, 0x300, "CFF module" )
+ FT_MODERRDEF( CID, 0x400, "CID module" )
+ FT_MODERRDEF( PCF, 0x500, "PCF module" )
+ FT_MODERRDEF( PSaux, 0x600, "PS auxiliary module" )
+ FT_MODERRDEF( PSnames, 0x700, "PS names module" )
+ FT_MODERRDEF( Raster, 0x800, "raster module" )
+ FT_MODERRDEF( SFNT, 0x900, "SFNT module" )
+ FT_MODERRDEF( Smooth, 0xA00, "smooth raster module" )
+ FT_MODERRDEF( TrueType, 0xB00, "TrueType module" )
+ FT_MODERRDEF( Type1, 0xC00, "Type 1 module" )
+ FT_MODERRDEF( Winfonts, 0xD00, "Windows FON/FNT module" )
+
+
+#ifdef FT_MODERR_END_LIST
+ FT_MODERR_END_LIST
+#endif
+
+
+ /*******************************************************************/
+ /*******************************************************************/
+ /***** *****/
+ /***** CLEANUP *****/
+ /***** *****/
+ /*******************************************************************/
+ /*******************************************************************/
+
+
+#ifdef FT_NEED_EXTERN_C
+ }
+#endif
+
+#undef FT_MODERR_START_LIST
+#undef FT_MODERR_END_LIST
+#undef FT_MODERRDEF
+#undef FT_NEED_EXTERN_C
+
+
+#endif /* __FTMODERR_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftmodule.h */
+/* */
+/* FreeType modules public interface (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTMODULE_H__
+#define __FTMODULE_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* module_management */
+ /* */
+ /* <Title> */
+ /* Module Management */
+ /* */
+ /* <Abstract> */
+ /* How to add, upgrade, and remove modules from FreeType. */
+ /* */
+ /* <Description> */
+ /* The definitions below are used to manage modules within FreeType. */
+ /* Modules can be added, upgraded, and removed at runtime. */
+ /* */
+ /*************************************************************************/
+
+
+ /* module bit flags */
+ typedef enum FT_Module_Flags_
+ {
+ ft_module_font_driver = 1, /* this module is a font driver */
+ ft_module_renderer = 2, /* this module is a renderer */
+ ft_module_hinter = 4, /* this module is a glyph hinter */
+ ft_module_styler = 8, /* this module is a styler */
+
+ ft_module_driver_scalable = 0x100, /* the driver supports scalable */
+ /* fonts */
+ ft_module_driver_no_outlines = 0x200, /* the driver does not support */
+ /* vector outlines */
+ ft_module_driver_has_hinter = 0x400 /* the driver provides its own */
+ /* hinter */
+
+ } FT_Module_Flags;
+
+
+ typedef void
+ (*FT_Module_Interface)( void );
+
+ typedef FT_Error
+ (*FT_Module_Constructor)( FT_Module module );
+
+ typedef void
+ (*FT_Module_Destructor)( FT_Module module );
+
+ typedef FT_Module_Interface
+ (*FT_Module_Requester)( FT_Module module,
+ const char* name );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Module_Class */
+ /* */
+ /* <Description> */
+ /* The module class descriptor. */
+ /* */
+ /* <Fields> */
+ /* module_flags :: Bit flags describing the module. */
+ /* */
+ /* module_size :: The size of one module object/instance in */
+ /* bytes. */
+ /* */
+ /* module_name :: The name of the module. */
+ /* */
+ /* module_version :: The version, as a 16.16 fixed number */
+ /* (major.minor). */
+ /* */
+ /* module_requires :: The version of FreeType this module requires */
+ /* (starts at version 2.0, i.e 0x20000) */
+ /* */
+ /* module_init :: A function used to initialize (not create) a */
+ /* new module object. */
+ /* */
+ /* module_done :: A function used to finalize (not destroy) a */
+ /* given module object */
+ /* */
+ /* get_interface :: Queries a given module for a specific */
+ /* interface by name. */
+ /* */
+ typedef struct FT_Module_Class_
+ {
+ FT_ULong module_flags;
+ FT_Int module_size;
+ const FT_String* module_name;
+ FT_Fixed module_version;
+ FT_Fixed module_requires;
+
+ const void* module_interface;
+
+ FT_Module_Constructor module_init;
+ FT_Module_Destructor module_done;
+ FT_Module_Requester get_interface;
+
+ } FT_Module_Class;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Add_Module */
+ /* */
+ /* <Description> */
+ /* Adds a new module to a given library instance. */
+ /* */
+ /* <InOut> */
+ /* library :: A handle to the library object. */
+ /* */
+ /* <Input> */
+ /* clazz :: A pointer to class descriptor for the module. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* An error will be returned if a module already exists by that name, */
+ /* or if the module requires a version of FreeType that is too great. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Add_Module( FT_Library library,
+ const FT_Module_Class* clazz );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Module */
+ /* */
+ /* <Description> */
+ /* Finds a module by its name. */
+ /* */
+ /* <Input> */
+ /* library :: A handle to the library object. */
+ /* */
+ /* module_name :: The module's name (as an ASCII string). */
+ /* */
+ /* <Return> */
+ /* A module handle. 0 if none was found. */
+ /* */
+ /* <Note> */
+ /* You should better be familiar with FreeType internals to know */
+ /* which module to look for :-) */
+ /* */
+ FT_EXPORT( FT_Module )
+ FT_Get_Module( FT_Library library,
+ const char* module_name );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Remove_Module */
+ /* */
+ /* <Description> */
+ /* Removes a given module from a library instance. */
+ /* */
+ /* <InOut> */
+ /* library :: A handle to a library object. */
+ /* */
+ /* <Input> */
+ /* module :: A handle to a module object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The module object is destroyed by the function in case of success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Remove_Module( FT_Library library,
+ FT_Module module );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_New_Library */
+ /* */
+ /* <Description> */
+ /* This function is used to create a new FreeType library instance */
+ /* from a given memory object. It is thus possible to use libraries */
+ /* with distinct memory allocators within the same program. */
+ /* */
+ /* <Input> */
+ /* memory :: A handle to the original memory object. */
+ /* */
+ /* <Output> */
+ /* alibrary :: A pointer to handle of a new library object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_New_Library( FT_Memory memory,
+ FT_Library *alibrary );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Done_Library */
+ /* */
+ /* <Description> */
+ /* Discards a given library object. This closes all drivers and */
+ /* discards all resource objects. */
+ /* */
+ /* <Input> */
+ /* library :: A handle to the target library. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Done_Library( FT_Library library );
+
+
+
+ typedef void
+ (*FT_DebugHook_Func)( void* arg );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Set_Debug_Hook */
+ /* */
+ /* <Description> */
+ /* Sets a debug hook function for debugging the interpreter of a font */
+ /* format. */
+ /* */
+ /* <InOut> */
+ /* library :: A handle to the library object. */
+ /* */
+ /* <Input> */
+ /* hook_index :: The index of the debug hook. You should use the */
+ /* values defined in ftobjs.h, e.g. */
+ /* FT_DEBUG_HOOK_TRUETYPE. */
+ /* */
+ /* debug_hook :: The function used to debug the interpreter. */
+ /* */
+ /* <Note> */
+ /* Currently, four debug hook slots are available, but only two (for */
+ /* the TrueType and the Type 1 interpreter) are defined. */
+ /* */
+ FT_EXPORT( void )
+ FT_Set_Debug_Hook( FT_Library library,
+ FT_UInt hook_index,
+ FT_DebugHook_Func debug_hook );
+
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Add_Default_Modules */
+ /* */
+ /* <Description> */
+ /* Adds the set of default drivers to a given library object. */
+ /* This is only useful when you create a library object with */
+ /* FT_New_Library() (usually to plug a custom memory manager). */
+ /* */
+ /* <InOut> */
+ /* library :: A handle to a new library object. */
+ /* */
+ FT_EXPORT( void )
+ FT_Add_Default_Modules( FT_Library library );
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FTMODULE_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftoutln.h */
+/* */
+/* Support for the FT_Outline type used to store glyph shapes of */
+/* most scalable font formats (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTOUTLN_H__
+#define __FTOUTLN_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* outline_processing */
+ /* */
+ /* <Title> */
+ /* Outline Processing */
+ /* */
+ /* <Abstract> */
+ /* Functions to create, transform, and render vectorial glyph images. */
+ /* */
+ /* <Description> */
+ /* This section contains routines used to create and destroy scalable */
+ /* glyph images known as `outlines'. These can also be measured, */
+ /* transformed, and converted into bitmaps and pixmaps. */
+ /* */
+ /* <Order> */
+ /* FT_Outline */
+ /* FT_Outline_Flags */
+ /* FT_Outline_New */
+ /* FT_Outline_Done */
+ /* FT_Outline_Copy */
+ /* FT_Outline_Translate */
+ /* FT_Outline_Transform */
+ /* FT_Outline_Reverse */
+ /* */
+ /* FT_Outline_Get_CBox */
+ /* FT_Outline_Get_BBox */
+ /* */
+ /* FT_Outline_Get_Bitmap */
+ /* FT_Outline_Render */
+ /* */
+ /* FT_Outline_Decompose */
+ /* FT_Outline_Funcs */
+ /* FT_Outline_MoveTo_Func */
+ /* FT_Outline_LineTo_Func */
+ /* FT_Outline_ConicTo_Func */
+ /* FT_Outline_CubicTo_Func */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Decompose */
+ /* */
+ /* <Description> */
+ /* Walks over an outline's structure to decompose it into individual */
+ /* segments and Bezier arcs. This function is also able to emit */
+ /* `move to' and `close to' operations to indicate the start and end */
+ /* of new contours in the outline. */
+ /* */
+ /* <Input> */
+ /* outline :: A pointer to the source target. */
+ /* */
+ /* interface :: A table of `emitters', i.e,. function pointers called */
+ /* during decomposition to indicate path operations. */
+ /* */
+ /* <InOut> */
+ /* user :: A typeless pointer which is passed to each emitter */
+ /* during the decomposition. It can be used to store */
+ /* the state during the decomposition. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means sucess. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Outline_Decompose( FT_Outline* outline,
+ const FT_Outline_Funcs* interface,
+ void* user );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_New */
+ /* */
+ /* <Description> */
+ /* Creates a new outline of a given size. */
+ /* */
+ /* <Input> */
+ /* library :: A handle to the library object from where the */
+ /* outline is allocated. Note however that the new */
+ /* outline will NOT necessarily be FREED, when */
+ /* destroying the library, by FT_Done_FreeType(). */
+ /* */
+ /* numPoints :: The maximal number of points within the outline. */
+ /* */
+ /* numContours :: The maximal number of contours within the outline. */
+ /* */
+ /* <Output> */
+ /* anoutline :: A handle to the new outline. NULL in case of */
+ /* error. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The reason why this function takes a `library' parameter is simply */
+ /* to use the library's memory allocator. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Outline_New( FT_Library library,
+ FT_UInt numPoints,
+ FT_Int numContours,
+ FT_Outline *anoutline );
+
+
+ FT_EXPORT( FT_Error )
+ FT_Outline_New_Internal( FT_Memory memory,
+ FT_UInt numPoints,
+ FT_Int numContours,
+ FT_Outline *anoutline );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Done */
+ /* */
+ /* <Description> */
+ /* Destroys an outline created with FT_Outline_New(). */
+ /* */
+ /* <Input> */
+ /* library :: A handle of the library object used to allocate the */
+ /* outline. */
+ /* */
+ /* outline :: A pointer to the outline object to be discarded. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* If the outline's `owner' field is not set, only the outline */
+ /* descriptor will be released. */
+ /* */
+ /* The reason why this function takes an `library' parameter is */
+ /* simply to use FT_Free(). */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Outline_Done( FT_Library library,
+ FT_Outline* outline );
+
+
+ FT_EXPORT( FT_Error )
+ FT_Outline_Done_Internal( FT_Memory memory,
+ FT_Outline* outline );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Get_CBox */
+ /* */
+ /* <Description> */
+ /* Returns an outline's `control box'. The control box encloses all */
+ /* the outline's points, including Bezier control points. Though it */
+ /* coincides with the exact bounding box for most glyphs, it can be */
+ /* slightly larger in some situations (like when rotating an outline */
+ /* which contains Bezier outside arcs). */
+ /* */
+ /* Computing the control box is very fast, while getting the bounding */
+ /* box can take much more time as it needs to walk over all segments */
+ /* and arcs in the outline. To get the latter, you can use the */
+ /* `ftbbox' component which is dedicated to this single task. */
+ /* */
+ /* <Input> */
+ /* outline :: A pointer to the source outline descriptor. */
+ /* */
+ /* <Output> */
+ /* acbox :: The outline's control box. */
+ /* */
+ FT_EXPORT( void )
+ FT_Outline_Get_CBox( FT_Outline* outline,
+ FT_BBox *acbox );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Translate */
+ /* */
+ /* <Description> */
+ /* Applies a simple translation to the points of an outline. */
+ /* */
+ /* <InOut> */
+ /* outline :: A pointer to the target outline descriptor. */
+ /* */
+ /* <Input> */
+ /* xOffset :: The horizontal offset. */
+ /* */
+ /* yOffset :: The vertical offset. */
+ /* */
+ FT_EXPORT( void )
+ FT_Outline_Translate( FT_Outline* outline,
+ FT_Pos xOffset,
+ FT_Pos yOffset );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Copy */
+ /* */
+ /* <Description> */
+ /* Copies an outline into another one. Both objects must have the */
+ /* same sizes (number of points & number of contours) when this */
+ /* function is called. */
+ /* */
+ /* <Input> */
+ /* source :: A handle to the source outline. */
+ /* */
+ /* <Output> */
+ /* target :: A handle to the target outline. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Outline_Copy( FT_Outline* source,
+ FT_Outline *target );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Transform */
+ /* */
+ /* <Description> */
+ /* Applies a simple 2x2 matrix to all of an outline's points. Useful */
+ /* for applying rotations, slanting, flipping, etc. */
+ /* */
+ /* <InOut> */
+ /* outline :: A pointer to the target outline descriptor. */
+ /* */
+ /* <Input> */
+ /* matrix :: A pointer to the transformation matrix. */
+ /* */
+ /* <Note> */
+ /* You can use FT_Outline_Translate() if you need to translate the */
+ /* outline's points. */
+ /* */
+ FT_EXPORT( void )
+ FT_Outline_Transform( FT_Outline* outline,
+ FT_Matrix* matrix );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Reverse */
+ /* */
+ /* <Description> */
+ /* Reverses the drawing direction of an outline. This is used to */
+ /* ensure consistent fill conventions for mirrored glyphs. */
+ /* */
+ /* <InOut> */
+ /* outline :: A pointer to the target outline descriptor. */
+ /* */
+ /* <Note> */
+ /* This functions toggles the bit flag `ft_outline_reverse_fill' in */
+ /* the outline's `flags' field. */
+ /* */
+ /* It shouldn't be used by a normal client application, unless it */
+ /* knows what it is doing. */
+ /* */
+ FT_EXPORT( void )
+ FT_Outline_Reverse( FT_Outline* outline );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Get_Bitmap */
+ /* */
+ /* <Description> */
+ /* Renders an outline within a bitmap. The outline's image is simply */
+ /* OR-ed to the target bitmap. */
+ /* */
+ /* <Input> */
+ /* library :: A handle to a FreeType library object. */
+ /* */
+ /* outline :: A pointer to the source outline descriptor. */
+ /* */
+ /* <Output> */
+ /* abitmap :: A pointer to the target bitmap descriptor. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* This function does NOT CREATE the bitmap, it only renders an */
+ /* outline image within the one you pass to it! */
+ /* */
+ /* It will use the raster correponding to the default glyph format. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Outline_Get_Bitmap( FT_Library library,
+ FT_Outline* outline,
+ FT_Bitmap *abitmap );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Outline_Render */
+ /* */
+ /* <Description> */
+ /* Renders an outline within a bitmap using the current scan-convert. */
+ /* This functions uses an FT_Raster_Params structure as an argument, */
+ /* allowing advanced features like direct composition, translucency, */
+ /* etc. */
+ /* */
+ /* <Input> */
+ /* library :: A handle to a FreeType library object. */
+ /* */
+ /* outline :: A pointer to the source outline descriptor. */
+ /* */
+ /* <InOut> */
+ /* params :: A pointer to a FT_Raster_Params structure used to */
+ /* describe the rendering operation. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* You should know what you are doing and how FT_Raster_Params works */
+ /* to use this function. */
+ /* */
+ /* The field `params.source' will be set to `outline' before the scan */
+ /* converter is called, which means that the value you give to it is */
+ /* actually ignored. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Outline_Render( FT_Library library,
+ FT_Outline* outline,
+ FT_Raster_Params* params );
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FTOUTLN_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftrender.h */
+/* */
+/* FreeType renderer modules public interface (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTRENDER_H__
+#define __FTRENDER_H__
+
+
+#include <ft2build.h>
+#include FT_MODULE_H
+#include FT_GLYPH_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* module_management */
+ /* */
+ /*************************************************************************/
+
+
+ /* create a new glyph object */
+ typedef FT_Error
+ (*FT_Glyph_Init_Func)( FT_Glyph glyph,
+ FT_GlyphSlot slot );
+
+ /* destroys a given glyph object */
+ typedef void
+ (*FT_Glyph_Done_Func)( FT_Glyph glyph );
+
+ typedef void
+ (*FT_Glyph_Transform_Func)( FT_Glyph glyph,
+ FT_Matrix* matrix,
+ FT_Vector* delta );
+
+ typedef void
+ (*FT_Glyph_BBox_Func)( FT_Glyph glyph,
+ FT_BBox* abbox );
+
+ typedef FT_Error
+ (*FT_Glyph_Copy_Func)( FT_Glyph source,
+ FT_Glyph target );
+
+ typedef FT_Error
+ (*FT_Glyph_Prepare_Func)( FT_Glyph glyph,
+ FT_GlyphSlot slot );
+
+
+ struct FT_Glyph_Class_
+ {
+ FT_UInt glyph_size;
+ FT_Glyph_Format glyph_format;
+ FT_Glyph_Init_Func glyph_init;
+ FT_Glyph_Done_Func glyph_done;
+ FT_Glyph_Copy_Func glyph_copy;
+ FT_Glyph_Transform_Func glyph_transform;
+ FT_Glyph_BBox_Func glyph_bbox;
+ FT_Glyph_Prepare_Func glyph_prepare;
+ };
+
+
+ typedef FT_Error
+ (*FTRenderer_render)( FT_Renderer renderer,
+ FT_GlyphSlot slot,
+ FT_UInt mode,
+ FT_Vector* origin );
+
+ typedef FT_Error
+ (*FTRenderer_transform)( FT_Renderer renderer,
+ FT_GlyphSlot slot,
+ FT_Matrix* matrix,
+ FT_Vector* delta );
+
+ typedef void
+ (*FTRenderer_getCBox)( FT_Renderer renderer,
+ FT_GlyphSlot slot,
+ FT_BBox* cbox );
+
+ typedef FT_Error
+ (*FTRenderer_setMode)( FT_Renderer renderer,
+ FT_ULong mode_tag,
+ FT_Pointer mode_ptr );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Renderer_Class */
+ /* */
+ /* <Description> */
+ /* The renderer module class descriptor. */
+ /* */
+ /* <Fields> */
+ /* root :: The root FT_Module_Class fields. */
+ /* */
+ /* glyph_format :: The glyph image format this renderer handles. */
+ /* */
+ /* render_glyph :: A method used to render the image that is in a */
+ /* given glyph slot into a bitmap. */
+ /* */
+ /* set_mode :: A method used to pass additional parameters. */
+ /* */
+ /* raster_class :: For `ft_glyph_format_outline' renderers only, this */
+ /* is a pointer to its raster's class. */
+ /* */
+ /* raster :: For `ft_glyph_format_outline' renderers only. this */
+ /* is a pointer to the corresponding raster object, */
+ /* if any. */
+ /* */
+ typedef struct FT_Renderer_Class_
+ {
+ FT_Module_Class root;
+
+ FT_Glyph_Format glyph_format;
+
+ FTRenderer_render render_glyph;
+ FTRenderer_transform transform_glyph;
+ FTRenderer_getCBox get_glyph_cbox;
+ FTRenderer_setMode set_mode;
+
+ FT_Raster_Funcs* raster_class;
+
+ } FT_Renderer_Class;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Renderer */
+ /* */
+ /* <Description> */
+ /* Retrieves the current renderer for a given glyph format. */
+ /* */
+ /* <Input> */
+ /* library :: A handle to the library object. */
+ /* */
+ /* format :: The glyph format. */
+ /* */
+ /* <Return> */
+ /* A renderer handle. 0 if none found. */
+ /* */
+ /* <Note> */
+ /* An error will be returned if a module already exists by that name, */
+ /* or if the module requires a version of FreeType that is too great. */
+ /* */
+ /* To add a new renderer, simply use FT_Add_Module(). To retrieve a */
+ /* renderer by its name, use FT_Get_Module(). */
+ /* */
+ FT_EXPORT( FT_Renderer )
+ FT_Get_Renderer( FT_Library library,
+ FT_Glyph_Format format );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Set_Renderer */
+ /* */
+ /* <Description> */
+ /* Sets the current renderer to use, and set additional mode. */
+ /* */
+ /* <InOut> */
+ /* library :: A handle to the library object. */
+ /* */
+ /* <Input> */
+ /* renderer :: A handle to the renderer object. */
+ /* */
+ /* num_params :: The number of additional parameters. */
+ /* */
+ /* parameters :: Additional parameters. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* In case of success, the renderer will be used to convert glyph */
+ /* images in the renderer's known format into bitmaps. */
+ /* */
+ /* This doesn't change the current renderer for other formats. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Set_Renderer( FT_Library library,
+ FT_Renderer renderer,
+ FT_UInt num_params,
+ FT_Parameter* parameters );
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FTRENDER_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftsizes.h */
+/* */
+/* FreeType size objects management (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* Typical application would normally not need to use these functions. */
+ /* However, they have been placed in a public API for the rare cases */
+ /* where they are needed. */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef __FTSIZES_H__
+#define __FTSIZES_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* sizes_management */
+ /* */
+ /* <Title> */
+ /* Size management */
+ /* */
+ /* <Abstract> */
+ /* Managing multiple sizes per face */
+ /* */
+ /* <Description> */
+ /* When creating a new face object (e.g. with @FT_New_Face), an */
+ /* @FT_Size object is automatically created and used to store all */
+ /* pixel-size dependent information, available in the "face->size" */
+ /* field. */
+ /* */
+ /* It is however possible to create more sizes for a given face, */
+ /* mostly in order to manage several character pixel sizes of the */
+ /* same font family and style. See @FT_New_Size and @FT_Done_Size. */
+ /* */
+ /* Note that @FT_Set_Pixel_Sizes and @FT_Set_Character_Size only */
+ /* modify the contents of the current "active" size; you thus need */
+ /* to use @FT_Activate_Size to change it. */
+ /* */
+ /* 99% of applications won't need the functions provided here, */
+ /* especially if they use the caching sub-system, so be cautious */
+ /* when using these. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_New_Size */
+ /* */
+ /* <Description> */
+ /* Creates a new size object from a given face object. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to a parent face object. */
+ /* */
+ /* <Output> */
+ /* asize :: A handle to a new size object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* You need to call @FT_Activate_Size in order to select the new size */
+ /* for upcoming calls to @FT_Set_Pixel_Sizes, @FT_Set_Char_Size, */
+ /* @FT_Load_Glyph, @FT_Load_Char, etc. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_New_Size( FT_Face face,
+ FT_Size* size );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Done_Size */
+ /* */
+ /* <Description> */
+ /* Discards a given size object. */
+ /* */
+ /* <Input> */
+ /* size :: A handle to a target size object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Done_Size( FT_Size size );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Activate_Size */
+ /* */
+ /* <Description> */
+ /* Even though it is possible to create several size objects for a */
+ /* given face (see @FT_New_Size for details), functions like */
+ /* @FT_Load_Glyph or @FT_Load_Char only use the last-created one to */
+ /* determine the "current character pixel size". */
+ /* */
+ /* This function can be used to "activate" a previously created size */
+ /* object. */
+ /* */
+ /* <Input> */
+ /* size :: A handle to a target size object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* If "face" is the size's parent face object, this function changes */
+ /* the value of "face->size" to the input size handle. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Activate_Size( FT_Size size );
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FTSIZES_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftsnames.h */
+/* */
+/* Simple interface to access SFNT name tables (which are used */
+/* to hold font names, copyright info, notices, etc.) (specification). */
+/* */
+/* This is _not_ used to retrieve glyph names! */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FT_SFNT_NAMES_H__
+#define __FT_SFNT_NAMES_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* sfnt_names */
+ /* */
+ /* <Title> */
+ /* SFNT Names */
+ /* */
+ /* <Abstract> */
+ /* Access the names embedded in TrueType and OpenType files. */
+ /* */
+ /* <Description> */
+ /* The TrueType and OpenType specification allow the inclusion of */
+ /* a special `names table' in font files. This table contains */
+ /* textual (and internationalized) information regarding the font, */
+ /* like family name, copyright, version, etc. */
+ /* */
+ /* The definitions below are used to access them if available. */
+ /* */
+ /* Note that this has nothing to do with glyph names! */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_SfntName */
+ /* */
+ /* <Description> */
+ /* A structure used to model an SFNT `name' table entry. */
+ /* */
+ /* <Fields> */
+ /* platform_id :: The platform ID for `string'. */
+ /* */
+ /* encoding_id :: The encoding ID for `string'. */
+ /* */
+ /* language_id :: The language ID for `string'. */
+ /* */
+ /* name_id :: An identifier for `string'. */
+ /* */
+ /* string :: The `name' string. Note that its format differs */
+ /* depending on the (platform,encoding) pair. It can */
+ /* be a Pascal String, a UTF-16 one, etc.. */
+ /* */
+ /* Generally speaking, the string is not */
+ /* zero-terminated. Please refer to the TrueType */
+ /* specification for details.. */
+ /* */
+ /* string_len :: The length of `string' in bytes. */
+ /* */
+ /* <Note> */
+ /* Possible values for `platform_id', `encoding_id', `language_id', */
+ /* and `name_id' are given in the file `ttnameid.h'. For details */
+ /* please refer to the TrueType or OpenType specification. */
+ /* */
+ typedef struct FT_SfntName_
+ {
+ FT_UShort platform_id;
+ FT_UShort encoding_id;
+ FT_UShort language_id;
+ FT_UShort name_id;
+
+ FT_Byte* string; /* this string is *not* null-terminated! */
+ FT_UInt string_len; /* in bytes */
+
+ } FT_SfntName;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Sfnt_Name_Count */
+ /* */
+ /* <Description> */
+ /* Retrieves the number of name strings in the SFNT `name' table. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face. */
+ /* */
+ /* <Return> */
+ /* The number of strings in the `name' table. */
+ /* */
+ FT_EXPORT( FT_UInt )
+ FT_Get_Sfnt_Name_Count( FT_Face face );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Sfnt_Name */
+ /* */
+ /* <Description> */
+ /* Retrieves a string of the SFNT `name' table for a given index. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face. */
+ /* */
+ /* index :: The index of the `name' string. */
+ /* */
+ /* <Output> */
+ /* aname :: The indexed FT_SfntName structure. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The `string' array returned in the `aname' structure is not */
+ /* null-terminated. */
+ /* */
+ /* Use FT_Get_Sfnt_Name_Count() to get the total number of available */
+ /* `name' table entries, then do a loop until you get the right */
+ /* platform, encoding, and name ID. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Get_Sfnt_Name( FT_Face face,
+ FT_UInt index,
+ FT_SfntName *aname );
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FT_SFNT_NAMES_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftsynth.h */
+/* */
+/* FreeType synthesizing code for emboldening and slanting */
+/* (specification). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********* *********/
+ /********* WARNING, THIS IS ALPHA CODE, THIS API *********/
+ /********* IS DUE TO CHANGE UNTIL STRICTLY NOTIFIED BY THE *********/
+ /********* FREETYPE DEVELOPMENT TEAM *********/
+ /********* *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#ifndef __FTSYNTH_H__
+#define __FTSYNTH_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+
+FT_BEGIN_HEADER
+
+
+ /* This code is completely experimental -- use with care! */
+ /* It will probably be completely rewritten in the future */
+ /* or even integrated into the library. */
+ FT_EXPORT( FT_Error )
+ FT_Outline_Embolden( FT_GlyphSlot original,
+ FT_Outline* outline,
+ FT_Pos* advance );
+
+ FT_EXPORT( FT_Error )
+ FT_Outline_Oblique( FT_GlyphSlot original,
+ FT_Outline* outline,
+ FT_Pos* advance );
+
+
+FT_END_HEADER
+
+#endif /* __FTSYNTH_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftsystem.h */
+/* */
+/* FreeType low-level system interface definition (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTSYSTEM_H__
+#define __FTSYSTEM_H__
+
+
+#include <ft2build.h>
+
+
+FT_BEGIN_HEADER
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* system_interface */
+ /* */
+ /* <Title> */
+ /* System Interface */
+ /* */
+ /* <Abstract> */
+ /* How FreeType manages memory and i/o. */
+ /* */
+ /* <Description> */
+ /* This section contains various definitions related to memory */
+ /* management and i/o access. You need to understand this */
+ /* information if you want to use a custom memory manager or you own */
+ /* input i/o streams. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* M E M O R Y M A N A G E M E N T */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* @type: */
+ /* FT_Memory */
+ /* */
+ /* @description: */
+ /* A handle to a given memory manager object, defined with a */
+ /* @FT_MemoryRec structure. */
+ /* */
+ typedef struct FT_MemoryRec_* FT_Memory;
+
+
+ /*************************************************************************/
+ /* */
+ /* @functype: */
+ /* FT_Alloc_Func */
+ /* */
+ /* @description: */
+ /* A function used to allocate `size' bytes from `memory'. */
+ /* */
+ /* @input: */
+ /* memory :: A handle to the source memory manager. */
+ /* */
+ /* size :: The size in bytes to allocate. */
+ /* */
+ /* @return: */
+ /* Address of new memory block. 0 in case of failure. */
+ /* */
+ typedef void*
+ (*FT_Alloc_Func)( FT_Memory memory,
+ long size );
+
+
+ /*************************************************************************/
+ /* */
+ /* @functype: */
+ /* FT_Free_Func */
+ /* */
+ /* @description: */
+ /* A function used to release a given block of memory. */
+ /* */
+ /* @input: */
+ /* memory :: A handle to the source memory manager. */
+ /* */
+ /* block :: The address of the target memory block. */
+ /* */
+ typedef void
+ (*FT_Free_Func)( FT_Memory memory,
+ void* block );
+
+
+ /*************************************************************************/
+ /* */
+ /* @functype: */
+ /* FT_Realloc_Func */
+ /* */
+ /* @description: */
+ /* a function used to re-allocate a given block of memory. */
+ /* */
+ /* @input: */
+ /* memory :: A handle to the source memory manager. */
+ /* */
+ /* cur_size :: The block's current size in bytes. */
+ /* */
+ /* new_size :: The block's requested new size. */
+ /* */
+ /* block :: The block's current address. */
+ /* */
+ /* @return: */
+ /* New block address. 0 in case of memory shortage. */
+ /* */
+ /* @note: */
+ /* In case of error, the old block must still be available. */
+ /* */
+ typedef void*
+ (*FT_Realloc_Func)( FT_Memory memory,
+ long cur_size,
+ long new_size,
+ void* block );
+
+
+ /*************************************************************************/
+ /* */
+ /* @struct: */
+ /* FT_MemoryRec */
+ /* */
+ /* @description: */
+ /* A structure used to describe a given memory manager to FreeType 2. */
+ /* */
+ /* @fields: */
+ /* user :: A generic typeless pointer for user data. */
+ /* */
+ /* alloc :: A pointer type to an allocation function. */
+ /* */
+ /* free :: A pointer type to an memory freeing function. */
+ /* */
+ /* realloc :: A pointer type to a reallocation function. */
+ /* */
+ struct FT_MemoryRec_
+ {
+ void* user;
+ FT_Alloc_Func alloc;
+ FT_Free_Func free;
+ FT_Realloc_Func realloc;
+ };
+
+
+ /*************************************************************************/
+ /* */
+ /* I / O M A N A G E M E N T */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* @type: */
+ /* FT_Stream */
+ /* */
+ /* @description: */
+ /* A handle to an input stream. */
+ /* */
+ typedef struct FT_StreamRec_* FT_Stream;
+
+
+ /*************************************************************************/
+ /* */
+ /* @struct: */
+ /* FT_StreamDesc */
+ /* */
+ /* @description: */
+ /* A union type used to store either a long or a pointer. This is */
+ /* used to store a file descriptor or a FILE* in an input stream. */
+ /* */
+ typedef union FT_StreamDesc_
+ {
+ long value;
+ void* pointer;
+
+ } FT_StreamDesc;
+
+
+ /*************************************************************************/
+ /* */
+ /* @functype: */
+ /* FT_Stream_IO */
+ /* */
+ /* @description: */
+ /* A function used to seek and read data from a given input stream. */
+ /* */
+ /* @input: */
+ /* stream :: A handle to the source stream. */
+ /* */
+ /* offset :: The offset of read in stream (always from start). */
+ /* */
+ /* buffer :: The address of the read buffer. */
+ /* */
+ /* count :: The number of bytes to read from the stream. */
+ /* */
+ /* @return: */
+ /* The number of bytes effectively read by the stream. */
+ /* */
+ /* @note: */
+ /* This function might be called to perform a seek or skip operation */
+ /* with a `count' of 0. */
+ /* */
+ typedef unsigned long
+ (*FT_Stream_IO)( FT_Stream stream,
+ unsigned long offset,
+ unsigned char* buffer,
+ unsigned long count );
+
+
+ /*************************************************************************/
+ /* */
+ /* @functype: */
+ /* FT_Stream_Close */
+ /* */
+ /* @description: */
+ /* A function used to close a given input stream. */
+ /* */
+ /* @input: */
+ /* stream :: A handle to the target stream. */
+ /* */
+ typedef void
+ (*FT_Stream_Close)( FT_Stream stream );
+
+
+ /*************************************************************************/
+ /* */
+ /* @struct: */
+ /* FT_StreamRec */
+ /* */
+ /* @description: */
+ /* A structure used to describe an input stream. */
+ /* */
+ /* @input: */
+ /* base :: For memory-based streams, this is the address of the */
+ /* first stream byte in memory. This field should */
+ /* always be set to NULL for disk-based streams. */
+ /* */
+ /* size :: The stream size in bytes. */
+ /* */
+ /* pos :: The current position within the stream. */
+ /* */
+ /* descriptor :: This field is a union that can hold an integer or a */
+ /* pointer. It is used by stream implementations to */
+ /* store file descriptors or FILE* pointers. */
+ /* */
+ /* pathname :: This field is completely ignored by FreeType. */
+ /* However, it is often useful during debugging to use */
+ /* it to store the stream's filename (where available). */
+ /* */
+ /* read :: The stream's input function. */
+ /* */
+ /* close :: The stream;s close function. */
+ /* */
+ /* memory :: The memory manager to use to preload frames. This is */
+ /* set internally by FreeType and shouldn't be touched */
+ /* by stream implementations. */
+ /* */
+ /* cursor :: This field is set and used internally by FreeType */
+ /* when parsing frames. */
+ /* */
+ /* limit :: This field is set and used internally by FreeType */
+ /* when parsing frames. */
+ /* */
+ struct FT_StreamRec_
+ {
+ unsigned char* base;
+ unsigned long size;
+ unsigned long pos;
+
+ FT_StreamDesc descriptor;
+ FT_StreamDesc pathname;
+ FT_Stream_IO read;
+ FT_Stream_Close close;
+
+ FT_Memory memory;
+ unsigned char* cursor;
+ unsigned char* limit;
+ };
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FTSYSTEM_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* fttrigon.h */
+/* */
+/* FreeType trigonometric functions (specification). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTTRIGON_H__
+#define __FTTRIGON_H__
+
+#include FT_FREETYPE_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 2*pi 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 :: The input angle. */
+ /* */
+ /* @return: */
+ /* The sinus value. */
+ /* */
+ /* @note: */
+ /* If you need both the sinus and cosinus for a given angle, 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 :: The input angle. */
+ /* */
+ /* @return: */
+ /* The cosinus value. */
+ /* */
+ /* @note: */
+ /* If you need both the sinus and cosinus for a given angle, 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 :: The input angle. */
+ /* */
+ /* @return: */
+ /* The 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 :: The horizontal vector coordinate. */
+ /* */
+ /* y :: The vertical vector coordinate. */
+ /* */
+ /* @return: */
+ /* The 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(angle)', 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. */
+ /* */
+ /* @output: */
+ /* vec :: The address of target vector. */
+ /* */
+ /* @input: */
+ /* angle :: The address of angle. */
+ /* */
+ FT_EXPORT( void )
+ FT_Vector_Unit( FT_Vector* vec,
+ FT_Angle angle );
+
+
+ /*************************************************************************/
+ /* */
+ /* @function: */
+ /* FT_Vector_Rotate */
+ /* */
+ /* @description: */
+ /* Rotate a vector by a given angle. */
+ /* */
+ /* @inout: */
+ /* vec :: The address of target vector. */
+ /* */
+ /* @input: */
+ /* angle :: The address of angle. */
+ /* */
+ FT_EXPORT( void )
+ FT_Vector_Rotate( FT_Vector* vec,
+ FT_Angle angle );
+
+
+ /*************************************************************************/
+ /* */
+ /* @function: */
+ /* FT_Vector_Length */
+ /* */
+ /* @description: */
+ /* Return the length of a given vector. */
+ /* */
+ /* @input: */
+ /* vec :: The address of target vector. */
+ /* */
+ /* @return: */
+ /* The 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). */
+ /* */
+ /* @inout: */
+ /* vec :: The 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 :: The address of source vector. */
+ /* */
+ /* @output: */
+ /* length :: The vector length. */
+ /* angle :: The vector angle. */
+ /* */
+ FT_EXPORT( void )
+ FT_Vector_Polarize( FT_Vector* vec,
+ FT_Fixed *length,
+ FT_Angle *angle );
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FTTRIGON_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* fttypes.h */
+/* */
+/* FreeType simple types definitions (specification only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTTYPES_H__
+#define __FTTYPES_H__
+
+
+#include <ft2build.h>
+#include FT_SYSTEM_H
+#include FT_IMAGE_H
+
+#include <stddef.h>
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* basic_types */
+ /* */
+ /* <Title> */
+ /* Basic Types */
+ /* */
+ /* <Abstract> */
+ /* The basic data types defined by the library. */
+ /* */
+ /* <Description> */
+ /* This section contains the basic data types defined by FreeType 2, */
+ /* ranging from simple scalar types to font specific ones. */
+ /* */
+ /* <Order> */
+ /* FT_Byte */
+ /* FT_Char */
+ /* FT_Int */
+ /* FT_UInt */
+ /* FT_Short */
+ /* FT_UShort */
+ /* FT_Long */
+ /* FT_ULong */
+ /* FT_Bool */
+ /* FT_Offset */
+ /* FT_PtrDist */
+ /* FT_Error */
+ /* FT_Fixed */
+ /* FT_Pointer */
+ /* FT_Pos */
+ /* FT_Vector */
+ /* FT_BBox */
+ /* FT_Matrix */
+ /* */
+ /* FT_Generic */
+ /* FT_Generic_Finalizer */
+ /* */
+ /* FT_Bitmap */
+ /* FT_Pixel_Mode */
+ /* FT_Palette_Mode */
+ /* FT_Glyph_Format */
+ /* FT_IMAGE_TAG */
+ /* FT_Glyph_Format */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Bool */
+ /* */
+ /* <Description> */
+ /* A typedef of unsigned char, used for simple booleans. */
+ /* */
+ typedef unsigned char FT_Bool;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_FWord */
+ /* */
+ /* <Description> */
+ /* A signed 16-bit integer used to store a distance in original font */
+ /* units. */
+ /* */
+ typedef signed short FT_FWord; /* distance in FUnits */
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_UFWord */
+ /* */
+ /* <Description> */
+ /* An unsigned 16-bit integer used to store a distance in original */
+ /* font units. */
+ /* */
+ typedef unsigned short FT_UFWord; /* unsigned distance */
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Char */
+ /* */
+ /* <Description> */
+ /* A simple typedef for the _signed_ char type. */
+ /* */
+ typedef signed char FT_Char;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Byte */
+ /* */
+ /* <Description> */
+ /* A simple typedef for the _unsigned_ char type. */
+ /* */
+ typedef unsigned char FT_Byte;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_String */
+ /* */
+ /* <Description> */
+ /* A simple typedef for the char type, usually used for strings. */
+ /* */
+ typedef char FT_String;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Short */
+ /* */
+ /* <Description> */
+ /* A typedef for signed short. */
+ /* */
+ typedef signed short FT_Short;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_UShort */
+ /* */
+ /* <Description> */
+ /* A typedef for unsigned short. */
+ /* */
+ typedef unsigned short FT_UShort;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Int */
+ /* */
+ /* <Description> */
+ /* A typedef for the int type. */
+ /* */
+ typedef int FT_Int;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_UInt */
+ /* */
+ /* <Description> */
+ /* A typedef for the unsigned int type. */
+ /* */
+ typedef unsigned int FT_UInt;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Long */
+ /* */
+ /* <Description> */
+ /* A typedef for signed long. */
+ /* */
+ typedef signed long FT_Long;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_ULong */
+ /* */
+ /* <Description> */
+ /* A typedef for unsigned long. */
+ /* */
+ typedef unsigned long FT_ULong;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_F2Dot14 */
+ /* */
+ /* <Description> */
+ /* A signed 2.14 fixed float type used for unit vectors. */
+ /* */
+ typedef signed short FT_F2Dot14;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_F26Dot6 */
+ /* */
+ /* <Description> */
+ /* A signed 26.6 fixed float type used for vectorial pixel */
+ /* coordinates. */
+ /* */
+ typedef signed long FT_F26Dot6;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Fixed */
+ /* */
+ /* <Description> */
+ /* This type is used to store 16.16 fixed float values, like scales */
+ /* or matrix coefficients. */
+ /* */
+ typedef signed long FT_Fixed;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Error */
+ /* */
+ /* <Description> */
+ /* The FreeType error code type. A value of 0 is always interpreted */
+ /* as a successful operation. */
+ /* */
+ typedef int FT_Error;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Pointer */
+ /* */
+ /* <Description> */
+ /* A simple typedef for a typeless pointer. */
+ /* */
+ typedef void* FT_Pointer;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_Offset */
+ /* */
+ /* <Description> */
+ /* This is equivalent to the ANSI C `size_t' type, i.e. the largest */
+ /* _unsigned_ integer type used to express a file size or position, */
+ /* or a memory block size. */
+ /* */
+ typedef size_t FT_Offset;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_PtrDist */
+ /* */
+ /* <Description> */
+ /* This is equivalent to the ANSI C `ptrdiff_t' type, i.e. the */
+ /* largest _signed_ integer type used to express the distance */
+ /* between two pointers. */
+ /* */
+ typedef size_t FT_PtrDist;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_UnitVector */
+ /* */
+ /* <Description> */
+ /* A simple structure used to store a 2D vector unit vector. Uses */
+ /* FT_F2Dot14 types. */
+ /* */
+ /* <Fields> */
+ /* x :: Horizontal coordinate. */
+ /* */
+ /* y :: Vertical coordinate. */
+ /* */
+ typedef struct FT_UnitVector_
+ {
+ FT_F2Dot14 x;
+ FT_F2Dot14 y;
+
+ } FT_UnitVector;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Matrix */
+ /* */
+ /* <Description> */
+ /* A simple structure used to store a 2x2 matrix. Coefficients are */
+ /* in 16.16 fixed float format. The computation performed is: */
+ /* */
+ /* { */
+ /* x' = x*xx + y*xy */
+ /* y' = x*yx + y*yy */
+ /* } */
+ /* */
+ /* <Fields> */
+ /* xx :: Matrix coefficient. */
+ /* */
+ /* xy :: Matrix coefficient. */
+ /* */
+ /* yx :: Matrix coefficient. */
+ /* */
+ /* yy :: Matrix coefficient. */
+ /* */
+ typedef struct FT_Matrix_
+ {
+ FT_Fixed xx, xy;
+ FT_Fixed yx, yy;
+
+ } FT_Matrix;
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Generic_Finalizer */
+ /* */
+ /* <Description> */
+ /* Describes a function used to destroy the `client' data of any */
+ /* FreeType object. See the description of the FT_Generic type for */
+ /* details of usage. */
+ /* */
+ /* <Input> */
+ /* The address of the FreeType object which is under finalization. */
+ /* Its client data is accessed through its `generic' field. */
+ /* */
+ typedef void (*FT_Generic_Finalizer)(void* object);
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Generic */
+ /* */
+ /* <Description> */
+ /* Client applications often need to associate their own data to a */
+ /* variety of FreeType core objects. For example, a text layout API */
+ /* might want to associate a glyph cache to a given size object. */
+ /* */
+ /* Most FreeType object contains a `generic' field, of type */
+ /* FT_Generic, which usage is left to client applications and font */
+ /* servers. */
+ /* */
+ /* It can be used to store a pointer to client-specific data, as well */
+ /* as the address of a `finalizer' function, which will be called by */
+ /* FreeType when the object is destroyed (for example, the previous */
+ /* client example would put the address of the glyph cache destructor */
+ /* in the `finalizer' field). */
+ /* */
+ /* <Fields> */
+ /* data :: A typeless pointer to any client-specified data. This */
+ /* field is completely ignored by the FreeType library. */
+ /* */
+ /* finalizer :: A pointer to a `generic finalizer' function, which */
+ /* will be called when the object is destroyed. If this */
+ /* field is set to NULL, no code will be called. */
+ /* */
+ typedef struct FT_Generic_
+ {
+ void* data;
+ FT_Generic_Finalizer finalizer;
+
+ } FT_Generic;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Macro> */
+ /* FT_MAKE_TAG */
+ /* */
+ /* <Description> */
+ /* This macro converts four letter tags which are used to label */
+ /* TrueType tables into an unsigned long to be used within FreeType. */
+ /* */
+#define FT_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
+ ( ( (FT_ULong)_x1 << 24 ) | \
+ ( (FT_ULong)_x2 << 16 ) | \
+ ( (FT_ULong)_x3 << 8 ) | \
+ (FT_ULong)_x4 )
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /* */
+ /* L I S T M A N A G E M E N T */
+ /* */
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* list_processing */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_ListNode */
+ /* */
+ /* <Description> */
+ /* Many elements and objects in FreeType are listed through a */
+ /* FT_List record (see FT_ListRec). As its name suggests, a */
+ /* FT_ListNode is a handle to a single list element. */
+ /* */
+ typedef struct FT_ListNodeRec_* FT_ListNode;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* FT_List */
+ /* */
+ /* <Description> */
+ /* A handle to a list record (see FT_ListRec). */
+ /* */
+ typedef struct FT_ListRec_* FT_List;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_ListNodeRec */
+ /* */
+ /* <Description> */
+ /* A structure used to hold a single list element. */
+ /* */
+ /* <Fields> */
+ /* prev :: The previous element in the list. NULL if first. */
+ /* */
+ /* next :: The next element in the list. NULL if last. */
+ /* */
+ /* data :: A typeless pointer to the listed object. */
+ /* */
+ typedef struct FT_ListNodeRec_
+ {
+ FT_ListNode prev;
+ FT_ListNode next;
+ void* data;
+
+ } FT_ListNodeRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_ListRec */
+ /* */
+ /* <Description> */
+ /* A structure used to hold a simple doubly-linked list. These are */
+ /* used in many parts of FreeType. */
+ /* */
+ /* <Fields> */
+ /* head :: The head (first element) of doubly-linked list. */
+ /* */
+ /* tail :: The tail (last element) of doubly-linked list. */
+ /* */
+ typedef struct FT_ListRec_
+ {
+ FT_ListNode head;
+ FT_ListNode tail;
+
+ } FT_ListRec;
+
+
+ /* */
+
+#define FT_IS_EMPTY( list ) ( (list).head == 0 )
+
+ /* return base error code (without module-specific prefix) */
+#define FT_ERROR_BASE( x ) ( (x) & 0xFF )
+
+ /* return module error code */
+#define FT_ERROR_MODULE( x ) ( (x) & 0xFF00U )
+
+#define FT_BOOL( x ) ( (FT_Bool)( x ) )
+
+FT_END_HEADER
+
+#endif /* __FTTYPES_H__ */
+
+
+/* END */
--- /dev/null
+## Process this file with automake to produce Makefile.in
+
+noinst_HEADERS = \
+ autohint.h fnttypes.h ftdebug.h ftextend.h ftobjs.h internal.h psaux.h sfnt.h tttypes.h \
+ cfftypes.h ftcalc.h ftdriver.h ftmemory.h ftstream.h pcftypes.h psnames.h t1types.h
--- /dev/null
+/***************************************************************************/
+/* */
+/* autohint.h */
+/* */
+/* High-level `autohint' module-specific interface (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* The auto-hinter is used to load and automatically hint glyphs if a */
+ /* format-specific hinter isn't available. */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef __AUTOHINT_H__
+#define __AUTOHINT_H__
+
+
+ /*************************************************************************/
+ /* */
+ /* A small technical note regarding automatic hinting in order to */
+ /* clarify this module interface. */
+ /* */
+ /* An automatic hinter might compute two kinds of data for a given face: */
+ /* */
+ /* - global hints: Usually some metrics that describe global properties */
+ /* of the face. It is computed by scanning more or less */
+ /* agressively the glyphs in the face, and thus can be */
+ /* very slow to compute (even if the size of global */
+ /* hints is really small). */
+ /* */
+ /* - glyph hints: These describe some important features of the glyph */
+ /* outline, as well as how to align them. They are */
+ /* generally much faster to compute than global hints. */
+ /* */
+ /* The current FreeType auto-hinter does a pretty good job while */
+ /* performing fast computations for both global and glyph hints. */
+ /* However, we might be interested in introducing more complex and */
+ /* powerful algorithms in the future, like the one described in the John */
+ /* D. Hobby paper, which unfortunately requires a lot more horsepower. */
+ /* */
+ /* Because a sufficiently sophisticated font management system would */
+ /* typically implement an LRU cache of opened face objects to reduce */
+ /* memory usage, it is a good idea to be able to avoid recomputing */
+ /* global hints every time the same face is re-opened. */
+ /* */
+ /* We thus provide the ability to cache global hints outside of the face */
+ /* object, in order to speed up font re-opening time. Of course, this */
+ /* feature is purely optional, so most client programs won't even notice */
+ /* it. */
+ /* */
+ /* I initially thought that it would be a good idea to cache the glyph */
+ /* hints too. However, my general idea now is that if you really need */
+ /* to cache these too, you are simply in need of a new font format, */
+ /* where all this information could be stored within the font file and */
+ /* decoded on the fly. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+
+FT_BEGIN_HEADER
+
+
+ typedef struct FT_AutoHinterRec_ *FT_AutoHinter;
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_AutoHinter_Get_Global_Func */
+ /* */
+ /* <Description> */
+ /* Retrieves the global hints computed for a given face object the */
+ /* resulting data is dissociated from the face and will survive a */
+ /* call to FT_Done_Face(). It must be discarded through the API */
+ /* FT_AutoHinter_Done_Global_Func(). */
+ /* */
+ /* <Input> */
+ /* hinter :: A handle to the source auto-hinter. */
+ /* */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* <Output> */
+ /* global_hints :: A typeless pointer to the global hints. */
+ /* */
+ /* global_len :: The size in bytes of the global hints. */
+ /* */
+ typedef void
+ (*FT_AutoHinter_Get_Global_Func)( FT_AutoHinter hinter,
+ FT_Face face,
+ void** global_hints,
+ long* global_len );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_AutoHinter_Done_Global_Func */
+ /* */
+ /* <Description> */
+ /* Discards the global hints retrieved through */
+ /* FT_AutoHinter_Get_Global_Func(). This is the only way these hints */
+ /* are freed from memory. */
+ /* */
+ /* <Input> */
+ /* hinter :: A handle to the auto-hinter module. */
+ /* */
+ /* global :: A pointer to retrieved global hints to discard. */
+ /* */
+ typedef void
+ (*FT_AutoHinter_Done_Global_Func)( FT_AutoHinter hinter,
+ void* global );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_AutoHinter_Reset_Func */
+ /* */
+ /* <Description> */
+ /* This function is used to recompute the global metrics in a given */
+ /* font. This is useful when global font data changes (e.g. Multiple */
+ /* Masters fonts where blend coordinates change). */
+ /* */
+ /* <Input> */
+ /* hinter :: A handle to the source auto-hinter. */
+ /* */
+ /* face :: A handle to the face. */
+ /* */
+ typedef void
+ (*FT_AutoHinter_Reset_Func)( FT_AutoHinter hinter,
+ FT_Face face );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_AutoHinter_Load_Func */
+ /* */
+ /* <Description> */
+ /* This function is used to load, scale, and automatically hint a */
+ /* glyph from a given face. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the face. */
+ /* glyph_index :: The glyph index. */
+ /* load_flags :: The load flags. */
+ /* */
+ /* <Note> */
+ /* This function is capable of loading composite glyphs by hinting */
+ /* each sub-glyph independently (which improves quality). */
+ /* */
+ /* It will call the font driver with FT_Load_Glyph(), with */
+ /* FT_LOAD_NO_SCALE set. */
+ /* */
+ typedef FT_Error
+ (*FT_AutoHinter_Load_Func)( FT_AutoHinter hinter,
+ FT_GlyphSlot slot,
+ FT_Size size,
+ FT_UInt glyph_index,
+ FT_ULong load_flags );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_AutoHinter_Interface */
+ /* */
+ /* <Description> */
+ /* The auto-hinter module's interface. */
+ /* */
+ typedef struct FT_AutoHinter_Interface
+ {
+ FT_AutoHinter_Reset_Func reset_face;
+ FT_AutoHinter_Load_Func load_glyph;
+
+ FT_AutoHinter_Get_Global_Func get_global_hints;
+ FT_AutoHinter_Done_Global_Func done_global_hints;
+
+ } FT_AutoHinter_Interface;
+
+
+FT_END_HEADER
+
+#endif /* __AUTOHINT_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* cfftypes.h */
+/* */
+/* Basic OpenType/CFF type definitions and interface (specification */
+/* only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __CFFTYPES_H__
+#define __CFFTYPES_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* CFF_Index */
+ /* */
+ /* <Description> */
+ /* A structure used to model a CFF Index table. */
+ /* */
+ /* <Fields> */
+ /* stream :: The source input stream. */
+ /* */
+ /* count :: The number of elements in the index. */
+ /* */
+ /* off_size :: The size in bytes of object offsets in index. */
+ /* */
+ /* data_offset :: The position of first data byte in the index's */
+ /* bytes. */
+ /* */
+ /* offsets :: A table of element offsets in the index. */
+ /* */
+ /* bytes :: If the index is loaded in memory, its bytes. */
+ /* */
+ typedef struct CFF_Index_
+ {
+ FT_Stream stream;
+ FT_UInt count;
+ FT_Byte off_size;
+ FT_ULong data_offset;
+
+ FT_ULong* offsets;
+ FT_Byte* bytes;
+
+ } CFF_Index;
+
+
+ typedef struct CFF_Encoding_
+ {
+ FT_UInt format;
+ FT_ULong offset;
+
+ FT_UShort* sids;
+ FT_UShort* codes;
+
+ } CFF_Encoding;
+
+
+ typedef struct CFF_Charset_
+ {
+
+ FT_UInt format;
+ FT_ULong offset;
+
+ FT_UShort* sids;
+
+ } CFF_Charset;
+
+
+ typedef struct CFF_Font_Dict_
+ {
+ FT_UInt version;
+ FT_UInt notice;
+ FT_UInt copyright;
+ FT_UInt full_name;
+ FT_UInt family_name;
+ FT_UInt weight;
+ FT_Bool is_fixed_pitch;
+ FT_Fixed italic_angle;
+ FT_Pos underline_position;
+ FT_Pos underline_thickness;
+ FT_Int paint_type;
+ FT_Int charstring_type;
+ FT_Matrix font_matrix;
+ FT_UShort units_per_em;
+ FT_Vector font_offset;
+ FT_ULong unique_id;
+ FT_BBox font_bbox;
+ FT_Pos stroke_width;
+ FT_ULong charset_offset;
+ FT_ULong encoding_offset;
+ FT_ULong charstrings_offset;
+ FT_ULong private_offset;
+ FT_ULong private_size;
+ FT_Long synthetic_base;
+ FT_UInt embedded_postscript;
+ FT_UInt base_font_name;
+ FT_UInt postscript;
+
+ /* these should only be used for the top-level font dictionary */
+ FT_UInt cid_registry;
+ FT_UInt cid_ordering;
+ FT_ULong cid_supplement;
+
+ FT_Long cid_font_version;
+ FT_Long cid_font_revision;
+ FT_Long cid_font_type;
+ FT_Long cid_count;
+ FT_ULong cid_uid_base;
+ FT_ULong cid_fd_array_offset;
+ FT_ULong cid_fd_select_offset;
+ FT_UInt cid_font_name;
+
+ } CFF_Font_Dict;
+
+
+ typedef struct CFF_Private_
+ {
+ FT_Byte num_blue_values;
+ FT_Byte num_other_blues;
+ FT_Byte num_family_blues;
+ FT_Byte num_family_other_blues;
+
+ FT_Pos blue_values[14];
+ FT_Pos other_blues[10];
+ FT_Pos family_blues[14];
+ FT_Pos family_other_blues[10];
+
+ FT_Fixed blue_scale;
+ FT_Pos blue_shift;
+ FT_Pos blue_fuzz;
+ FT_Pos standard_width;
+ FT_Pos standard_height;
+
+ FT_Byte num_snap_widths;
+ FT_Byte num_snap_heights;
+ FT_Pos snap_widths[13];
+ FT_Pos snap_heights[13];
+ FT_Bool force_bold;
+ FT_Fixed force_bold_threshold;
+ FT_Int lenIV;
+ FT_Int language_group;
+ FT_Fixed expansion_factor;
+ FT_Long initial_random_seed;
+ FT_ULong local_subrs_offset;
+ FT_Pos default_width;
+ FT_Pos nominal_width;
+
+ } CFF_Private;
+
+
+ typedef struct CFF_FD_Select_
+ {
+ FT_Byte format;
+ FT_UInt range_count;
+
+ /* that's the table, taken from the file `as is' */
+ FT_Byte* data;
+ FT_UInt data_size;
+
+ /* small cache for format 3 only */
+ FT_UInt cache_first;
+ FT_UInt cache_count;
+ FT_Byte cache_fd;
+
+ } CFF_FD_Select;
+
+
+ /* A SubFont packs a font dict and a private dict together. They are */
+ /* needed to support CID-keyed CFF fonts. */
+ typedef struct CFF_SubFont_
+ {
+ CFF_Font_Dict font_dict;
+ CFF_Private private_dict;
+
+ CFF_Index local_subrs_index;
+ FT_UInt num_local_subrs;
+ FT_Byte** local_subrs;
+
+ } CFF_SubFont;
+
+
+ /* maximum number of sub-fonts in a CID-keyed file */
+#define CFF_MAX_CID_FONTS 16
+
+
+ typedef struct CFF_Font_
+ {
+ FT_Stream stream;
+ FT_Memory memory;
+ FT_UInt num_faces;
+ FT_UInt num_glyphs;
+
+ FT_Byte version_major;
+ FT_Byte version_minor;
+ FT_Byte header_size;
+ FT_Byte absolute_offsize;
+
+
+ CFF_Index name_index;
+ CFF_Index top_dict_index;
+ CFF_Index string_index;
+ CFF_Index global_subrs_index;
+
+ CFF_Encoding encoding;
+ CFF_Charset charset;
+
+ CFF_Index charstrings_index;
+ CFF_Index font_dict_index;
+ CFF_Index private_index;
+ CFF_Index local_subrs_index;
+
+ FT_String* font_name;
+ FT_UInt num_global_subrs;
+ FT_Byte** global_subrs;
+
+ CFF_SubFont top_font;
+ FT_UInt num_subfonts;
+ CFF_SubFont* subfonts[CFF_MAX_CID_FONTS];
+
+ CFF_FD_Select fd_select;
+
+ } CFF_Font;
+
+
+FT_END_HEADER
+
+#endif /* __CFFTYPES_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* fnttypes.h */
+/* */
+/* Basic Windows FNT/FON type definitions and interface (specification */
+/* only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FNTTYPES_H__
+#define __FNTTYPES_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+
+FT_BEGIN_HEADER
+
+
+ typedef struct WinMZ_Header_
+ {
+ FT_UShort magic;
+ /* skipped content */
+ FT_UShort lfanew;
+
+ } WinMZ_Header;
+
+
+ typedef struct WinNE_Header_
+ {
+ FT_UShort magic;
+ /* skipped content */
+ FT_UShort resource_tab_offset;
+ FT_UShort rname_tab_offset;
+
+ } WinNE_Header;
+
+
+ typedef struct WinNameInfo_
+ {
+ FT_UShort offset;
+ FT_UShort length;
+ FT_UShort flags;
+ FT_UShort id;
+ FT_UShort handle;
+ FT_UShort usage;
+
+ } WinNameInfo;
+
+
+ typedef struct WinResourceInfo_
+ {
+ FT_UShort type_id;
+ FT_UShort count;
+
+ } WinResourceInfo;
+
+
+#define WINFNT_MZ_MAGIC 0x5A4D
+#define WINFNT_NE_MAGIC 0x454E
+
+
+ typedef struct WinFNT_Header_
+ {
+ FT_UShort version;
+ FT_ULong file_size;
+ FT_Byte copyright[60];
+ FT_UShort file_type;
+ FT_UShort nominal_point_size;
+ FT_UShort vertical_resolution;
+ FT_UShort horizontal_resolution;
+ FT_UShort ascent;
+ FT_UShort internal_leading;
+ FT_UShort external_leading;
+ FT_Byte italic;
+ FT_Byte underline;
+ FT_Byte strike_out;
+ FT_UShort weight;
+ FT_Byte charset;
+ FT_UShort pixel_width;
+ FT_UShort pixel_height;
+ FT_Byte pitch_and_family;
+ FT_UShort avg_width;
+ FT_UShort max_width;
+ FT_Byte first_char;
+ FT_Byte last_char;
+ FT_Byte default_char;
+ FT_Byte break_char;
+ FT_UShort bytes_per_row;
+ FT_ULong device_offset;
+ FT_ULong face_name_offset;
+ FT_ULong bits_pointer;
+ FT_ULong bits_offset;
+ FT_Byte reserved;
+ FT_ULong flags;
+ FT_UShort A_space;
+ FT_UShort B_space;
+ FT_UShort C_space;
+ FT_UShort color_table_offset;
+ FT_Byte reserved2[4];
+
+ } WinFNT_Header;
+
+
+ typedef struct FNT_Font_
+ {
+ FT_ULong offset;
+ FT_Int size_shift;
+
+ WinFNT_Header header;
+
+ FT_Byte* fnt_frame;
+ FT_ULong fnt_size;
+
+ } FNT_Font;
+
+
+ typedef struct FNT_SizeRec_
+ {
+ FT_SizeRec root;
+ FNT_Font* font;
+
+ } FNT_SizeRec, *FNT_Size;
+
+
+ typedef struct FNT_FaceRec_
+ {
+ FT_FaceRec root;
+
+ FT_UInt num_fonts;
+ FNT_Font* fonts;
+
+ FT_CharMap charmap_handle;
+ FT_CharMapRec charmap; /* a single charmap per face */
+
+ } FNT_FaceRec, *FNT_Face;
+
+
+FT_END_HEADER
+
+#endif /* __FNTTYPES_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftcalc.h */
+/* */
+/* Arithmetic computations (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTCALC_H__
+#define __FTCALC_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+
+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 )
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Sqrt32 */
+ /* */
+ /* <Description> */
+ /* Computes the square root of an Int32 integer (which will be */
+ /* handled as an unsigned long value). */
+ /* */
+ /* <Input> */
+ /* x :: The value to compute the root for. */
+ /* */
+ /* <Return> */
+ /* The result of `sqrt(x)'. */
+ /* */
+ FT_EXPORT( FT_Int32 )
+ FT_Sqrt32( FT_Int32 x );
+
+
+#endif /* !FT_CONFIG_OPTION_OLD_CALCS */
+
+
+ /*************************************************************************/
+ /* */
+ /* FT_MulDiv() and FT_MulFix() are declared in freetype.h. */
+ /* */
+ /*************************************************************************/
+
+
+#define INT_TO_F26DOT6( x ) ( (FT_Long)(x) << 6 )
+#define INT_TO_F2DOT14( x ) ( (FT_Long)(x) << 14 )
+#define INT_TO_FIXED( x ) ( (FT_Long)(x) << 16 )
+#define F2DOT14_TO_FIXED( x ) ( (FT_Long)(x) << 2 )
+#define FLOAT_TO_FIXED( x ) ( (FT_Long)( x * 65536.0 ) )
+
+#define ROUND_F26DOT6( x ) ( x >= 0 ? ( ( (x) + 32 ) & -64 ) \
+ : ( -( ( 32 - (x) ) & -64 ) ) )
+
+
+FT_END_HEADER
+
+#endif /* __FTCALC_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftdebug.h */
+/* */
+/* Debugging and logging component (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTDEBUG_H__
+#define __FTDEBUG_H__
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+
+
+FT_BEGIN_HEADER
+
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+
+
+ /* note that not all levels are used currently */
+
+ typedef enum FT_Trace_
+ {
+ /* the first level must always be `trace_any' */
+ trace_any = 0,
+
+ /* base components */
+ trace_aaraster, /* anti-aliasing raster (ftgrays.c) */
+ trace_calc, /* calculations (ftcalc.c) */
+ trace_extend, /* extension manager (ftextend.c) */
+ trace_glyph, /* glyph manager (ftglyph.c) */
+ trace_io, /* i/o monitoring (ftsystem.c) */
+ trace_init, /* initialization (ftinit.c) */
+ trace_list, /* list manager (ftlist.c) */
+ trace_memory, /* memory manager (ftobjs.c) */
+ trace_mm, /* MM interface (ftmm.c) */
+ trace_objs, /* base objects (ftobjs.c) */
+ trace_outline, /* outline management (ftoutln.c) */
+ trace_raster, /* rasterizer (ftraster.c) */
+ trace_stream, /* stream manager (ftstream.c) */
+
+ /* Cache sub-system */
+ trace_cache,
+
+ /* SFNT driver components */
+ trace_sfobjs, /* SFNT object handler (sfobjs.c) */
+ trace_ttcmap, /* charmap handler (ttcmap.c) */
+ trace_ttload, /* basic TrueType tables (ttload.c) */
+ trace_ttpost, /* PS table processing (ttpost.c) */
+ trace_ttsbit, /* TrueType sbit handling (ttsbit.c) */
+
+ /* TrueType driver components */
+ trace_ttdriver, /* TT font driver (ttdriver.c) */
+ trace_ttgload, /* TT glyph loader (ttgload.c) */
+ trace_ttinterp, /* bytecode interpreter (ttinterp.c) */
+ trace_ttobjs, /* TT objects manager (ttobjs.c) */
+ trace_ttpload, /* TT data/program loader (ttpload.c) */
+
+ /* Type 1 driver components */
+ trace_t1driver,
+ trace_t1gload,
+ trace_t1hint,
+ trace_t1load,
+ trace_t1objs,
+ trace_t1parse,
+
+ /* PostScript helper module `psaux' */
+ trace_t1decode,
+ trace_psobjs,
+
+ /* Type 2 driver components */
+ trace_cffdriver,
+ trace_cffgload,
+ trace_cffload,
+ trace_cffobjs,
+ trace_cffparse,
+
+ /* CID driver components */
+ trace_cidafm,
+ trace_ciddriver,
+ trace_cidgload,
+ trace_cidload,
+ trace_cidobjs,
+ trace_cidparse,
+
+ /* Windows fonts component */
+ trace_winfnt,
+
+ /* PCF fonts component */
+ trace_pcfdriver,
+ trace_pcfread,
+
+ /* the last level must always be `trace_max' */
+ trace_max
+
+ } FT_Trace;
+
+
+ /* declared in ftdebug.c */
+ extern char ft_trace_levels[trace_max];
+
+
+ /*************************************************************************/
+ /* */
+ /* IMPORTANT! */
+ /* */
+ /* Each component must define the macro FT_COMPONENT to a valid FT_Trace */
+ /* value before using any TRACE macro. */
+ /* */
+ /*************************************************************************/
+
+
+#define FT_TRACE( level, varformat ) \
+ do \
+ { \
+ if ( ft_trace_levels[FT_COMPONENT] >= level ) \
+ FT_Message varformat; \
+ } while ( 0 )
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_SetTraceLevel */
+ /* */
+ /* <Description> */
+ /* Sets the trace level for debugging. */
+ /* */
+ /* <Input> */
+ /* component :: The component which should be traced. See above for */
+ /* a complete list. If set to `trace_any', all */
+ /* components will be traced. */
+ /* */
+ /* level :: The tracing level. */
+ /* */
+ FT_EXPORT( void )
+ FT_SetTraceLevel( FT_Trace component,
+ char level );
+
+
+#elif defined( FT_DEBUG_LEVEL_ERROR )
+
+
+#define FT_TRACE( level, varformat ) do ; while ( 0 ) /* nothing */
+
+
+#else /* release mode */
+
+
+#define FT_Assert( condition ) do ; while ( 0 ) /* nothing */
+
+#define FT_TRACE( level, varformat ) do ; while ( 0 ) /* nothing */
+#define FT_ERROR( varformat ) do ; while ( 0 ) /* nothing */
+
+
+#endif /* FT_DEBUG_LEVEL_TRACE, FT_DEBUG_LEVEL_ERROR */
+
+
+ /*************************************************************************/
+ /* */
+ /* Define macros and functions that are common to the debug and trace */
+ /* modes. */
+ /* */
+ /* You need vprintf() to be able to compile ftdebug.c. */
+ /* */
+ /*************************************************************************/
+
+
+#if defined( FT_DEBUG_LEVEL_TRACE ) || defined( FT_DEBUG_LEVEL_ERROR )
+
+
+#include "stdio.h" /* for vprintf() */
+
+
+#define FT_Assert( condition ) \
+ do \
+ { \
+ if ( !( condition ) ) \
+ FT_Panic( "assertion failed on line %d of file %s\n", \
+ __LINE__, __FILE__ ); \
+ } while ( 0 )
+
+ /* print a message */
+ FT_EXPORT( void )
+ FT_Message( const char* fmt, ... );
+
+ /* print a message and exit */
+ FT_EXPORT( void )
+ FT_Panic( const char* fmt, ... );
+
+#define FT_ERROR( varformat ) FT_Message varformat
+
+
+#endif /* FT_DEBUG_LEVEL_TRACE || FT_DEBUG_LEVEL_ERROR */
+
+
+ /*************************************************************************/
+ /* */
+ /* You need two opening resp. closing parentheses! */
+ /* */
+ /* Example: FT_TRACE0(( "Value is %i", foo )) */
+ /* */
+ /*************************************************************************/
+
+#define FT_TRACE0( varformat ) FT_TRACE( 0, varformat )
+#define FT_TRACE1( varformat ) FT_TRACE( 1, varformat )
+#define FT_TRACE2( varformat ) FT_TRACE( 2, varformat )
+#define FT_TRACE3( varformat ) FT_TRACE( 3, varformat )
+#define FT_TRACE4( varformat ) FT_TRACE( 4, varformat )
+#define FT_TRACE5( varformat ) FT_TRACE( 5, varformat )
+#define FT_TRACE6( varformat ) FT_TRACE( 6, varformat )
+#define FT_TRACE7( varformat ) FT_TRACE( 7, varformat )
+
+
+#if defined( _MSC_VER ) /* Visual C++ (and Intel C++) */
+
+ /* we disable the warning `conditional expression is constant' here */
+ /* in order to compile cleanly with the maximum level of warnings */
+#pragma warning( disable : 4127 )
+
+#endif /* _MSC_VER */
+
+
+FT_END_HEADER
+
+#endif /* __FTDEBUG_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftdriver.h */
+/* */
+/* FreeType font driver interface (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTDRIVER_H__
+#define __FTDRIVER_H__
+
+
+#include <ft2build.h>
+#include FT_MODULE_H
+
+
+FT_BEGIN_HEADER
+
+
+ typedef FT_Error
+ (*FTDriver_initFace)( FT_Stream stream,
+ FT_Face face,
+ FT_Int typeface_index,
+ FT_Int num_params,
+ FT_Parameter* parameters );
+
+ typedef void
+ (*FTDriver_doneFace)( FT_Face face );
+
+
+ typedef FT_Error
+ (*FTDriver_initSize)( FT_Size size );
+
+ typedef void
+ (*FTDriver_doneSize)( FT_Size size );
+
+
+ typedef FT_Error
+ (*FTDriver_initGlyphSlot)( FT_GlyphSlot slot );
+
+ typedef void
+ (*FTDriver_doneGlyphSlot)( FT_GlyphSlot slot );
+
+
+ typedef FT_Error
+ (*FTDriver_setCharSizes)( FT_Size size,
+ FT_F26Dot6 char_width,
+ FT_F26Dot6 char_height,
+ FT_UInt horz_resolution,
+ FT_UInt vert_resolution );
+
+ typedef FT_Error
+ (*FTDriver_setPixelSizes)( FT_Size size,
+ FT_UInt pixel_width,
+ FT_UInt pixel_height );
+
+ typedef FT_Error
+ (*FTDriver_loadGlyph)( FT_GlyphSlot slot,
+ FT_Size size,
+ FT_UInt glyph_index,
+ FT_Int load_flags );
+
+
+ typedef FT_UInt
+ (*FTDriver_getCharIndex)( FT_CharMap charmap,
+ FT_Long charcode );
+
+ typedef FT_Error
+ (*FTDriver_getKerning)( FT_Face face,
+ FT_UInt left_glyph,
+ FT_UInt right_glyph,
+ FT_Vector* kerning );
+
+
+ typedef FT_Error
+ (*FTDriver_attachFile)( FT_Face face,
+ FT_Stream stream );
+
+
+ typedef FT_Error
+ (*FTDriver_getAdvances)( FT_Face face,
+ FT_UInt first,
+ FT_UInt count,
+ FT_Bool vertical,
+ FT_UShort* advances );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Driver_Class */
+ /* */
+ /* <Description> */
+ /* The font driver class. This structure mostly contains pointers to */
+ /* driver methods. */
+ /* */
+ /* <Fields> */
+ /* root :: The parent module. */
+ /* */
+ /* face_object_size :: The size of a face object in bytes. */
+ /* */
+ /* size_object_size :: The size of a size object in bytes. */
+ /* */
+ /* slot_object_size :: The size of a glyph object in bytes. */
+ /* */
+ /* init_face :: The format-specific face constructor. */
+ /* */
+ /* done_face :: The format-specific face destructor. */
+ /* */
+ /* init_size :: The format-specific size constructor. */
+ /* */
+ /* done_size :: The format-specific size destructor. */
+ /* */
+ /* init_slot :: The format-specific slot constructor. */
+ /* */
+ /* done_slot :: The format-specific slot destructor. */
+ /* */
+ /* set_char_sizes :: A handle to a function used to set the new */
+ /* character size in points + resolution. Can be */
+ /* set to 0 to indicate default behaviour. */
+ /* */
+ /* set_pixel_sizes :: A handle to a function used to set the new */
+ /* character size in pixels. Can be set to 0 to */
+ /* indicate default behaviour. */
+ /* */
+ /* load_glyph :: A function handle to load a given glyph image */
+ /* in a slot. This field is mandatory! */
+ /* */
+ /* get_char_index :: A function handle to return the glyph index of */
+ /* a given character for a given charmap. This */
+ /* field is mandatory! */
+ /* */
+ /* get_kerning :: A function handle to return the unscaled */
+ /* kerning for a given pair of glyphs. Can be */
+ /* set to 0 if the format doesn't support */
+ /* kerning. */
+ /* */
+ /* attach_file :: This function handle is used to read */
+ /* additional data for a face from another */
+ /* file/stream. For example, this can be used to */
+ /* add data from AFM or PFM files on a Type 1 */
+ /* face, or a CIDMap on a CID-keyed face. */
+ /* */
+ /* get_advances :: A function handle used to return the advances */
+ /* of 'count' glyphs, starting at `index'. the */
+ /* `vertical' flags must be set when vertical */
+ /* advances are queried. The advances buffer is */
+ /* caller-allocated. */
+ /* */
+ /* <Note> */
+ /* Most function pointers, with the exception of `load_glyph' and */
+ /* `get_char_index' can be set to 0 to indicate a default behaviour. */
+ /* */
+ typedef struct FT_Driver_Class_
+ {
+ FT_Module_Class root;
+
+ FT_Int face_object_size;
+ FT_Int size_object_size;
+ FT_Int slot_object_size;
+
+ FTDriver_initFace init_face;
+ FTDriver_doneFace done_face;
+
+ FTDriver_initSize init_size;
+ FTDriver_doneSize done_size;
+
+ FTDriver_initGlyphSlot init_slot;
+ FTDriver_doneGlyphSlot done_slot;
+
+ FTDriver_setCharSizes set_char_sizes;
+ FTDriver_setPixelSizes set_pixel_sizes;
+
+ FTDriver_loadGlyph load_glyph;
+ FTDriver_getCharIndex get_char_index;
+
+ FTDriver_getKerning get_kerning;
+ FTDriver_attachFile attach_file;
+
+ FTDriver_getAdvances get_advances;
+
+ } FT_Driver_Class;
+
+
+FT_END_HEADER
+
+#endif /* __FTDRIVER_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftextend.h */
+/* */
+/* FreeType extensions implementation (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTEXTEND_H__
+#define __FTEXTEND_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* The extensions don't need to be integrated at compile time into the */
+ /* engine, only at link time. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Extension_Initializer */
+ /* */
+ /* <Description> */
+ /* Each new face object can have several extensions associated with */
+ /* it at creation time. This function is used to initialize given */
+ /* extension data for a given face. */
+ /* */
+ /* <InOut> */
+ /* ext :: A typeless pointer to the extension data. */
+ /* */
+ /* face :: A handle to the source face object the extension is */
+ /* associated with. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* In case of error, the initializer should not destroy the extension */
+ /* data, as the finalizer will get called later by the function's */
+ /* caller. */
+ /* */
+ typedef FT_Error
+ (*FT_Extension_Initializer)( void* ext,
+ FT_Face face );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* FT_Extension_Finalizer */
+ /* */
+ /* <Description> */
+ /* Each new face object can have several extensions associated with */
+ /* it at creation time. This function is used to finalize given */
+ /* extension data for a given face; it occurs before the face object */
+ /* itself is finalized. */
+ /* */
+ /* <InOut> */
+ /* ext :: A typeless pointer to the extension data. */
+ /* */
+ /* face :: A handle to the source face object the extension is */
+ /* associated with. */
+ /* */
+ typedef void
+ (*FT_Extension_Finalizer)( void* ext,
+ FT_Face face );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Extension_Class */
+ /* */
+ /* <Description> */
+ /* A simple structure used to describe a given extension to the */
+ /* FreeType base layer. An FT_Extension_Class is used as a parameter */
+ /* for FT_Register_Extension(). */
+ /* */
+ /* <Fields> */
+ /* id :: The extension's ID. This is a normal C string that */
+ /* is used to uniquely reference the extension's */
+ /* interface. */
+ /* */
+ /* size :: The size in bytes of the extension data that must be */
+ /* associated with each face object. */
+ /* */
+ /* init :: A pointer to the extension data's initializer. */
+ /* */
+ /* finalize :: A pointer to the extension data's finalizer. */
+ /* */
+ /* interface :: This pointer can be anything, but should usually */
+ /* point to a table of function pointers which implement */
+ /* the extension's interface. */
+ /* */
+ /* offset :: This field is set and used within the base layer and */
+ /* should be set to 0 when registering an extension */
+ /* through FT_Register_Extension(). It contains an */
+ /* offset within the face's extension block for the */
+ /* current extension's data. */
+ /* */
+ typedef struct FT_Extension_Class_
+ {
+ const char* id;
+ FT_ULong size;
+ FT_Extension_Initializer init;
+ FT_Extension_Finalizer finalize;
+ void* interface;
+
+ FT_ULong offset;
+
+ } FT_Extension_Class;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Register_Extension */
+ /* */
+ /* <Description> */
+ /* Registers a new extension. */
+ /* */
+ /* <InOut> */
+ /* driver :: A handle to the driver object. */
+ /* */
+ /* class :: A pointer to a class describing the extension. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_Register_Extension( FT_Driver driver,
+ FT_Extension_Class* clazz );
+
+
+#ifdef FT_CONFIG_OPTION_EXTEND_ENGINE
+
+
+ /* Initialize the extension component */
+ FT_LOCAL FT_Error
+ FT_Init_Extensions( FT_Library library );
+
+ /* Finalize the extension component */
+ FT_LOCAL FT_Error
+ FT_Done_Extensions( FT_Library library );
+
+ /* Create an extension within a face object. Called by the */
+ /* face object constructor. */
+ FT_LOCAL FT_Error
+ FT_Create_Extensions( FT_Face face );
+
+ /* Destroy all extensions within a face object. Called by the */
+ /* face object destructor. */
+ FT_LOCAL FT_Error
+ FT_Destroy_Extensions( FT_Face face );
+
+
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Extension */
+ /* */
+ /* <Description> */
+ /* Queries an extension block by an extension ID string. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the face object. */
+ /* extension_id :: An ID string identifying the extension. */
+ /* */
+ /* <Output> */
+ /* extension_interface :: A generic pointer, usually pointing to a */
+ /* table of functions implementing the */
+ /* extension interface. */
+ /* */
+ /* <Return> */
+ /* A generic pointer to the extension block. */
+ /* */
+ FT_EXPORT( void* )
+ FT_Get_Extension( FT_Face face,
+ const char* extension_id,
+ void** extension_interface );
+
+
+FT_END_HEADER
+
+#endif /* __FTEXTEND_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftmemory.h */
+/* */
+/* The FreeType memory management macros (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTMEMORY_H__
+#define __FTMEMORY_H__
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include FT_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Macro> */
+ /* FT_SET_ERROR */
+ /* */
+ /* <Description> */
+ /* This macro is used to set an implicit `error' variable to a given */
+ /* expression's value (usually a function call), and convert it to a */
+ /* boolean which is set whenever the value is != 0. */
+ /* */
+#undef FT_SET_ERROR
+#define FT_SET_ERROR( expression ) \
+ ( ( error = (expression) ) != 0 )
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** M E M O R Y ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Alloc */
+ /* */
+ /* <Description> */
+ /* Allocates a new block of memory. The returned area is always */
+ /* zero-filled; this is a strong convention in many FreeType parts. */
+ /* */
+ /* <Input> */
+ /* memory :: A handle to a given `memory object' which handles */
+ /* allocation. */
+ /* */
+ /* size :: The size in bytes of the block to allocate. */
+ /* */
+ /* <Output> */
+ /* P :: A pointer to the fresh new block. It should be set to */
+ /* NULL if `size' is 0, or in case of error. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_BASE( FT_Error )
+ FT_Alloc( FT_Memory memory,
+ FT_Long size,
+ void* *P );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Realloc */
+ /* */
+ /* <Description> */
+ /* Reallocates a block of memory pointed to by `*P' to `Size' bytes */
+ /* from the heap, possibly changing `*P'. */
+ /* */
+ /* <Input> */
+ /* memory :: A handle to a given `memory object' which handles */
+ /* reallocation. */
+ /* */
+ /* current :: The current block size in bytes. */
+ /* */
+ /* size :: The new block size in bytes. */
+ /* */
+ /* <InOut> */
+ /* P :: A pointer to the fresh new block. It should be set to */
+ /* NULL if `size' is 0, or in case of error. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* All callers of FT_Realloc() _must_ provide the current block size */
+ /* as well as the new one. */
+ /* */
+ FT_BASE( FT_Error )
+ FT_Realloc( FT_Memory memory,
+ FT_Long current,
+ FT_Long size,
+ void** P );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Free */
+ /* */
+ /* <Description> */
+ /* Releases a given block of memory allocated through FT_Alloc(). */
+ /* */
+ /* <Input> */
+ /* memory :: A handle to a given `memory object' which handles */
+ /* memory deallocation */
+ /* */
+ /* P :: This is the _address_ of a _pointer_ which points to the */
+ /* allocated block. It is always set to NULL on exit. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* If P or *P are NULL, this function should return successfully. */
+ /* This is a strong convention within all of FreeType and its */
+ /* drivers. */
+ /* */
+ FT_BASE( void )
+ FT_Free( FT_Memory memory,
+ void** P );
+
+
+
+ /* This `#include' is needed by the MEM_xxx() macros; it should be */
+ /* available on all platforms we know of. */
+#include <string.h>
+
+#define MEM_Set( dest, byte, count ) memset( dest, byte, count )
+
+#define MEM_Copy( dest, source, count ) memcpy( dest, source, count )
+
+#define MEM_Move( dest, source, count ) memmove( dest, source, count )
+
+
+ /*************************************************************************/
+ /* */
+ /* We now support closures to produce completely reentrant code. This */
+ /* means the allocation functions now takes an additional argument */
+ /* (`memory'). It is a handle to a given memory object, responsible for */
+ /* all low-level operations, including memory management and */
+ /* synchronisation. */
+ /* */
+ /* In order to keep our code readable and use the same macros in the */
+ /* font drivers and the rest of the library, MEM_Alloc(), ALLOC(), and */
+ /* ALLOC_ARRAY() now use an implicit variable, `memory'. It must be */
+ /* defined at all locations where a memory operation is queried. */
+ /* */
+#define MEM_Alloc( _pointer_, _size_ ) \
+ FT_Alloc( memory, _size_, (void**)&(_pointer_) )
+
+#define MEM_Alloc_Array( _pointer_, _count_, _type_ ) \
+ FT_Alloc( memory, (_count_)*sizeof ( _type_ ), \
+ (void**)&(_pointer_) )
+
+#define MEM_Realloc( _pointer_, _current_, _size_ ) \
+ FT_Realloc( memory, _current_, _size_, (void**)&(_pointer_) )
+
+#define MEM_Realloc_Array( _pointer_, _current_, _new_, _type_ ) \
+ FT_Realloc( memory, (_current_)*sizeof ( _type_ ), \
+ (_new_)*sizeof ( _type_ ), (void**)&(_pointer_) )
+
+#define ALLOC( _pointer_, _size_ ) \
+ FT_SET_ERROR( MEM_Alloc( _pointer_, _size_ ) )
+
+#define REALLOC( _pointer_, _current_, _size_ ) \
+ FT_SET_ERROR( MEM_Realloc( _pointer_, _current_, _size_ ) )
+
+#define ALLOC_ARRAY( _pointer_, _count_, _type_ ) \
+ FT_SET_ERROR( MEM_Alloc( _pointer_, \
+ (_count_)*sizeof ( _type_ ) ) )
+
+#define REALLOC_ARRAY( _pointer_, _current_, _count_, _type_ ) \
+ FT_SET_ERROR( MEM_Realloc( _pointer_, \
+ (_current_)*sizeof ( _type_ ), \
+ (_count_)*sizeof ( _type_ ) ) )
+
+#define FREE( _pointer_ ) FT_Free( memory, (void**)&(_pointer_) )
+
+
+FT_END_HEADER
+
+#endif /* __FTMEMORY_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftobjs.h */
+/* */
+/* The FreeType private base classes (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file contains the definition of all internal FreeType classes. */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef __FTOBJS_H__
+#define __FTOBJS_H__
+
+
+#include <ft2build.h>
+#include FT_RENDER_H
+#include FT_SIZES_H
+#include FT_INTERNAL_MEMORY_H
+#include FT_INTERNAL_DRIVER_H
+#include FT_INTERNAL_AUTOHINT_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* Some generic definitions. */
+ /* */
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef NULL
+#define NULL (void*)0
+#endif
+
+#ifndef UNUSED
+#define UNUSED( arg ) ( (arg)=(arg) )
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* The min and max functions missing in C. As usual, be careful not to */
+ /* write things like MIN( a++, b++ ) to avoid side effects. */
+ /* */
+#ifndef MIN
+#define MIN( a, b ) ( (a) < (b) ? (a) : (b) )
+#endif
+
+#ifndef MAX
+#define MAX( a, b ) ( (a) > (b) ? (a) : (b) )
+#endif
+
+#ifndef ABS
+#define ABS( a ) ( (a) < 0 ? -(a) : (a) )
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_GlyphLoader */
+ /* */
+ /* <Description> */
+ /* The glyph loader is an internal object used to load several glyphs */
+ /* together (for example, in the case of composites). */
+ /* */
+ /* <Note> */
+ /* The glyph loader implementation is not part of the high-level API, */
+ /* hence the forward structure declaration. */
+ /* */
+ typedef struct FT_GlyphLoader_ FT_GlyphLoader;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Face_InternalRec */
+ /* */
+ /* <Description> */
+ /* This structure contains the internal fields of each FT_Face */
+ /* object. These fields may change between different releases of */
+ /* FreeType. */
+ /* */
+ /* <Fields> */
+ /* max_points :: The maximal number of points used to store the */
+ /* vectorial outline of any glyph in this face. */
+ /* If this value cannot be known in advance, or */
+ /* if the face isn't scalable, this should be set */
+ /* to 0. Only relevant for scalable formats. */
+ /* */
+ /* max_contours :: The maximal number of contours used to store */
+ /* the vectorial outline of any glyph in this */
+ /* face. If this value cannot be known in */
+ /* advance, or if the face isn't scalable, this */
+ /* should be set to 0. Only relevant for */
+ /* scalable formats. */
+ /* */
+ /* transform_matrix :: A 2x2 matrix of 16.16 coefficients used to */
+ /* transform glyph outlines after they are loaded */
+ /* from the font. Only used by the convenience */
+ /* functions. */
+ /* */
+ /* transform_delta :: A translation vector used to transform glyph */
+ /* outlines after they are loaded from the font. */
+ /* Only used by the convenience functions. */
+ /* */
+ /* transform_flags :: Some flags used to classify the transform. */
+ /* Only used by the convenience functions. */
+ /* */
+ /* postscript_name :: Postscript font name for this face. */
+ /* */
+ typedef struct FT_Face_InternalRec_
+ {
+ FT_UShort max_points;
+ FT_Short max_contours;
+
+ FT_Matrix transform_matrix;
+ FT_Vector transform_delta;
+ FT_Int transform_flags;
+
+ const char* postscript_name;
+
+ } FT_Face_InternalRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_Slot_InternalRec */
+ /* */
+ /* <Description> */
+ /* This structure contains the internal fields of each FT_GlyphSlot */
+ /* object. These fields may change between different releases of */
+ /* FreeType. */
+ /* */
+ /* <Fields> */
+ /* loader :: The glyph loader object used to load outlines */
+ /* into the glyph slot. */
+ /* */
+ /* glyph_transformed :: Boolean. Set to TRUE when the loaded glyph */
+ /* must be transformed through a specific */
+ /* font transformation. This is _not_ the same */
+ /* as the face transform set through */
+ /* FT_Set_Transform(). */
+ /* */
+ /* glyph_matrix :: The 2x2 matrix corresponding to the glyph */
+ /* transformation, if necessary. */
+ /* */
+ /* glyph_delta :: The 2d translation vector corresponding to */
+ /* the glyph transformation, if necessary. */
+ /* */
+ typedef struct FT_Slot_InternalRec_
+ {
+ FT_GlyphLoader* loader;
+ FT_Bool glyph_transformed;
+ FT_Matrix glyph_matrix;
+ FT_Vector glyph_delta;
+
+ } FT_GlyphSlot_InternalRec;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** M O D U L E S ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_ModuleRec */
+ /* */
+ /* <Description> */
+ /* A module object instance. */
+ /* */
+ /* <Fields> */
+ /* clazz :: A pointer to the module's class. */
+ /* */
+ /* library :: A handle to the parent library object. */
+ /* */
+ /* memory :: A handle to the memory manager. */
+ /* */
+ /* generic :: A generic structure for user-level extensibility (?). */
+ /* */
+ typedef struct FT_ModuleRec_
+ {
+ FT_Module_Class* clazz;
+ FT_Library library;
+ FT_Memory memory;
+ FT_Generic generic;
+
+ } FT_ModuleRec;
+
+
+ /* typecast an object to a FT_Module */
+#define FT_MODULE( x ) ((FT_Module)(x))
+#define FT_MODULE_CLASS( x ) FT_MODULE(x)->clazz
+#define FT_MODULE_LIBRARY( x ) FT_MODULE(x)->library
+#define FT_MODULE_MEMORY( x ) FT_MODULE(x)->memory
+
+#define FT_MODULE_IS_DRIVER( x ) ( FT_MODULE_CLASS( x )->module_flags & \
+ ft_module_font_driver )
+
+#define FT_MODULE_IS_RENDERER( x ) ( FT_MODULE_CLASS( x )->module_flags & \
+ ft_module_renderer )
+
+#define FT_MODULE_IS_HINTER( x ) ( FT_MODULE_CLASS( x )->module_flags & \
+ ft_module_hinter )
+
+#define FT_MODULE_IS_STYLER( x ) ( FT_MODULE_CLASS( x )->module_flags & \
+ ft_module_styler )
+
+#define FT_DRIVER_IS_SCALABLE( x ) ( FT_MODULE_CLASS(x)->module_flags & \
+ ft_module_driver_scalable )
+
+#define FT_DRIVER_USES_OUTLINES( x ) !( FT_MODULE_CLASS(x)->module_flags & \
+ ft_module_driver_no_outlines )
+
+#define FT_DRIVER_HAS_HINTER( x ) ( FT_MODULE_CLASS(x)->module_flags & \
+ ft_module_driver_has_hinter )
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Module_Interface */
+ /* */
+ /* <Description> */
+ /* Finds a module and returns its specific interface as a typeless */
+ /* pointer. */
+ /* */
+ /* <Input> */
+ /* library :: A handle to the library object. */
+ /* */
+ /* module_name :: The module's name (as an ASCII string). */
+ /* */
+ /* <Return> */
+ /* A module-specific interface if available, 0 otherwise. */
+ /* */
+ /* <Note> */
+ /* You should better be familiar with FreeType internals to know */
+ /* which module to look for, and what its interface is :-) */
+ /* */
+ FT_BASE( const void* )
+ FT_Get_Module_Interface( FT_Library library,
+ const char* mod_name );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** FACE, SIZE & GLYPH SLOT OBJECTS ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* a few macros used to perform easy typecasts with minimal brain damage */
+
+#define FT_FACE( x ) ((FT_Face)(x))
+#define FT_SIZE( x ) ((FT_Size)(x))
+#define FT_SLOT( x ) ((FT_GlyphSlot)(x))
+
+#define FT_FACE_DRIVER( x ) FT_FACE( x )->driver
+#define FT_FACE_LIBRARY( x ) FT_FACE_DRIVER( x )->root.library
+#define FT_FACE_MEMORY( x ) FT_FACE( x )->memory
+
+#define FT_SIZE_FACE( x ) FT_SIZE( x )->face
+#define FT_SLOT_FACE( x ) FT_SLOT( x )->face
+
+#define FT_FACE_SLOT( x ) FT_FACE( x )->glyph
+#define FT_FACE_SIZE( x ) FT_FACE( x )->size
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_New_GlyphSlot */
+ /* */
+ /* <Description> */
+ /* It is sometimes useful to have more than one glyph slot for a */
+ /* given face object. This function is used to create additional */
+ /* slots. All of them are automatically discarded when the face is */
+ /* destroyed. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to a parent face object. */
+ /* */
+ /* <Output> */
+ /* aslot :: A handle to a new glyph slot object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_BASE( FT_Error )
+ FT_New_GlyphSlot( FT_Face face,
+ FT_GlyphSlot *aslot );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Done_GlyphSlot */
+ /* */
+ /* <Description> */
+ /* Destroys a given glyph slot. Remember however that all slots are */
+ /* automatically destroyed with its parent. Using this function is */
+ /* not always mandatory. */
+ /* */
+ /* <Input> */
+ /* slot :: A handle to a target glyph slot. */
+ /* */
+ FT_BASE( void )
+ FT_Done_GlyphSlot( FT_GlyphSlot slot );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** G L Y P H L O A D E R ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#define FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS 1
+#define FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES 2
+#define FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID 4
+#define FT_SUBGLYPH_FLAG_SCALE 8
+#define FT_SUBGLYPH_FLAG_XY_SCALE 0x40
+#define FT_SUBGLYPH_FLAG_2X2 0x80
+#define FT_SUBGLYPH_FLAG_USE_MY_METRICS 0x200
+
+
+ enum
+ {
+ ft_glyph_own_bitmap = 1
+ };
+
+
+ struct FT_SubGlyph_
+ {
+ FT_Int index;
+ FT_UShort flags;
+ FT_Int arg1;
+ FT_Int arg2;
+ FT_Matrix transform;
+ };
+
+
+ typedef struct FT_GlyphLoad_
+ {
+ FT_Outline outline; /* outline */
+ FT_UInt num_subglyphs; /* number of subglyphs */
+ FT_SubGlyph* subglyphs; /* subglyphs */
+ FT_Vector* extra_points; /* extra points table */
+
+ } FT_GlyphLoad;
+
+
+ struct FT_GlyphLoader_
+ {
+ FT_Memory memory;
+ FT_UInt max_points;
+ FT_UInt max_contours;
+ FT_UInt max_subglyphs;
+ FT_Bool use_extra;
+
+ FT_GlyphLoad base;
+ FT_GlyphLoad current;
+
+ void* other; /* for possible future extension? */
+
+ };
+
+
+ FT_BASE( FT_Error )
+ FT_GlyphLoader_New( FT_Memory memory,
+ FT_GlyphLoader* *aloader );
+
+ FT_BASE( FT_Error )
+ FT_GlyphLoader_Create_Extra( FT_GlyphLoader* loader );
+
+ FT_BASE( void )
+ FT_GlyphLoader_Done( FT_GlyphLoader* loader );
+
+ FT_BASE( void )
+ FT_GlyphLoader_Reset( FT_GlyphLoader* loader );
+
+ FT_BASE( void )
+ FT_GlyphLoader_Rewind( FT_GlyphLoader* loader );
+
+ FT_BASE( FT_Error )
+ FT_GlyphLoader_Check_Points( FT_GlyphLoader* loader,
+ FT_UInt n_points,
+ FT_UInt n_contours );
+
+ FT_BASE( FT_Error )
+ FT_GlyphLoader_Check_Subglyphs( FT_GlyphLoader* loader,
+ FT_UInt n_subs );
+
+ FT_BASE( void )
+ FT_GlyphLoader_Prepare( FT_GlyphLoader* loader );
+
+ FT_BASE( void )
+ FT_GlyphLoader_Add( FT_GlyphLoader* loader );
+
+ FT_BASE( FT_Error )
+ FT_GlyphLoader_Copy_Points( FT_GlyphLoader* target,
+ FT_GlyphLoader* source );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** R E N D E R E R S ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#define FT_RENDERER( x ) ((FT_Renderer)( x ))
+#define FT_GLYPH( x ) ((FT_Glyph)( x ))
+#define FT_BITMAP_GLYPH( x ) ((FT_BitmapGlyph)( x ))
+#define FT_OUTLINE_GLYPH( x ) ((FT_OutlineGlyph)( x ))
+
+
+ typedef struct FT_RendererRec_
+ {
+ FT_ModuleRec root;
+ FT_Renderer_Class* clazz;
+ FT_Glyph_Format glyph_format;
+ FT_Glyph_Class glyph_class;
+
+ FT_Raster raster;
+ FT_Raster_Render_Func raster_render;
+ FTRenderer_render render;
+
+ } FT_RendererRec;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** F O N T D R I V E R S ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* typecast a module into a driver easily */
+#define FT_DRIVER( x ) ((FT_Driver)(x))
+
+ /* typecast a module as a driver, and get its driver class */
+#define FT_DRIVER_CLASS( x ) FT_DRIVER( x )->clazz
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_DriverRec */
+ /* */
+ /* <Description> */
+ /* The root font driver class. A font driver is responsible for */
+ /* managing and loading font files of a given format. */
+ /* */
+ /* <Fields> */
+ /* root :: Contains the fields of the root module class. */
+ /* */
+ /* clazz :: A pointer to the font driver's class. Note that */
+ /* this is NOT root.clazz. `class' wasn't used */
+ /* as it is a reserved word in C++. */
+ /* */
+ /* faces_list :: The list of faces currently opened by this */
+ /* driver. */
+ /* */
+ /* extensions :: A typeless pointer to the driver's extensions */
+ /* registry, if they are supported through the */
+ /* configuration macro FT_CONFIG_OPTION_EXTENSIONS. */
+ /* */
+ /* glyph_loader :: The glyph loader for all faces managed by this */
+ /* driver. This object isn't defined for unscalable */
+ /* formats. */
+ /* */
+ typedef struct FT_DriverRec_
+ {
+ FT_ModuleRec root;
+ FT_Driver_Class* clazz;
+
+ FT_ListRec faces_list;
+ void* extensions;
+
+ FT_GlyphLoader* glyph_loader;
+
+ } FT_DriverRec;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** L I B R A R I E S ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#define FT_DEBUG_HOOK_TRUETYPE 0
+#define FT_DEBUG_HOOK_TYPE1 1
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* FT_LibraryRec */
+ /* */
+ /* <Description> */
+ /* The FreeType library class. This is the root of all FreeType */
+ /* data. Use FT_New_Library() to create a library object, and */
+ /* FT_Done_Library() to discard it and all child objects. */
+ /* */
+ /* <Fields> */
+ /* memory :: The library's memory object. Manages memory */
+ /* allocation. */
+ /* */
+ /* generic :: Client data variable. Used to extend the */
+ /* Library class by higher levels and clients. */
+ /* */
+ /* num_modules :: The number of modules currently registered */
+ /* within this library. This is set to 0 for new */
+ /* libraries. New modules are added through the */
+ /* FT_Add_Module() API function. */
+ /* */
+ /* modules :: A table used to store handles to the currently */
+ /* registered modules. Note that each font driver */
+ /* contains a list of its opened faces. */
+ /* */
+ /* renderers :: The list of renderers currently registered */
+ /* within the library. */
+ /* */
+ /* cur_renderer :: The current outline renderer. This is a */
+ /* shortcut used to avoid parsing the list on */
+ /* each call to FT_Outline_Render(). It is a */
+ /* handle to the current renderer for the */
+ /* ft_glyph_format_outline format. */
+ /* */
+ /* auto_hinter :: XXX */
+ /* */
+ /* raster_pool :: The raster object's render pool. This can */
+ /* ideally be changed dynamically at run-time. */
+ /* */
+ /* raster_pool_size :: The size of the render pool in bytes. */
+ /* */
+ /* debug_hooks :: XXX */
+ /* */
+ typedef struct FT_LibraryRec_
+ {
+ FT_Memory memory; /* library's memory manager */
+
+ FT_Generic generic;
+
+ FT_UInt num_modules;
+ FT_Module modules[FT_MAX_MODULES]; /* module objects */
+
+ FT_ListRec renderers; /* list of renderers */
+ FT_Renderer cur_renderer; /* current outline renderer */
+ FT_Module auto_hinter;
+
+ FT_Byte* raster_pool; /* scan-line conversion */
+ /* render pool */
+ FT_ULong raster_pool_size; /* size of render pool in bytes */
+
+ FT_DebugHook_Func debug_hooks[4];
+
+ } FT_LibraryRec;
+
+
+ FT_BASE( FT_Renderer )
+ FT_Lookup_Renderer( FT_Library library,
+ FT_Glyph_Format format,
+ FT_ListNode* node );
+
+ FT_BASE( FT_Error )
+ FT_Render_Glyph_Internal( FT_Library library,
+ FT_GlyphSlot slot,
+ FT_UInt render_mode );
+
+ typedef const char*
+ (*FT_PSName_Requester)( FT_Face face );
+
+ typedef FT_Error
+ (*FT_Glyph_Name_Requester)( FT_Face face,
+ FT_UInt glyph_index,
+ FT_Pointer buffer,
+ FT_UInt buffer_max );
+
+ typedef FT_UInt
+ (*FT_Name_Index_Requester)( FT_Face face,
+ FT_String* glyph_name );
+
+
+#ifndef FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_New_Stream */
+ /* */
+ /* <Description> */
+ /* Creates a new stream object. */
+ /* */
+ /* <Input> */
+ /* filepathname :: The name of the stream (usually a file) to be */
+ /* opened. */
+ /* */
+ /* stream :: A pointer to the stream object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_EXPORT( FT_Error )
+ FT_New_Stream( const char* filepathname,
+ FT_Stream astream );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Done_Stream */
+ /* */
+ /* <Description> */
+ /* Closes and destroys a stream object. */
+ /* */
+ /* <Input> */
+ /* stream :: The stream to be closed and destroyed. */
+ /* */
+ FT_EXPORT( void )
+ FT_Done_Stream( FT_Stream stream );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_New_Memory */
+ /* */
+ /* <Description> */
+ /* Creates a new memory object. */
+ /* */
+ /* <Return> */
+ /* A pointer to the new memory object. 0 in case of error. */
+ /* */
+ FT_EXPORT( FT_Memory )
+ FT_New_Memory( void );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Done_Memory */
+ /* */
+ /* <Description> */
+ /* Discards memory manager. */
+ /* */
+ /* <Input> */
+ /* memory :: A handle to the memory manager. */
+ /* */
+ FT_EXPORT( void )
+ FT_Done_Memory( FT_Memory memory );
+
+#endif /* !FT_CONFIG_OPTION_NO_DEFAULT_SYSTEM */
+
+
+ /* Define default raster's interface. The default raster is located in */
+ /* `src/base/ftraster.c'. */
+ /* */
+ /* Client applications can register new rasters through the */
+ /* FT_Set_Raster() API. */
+
+#ifndef FT_NO_DEFAULT_RASTER
+ FT_EXPORT_VAR( FT_Raster_Funcs ) ft_default_raster;
+#endif
+
+
+FT_END_HEADER
+
+#endif /* __FTOBJS_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftstream.h */
+/* */
+/* Stream handling(specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTSTREAM_H__
+#define __FTSTREAM_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+
+
+FT_BEGIN_HEADER
+
+
+ /* format of an 8-bit frame_op value = [ xxxxx | e | s ] */
+ /* s is set to 1 if the value is signed, */
+ /* e is set to 1 if the value is little-endian */
+ /* xxxxx is a command */
+
+#define FT_FRAME_OP_SHIFT 2
+#define FT_FRAME_OP_SIGNED 1
+#define FT_FRAME_OP_LITTLE 2
+#define FT_FRAME_OP_COMMAND( x ) ( x >> FT_FRAME_OP_SHIFT )
+
+#define FT_MAKE_FRAME_OP( command, little, sign ) \
+ ( ( command << FT_FRAME_OP_SHIFT ) | ( little << 1 ) | sign )
+
+#define FT_FRAME_OP_END 0
+#define FT_FRAME_OP_START 1 /* start a new frame */
+#define FT_FRAME_OP_BYTE 2 /* read 1-byte value */
+#define FT_FRAME_OP_SHORT 3 /* read 2-byte value */
+#define FT_FRAME_OP_LONG 4 /* read 4-byte value */
+#define FT_FRAME_OP_OFF3 5 /* read 3-byte value */
+#define FT_FRAME_OP_BYTES 6 /* read a bytes sequence */
+
+
+ typedef enum FT_Frame_Op_
+ {
+ ft_frame_end = 0,
+ ft_frame_start = FT_MAKE_FRAME_OP( FT_FRAME_OP_START, 0, 0 ),
+
+ ft_frame_byte = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTE, 0, 0 ),
+ ft_frame_schar = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTE, 0, 1 ),
+
+ ft_frame_ushort_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 0, 0 ),
+ ft_frame_short_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 0, 1 ),
+ ft_frame_ushort_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 1, 0 ),
+ ft_frame_short_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 1, 1 ),
+
+ ft_frame_ulong_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 0, 0 ),
+ ft_frame_long_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 0, 1 ),
+ ft_frame_ulong_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 1, 0 ),
+ ft_frame_long_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 1, 1 ),
+
+ ft_frame_uoff3_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 0, 0 ),
+ ft_frame_off3_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 0, 1 ),
+ ft_frame_uoff3_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 1, 0 ),
+ ft_frame_off3_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 1, 1 ),
+
+ ft_frame_bytes = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTES, 0, 0 ),
+ ft_frame_skip = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTES, 0, 1 )
+
+ } FT_Frame_Op;
+
+
+ typedef struct FT_Frame_Field_
+ {
+ FT_Byte value;
+ FT_Byte size;
+ FT_UShort offset;
+
+ } FT_Frame_Field;
+
+
+ /* Construct an FT_Frame_Field out of a structure type and a field name. */
+ /* The structure type must be set in the FT_STRUCTURE macro before */
+ /* calling the FT_FRAME_START() macro. */
+#define FT_FIELD_SIZE( f ) \
+ (FT_Byte)sizeof ( ((FT_STRUCTURE*)0)->f )
+
+#define FT_FIELD_SIZE_DELTA( f ) \
+ (FT_Byte)sizeof ( ((FT_STRUCTURE*)0)->f[0] )
+
+#define FT_FIELD_OFFSET( f ) \
+ (FT_UShort)( offsetof( FT_STRUCTURE, f ) )
+
+#define FT_FRAME_FIELD( frame_op, field ) \
+ { \
+ frame_op, \
+ FT_FIELD_SIZE( field ), \
+ FT_FIELD_OFFSET( field ) \
+ }
+
+#define FT_MAKE_EMPTY_FIELD( frame_op ) { frame_op, 0, 0 }
+
+#define FT_FRAME_START( size ) { ft_frame_start, 0, size }
+#define FT_FRAME_END { ft_frame_end, 0, 0 }
+
+#define FT_FRAME_LONG( f ) FT_FRAME_FIELD( ft_frame_long_be, f )
+#define FT_FRAME_ULONG( f ) FT_FRAME_FIELD( ft_frame_ulong_be, f )
+#define FT_FRAME_SHORT( f ) FT_FRAME_FIELD( ft_frame_short_be, f )
+#define FT_FRAME_USHORT( f ) FT_FRAME_FIELD( ft_frame_ushort_be, f )
+#define FT_FRAME_BYTE( f ) FT_FRAME_FIELD( ft_frame_byte, f )
+#define FT_FRAME_CHAR( f ) FT_FRAME_FIELD( ft_frame_schar, f )
+
+#define FT_FRAME_LONG_LE( f ) FT_FRAME_FIELD( ft_frame_long_le, f )
+#define FT_FRAME_ULONG_LE( f ) FT_FRAME_FIELD( ft_frame_ulong_le, f )
+#define FT_FRAME_SHORT_LE( f ) FT_FRAME_FIELD( ft_frame_short_le, f )
+#define FT_FRAME_USHORT_LE( f ) FT_FRAME_FIELD( ft_frame_ushort_le, f )
+
+#define FT_FRAME_SKIP_LONG { ft_frame_long_be, 0, 0 }
+#define FT_FRAME_SKIP_SHORT { ft_frame_short_be, 0, 0 }
+#define FT_FRAME_SKIP_BYTE { ft_frame_byte, 0, 0 }
+
+#define FT_FRAME_BYTES( field, count ) \
+ { \
+ ft_frame_bytes, \
+ count, \
+ FT_FIELD_OFFSET( field ) \
+ }
+
+#define FT_FRAME_SKIP_BYTES( count ) { ft_frame_skip, count, 0 }
+
+
+
+ /*************************************************************************/
+ /* */
+ /* integer extraction macros -- the `buffer' parameter must ALWAYS be of */
+ /* type `char*' or equivalent (1-byte elements). */
+ /* */
+
+#define FT_GET_SHORT_BE( p ) \
+ ((FT_Int16)( ( (FT_Int16)(FT_Char)(p)[0] << 8 ) | \
+ (FT_Int16)(FT_Byte)(p)[1] ) )
+
+#define FT_GET_USHORT_BE( p ) \
+ ((FT_Int16)( ( (FT_UInt16)(FT_Byte)(p)[0] << 8 ) | \
+ (FT_UInt16)(FT_Byte)(p)[1] ) )
+
+#define FT_GET_OFF3_BE( p ) \
+ ( (FT_Int32) ( ( (FT_Int32)(FT_Char)(p)[0] << 16 ) | \
+ ( (FT_Int32)(FT_Byte)(p)[1] << 8 ) | \
+ (FT_Int32)(FT_Byte)(p)[2] ) )
+
+#define FT_GET_UOFF3_BE( p ) \
+ ( (FT_Int32) ( ( (FT_UInt32)(FT_Byte)(p)[0] << 16 ) | \
+ ( (FT_UInt32)(FT_Byte)(p)[1] << 8 ) | \
+ (FT_UInt32)(FT_Byte)(p)[2] ) )
+
+#define FT_GET_LONG_BE( p ) \
+ ( (FT_Int32) ( ( (FT_Int32)(FT_Char)(p)[0] << 24 ) | \
+ ( (FT_Int32)(FT_Byte)(p)[1] << 16 ) | \
+ ( (FT_Int32)(FT_Byte)(p)[2] << 8 ) | \
+ (FT_Int32)(FT_Byte)(p)[3] ) )
+
+#define FT_GET_ULONG_BE( p ) \
+ ( (FT_Int32) ( ( (FT_UInt32)(FT_Byte)(p)[0] << 24 ) | \
+ ( (FT_UInt32)(FT_Byte)(p)[1] << 16 ) | \
+ ( (FT_UInt32)(FT_Byte)(p)[2] << 8 ) | \
+ (FT_UInt32)(FT_Byte)(p)[3] ) )
+
+#define FT_GET_SHORT_LE( p ) \
+ ((FT_Int16)( ( (FT_Int16)(FT_Char)(p)[1] << 8 ) | \
+ (FT_Int16)(FT_Byte)(p)[0] ) )
+
+#define FT_GET_USHORT_LE( p ) \
+ ((FT_Int16)( ( (FT_UInt16)(FT_Byte)(p)[1] << 8 ) | \
+ (FT_UInt16)(FT_Byte)(p)[0] ) )
+
+#define FT_GET_OFF3_LE( p ) \
+ ( (FT_Int32) ( ( (FT_Int32)(FT_Char)(p)[2] << 16 ) | \
+ ( (FT_Int32)(FT_Byte)(p)[1] << 8 ) | \
+ (FT_Int32)(FT_Byte)(p)[0] ) )
+
+#define FT_GET_UOFF3_LE( p ) \
+ ( (FT_Int32) ( ( (FT_UInt32)(FT_Byte)(p)[2] << 16 ) | \
+ ( (FT_UInt32)(FT_Byte)(p)[1] << 8 ) | \
+ (FT_UInt32)(FT_Byte)(p)[0] ) )
+
+#define FT_GET_LONG_LE( p ) \
+ ( (FT_Int32) ( ( (FT_Int32)(FT_Char)(p)[3] << 24 ) | \
+ ( (FT_Int32)(FT_Byte)(p)[2] << 16 ) | \
+ ( (FT_Int32)(FT_Byte)(p)[1] << 8 ) | \
+ (FT_Int32)(FT_Byte)(p)[0] ) )
+
+#define FT_GET_ULONG_LE( p ) \
+ ( (FT_Int32) ( ( (FT_UInt32)(FT_Byte)(p)[3] << 24 ) | \
+ ( (FT_UInt32)(FT_Byte)(p)[2] << 16 ) | \
+ ( (FT_UInt32)(FT_Byte)(p)[1] << 8 ) | \
+ (FT_UInt32)(FT_Byte)(p)[0] ) )
+
+
+#define NEXT_Char( buffer ) \
+ ( (signed char)*buffer++ )
+
+#define NEXT_Byte( buffer ) \
+ ( (unsigned char)*buffer++ )
+
+#define NEXT_Short( buffer ) \
+ ( (short)( buffer += 2, FT_GET_SHORT_BE( buffer - 2 ) ) )
+
+#define NEXT_UShort( buffer ) \
+ ( (unsigned short)( buffer += 2, FT_GET_USHORT_BE( buffer - 2 ) ) )
+
+#define NEXT_Offset( buffer ) \
+ ( (long)( buffer += 3, FT_GET_OFF3_BE( buffer - 3 ) ) )
+
+#define NEXT_UOffset( buffer ) \
+ ( (unsigned long)( buffer += 3, FT_GET_UOFF3_BE( buffer - 3 ) ) )
+
+#define NEXT_Long( buffer ) \
+ ( (long)( buffer += 4, FT_GET_LONG_BE( buffer - 4 ) ) )
+
+#define NEXT_ULong( buffer ) \
+ ( (unsigned long)( buffer += 4, FT_GET_ULONG_BE( buffer - 4 ) ) )
+
+
+#define NEXT_ShortLE( buffer ) \
+ ( (short)( buffer += 2, FT_GET_SHORT_LE( buffer - 2 ) ) )
+
+#define NEXT_UShortLE( buffer ) \
+ ( (unsigned short)( buffer += 2, FT_GET_USHORT_LE( buffer - 2 ) ) )
+
+#define NEXT_OffsetLE( buffer ) \
+ ( (long)( buffer += 3, FT_GET_OFF3_LE( buffer - 3 ) ) )
+
+#define NEXT_UOffsetLE( buffer ) \
+ ( (unsigned long)( buffer += 3, FT_GET_UOFF3_LE( buffer - 3 ) ) )
+
+
+#define NEXT_LongLE( buffer ) \
+ ( (long)( buffer += 4, FT_GET_LONG_LE( buffer - 4 ) ) )
+
+#define NEXT_ULongLE( buffer ) \
+ ( (unsigned long)( buffer += 4, FT_GET_ULONG_LE( buffer - 4 ) ) )
+
+
+ /*************************************************************************/
+ /* */
+ /* Each GET_xxxx() macro uses an implicit `stream' variable. */
+ /* */
+#define FT_GET_MACRO( func, type ) ( (type)func( stream ) )
+
+#define GET_Char() FT_GET_MACRO( FT_Get_Char, FT_Char )
+#define GET_Byte() FT_GET_MACRO( FT_Get_Char, FT_Byte )
+#define GET_Short() FT_GET_MACRO( FT_Get_Short, FT_Short )
+#define GET_UShort() FT_GET_MACRO( FT_Get_Short, FT_UShort )
+#define GET_Offset() FT_GET_MACRO( FT_Get_Offset, FT_Long )
+#define GET_UOffset() FT_GET_MACRO( FT_Get_Offset, FT_ULong )
+#define GET_Long() FT_GET_MACRO( FT_Get_Long, FT_Long )
+#define GET_ULong() FT_GET_MACRO( FT_Get_Long, FT_ULong )
+#define GET_Tag4() FT_GET_MACRO( FT_Get_Long, FT_ULong )
+
+#define GET_ShortLE() FT_GET_MACRO( FT_Get_ShortLE, FT_Short )
+#define GET_UShortLE() FT_GET_MACRO( FT_Get_ShortLE, FT_UShort )
+#define GET_LongLE() FT_GET_MACRO( FT_Get_LongLE, FT_Short )
+#define GET_ULongLE() FT_GET_MACRO( FT_Get_LongLE, FT_Short )
+
+#define FT_READ_MACRO( func, type, var ) \
+ ( var = (type)func( stream, &error ), \
+ error != FT_Err_Ok )
+
+#define READ_Byte( var ) FT_READ_MACRO( FT_Read_Char, FT_Byte, var )
+#define READ_Char( var ) FT_READ_MACRO( FT_Read_Char, FT_Char, var )
+#define READ_Short( var ) FT_READ_MACRO( FT_Read_Short, FT_Short, var )
+#define READ_UShort( var ) FT_READ_MACRO( FT_Read_Short, FT_UShort, var )
+#define READ_Offset( var ) FT_READ_MACRO( FT_Read_Offset, FT_Long, var )
+#define READ_UOffset( var ) FT_READ_MACRO( FT_Read_Offset, FT_ULong, var )
+#define READ_Long( var ) FT_READ_MACRO( FT_Read_Long, FT_Long, var )
+#define READ_ULong( var ) FT_READ_MACRO( FT_Read_Long, FT_ULong, var )
+
+#define READ_ShortLE( var ) FT_READ_MACRO( FT_Read_ShortLE, FT_Short, var )
+#define READ_UShortLE( var ) FT_READ_MACRO( FT_Read_ShortLE, FT_UShort, var )
+#define READ_LongLE( var ) FT_READ_MACRO( FT_Read_LongLE, FT_Long, var )
+#define READ_ULongLE( var ) FT_READ_MACRO( FT_Read_LongLE, FT_ULong, var )
+
+
+ FT_BASE( void )
+ FT_New_Memory_Stream( FT_Library library,
+ FT_Byte* base,
+ FT_ULong size,
+ FT_Stream stream );
+
+ FT_BASE( FT_Error )
+ FT_Seek_Stream( FT_Stream stream,
+ FT_ULong pos );
+
+ FT_BASE( FT_Error )
+ FT_Skip_Stream( FT_Stream stream,
+ FT_Long distance );
+
+ FT_BASE( FT_Long )
+ FT_Stream_Pos( FT_Stream stream );
+
+
+ FT_BASE( FT_Error )
+ FT_Read_Stream( FT_Stream stream,
+ FT_Byte* buffer,
+ FT_ULong count );
+
+ FT_BASE( FT_Error )
+ FT_Read_Stream_At( FT_Stream stream,
+ FT_ULong pos,
+ FT_Byte* buffer,
+ FT_ULong count );
+
+ FT_BASE( FT_Error )
+ FT_Access_Frame( FT_Stream stream,
+ FT_ULong count );
+
+ FT_BASE( void )
+ FT_Forget_Frame( FT_Stream stream );
+
+ FT_BASE( FT_Error )
+ FT_Extract_Frame( FT_Stream stream,
+ FT_ULong count,
+ FT_Byte** pbytes );
+
+ FT_BASE( void )
+ FT_Release_Frame( FT_Stream stream,
+ FT_Byte** pbytes );
+
+ FT_BASE( FT_Char )
+ FT_Get_Char( FT_Stream stream );
+
+ FT_BASE( FT_Short )
+ FT_Get_Short( FT_Stream stream );
+
+ FT_BASE( FT_Long )
+ FT_Get_Offset( FT_Stream stream );
+
+ FT_BASE( FT_Long )
+ FT_Get_Long( FT_Stream stream );
+
+ FT_BASE( FT_Short )
+ FT_Get_ShortLE( FT_Stream stream );
+
+ FT_BASE( FT_Long )
+ FT_Get_LongLE( FT_Stream stream );
+
+
+ FT_BASE( FT_Char )
+ FT_Read_Char( FT_Stream stream,
+ FT_Error* error );
+
+ FT_BASE( FT_Short )
+ FT_Read_Short( FT_Stream stream,
+ FT_Error* error );
+
+ FT_BASE( FT_Long )
+ FT_Read_Offset( FT_Stream stream,
+ FT_Error* error );
+
+ FT_BASE( FT_Long )
+ FT_Read_Long( FT_Stream stream,
+ FT_Error* error );
+
+ FT_BASE( FT_Short )
+ FT_Read_ShortLE( FT_Stream stream,
+ FT_Error* error );
+
+ FT_BASE( FT_Long )
+ FT_Read_LongLE( FT_Stream stream,
+ FT_Error* error );
+
+ FT_BASE( FT_Error )
+ FT_Read_Fields( FT_Stream stream,
+ const FT_Frame_Field* fields,
+ void* structure );
+
+
+#define USE_Stream( resource, stream ) \
+ FT_SET_ERROR( FT_Open_Stream( resource, stream ) )
+
+#define DONE_Stream( stream ) \
+ FT_Done_Stream( stream )
+
+
+#define ACCESS_Frame( size ) \
+ FT_SET_ERROR( FT_Access_Frame( stream, size ) )
+
+#define FORGET_Frame() \
+ FT_Forget_Frame( stream )
+
+#define EXTRACT_Frame( size, bytes ) \
+ FT_SET_ERROR( FT_Extract_Frame( stream, size, \
+ (FT_Byte**)&(bytes) ) )
+
+#define RELEASE_Frame( bytes ) \
+ FT_Release_Frame( stream, (FT_Byte**)&(bytes) )
+
+#define FILE_Seek( position ) \
+ FT_SET_ERROR( FT_Seek_Stream( stream, position ) )
+
+#define FILE_Skip( distance ) \
+ FT_SET_ERROR( FT_Skip_Stream( stream, distance ) )
+
+#define FILE_Pos() \
+ FT_Stream_Pos( stream )
+
+#define FILE_Read( buffer, count ) \
+ FT_SET_ERROR( FT_Read_Stream( stream, \
+ (FT_Byte*)buffer, \
+ count ) )
+
+#define FILE_Read_At( position, buffer, count ) \
+ FT_SET_ERROR( FT_Read_Stream_At( stream, \
+ position, \
+ (FT_Byte*)buffer, \
+ count ) )
+
+#define READ_Fields( fields, object ) \
+ ( ( error = FT_Read_Fields( stream, fields, object ) ) != FT_Err_Ok )
+
+
+FT_END_HEADER
+
+#endif /* __FTSTREAM_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* internal.h */
+/* */
+/* Internal header files (specification only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is automatically included by `ft2build.h'. */
+ /* Do not include it manually! */
+ /* */
+ /*************************************************************************/
+
+
+#define FT_INTERNAL_OBJECTS_H <freetype/internal/ftobjs.h>
+#define FT_INTERNAL_STREAM_H <freetype/internal/ftstream.h>
+#define FT_INTERNAL_MEMORY_H <freetype/internal/ftmemory.h>
+#define FT_INTERNAL_EXTENSION_H <freetype/internal/ftextend.h>
+#define FT_INTERNAL_DEBUG_H <freetype/internal/ftdebug.h>
+#define FT_INTERNAL_CALC_H <freetype/internal/ftcalc.h>
+#define FT_INTERNAL_DRIVER_H <freetype/internal/ftdriver.h>
+#define FT_INTERNAL_EXTEND_H <freetype/internal/ftextend.h>
+
+#define FT_INTERNAL_SFNT_H <freetype/internal/sfnt.h>
+
+#define FT_INTERNAL_TRUETYPE_TYPES_H <freetype/internal/tttypes.h>
+#define FT_INTERNAL_TYPE1_TYPES_H <freetype/internal/t1types.h>
+#define FT_INTERNAL_CFF_TYPES_H <freetype/internal/cfftypes.h>
+#define FT_INTERNAL_FNT_TYPES_H <freetype/internal/fnttypes.h>
+
+#define FT_INTERNAL_POSTSCRIPT_NAMES_H <freetype/internal/psnames.h>
+#define FT_INTERNAL_POSTSCRIPT_AUX_H <freetype/internal/psaux.h>
+
+#define FT_INTERNAL_AUTOHINT_H <freetype/internal/autohint.h>
+
+
+/* END */
--- /dev/null
+/* pcftypes.h
+
+ FreeType font driver for pcf fonts
+
+ Copyright (C) 2000-2001 by
+ Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#ifndef __PCFTYPES_H__
+#define __PCFTYPES_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+
+FT_BEGIN_HEADER
+
+
+ typedef struct PCF_Public_FaceRec_
+ {
+ FT_FaceRec root;
+
+ char* charset_encoding;
+ char* charset_registry;
+
+ } PCF_Public_FaceRec, *PCF_Public_Face;
+
+
+FT_END_HEADER
+
+#endif /* __PCFTYPES_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* psaux.h */
+/* */
+/* Auxiliary functions and data structures related to PostScript fonts */
+/* (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __PSAUX_H__
+#define __PSAUX_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** T1_TABLE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ typedef struct PS_Table_ PS_Table;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* PS_Table_Funcs */
+ /* */
+ /* <Description> */
+ /* A set of function pointers to manage PS_Table objects. */
+ /* */
+ /* <Fields> */
+ /* table_init :: Used to initialize a table. */
+ /* */
+ /* table_done :: Finalizes resp. destroy a given table. */
+ /* */
+ /* table_add :: Adds a new object to a table. */
+ /* */
+ /* table_release :: Releases table data, then finalizes it. */
+ /* */
+ typedef struct PS_Table_Funcs_
+ {
+ FT_Error
+ (*init)( PS_Table* table,
+ FT_Int count,
+ FT_Memory memory );
+
+ void
+ (*done)( PS_Table* table );
+
+ FT_Error
+ (*add)( PS_Table* table,
+ FT_Int index,
+ void* object,
+ FT_Int length );
+
+ void
+ (*release)( PS_Table* table );
+
+ } PS_Table_Funcs;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* PS_Table */
+ /* */
+ /* <Description> */
+ /* A PS_Table is a simple object used to store an array of objects in */
+ /* a single memory block. */
+ /* */
+ /* <Fields> */
+ /* block :: The address in memory of the growheap's block. This */
+ /* can change between two object adds, due to */
+ /* reallocation. */
+ /* */
+ /* cursor :: The current top of the grow heap within its block. */
+ /* */
+ /* capacity :: The current size of the heap block. Increments by */
+ /* 1kByte chunks. */
+ /* */
+ /* max_elems :: The maximum number of elements in table. */
+ /* */
+ /* num_elems :: The current number of elements in table. */
+ /* */
+ /* elements :: A table of element addresses within the block. */
+ /* */
+ /* lengths :: A table of element sizes within the block. */
+ /* */
+ /* memory :: The object used for memory operations */
+ /* (alloc/realloc). */
+ /* */
+ /* funcs :: A table of method pointers for this object. */
+ /* */
+ struct PS_Table_
+ {
+ FT_Byte* block; /* current memory block */
+ FT_Offset cursor; /* current cursor in memory block */
+ FT_Offset capacity; /* current size of memory block */
+ FT_Long init;
+
+ FT_Int max_elems;
+ FT_Int num_elems;
+ FT_Byte** elements; /* addresses of table elements */
+ FT_Int* lengths; /* lengths of table elements */
+
+ FT_Memory memory;
+ PS_Table_Funcs funcs;
+
+ };
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** T1 FIELDS & TOKENS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ typedef struct T1_Parser_ T1_Parser;
+
+ /* simple enumeration type used to identify token types */
+ typedef enum T1_Token_Type_
+ {
+ t1_token_none = 0,
+ t1_token_any,
+ t1_token_string,
+ t1_token_array,
+
+ /* do not remove */
+ t1_token_max
+
+ } T1_Token_Type;
+
+
+ /* a simple structure used to identify tokens */
+ typedef struct T1_Token_
+ {
+ FT_Byte* start; /* first character of token in input stream */
+ FT_Byte* limit; /* first character after the token */
+ T1_Token_Type type; /* type of token */
+
+ } T1_Token;
+
+
+ /* enumeration type used to identify object fields */
+ typedef enum T1_Field_Type_
+ {
+ t1_field_none = 0,
+ t1_field_bool,
+ t1_field_integer,
+ t1_field_fixed,
+ t1_field_string,
+ t1_field_integer_array,
+ t1_field_fixed_array,
+ t1_field_callback,
+
+ /* do not remove */
+ t1_field_max
+
+ } T1_Field_Type;
+
+ typedef enum T1_Field_Location_
+ {
+ t1_field_cid_info,
+ t1_field_font_dict,
+ t1_field_font_info,
+ t1_field_private,
+
+ /* do not remove */
+ t1_field_location_max
+
+ } T1_Field_Location;
+
+
+ typedef void
+ (*T1_Field_Parser)( FT_Face face,
+ FT_Pointer parser );
+
+
+ /* structure type used to model object fields */
+ typedef struct T1_Field_
+ {
+ const char* ident; /* field identifier */
+ T1_Field_Location location;
+ T1_Field_Type type; /* type of field */
+ T1_Field_Parser reader;
+ FT_UInt offset; /* offset of field in object */
+ FT_Byte size; /* size of field in bytes */
+ FT_UInt array_max; /* maximal number of elements for */
+ /* array */
+ FT_UInt count_offset; /* offset of element count for */
+ /* arrays */
+ } T1_Field;
+
+
+#define T1_NEW_SIMPLE_FIELD( _ident, _type, _fname ) \
+ { \
+ _ident, T1CODE, _type, \
+ 0, \
+ FT_FIELD_OFFSET( _fname ), \
+ FT_FIELD_SIZE( _fname ), \
+ 0, 0 \
+ },
+
+#define T1_NEW_CALLBACK_FIELD( _ident, _reader ) \
+ { \
+ _ident, T1CODE, t1_field_callback, \
+ (T1_Field_Parser)_reader, \
+ 0, 0, \
+ 0, 0 \
+ },
+
+#define T1_NEW_TABLE_FIELD( _ident, _type, _fname, _max ) \
+ { \
+ _ident, T1CODE, _type, \
+ 0, \
+ FT_FIELD_OFFSET( _fname ), \
+ FT_FIELD_SIZE_DELTA( _fname ), \
+ _max, \
+ FT_FIELD_OFFSET( num_ ## _fname ) \
+ },
+
+#define T1_NEW_TABLE_FIELD2( _ident, _type, _fname, _max ) \
+ { \
+ _ident, T1CODE, _type, \
+ 0, \
+ FT_FIELD_OFFSET( _fname ), \
+ FT_FIELD_SIZE_DELTA( _fname ), \
+ _max, 0 \
+ },
+
+
+#define T1_FIELD_BOOL( _ident, _fname ) \
+ T1_NEW_SIMPLE_FIELD( _ident, t1_field_bool, _fname )
+
+#define T1_FIELD_NUM( _ident, _fname ) \
+ T1_NEW_SIMPLE_FIELD( _ident, t1_field_integer, _fname )
+
+#define T1_FIELD_FIXED( _ident, _fname ) \
+ T1_NEW_SIMPLE_FIELD( _ident, t1_field_fixed, _fname )
+
+#define T1_FIELD_STRING( _ident, _fname ) \
+ T1_NEW_SIMPLE_FIELD( _ident, t1_field_string, _fname )
+
+#define T1_FIELD_NUM_TABLE( _ident, _fname, _fmax ) \
+ T1_NEW_TABLE_FIELD( _ident, t1_field_integer_array, \
+ _fname, _fmax )
+
+#define T1_FIELD_FIXED_TABLE( _ident, _fname, _fmax ) \
+ T1_NEW_TABLE_FIELD( _ident, t1_field_fixed_array, \
+ _fname, _fmax )
+
+#define T1_FIELD_NUM_TABLE2( _ident, _fname, _fmax ) \
+ T1_NEW_TABLE_FIELD2( _ident, t1_field_integer_array, \
+ _fname, _fmax )
+
+#define T1_FIELD_FIXED_TABLE2( _ident, _fname, _fmax ) \
+ T1_NEW_TABLE_FIELD2( _ident, t1_field_fixed_array, \
+ _fname, _fmax )
+
+#define T1_FIELD_CALLBACK( _ident, _name ) \
+ T1_NEW_CALLBACK_FIELD( _ident, _name )
+
+
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** T1 PARSER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ typedef struct T1_Parser_Funcs_
+ {
+ void
+ (*init)( T1_Parser* parser,
+ FT_Byte* base,
+ FT_Byte* limit,
+ FT_Memory memory );
+
+ void
+ (*done)( T1_Parser* parser );
+
+ void
+ (*skip_spaces)( T1_Parser* parser );
+ void
+ (*skip_alpha)( T1_Parser* parser );
+
+ FT_Long
+ (*to_int)( T1_Parser* parser );
+ FT_Fixed
+ (*to_fixed)( T1_Parser* parser,
+ FT_Int power_ten );
+ FT_Int
+ (*to_coord_array)( T1_Parser* parser,
+ FT_Int max_coords,
+ FT_Short* coords );
+ FT_Int
+ (*to_fixed_array)( T1_Parser* parser,
+ FT_Int max_values,
+ FT_Fixed* values,
+ FT_Int power_ten );
+
+ void
+ (*to_token)( T1_Parser* parser,
+ T1_Token* token );
+ void
+ (*to_token_array)( T1_Parser* parser,
+ T1_Token* tokens,
+ FT_UInt max_tokens,
+ FT_Int* pnum_tokens );
+
+ FT_Error
+ (*load_field)( T1_Parser* parser,
+ const T1_Field* field,
+ void** objects,
+ FT_UInt max_objects,
+ FT_ULong* pflags );
+
+ FT_Error
+ (*load_field_table)( T1_Parser* parser,
+ const T1_Field* field,
+ void** objects,
+ FT_UInt max_objects,
+ FT_ULong* pflags );
+
+ } T1_Parser_Funcs;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* T1_Parser */
+ /* */
+ /* <Description> */
+ /* A T1_Parser is an object used to parse a Type 1 font very quickly. */
+ /* */
+ /* <Fields> */
+ /* cursor :: The current position in the text. */
+ /* */
+ /* base :: Start of the processed text. */
+ /* */
+ /* limit :: End of the processed text. */
+ /* */
+ /* error :: The last error returned. */
+ /* */
+ /* memory :: The object used for memory operations (alloc/realloc). */
+ /* */
+ /* funcs :: A table of functions for the parser. */
+ /* */
+ struct T1_Parser_
+ {
+ FT_Byte* cursor;
+ FT_Byte* base;
+ FT_Byte* limit;
+ FT_Error error;
+ FT_Memory memory;
+
+ T1_Parser_Funcs funcs;
+ };
+
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** T1 BUILDER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ typedef struct T1_Builder_ T1_Builder;
+
+
+ typedef FT_Error
+ (*T1_Builder_Check_Points_Func)( T1_Builder* builder,
+ FT_Int count );
+
+ typedef void
+ (*T1_Builder_Add_Point_Func)( T1_Builder* builder,
+ FT_Pos x,
+ FT_Pos y,
+ FT_Byte flag );
+
+ typedef FT_Error
+ (*T1_Builder_Add_Point1_Func)( T1_Builder* builder,
+ FT_Pos x,
+ FT_Pos y );
+
+ typedef FT_Error
+ (*T1_Builder_Add_Contour_Func)( T1_Builder* builder );
+
+ typedef FT_Error
+ (*T1_Builder_Start_Point_Func)( T1_Builder* builder,
+ FT_Pos x,
+ FT_Pos y );
+
+ typedef void
+ (*T1_Builder_Close_Contour_Func)( T1_Builder* builder );
+
+
+ typedef struct T1_Builder_Funcs_
+ {
+ void
+ (*init)( T1_Builder* builder,
+ FT_Face face,
+ FT_Size size,
+ FT_GlyphSlot slot );
+
+ void
+ (*done)( T1_Builder* builder );
+
+ T1_Builder_Check_Points_Func check_points;
+ T1_Builder_Add_Point_Func add_point;
+ T1_Builder_Add_Point1_Func add_point1;
+ T1_Builder_Add_Contour_Func add_contour;
+ T1_Builder_Start_Point_Func start_point;
+ T1_Builder_Close_Contour_Func close_contour;
+
+ } T1_Builder_Funcs;
+
+
+
+ /*************************************************************************/
+ /* */
+ /* <Structure> */
+ /* T1_Builder */
+ /* */
+ /* <Description> */
+ /* A structure used during glyph loading to store its outline. */
+ /* */
+ /* <Fields> */
+ /* memory :: The current memory object. */
+ /* */
+ /* face :: The current face object. */
+ /* */
+ /* glyph :: The current glyph slot. */
+ /* */
+ /* loader :: XXX */
+ /* */
+ /* base :: The base glyph outline. */
+ /* */
+ /* current :: The current glyph outline. */
+ /* */
+ /* max_points :: maximum points in builder outline */
+ /* */
+ /* max_contours :: Maximal number of contours in builder outline. */
+ /* */
+ /* last :: The last point position. */
+ /* */
+ /* scale_x :: The horizontal scale (FUnits to sub-pixels). */
+ /* */
+ /* scale_y :: The vertical scale (FUnits to sub-pixels). */
+ /* */
+ /* pos_x :: The horizontal translation (if composite glyph). */
+ /* */
+ /* pos_y :: The vertical translation (if composite glyph). */
+ /* */
+ /* left_bearing :: The left side bearing point. */
+ /* */
+ /* advance :: The horizontal advance vector. */
+ /* */
+ /* bbox :: Unused. */
+ /* */
+ /* path_begun :: A flag which indicates that a new path has begun. */
+ /* */
+ /* load_points :: If this flag is not set, no points are loaded. */
+ /* */
+ /* no_recurse :: Set but not used. */
+ /* */
+ /* error :: An error code that is only used to report memory */
+ /* allocation problems. */
+ /* */
+ /* metrics_only :: A boolean indicating that we only want to compute */
+ /* the metrics of a given glyph, not load all of its */
+ /* points. */
+ /* */
+ /* funcs :: An array of function pointers for the builder. */
+ /* */
+ struct T1_Builder_
+ {
+ FT_Memory memory;
+ FT_Face face;
+ FT_GlyphSlot glyph;
+ FT_GlyphLoader* loader;
+ FT_Outline* base;
+ FT_Outline* current;
+
+ FT_Vector last;
+
+ FT_Fixed scale_x;
+ FT_Fixed scale_y;
+
+ FT_Pos pos_x;
+ FT_Pos pos_y;
+
+ FT_Vector left_bearing;
+ FT_Vector advance;
+
+ FT_BBox bbox; /* bounding box */
+ FT_Bool path_begun;
+ FT_Bool load_points;
+ FT_Bool no_recurse;
+ FT_Bool shift;
+
+ FT_Error error; /* only used for memory errors */
+ FT_Bool metrics_only;
+
+ T1_Builder_Funcs funcs;
+ };
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** T1 DECODER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+#if 0
+
+ /*************************************************************************/
+ /* */
+ /* T1_MAX_SUBRS_CALLS details the maximum number of nested sub-routine */
+ /* calls during glyph loading. */
+ /* */
+#define T1_MAX_SUBRS_CALLS 8
+
+
+ /*************************************************************************/
+ /* */
+ /* T1_MAX_CHARSTRING_OPERANDS is the charstring stack's capacity. A */
+ /* minimum of 16 is required. */
+ /* */
+#define T1_MAX_CHARSTRINGS_OPERANDS 32
+
+#endif /* 0 */
+
+
+ typedef struct T1_Decoder_Zone_
+ {
+ FT_Byte* cursor;
+ FT_Byte* base;
+ FT_Byte* limit;
+
+ } T1_Decoder_Zone;
+
+
+ typedef struct T1_Decoder_ T1_Decoder;
+ typedef struct T1_Decoder_Funcs_ T1_Decoder_Funcs;
+
+
+ typedef FT_Error
+ (*T1_Decoder_Callback)( T1_Decoder* decoder,
+ FT_UInt glyph_index );
+
+
+ struct T1_Decoder_Funcs_
+ {
+ FT_Error
+ (*init)( T1_Decoder* decoder,
+ FT_Face face,
+ FT_Size size,
+ FT_GlyphSlot slot,
+ FT_Byte** glyph_names,
+ T1_Blend* blend,
+ T1_Decoder_Callback callback );
+
+ void
+ (*done)( T1_Decoder* decoder );
+
+ FT_Error
+ (*parse_charstrings)( T1_Decoder* decoder,
+ FT_Byte* base,
+ FT_UInt len );
+ };
+
+
+ struct T1_Decoder_
+ {
+ T1_Builder builder;
+
+ FT_Long stack[T1_MAX_CHARSTRINGS_OPERANDS];
+ FT_Long* top;
+
+ T1_Decoder_Zone zones[T1_MAX_SUBRS_CALLS + 1];
+ T1_Decoder_Zone* zone;
+
+ PSNames_Interface* psnames; /* for seac */
+ FT_UInt num_glyphs;
+ FT_Byte** glyph_names;
+
+ FT_Int lenIV; /* internal for sub routine calls */
+ FT_UInt num_subrs;
+ FT_Byte** subrs;
+ FT_Int* subrs_len; /* array of subrs length (optional) */
+
+ FT_Matrix font_matrix;
+ FT_Vector font_offset;
+
+ FT_Int flex_state;
+ FT_Int num_flex_vectors;
+ FT_Vector flex_vectors[7];
+
+ T1_Blend* blend; /* for multiple master support */
+
+ T1_Decoder_Callback parse_callback;
+ T1_Decoder_Funcs funcs;
+ };
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** PSAux Module Interface *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ typedef struct PSAux_Interface_
+ {
+ const PS_Table_Funcs* ps_table_funcs;
+ const T1_Parser_Funcs* t1_parser_funcs;
+ const T1_Builder_Funcs* t1_builder_funcs;
+ const T1_Decoder_Funcs* t1_decoder_funcs;
+
+ void
+ (*t1_decrypt)( FT_Byte* buffer,
+ FT_Offset length,
+ FT_UShort seed );
+
+ } PSAux_Interface;
+
+
+FT_END_HEADER
+
+#endif /* __PSAUX_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* psnames.h */
+/* */
+/* High-level interface for the `PSNames' module (in charge of */
+/* various functions related to Postscript glyph names conversion). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __PSNAMES_H__
+#define __PSNAMES_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* PS_Unicode_Value_Func */
+ /* */
+ /* <Description> */
+ /* A function used to return the Unicode index corresponding to a */
+ /* given glyph name. */
+ /* */
+ /* <Input> */
+ /* glyph_name :: The glyph name. */
+ /* */
+ /* <Return> */
+ /* The Unicode character index resp. the non-Unicode value 0xFFFF if */
+ /* the glyph name has no known Unicode meaning. */
+ /* */
+ /* <Note> */
+ /* This function is able to map several different glyph names to the */
+ /* same Unicode value, according to the rules defined in the Adobe */
+ /* Glyph List table. */
+ /* */
+ /* This function will not be compiled if the configuration macro */
+ /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST is undefined. */
+ /* */
+ typedef FT_ULong
+ (*PS_Unicode_Value_Func)( const char* glyph_name );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* PS_Unicode_Index_Func */
+ /* */
+ /* <Description> */
+ /* A function used to return the glyph index corresponding to a given */
+ /* Unicode value. */
+ /* */
+ /* <Input> */
+ /* num_glyphs :: The number of glyphs in the face. */
+ /* */
+ /* glyph_names :: An array of glyph name pointers. */
+ /* */
+ /* unicode :: The Unicode value. */
+ /* */
+ /* <Return> */
+ /* The glyph index resp. 0xFFFF if no glyph corresponds to this */
+ /* Unicode value. */
+ /* */
+ /* <Note> */
+ /* This function is able to recognize several glyph names per Unicode */
+ /* value, according to the Adobe Glyph List. */
+ /* */
+ /* This function will not be compiled if the configuration macro */
+ /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST is undefined. */
+ /* */
+ typedef FT_UInt
+ (*PS_Unicode_Index_Func)( FT_UInt num_glyphs,
+ const char** glyph_names,
+ FT_ULong unicode );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* PS_Macintosh_Name_Func */
+ /* */
+ /* <Description> */
+ /* A function used to return the glyph name corresponding to an Apple */
+ /* glyph name index. */
+ /* */
+ /* <Input> */
+ /* name_index :: The index of the Mac name. */
+ /* */
+ /* <Return> */
+ /* The glyph name, or 0 if the index is invalid. */
+ /* */
+ /* <Note> */
+ /* This function will not be compiled if the configuration macro */
+ /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES is undefined. */
+ /* */
+ typedef const char*
+ (*PS_Macintosh_Name_Func)( FT_UInt name_index );
+
+
+ typedef const char*
+ (*PS_Adobe_Std_Strings_Func)( FT_UInt string_index );
+
+
+ typedef struct PS_UniMap_
+ {
+ FT_UInt unicode;
+ FT_UInt glyph_index;
+
+ } PS_UniMap;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* PS_Unicodes */
+ /* */
+ /* <Description> */
+ /* A simple table used to map Unicode values to glyph indices. It is */
+ /* built by the PS_Build_Unicodes table according to the glyphs */
+ /* present in a font file. */
+ /* */
+ /* <Fields> */
+ /* num_codes :: The number of glyphs in the font that match a given */
+ /* Unicode value. */
+ /* */
+ /* unicodes :: An array of unicode values, sorted in increasing */
+ /* order. */
+ /* */
+ /* gindex :: An array of glyph indices, corresponding to each */
+ /* Unicode value. */
+ /* */
+ /* <Note> */
+ /* Use the function PS_Lookup_Unicode() to retrieve the glyph index */
+ /* corresponding to a given Unicode character code. */
+ /* */
+ typedef struct PS_Unicodes_
+ {
+ FT_UInt num_maps;
+ PS_UniMap* maps;
+
+ } PS_Unicodes;
+
+
+ typedef FT_Error
+ (*PS_Build_Unicodes_Func)( FT_Memory memory,
+ FT_UInt num_glyphs,
+ const char** glyph_names,
+ PS_Unicodes* unicodes );
+
+ typedef FT_UInt
+ (*PS_Lookup_Unicode_Func)( PS_Unicodes* unicodes,
+ FT_UInt unicode );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* PSNames_Interface */
+ /* */
+ /* <Description> */
+ /* This structure defines the PSNames interface. */
+ /* */
+ /* <Fields> */
+ /* unicode_value :: A function used to convert a glyph name */
+ /* into a Unicode character code. */
+ /* */
+ /* build_unicodes :: A function which builds up the Unicode */
+ /* mapping table. */
+ /* */
+ /* lookup_unicode :: A function used to return the glyph index */
+ /* corresponding to a given Unicode */
+ /* character. */
+ /* */
+ /* macintosh_name :: A function used to return the standard */
+ /* Apple glyph Postscript name corresponding */
+ /* to a given string index (used by the */
+ /* TrueType `post' table). */
+ /* */
+ /* adobe_std_strings :: A function that returns a pointer to a */
+ /* Adobe Standard String for a given SID. */
+ /* */
+ /* adobe_std_encoding :: A table of 256 unsigned shorts that maps */
+ /* character codes in the Adobe Standard */
+ /* Encoding to SIDs. */
+ /* */
+ /* adobe_expert_encoding :: A table of 256 unsigned shorts that maps */
+ /* character codes in the Adobe Expert */
+ /* Encoding to SIDs. */
+ /* */
+ /* <Note> */
+ /* `unicode_value' and `unicode_index' will be set to 0 if the */
+ /* configuration macro FT_CONFIG_OPTION_ADOBE_GLYPH_LIST is */
+ /* undefined. */
+ /* */
+ /* `macintosh_name' will be set to 0 if the configuration macro */
+ /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES is undefined. */
+ /* */
+ typedef struct PSNames_Interface_
+ {
+ PS_Unicode_Value_Func unicode_value;
+ PS_Build_Unicodes_Func build_unicodes;
+ PS_Lookup_Unicode_Func lookup_unicode;
+ PS_Macintosh_Name_Func macintosh_name;
+
+ PS_Adobe_Std_Strings_Func adobe_std_strings;
+ const unsigned short* adobe_std_encoding;
+ const unsigned short* adobe_expert_encoding;
+
+ } PSNames_Interface;
+
+
+FT_END_HEADER
+
+#endif /* __PSNAMES_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* sfnt.h */
+/* */
+/* High-level `sfnt' driver interface (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __SFNT_H__
+#define __SFNT_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* TT_Init_Face_Func */
+ /* */
+ /* <Description> */
+ /* First part of the SFNT face object initialization. This will find */
+ /* the face in a SFNT file or collection, and load its format tag in */
+ /* face->format_tag. */
+ /* */
+ /* <Input> */
+ /* stream :: The input stream. */
+ /* */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* face_index :: The index of the TrueType font, if we are opening a */
+ /* collection. */
+ /* */
+ /* num_params :: The number of additional parameters. */
+ /* */
+ /* params :: Optional additional parameters. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The stream cursor must be at the font file's origin. */
+ /* */
+ /* This function recognizes fonts embedded in a `TrueType */
+ /* collection'. */
+ /* */
+ /* Once the format tag has been validated by the font driver, it */
+ /* should then call the TT_Load_Face_Func() callback to read the rest */
+ /* of the SFNT tables in the object. */
+ /* */
+ typedef FT_Error
+ (*TT_Init_Face_Func)( FT_Stream stream,
+ TT_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* TT_Load_Face_Func */
+ /* */
+ /* <Description> */
+ /* Second part of the SFNT face object initialization. This will */
+ /* load the common SFNT tables (head, OS/2, maxp, metrics, etc.) in */
+ /* the face object. */
+ /* */
+ /* <Input> */
+ /* stream :: The input stream. */
+ /* */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* face_index :: The index of the TrueType font, if we are opening a */
+ /* collection. */
+ /* */
+ /* num_params :: The number of additional parameters. */
+ /* */
+ /* params :: Optional additional parameters. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* This function must be called after TT_Init_Face_Func(). */
+ /* */
+ typedef FT_Error
+ (*TT_Load_Face_Func)( FT_Stream stream,
+ TT_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* TT_Done_Face_Func */
+ /* */
+ /* <Description> */
+ /* A callback used to delete the common SFNT data from a face. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* <Note> */
+ /* This function does NOT destroy the face object. */
+ /* */
+ typedef void
+ (*TT_Done_Face_Func)( TT_Face face );
+
+
+ typedef FT_Module_Interface
+ (*SFNT_Get_Interface_Func)( FT_Module module,
+ const char* interface );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* TT_Load_SFNT_Header_Func */
+ /* */
+ /* <Description> */
+ /* Loads the header of a SFNT font file. Supports collections. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* face_index :: The index of the TrueType font, if we are opening a */
+ /* collection. */
+ /* */
+ /* <Output> */
+ /* sfnt :: The SFNT header. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The stream cursor must be at the font file's origin. */
+ /* */
+ /* This function recognizes fonts embedded in a `TrueType */
+ /* collection'. */
+ /* */
+ /* This function checks that the header is valid by looking at the */
+ /* values of `search_range', `entry_selector', and `range_shift'. */
+ /* */
+ typedef FT_Error
+ (*TT_Load_SFNT_Header_Func)( TT_Face face,
+ FT_Stream stream,
+ FT_Long face_index,
+ SFNT_Header* sfnt );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* TT_Load_Directory_Func */
+ /* */
+ /* <Description> */
+ /* Loads the table directory into a face object. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* sfnt :: The SFNT header. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The stream cursor must be on the first byte after the 4-byte font */
+ /* format tag. This is the case just after a call to */
+ /* TT_Load_Format_Tag(). */
+ /* */
+ typedef FT_Error
+ (*TT_Load_Directory_Func)( TT_Face face,
+ FT_Stream stream,
+ SFNT_Header* sfnt );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* TT_Load_Any_Func */
+ /* */
+ /* <Description> */
+ /* Loads any font table into client memory. */
+ /* */
+ /* <Input> */
+ /* face :: The face object to look for. */
+ /* */
+ /* tag :: The tag of table to load. Use the value 0 if you want */
+ /* to access the whole font file, else set this parameter */
+ /* to a valid TrueType table tag that you can forge with */
+ /* the MAKE_TT_TAG macro. */
+ /* */
+ /* offset :: The starting offset in the table (or the file if */
+ /* tag == 0). */
+ /* */
+ /* length :: The address of the decision variable: */
+ /* */
+ /* If length == NULL: */
+ /* Loads the whole table. Returns an error if */
+ /* `offset' == 0! */
+ /* */
+ /* If *length == 0: */
+ /* Exits immediately; returning the length of the given */
+ /* table or of the font file, depending on the value of */
+ /* `tag'. */
+ /* */
+ /* If *length != 0: */
+ /* Loads the next `length' bytes of table or font, */
+ /* starting at offset `offset' (in table or font too). */
+ /* */
+ /* <Output> */
+ /* buffer :: The address of target buffer. */
+ /* */
+ /* <Return> */
+ /* TrueType error code. 0 means success. */
+ /* */
+ typedef FT_Error
+ (*TT_Load_Any_Func)( TT_Face face,
+ FT_ULong tag,
+ FT_Long offset,
+ FT_Byte *buffer,
+ FT_ULong* length );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* TT_Load_SBit_Image_Func */
+ /* */
+ /* <Description> */
+ /* Loads a given glyph sbit image from the font resource. This also */
+ /* returns its metrics. */
+ /* */
+ /* <Input> */
+ /* face :: The target face object. */
+ /* */
+ /* x_ppem :: The horizontal resolution in points per EM. */
+ /* */
+ /* y_ppem :: The vertical resolution in points per EM. */
+ /* */
+ /* glyph_index :: The current glyph index. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* <Output> */
+ /* amap :: The target pixmap. */
+ /* */
+ /* ametrics :: A big sbit metrics structure for the glyph image. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. Returns an error if no */
+ /* glyph sbit exists for the index. */
+ /* */
+ /* <Note> */
+ /* The `map.buffer' field is always freed before the glyph is loaded. */
+ /* */
+ typedef FT_Error
+ (*TT_Load_SBit_Image_Func)( TT_Face face,
+ FT_ULong strike_index,
+ FT_UInt glyph_index,
+ FT_UInt load_flags,
+ FT_Stream stream,
+ FT_Bitmap *amap,
+ TT_SBit_Metrics *ametrics );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* TT_Set_SBit_Strike_Func */
+ /* */
+ /* <Description> */
+ /* Selects an sbit strike for given horizontal and vertical ppem */
+ /* values. */
+ /* */
+ /* <Input> */
+ /* face :: The target face object. */
+ /* */
+ /* x_ppem :: The horizontal resolution in points per EM. */
+ /* */
+ /* y_ppem :: The vertical resolution in points per EM. */
+ /* */
+ /* <Output> */
+ /* astrike_index :: The index of the sbit strike. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. Returns an error if no */
+ /* sbit strike exists for the selected ppem values. */
+ /* */
+ typedef FT_Error
+ (*TT_Set_SBit_Strike_Func)( TT_Face face,
+ FT_Int x_ppem,
+ FT_Int y_ppem,
+ FT_ULong *astrike_index );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* TT_Get_PS_Name_Func */
+ /* */
+ /* <Description> */
+ /* Gets the PostScript glyph name of a glyph. */
+ /* */
+ /* <Input> */
+ /* index :: The glyph index. */
+ /* */
+ /* PSname :: The address of a string pointer. Will be NULL in case */
+ /* of error, otherwise it is a pointer to the glyph name. */
+ /* */
+ /* You must not modify the returned string! */
+ /* */
+ /* <Output> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ typedef FT_Error
+ (*TT_Get_PS_Name_Func)( TT_Face face,
+ FT_UInt index,
+ FT_String** PSname );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* TT_Load_Metrics_Func */
+ /* */
+ /* <Description> */
+ /* Loads the horizontal or vertical header in a face object. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* vertical :: A boolean flag. If set, load vertical metrics. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ typedef FT_Error
+ (*TT_Load_Metrics_Func)( TT_Face face,
+ FT_Stream stream,
+ FT_Bool vertical );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* TT_CharMap_Load_Func */
+ /* */
+ /* <Description> */
+ /* Loads a given TrueType character map into memory. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the parent face object. */
+ /* */
+ /* stream :: A handle to the current stream object. */
+ /* */
+ /* <InOut> */
+ /* cmap :: A pointer to a cmap object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The function assumes that the stream is already in use (i.e., */
+ /* opened). In case of error, all partially allocated tables are */
+ /* released. */
+ /* */
+ typedef FT_Error
+ (*TT_CharMap_Load_Func)( TT_Face face,
+ TT_CMapTable* cmap,
+ FT_Stream input );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* TT_CharMap_Free_Func */
+ /* */
+ /* <Description> */
+ /* Destroys a character mapping table. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the parent face object. */
+ /* */
+ /* cmap :: A handle to a cmap object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ typedef FT_Error
+ (*TT_CharMap_Free_Func)( TT_Face face,
+ TT_CMapTable* cmap );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* TT_Load_Table_Func */
+ /* */
+ /* <Description> */
+ /* Loads a given TrueType table. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The function will use `face->goto_table' to seek the stream to */
+ /* the start of the table. */
+ /* */
+ typedef FT_Error
+ (*TT_Load_Table_Func)( TT_Face face,
+ FT_Stream stream );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* TT_Free_Table_Func */
+ /* */
+ /* <Description> */
+ /* Frees a given TrueType table. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ typedef void
+ (*TT_Free_Table_Func)( TT_Face face );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* SFNT_Interface */
+ /* */
+ /* <Description> */
+ /* This structure holds pointers to the functions used to load and */
+ /* free the basic tables that are required in a `sfnt' font file. */
+ /* */
+ /* <Fields> */
+ /* Check the various xxx_Func() descriptions for details. */
+ /* */
+ typedef struct SFNT_Interface_
+ {
+ TT_Goto_Table_Func goto_table;
+
+ TT_Init_Face_Func init_face;
+ TT_Load_Face_Func load_face;
+ TT_Done_Face_Func done_face;
+ SFNT_Get_Interface_Func get_interface;
+
+ TT_Load_Any_Func load_any;
+ TT_Load_SFNT_Header_Func load_sfnt_header;
+ TT_Load_Directory_Func load_directory;
+
+ /* these functions are called by `load_face' but they can also */
+ /* be called from external modules, if there is a need to do so */
+ TT_Load_Table_Func load_header;
+ TT_Load_Metrics_Func load_metrics;
+ TT_Load_Table_Func load_charmaps;
+ TT_Load_Table_Func load_max_profile;
+ TT_Load_Table_Func load_os2;
+ TT_Load_Table_Func load_psnames;
+
+ TT_Load_Table_Func load_names;
+ TT_Free_Table_Func free_names;
+
+ /* optional tables */
+ TT_Load_Table_Func load_hdmx;
+ TT_Free_Table_Func free_hdmx;
+
+ TT_Load_Table_Func load_kerning;
+ TT_Load_Table_Func load_gasp;
+ TT_Load_Table_Func load_pclt;
+
+ /* see `ttload.h' */
+ TT_Load_Table_Func load_bitmap_header;
+
+ /* see `ttsbit.h' */
+ TT_Set_SBit_Strike_Func set_sbit_strike;
+ TT_Load_Table_Func load_sbits;
+ TT_Load_SBit_Image_Func load_sbit_image;
+ TT_Free_Table_Func free_sbits;
+
+ /* see `ttpost.h' */
+ TT_Get_PS_Name_Func get_psname;
+ TT_Free_Table_Func free_psnames;
+
+ /* see `ttcmap.h' */
+ TT_CharMap_Load_Func load_charmap;
+ TT_CharMap_Free_Func free_charmap;
+
+ } SFNT_Interface;
+
+
+FT_END_HEADER
+
+#endif /* __SFNT_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* t1types.h */
+/* */
+/* Basic Type1/Type2 type definitions and interface (specification */
+/* only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __T1TYPES_H__
+#define __T1TYPES_H__
+
+
+#include<ft2build.h>
+#include FT_TYPE1_TABLES_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*** ***/
+ /*** ***/
+ /*** REQUIRED TYPE1/TYPE2 TABLES DEFINITIONS ***/
+ /*** ***/
+ /*** ***/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* T1_Encoding */
+ /* */
+ /* <Description> */
+ /* A structure modeling a custom encoding. */
+ /* */
+ /* <Fields> */
+ /* num_chars :: The number of character codes in the encoding. */
+ /* Usually 256. */
+ /* */
+ /* code_first :: The lowest valid character code in the encoding. */
+ /* */
+ /* code_last :: The highest valid character code in the encoding. */
+ /* */
+ /* char_index :: An array of corresponding glyph indices. */
+ /* */
+ /* char_name :: An array of corresponding glyph names. */
+ /* */
+ typedef struct T1_Encoding_
+ {
+ FT_Int num_chars;
+ FT_Int code_first;
+ FT_Int code_last;
+
+ FT_UShort* char_index;
+ FT_String** char_name;
+
+ } T1_Encoding;
+
+
+ typedef enum T1_EncodingType_
+ {
+ t1_encoding_none = 0,
+ t1_encoding_array,
+ t1_encoding_standard,
+ t1_encoding_expert
+
+ } T1_EncodingType;
+
+
+ typedef struct T1_Font_
+ {
+ /* font info dictionary */
+ T1_FontInfo font_info;
+
+ /* private dictionary */
+ T1_Private private_dict;
+
+ /* top-level dictionary */
+ FT_String* font_name;
+
+ T1_EncodingType encoding_type;
+ T1_Encoding encoding;
+
+ FT_Byte* subrs_block;
+ FT_Byte* charstrings_block;
+ FT_Byte* glyph_names_block;
+
+ FT_Int num_subrs;
+ FT_Byte** subrs;
+ FT_Int* subrs_len;
+
+ FT_Int num_glyphs;
+ FT_String** glyph_names; /* array of glyph names */
+ FT_Byte** charstrings; /* array of glyph charstrings */
+ FT_Int* charstrings_len;
+
+ FT_Byte paint_type;
+ FT_Byte font_type;
+ FT_Matrix font_matrix;
+ FT_Vector font_offset;
+ FT_BBox font_bbox;
+ FT_Long font_id;
+
+ FT_Int stroke_width;
+
+ } T1_Font;
+
+
+ typedef struct CID_Subrs_
+ {
+ FT_UInt num_subrs;
+ FT_Byte** code;
+
+ } CID_Subrs;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*** ***/
+ /*** ***/
+ /*** ORIGINAL T1_FACE CLASS DEFINITION ***/
+ /*** ***/
+ /*** ***/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This structure/class is defined here because it is common to the */
+ /* following formats: TTF, OpenType-TT, and OpenType-CFF. */
+ /* */
+ /* Note, however, that the classes TT_Size, TT_GlyphSlot, and TT_CharMap */
+ /* are not shared between font drivers, and are thus defined normally in */
+ /* `ttobjs.h'. */
+ /* */
+ /*************************************************************************/
+
+ typedef struct T1_FaceRec_* T1_Face;
+ typedef struct CID_FaceRec_* CID_Face;
+
+
+ typedef struct T1_FaceRec_
+ {
+ FT_FaceRec root;
+ T1_Font type1;
+ void* psnames;
+ void* psaux;
+ void* afm_data;
+ FT_CharMapRec charmaprecs[2];
+ FT_CharMap charmaps[2];
+ PS_Unicodes unicode_map;
+
+ /* support for Multiple Masters fonts */
+ T1_Blend* blend;
+
+ } T1_FaceRec;
+
+
+ typedef struct CID_FaceRec_
+ {
+ FT_FaceRec root;
+ void* psnames;
+ void* psaux;
+ CID_Info cid;
+ void* afm_data;
+ CID_Subrs* subrs;
+
+ } CID_FaceRec;
+
+
+FT_END_HEADER
+
+#endif /* __T1TYPES_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* tttypes.h */
+/* */
+/* Basic SFNT/TrueType type definitions and interface (specification */
+/* only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTTYPES_H__
+#define __TTTYPES_H__
+
+
+#include <ft2build.h>
+#include FT_TRUETYPE_TABLES_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*** ***/
+ /*** ***/
+ /*** REQUIRED TRUETYPE/OPENTYPE TABLES DEFINITIONS ***/
+ /*** ***/
+ /*** ***/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TTC_Header */
+ /* */
+ /* <Description> */
+ /* TrueType collection header. This table contains the offsets of */
+ /* the font headers of each distinct TrueType face in the file. */
+ /* */
+ /* <Fields> */
+ /* tag :: Must be `ttc ' to indicate a TrueType collection. */
+ /* */
+ /* version :: The version number. */
+ /* */
+ /* count :: The number of faces in the collection. The */
+ /* specification says this should be an unsigned long, but */
+ /* we use a signed long since we need the value -1 for */
+ /* specific purposes. */
+ /* */
+ /* offsets :: The offsets of the font headers, one per face. */
+ /* */
+ typedef struct TTC_Header_
+ {
+ FT_ULong tag;
+ FT_Fixed version;
+ FT_Long count;
+ FT_ULong* offsets;
+
+ } TTC_Header;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* SFNT_Header */
+ /* */
+ /* <Description> */
+ /* SFNT file format header. */
+ /* */
+ /* <Fields> */
+ /* format_tag :: The font format tag. */
+ /* */
+ /* num_tables :: The number of tables in file. */
+ /* */
+ /* search_range :: Must be 16*(max power of 2 <= num_tables). */
+ /* */
+ /* entry_selector :: Must be log2 of search_range/16. */
+ /* */
+ /* range_shift :: Must be num_tables*16 - search_range. */
+ /* */
+ typedef struct SFNT_Header_
+ {
+ FT_ULong format_tag;
+ FT_UShort num_tables;
+ FT_UShort search_range;
+ FT_UShort entry_selector;
+ FT_UShort range_shift;
+
+ } SFNT_Header;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_TableDir */
+ /* */
+ /* <Description> */
+ /* This structure models a TrueType table directory. It is used to */
+ /* access the various tables of the font face. */
+ /* */
+ /* <Fields> */
+ /* version :: The version number; starts with 0x00010000. */
+ /* */
+ /* numTables :: The number of tables. */
+ /* */
+ /* searchRange :: Unused. */
+ /* */
+ /* entrySelector :: Unused. */
+ /* */
+ /* rangeShift :: Unused. */
+ /* */
+ /* <Note> */
+ /* This structure is only used during font opening. */
+ /* */
+ typedef struct TT_TableDir_
+ {
+ FT_Fixed version; /* should be 0x10000 */
+ FT_UShort numTables; /* number of tables */
+
+ FT_UShort searchRange; /* These parameters are only used */
+ FT_UShort entrySelector; /* for a dichotomy search in the */
+ FT_UShort rangeShift; /* directory. We ignore them. */
+
+ } TT_TableDir;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_Table */
+ /* */
+ /* <Description> */
+ /* This structure describes a given table of a TrueType font. */
+ /* */
+ /* <Fields> */
+ /* Tag :: A four-bytes tag describing the table. */
+ /* */
+ /* CheckSum :: The table checksum. This value can be ignored. */
+ /* */
+ /* Offset :: The offset of the table from the start of the TrueType */
+ /* font in its resource. */
+ /* */
+ /* Length :: The table length (in bytes). */
+ /* */
+ typedef struct TT_Table_
+ {
+ FT_ULong Tag; /* table type */
+ FT_ULong CheckSum; /* table checksum */
+ FT_ULong Offset; /* table file offset */
+ FT_ULong Length; /* table length */
+
+ } TT_Table;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_CMapDir */
+ /* */
+ /* <Description> */
+ /* This structure describes the directory of the `cmap' table, */
+ /* containing the font's character mappings table. */
+ /* */
+ /* <Fields> */
+ /* tableVersionNumber :: The version number. */
+ /* */
+ /* numCMaps :: The number of charmaps in the font. */
+ /* */
+ /* <Note> */
+ /* This structure is only used during font loading. */
+ /* */
+ typedef struct TT_CMapDir_
+ {
+ FT_UShort tableVersionNumber;
+ FT_UShort numCMaps;
+
+ } TT_CMapDir;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_CMapDirEntry */
+ /* */
+ /* <Description> */
+ /* This structure describes a charmap in a TrueType font. */
+ /* */
+ /* <Fields> */
+ /* platformID :: An ID used to specify for which platform this */
+ /* charmap is defined (FreeType manages all platforms). */
+ /* */
+ /* encodingID :: A platform-specific ID used to indicate which source */
+ /* encoding is used in this charmap. */
+ /* */
+ /* offset :: The offset of the charmap relative to the start of */
+ /* the `cmap' table. */
+ /* */
+ /* <Note> */
+ /* This structure is only used during font loading. */
+ /* */
+ typedef struct TT_CMapDirEntry_
+ {
+ FT_UShort platformID;
+ FT_UShort platformEncodingID;
+ FT_Long offset;
+
+ } TT_CMapDirEntry;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_LongMetrics */
+ /* */
+ /* <Description> */
+ /* A structure modeling the long metrics of the `hmtx' and `vmtx' */
+ /* TrueType tables. The values are expressed in font units. */
+ /* */
+ /* <Fields> */
+ /* advance :: The advance width or height for the glyph. */
+ /* */
+ /* bearing :: The left-side or top-side bearing for the glyph. */
+ /* */
+ typedef struct TT_LongMetrics_
+ {
+ FT_UShort advance;
+ FT_Short bearing;
+
+ } TT_LongMetrics;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> TT_ShortMetrics */
+ /* */
+ /* <Description> */
+ /* A simple type to model the short metrics of the `hmtx' and `vmtx' */
+ /* tables. */
+ /* */
+ typedef FT_Short TT_ShortMetrics;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_NameRec */
+ /* */
+ /* <Description> */
+ /* A structure modeling TrueType name records. Name records are used */
+ /* to store important strings like family name, style name, */
+ /* copyright, etc. in _localized_ versions (i.e., language, encoding, */
+ /* etc). */
+ /* */
+ /* <Fields> */
+ /* platformID :: The ID of the name's encoding platform. */
+ /* */
+ /* encodingID :: The platform-specific ID for the name's encoding. */
+ /* */
+ /* languageID :: The platform-specific ID for the name's language. */
+ /* */
+ /* nameID :: The ID specifying what kind of name this is. */
+ /* */
+ /* stringLength :: The length of the string in bytes. */
+ /* */
+ /* stringOffset :: The offset to the string in the `name' table. */
+ /* */
+ /* string :: A pointer to the string's bytes. Note that these */
+ /* are usually UTF-16 encoded characters. */
+ /* */
+ typedef struct TT_NameRec_
+ {
+ FT_UShort platformID;
+ FT_UShort encodingID;
+ FT_UShort languageID;
+ FT_UShort nameID;
+ FT_UShort stringLength;
+ FT_UShort stringOffset;
+
+ /* this last field is not defined in the spec */
+ /* but used by the FreeType engine */
+
+ FT_Byte* string;
+
+ } TT_NameRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_NameTable */
+ /* */
+ /* <Description> */
+ /* A structure modeling the TrueType name table. */
+ /* */
+ /* <Fields> */
+ /* format :: The format of the name table. */
+ /* */
+ /* numNameRecords :: The number of names in table. */
+ /* */
+ /* storageOffset :: The offset of the name table in the `name' */
+ /* TrueType table. */
+ /* */
+ /* names :: An array of name records. */
+ /* */
+ /* storage :: The names storage area. */
+ /* */
+ typedef struct TT_NameTable_
+ {
+ FT_UShort format;
+ FT_UShort numNameRecords;
+ FT_UShort storageOffset;
+ TT_NameRec* names;
+ FT_Byte* storage;
+
+ } TT_NameTable;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*** ***/
+ /*** ***/
+ /*** OPTIONAL TRUETYPE/OPENTYPE TABLES DEFINITIONS ***/
+ /*** ***/
+ /*** ***/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_GaspRange */
+ /* */
+ /* <Description> */
+ /* A tiny structure used to model a gasp range according to the */
+ /* TrueType specification. */
+ /* */
+ /* <Fields> */
+ /* maxPPEM :: The maximum ppem value to which `gaspFlag' applies. */
+ /* */
+ /* gaspFlag :: A flag describing the grid-fitting and anti-aliasing */
+ /* modes to be used. */
+ /* */
+ typedef struct TT_GaspRange_
+ {
+ FT_UShort maxPPEM;
+ FT_UShort gaspFlag;
+
+ } TT_GaspRange;
+
+
+#define TT_GASP_GRIDFIT 0x01
+#define TT_GASP_DOGRAY 0x02
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_Gasp */
+ /* */
+ /* <Description> */
+ /* A structure modeling the TrueType `gasp' table used to specify */
+ /* grid-fitting and anti-aliasing behaviour. */
+ /* */
+ /* <Fields> */
+ /* version :: The version number. */
+ /* */
+ /* numRanges :: The number of gasp ranges in table. */
+ /* */
+ /* gaspRanges :: An array of gasp ranges. */
+ /* */
+ typedef struct TT_Gasp_
+ {
+ FT_UShort version;
+ FT_UShort numRanges;
+ TT_GaspRange* gaspRanges;
+
+ } TT_Gasp;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_HdmxRec */
+ /* */
+ /* <Description> */
+ /* A small structure used to model the pre-computed widths of a given */
+ /* size. They are found in the `hdmx' table. */
+ /* */
+ /* <Fields> */
+ /* ppem :: The pixels per EM value at which these metrics apply. */
+ /* */
+ /* max_width :: The maximum advance width for this metric. */
+ /* */
+ /* widths :: An array of widths. Note: These are 8-bit bytes. */
+ /* */
+ typedef struct TT_HdmxRec_
+ {
+ FT_Byte ppem;
+ FT_Byte max_width;
+ FT_Byte* widths;
+
+ } TT_HdmxRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_Hdmx */
+ /* */
+ /* <Description> */
+ /* A structure used to model the `hdmx' table, which contains */
+ /* pre-computed widths for a set of given sizes/dimensions. */
+ /* */
+ /* <Fields> */
+ /* version :: The version number. */
+ /* */
+ /* num_records :: The number of hdmx records. */
+ /* */
+ /* records :: An array of hdmx records. */
+ /* */
+ typedef struct TT_Hdmx_
+ {
+ FT_UShort version;
+ FT_Short num_records;
+ TT_HdmxRec* records;
+
+ } TT_Hdmx;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_Kern_0_Pair */
+ /* */
+ /* <Description> */
+ /* A structure used to model a kerning pair for the kerning table */
+ /* format 0. The engine now loads this table if it finds one in the */
+ /* font file. */
+ /* */
+ /* <Fields> */
+ /* left :: The index of the left glyph in pair. */
+ /* */
+ /* right :: The index of the right glyph in pair. */
+ /* */
+ /* value :: The kerning distance. A positive value spaces the */
+ /* glyphs, a negative one makes them closer. */
+ /* */
+ typedef struct TT_Kern_0_Pair_
+ {
+ FT_UShort left; /* index of left glyph in pair */
+ FT_UShort right; /* index of right glyph in pair */
+ FT_FWord value; /* kerning value */
+
+ } TT_Kern_0_Pair;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*** ***/
+ /*** ***/
+ /*** EMBEDDED BITMAPS SUPPORT ***/
+ /*** ***/
+ /*** ***/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_SBit_Metrics */
+ /* */
+ /* <Description> */
+ /* A structure used to hold the big metrics of a given glyph bitmap */
+ /* in a TrueType or OpenType font. These are usually found in the */
+ /* `EBDT' (Microsoft) or `bloc' (Apple) table. */
+ /* */
+ /* <Fields> */
+ /* height :: The glyph height in pixels. */
+ /* */
+ /* width :: The glyph width in pixels. */
+ /* */
+ /* horiBearingX :: The horizontal left bearing. */
+ /* */
+ /* horiBearingY :: The horizontal top bearing. */
+ /* */
+ /* horiAdvance :: The horizontal advance. */
+ /* */
+ /* vertBearingX :: The vertical left bearing. */
+ /* */
+ /* vertBearingY :: The vertical top bearing. */
+ /* */
+ /* vertAdvance :: The vertical advance. */
+ /* */
+ typedef struct TT_SBit_Metrics_
+ {
+ FT_Byte height;
+ FT_Byte width;
+
+ FT_Char horiBearingX;
+ FT_Char horiBearingY;
+ FT_Byte horiAdvance;
+
+ FT_Char vertBearingX;
+ FT_Char vertBearingY;
+ FT_Byte vertAdvance;
+
+ } TT_SBit_Metrics;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_SBit_Small_Metrics */
+ /* */
+ /* <Description> */
+ /* A structure used to hold the small metrics of a given glyph bitmap */
+ /* in a TrueType or OpenType font. These are usually found in the */
+ /* `EBDT' (Microsoft) or the `bdat' (Apple) table. */
+ /* */
+ /* <Fields> */
+ /* height :: The glyph height in pixels. */
+ /* */
+ /* width :: The glyph width in pixels. */
+ /* */
+ /* bearingX :: The left-side bearing. */
+ /* */
+ /* bearingY :: The top-side bearing. */
+ /* */
+ /* advance :: The advance width or height. */
+ /* */
+ typedef struct TT_SBit_Small_Metrics_
+ {
+ FT_Byte height;
+ FT_Byte width;
+
+ FT_Char bearingX;
+ FT_Char bearingY;
+ FT_Byte advance;
+
+ } TT_SBit_Small_Metrics;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_SBit_Line_Metrics */
+ /* */
+ /* <Description> */
+ /* A structure used to describe the text line metrics of a given */
+ /* bitmap strike, for either a horizontal or vertical layout. */
+ /* */
+ /* <Fields> */
+ /* ascender :: The ascender in pixels. */
+ /* */
+ /* descender :: The descender in pixels. */
+ /* */
+ /* max_width :: The maximum glyph width in pixels. */
+ /* */
+ /* caret_slope_enumerator :: Rise of the caret slope, typically set */
+ /* to 1 for non-italic fonts. */
+ /* */
+ /* caret_slope_denominator :: Rise of the caret slope, typically set */
+ /* to 0 for non-italic fonts. */
+ /* */
+ /* caret_offset :: Offset in pixels to move the caret for */
+ /* proper positioning. */
+ /* */
+ /* min_origin_SB :: Minimum of horiBearingX (resp. */
+ /* vertBearingY). */
+ /* min_advance_SB :: Minimum of */
+ /* */
+ /* horizontal advance - */
+ /* ( horiBearingX + width ) */
+ /* */
+ /* resp. */
+ /* */
+ /* vertical advance - */
+ /* ( vertBearingY + height ) */
+ /* */
+ /* max_before_BL :: Maximum of horiBearingY (resp. */
+ /* vertBearingY). */
+ /* */
+ /* min_after_BL :: Minimum of */
+ /* */
+ /* horiBearingY - height */
+ /* */
+ /* resp. */
+ /* */
+ /* vertBearingX - width */
+ /* */
+ /* pads :: Unused (to make the size of the record */
+ /* a multiple of 32 bits. */
+ /* */
+ typedef struct TT_SBit_Line_Metrics_
+ {
+ FT_Char ascender;
+ FT_Char descender;
+ FT_Byte max_width;
+ FT_Char caret_slope_numerator;
+ FT_Char caret_slope_denominator;
+ FT_Char caret_offset;
+ FT_Char min_origin_SB;
+ FT_Char min_advance_SB;
+ FT_Char max_before_BL;
+ FT_Char min_after_BL;
+ FT_Char pads[2];
+
+ } TT_SBit_Line_Metrics;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_SBit_Range */
+ /* */
+ /* <Description> */
+ /* A TrueType/OpenType subIndexTable as defined in the `EBLC' */
+ /* (Microsoft) or `bloc' (Apple) tables. */
+ /* */
+ /* <Fields> */
+ /* first_glyph :: The first glyph index in the range. */
+ /* */
+ /* last_glyph :: The last glyph index in the range. */
+ /* */
+ /* index_format :: The format of index table. Valid values are 1 */
+ /* to 5. */
+ /* */
+ /* image_format :: The format of `EBDT' image data. */
+ /* */
+ /* image_offset :: The offset to image data in `EBDT'. */
+ /* */
+ /* image_size :: For index formats 2 and 5. This is the size in */
+ /* bytes of each glyph bitmap. */
+ /* */
+ /* big_metrics :: For index formats 2 and 5. This is the big */
+ /* metrics for each glyph bitmap. */
+ /* */
+ /* num_glyphs :: For index formats 4 and 5. This is the number of */
+ /* glyphs in the code array. */
+ /* */
+ /* glyph_offsets :: For index formats 1 and 3. */
+ /* */
+ /* glyph_codes :: For index formats 4 and 5. */
+ /* */
+ /* table_offset :: The offset of the index table in the `EBLC' */
+ /* table. Only used during strike loading. */
+ /* */
+ typedef struct TT_SBit_Range
+ {
+ FT_UShort first_glyph;
+ FT_UShort last_glyph;
+
+ FT_UShort index_format;
+ FT_UShort image_format;
+ FT_ULong image_offset;
+
+ FT_ULong image_size;
+ TT_SBit_Metrics metrics;
+ FT_ULong num_glyphs;
+
+ FT_ULong* glyph_offsets;
+ FT_UShort* glyph_codes;
+
+ FT_ULong table_offset;
+
+ } TT_SBit_Range;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_SBit_Strike */
+ /* */
+ /* <Description> */
+ /* A structure used describe a given bitmap strike in the `EBLC' */
+ /* (Microsoft) or `bloc' (Apple) tables. */
+ /* */
+ /* <Fields> */
+ /* num_index_ranges :: The number of index ranges. */
+ /* */
+ /* index_ranges :: An array of glyph index ranges. */
+ /* */
+ /* color_ref :: Unused. `color_ref' is put in for future */
+ /* enhancements, but these fields are already */
+ /* in use by other platforms (e.g. Newton). */
+ /* For details, please see */
+ /* */
+ /* http://fonts.apple.com/ */
+ /* TTRefMan/RM06/Chap6bloc.html */
+ /* */
+ /* hori :: The line metrics for horizontal layouts. */
+ /* */
+ /* vert :: The line metrics for vertical layouts. */
+ /* */
+ /* start_glyph :: The lowest glyph index for this strike. */
+ /* */
+ /* end_glyph :: The highest glyph index for this strike. */
+ /* */
+ /* x_ppem :: The number of horizontal pixels per EM. */
+ /* */
+ /* y_ppem :: The number of vertical pixels per EM. */
+ /* */
+ /* bit_depth :: The bit depth. Valid values are 1, 2, 4, */
+ /* and 8. */
+ /* */
+ /* flags :: Is this a vertical or horizontal strike? For */
+ /* details, please see */
+ /* */
+ /* http://fonts.apple.com/ */
+ /* TTRefMan/RM06/Chap6bloc.html */
+ /* */
+ typedef struct TT_SBit_Strike_
+ {
+ FT_Int num_ranges;
+ TT_SBit_Range* sbit_ranges;
+ FT_ULong ranges_offset;
+
+ FT_ULong color_ref;
+
+ TT_SBit_Line_Metrics hori;
+ TT_SBit_Line_Metrics vert;
+
+ FT_UShort start_glyph;
+ FT_UShort end_glyph;
+
+ FT_Byte x_ppem;
+ FT_Byte y_ppem;
+
+ FT_Byte bit_depth;
+ FT_Char flags;
+
+ } TT_SBit_Strike;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_SBit_Component */
+ /* */
+ /* <Description> */
+ /* A simple structure to describe a compound sbit element. */
+ /* */
+ /* <Fields> */
+ /* glyph_code :: The element's glyph index. */
+ /* */
+ /* x_offset :: The element's left bearing. */
+ /* */
+ /* y_offset :: The element's top bearing. */
+ /* */
+ typedef struct TT_SBit_Component_
+ {
+ FT_UShort glyph_code;
+ FT_Char x_offset;
+ FT_Char y_offset;
+
+ } TT_SBit_Component;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_SBit_Scale */
+ /* */
+ /* <Description> */
+ /* A structure used describe a given bitmap scaling table, as defined */
+ /* in the `EBSC' table. */
+ /* */
+ /* <Fields> */
+ /* hori :: The horizontal line metrics. */
+ /* */
+ /* vert :: The vertical line metrics. */
+ /* */
+ /* x_ppem :: The number of horizontal pixels per EM. */
+ /* */
+ /* y_ppem :: The number of vertical pixels per EM. */
+ /* */
+ /* x_ppem_substitute :: Substitution x_ppem value. */
+ /* */
+ /* y_ppem_substitute :: Substitution y_ppem value. */
+ /* */
+ typedef struct TT_SBit_Scale_
+ {
+ TT_SBit_Line_Metrics hori;
+ TT_SBit_Line_Metrics vert;
+
+ FT_Byte x_ppem;
+ FT_Byte y_ppem;
+
+ FT_Byte x_ppem_substitute;
+ FT_Byte y_ppem_substitute;
+
+ } TT_SBit_Scale;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*** ***/
+ /*** ***/
+ /*** POSTSCRIPT GLYPH NAMES SUPPORT ***/
+ /*** ***/
+ /*** ***/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_Post_20 */
+ /* */
+ /* <Description> */
+ /* Postscript names sub-table, format 2.0. Stores the PS name of */
+ /* each glyph in the font face. */
+ /* */
+ /* <Fields> */
+ /* num_glyphs :: The number of named glyphs in the table. */
+ /* */
+ /* num_names :: The number of PS names stored in the table. */
+ /* */
+ /* glyph_indices :: The indices of the glyphs in the names arrays. */
+ /* */
+ /* glyph_names :: The PS names not in Mac Encoding. */
+ /* */
+ typedef struct TT_Post_20_
+ {
+ FT_UShort num_glyphs;
+ FT_UShort num_names;
+ FT_UShort* glyph_indices;
+ FT_Char** glyph_names;
+
+ } TT_Post_20;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_Post_25 */
+ /* */
+ /* <Description> */
+ /* Postscript names sub-table, format 2.5. Stores the PS name of */
+ /* each glyph in the font face. */
+ /* */
+ /* <Fields> */
+ /* num_glyphs :: The number of glyphs in the table. */
+ /* */
+ /* offsets :: An array of signed offsets in a normal Mac */
+ /* Postscript name encoding. */
+ /* */
+ typedef struct TT_Post_25_
+ {
+ FT_UShort num_glyphs;
+ FT_Char* offsets;
+
+ } TT_Post_25;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_Post_Names */
+ /* */
+ /* <Description> */
+ /* Postscript names table, either format 2.0 or 2.5. */
+ /* */
+ /* <Fields> */
+ /* loaded :: A flag to indicate whether the PS names are loaded. */
+ /* */
+ /* format_20 :: The sub-table used for format 2.0. */
+ /* */
+ /* format_25 :: The sub-table used for format 2.5. */
+ /* */
+ typedef struct TT_Post_Names_
+ {
+ FT_Bool loaded;
+
+ union
+ {
+ TT_Post_20 format_20;
+ TT_Post_25 format_25;
+
+ } names;
+
+ } TT_Post_Names;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*** ***/
+ /*** ***/
+ /*** TRUETYPE CHARMAPS SUPPORT ***/
+ /*** ***/
+ /*** ***/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* format 0 */
+
+ typedef struct TT_CMap0_
+ {
+ FT_ULong language; /* for Mac fonts (originally ushort) */
+
+ FT_Byte* glyphIdArray;
+
+ } TT_CMap0;
+
+
+ /* format 2 */
+
+ typedef struct TT_CMap2SubHeader_
+ {
+ FT_UShort firstCode; /* first valid low byte */
+ FT_UShort entryCount; /* number of valid low bytes */
+ FT_Short idDelta; /* delta value to glyphIndex */
+ FT_UShort idRangeOffset; /* offset from here to 1st code */
+
+ } TT_CMap2SubHeader;
+
+
+ typedef struct TT_CMap2_
+ {
+ FT_ULong language; /* for Mac fonts (originally ushort) */
+
+ FT_UShort* subHeaderKeys;
+ /* high byte mapping table */
+ /* value = subHeader index * 8 */
+
+ TT_CMap2SubHeader* subHeaders;
+ FT_UShort* glyphIdArray;
+ FT_UShort numGlyphId; /* control value */
+
+ } TT_CMap2;
+
+
+ /* format 4 */
+
+ typedef struct TT_CMap4Segment_
+ {
+ FT_UShort endCount;
+ FT_UShort startCount;
+ FT_Short idDelta;
+ FT_UShort idRangeOffset;
+
+ } TT_CMap4Segment;
+
+
+ typedef struct TT_CMap4_
+ {
+ FT_ULong language; /* for Mac fonts (originally ushort) */
+
+ FT_UShort segCountX2; /* number of segments * 2 */
+ FT_UShort searchRange; /* these parameters can be used */
+ FT_UShort entrySelector; /* for a binary search */
+ FT_UShort rangeShift;
+
+ TT_CMap4Segment* segments;
+ FT_UShort* glyphIdArray;
+ FT_UShort numGlyphId; /* control value */
+
+ TT_CMap4Segment* last_segment; /* last used segment; this is a small */
+ /* cache to potentially increase speed */
+ } TT_CMap4;
+
+
+ /* format 6 */
+
+ typedef struct TT_CMap6_
+ {
+ FT_ULong language; /* for Mac fonts (originally ushort) */
+
+ FT_UShort firstCode; /* first character code of subrange */
+ FT_UShort entryCount; /* number of character codes in subrange */
+
+ FT_UShort* glyphIdArray;
+
+ } TT_CMap6;
+
+
+ /* auxiliary table for format 8 and 12 */
+
+ typedef struct TT_CMapGroup_
+ {
+ FT_ULong startCharCode;
+ FT_ULong endCharCode;
+ FT_ULong startGlyphID;
+
+ } TT_CMapGroup;
+
+
+ /* FreeType handles format 8 and 12 identically. It is not necessary to
+ cover mixed 16bit and 32bit codes since FreeType always uses FT_ULong
+ for input character codes -- converting Unicode surrogates to 32bit
+ character codes must be done by the application. */
+
+ typedef struct TT_CMap8_12_
+ {
+ FT_ULong language; /* for Mac fonts */
+
+ FT_ULong nGroups;
+ TT_CMapGroup* groups;
+
+ TT_CMapGroup* last_group; /* last used group; this is a small */
+ /* cache to potentially increase speed */
+ } TT_CMap8_12;
+
+
+ /* format 10 */
+
+ typedef struct TT_CMap10_
+ {
+ FT_ULong language; /* for Mac fonts */
+
+ FT_ULong startCharCode; /* first character covered */
+ FT_ULong numChars; /* number of characters covered */
+
+ FT_UShort* glyphs;
+
+ } TT_CMap10;
+
+
+ typedef struct TT_CMapTable_ TT_CMapTable;
+
+
+ typedef FT_UInt
+ (*TT_CharMap_Func)( TT_CMapTable* charmap,
+ FT_ULong char_code );
+
+
+ /* charmap table */
+ struct TT_CMapTable_
+ {
+ FT_UShort platformID;
+ FT_UShort platformEncodingID;
+ FT_UShort format;
+ FT_ULong length; /* must be ulong for formats 8, 10, and 12 */
+
+ FT_Bool loaded;
+ FT_ULong offset;
+
+ union
+ {
+ TT_CMap0 cmap0;
+ TT_CMap2 cmap2;
+ TT_CMap4 cmap4;
+ TT_CMap6 cmap6;
+ TT_CMap8_12 cmap8_12;
+ TT_CMap10 cmap10;
+ } c;
+
+ TT_CharMap_Func get_index;
+ };
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_CharMapRec */
+ /* */
+ /* <Description> */
+ /* The TrueType character map object type. */
+ /* */
+ /* <Fields> */
+ /* root :: The parent character map structure. */
+ /* */
+ /* cmap :: The used character map. */
+ /* */
+ typedef struct TT_CharMapRec_
+ {
+ FT_CharMapRec root;
+ TT_CMapTable cmap;
+
+ } TT_CharMapRec;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*** ***/
+ /*** ***/
+ /*** ORIGINAL TT_FACE CLASS DEFINITION ***/
+ /*** ***/
+ /*** ***/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This structure/class is defined here because it is common to the */
+ /* following formats: TTF, OpenType-TT, and OpenType-CFF. */
+ /* */
+ /* Note, however, that the classes TT_Size, TT_GlyphSlot, and TT_CharMap */
+ /* are not shared between font drivers, and are thus defined normally in */
+ /* `ttobjs.h'. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* TT_Face */
+ /* */
+ /* <Description> */
+ /* A handle to a TrueType face/font object. A TT_Face encapsulates */
+ /* the resolution and scaling independent parts of a TrueType font */
+ /* resource. */
+ /* */
+ /* <Note> */
+ /* The TT_Face structure is also used as a `parent class' for the */
+ /* OpenType-CFF class (T2_Face). */
+ /* */
+ typedef struct TT_FaceRec_* TT_Face;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* TT_CharMap */
+ /* */
+ /* <Description> */
+ /* A handle to a TrueType character mapping object. */
+ /* */
+ typedef struct TT_CharMapRec_* TT_CharMap;
+
+
+ /* a function type used for the truetype bytecode interpreter hooks */
+ typedef FT_Error
+ (*TT_Interpreter)( void* exec_context );
+
+ /* forward declaration */
+ typedef struct TT_Loader_ TT_Loader;
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* TT_Goto_Table_Func */
+ /* */
+ /* <Description> */
+ /* Seeks a stream to the start of a given TrueType table. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* tag :: A 4-byte tag used to name the table. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* <Output> */
+ /* length :: The length of the table in bytes. Set to 0 if not */
+ /* needed. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The stream cursor must be at the font file's origin. */
+ /* */
+ typedef FT_Error
+ (*TT_Goto_Table_Func)( TT_Face face,
+ FT_ULong tag,
+ FT_Stream stream,
+ FT_ULong* length );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* TT_Access_Glyph_Frame_Func */
+ /* */
+ /* <Description> */
+ /* Seeks a stream to the start of a given glyph element, and opens a */
+ /* frame for it. */
+ /* */
+ /* <Input> */
+ /* loader :: The current TrueType glyph loader object. */
+ /* */
+ /* glyph index :: The index of the glyph to access. */
+ /* */
+ /* offset :: The offset of the glyph according to the */
+ /* `locations' table. */
+ /* */
+ /* byte_count :: The size of the frame in bytes. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* This function is normally equivalent to FILE_Seek(offset) */
+ /* followed by ACCESS_Frame(byte_count) with the loader's stream, but */
+ /* alternative formats (e.g. compressed ones) might use something */
+ /* different. */
+ /* */
+ typedef FT_Error
+ (*TT_Access_Glyph_Frame_Func)( TT_Loader* loader,
+ FT_UInt glyph_index,
+ FT_ULong offset,
+ FT_UInt byte_count );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* TT_Load_Glyph_Element_Func */
+ /* */
+ /* <Description> */
+ /* Reads one glyph element (its header, a simple glyph, or a */
+ /* composite) from the loader's current stream frame. */
+ /* */
+ /* <Input> */
+ /* loader :: The current TrueType glyph loader object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ typedef FT_Error
+ (*TT_Load_Glyph_Element_Func)( TT_Loader* loader );
+
+
+ /*************************************************************************/
+ /* */
+ /* <FuncType> */
+ /* TT_Forget_Glyph_Frame_Func */
+ /* */
+ /* <Description> */
+ /* Closes the current loader stream frame for the glyph. */
+ /* */
+ /* <Input> */
+ /* loader :: The current TrueType glyph loader object. */
+ /* */
+ typedef void
+ (*TT_Forget_Glyph_Frame_Func)( TT_Loader* loader );
+
+
+
+ /*************************************************************************/
+ /* */
+ /* TrueType Face Type */
+ /* */
+ /* <Struct> */
+ /* TT_Face */
+ /* */
+ /* <Description> */
+ /* The TrueType face class. These objects model the resolution and */
+ /* point-size independent data found in a TrueType font file. */
+ /* */
+ /* <Fields> */
+ /* root :: The base FT_Face structure, managed by the */
+ /* base layer. */
+ /* */
+ /* ttc_header :: The TrueType collection header, used when */
+ /* the file is a `ttc' rather than a `ttf'. */
+ /* For ordinary font files, the field */
+ /* `ttc_header.count' is set to 0. */
+ /* */
+ /* format_tag :: The font format tag. */
+ /* */
+ /* num_tables :: The number of TrueType tables in this font */
+ /* file. */
+ /* */
+ /* dir_tables :: The directory of TrueType tables for this */
+ /* font file. */
+ /* */
+ /* header :: The font's font header (`head' table). */
+ /* Read on font opening. */
+ /* */
+ /* horizontal :: The font's horizontal header (`hhea' */
+ /* table). This field also contains the */
+ /* associated horizontal metrics table */
+ /* (`hmtx'). */
+ /* */
+ /* max_profile :: The font's maximum profile table. Read on */
+ /* font opening. Note that some maximum */
+ /* values cannot be taken directly from this */
+ /* table. We thus define additional fields */
+ /* below to hold the computed maxima. */
+ /* */
+ /* max_components :: The maximum number of glyph components */
+ /* required to load any composite glyph from */
+ /* this font. Used to size the load stack. */
+ /* */
+ /* vertical_info :: A boolean which is set when the font file */
+ /* contains vertical metrics. If not, the */
+ /* value of the `vertical' field is */
+ /* undefined. */
+ /* */
+ /* vertical :: The font's vertical header (`vhea' table). */
+ /* This field also contains the associated */
+ /* vertical metrics table (`vmtx'), if found. */
+ /* IMPORTANT: The contents of this field is */
+ /* undefined if the `verticalInfo' field is */
+ /* unset. */
+ /* */
+ /* num_names :: The number of name records within this */
+ /* TrueType font. */
+ /* */
+ /* name_table :: The table of name records (`name'). */
+ /* */
+ /* os2 :: The font's OS/2 table (`OS/2'). */
+ /* */
+ /* postscript :: The font's PostScript table (`post' */
+ /* table). The PostScript glyph names are */
+ /* not loaded by the driver on face opening. */
+ /* See the `ttpost' module for more details. */
+ /* */
+ /* num_charmaps :: The number of character mappings in the */
+ /* font. */
+ /* */
+ /* charmaps :: The array of charmap objects for this font */
+ /* file. Note that this field is a typeless */
+ /* pointer. The Reason is that the format of */
+ /* charmaps varies with the underlying font */
+ /* format and cannot be determined here. */
+ /* */
+ /* goto_table :: A function called by each TrueType table */
+ /* loader to position a stream's cursor to */
+ /* the start of a given table according to */
+ /* its tag. It defaults to TT_Goto_Face but */
+ /* can be different for strange formats (e.g. */
+ /* Type 42). */
+ /* */
+ /* access_glyph_frame :: XXX */
+ /* */
+ /* read_glyph_header :: XXX */
+ /* */
+ /* read_simple_glyph :: XXX */
+ /* */
+ /* read_composite_glyph :: XXX */
+ /* */
+ /* forget_glyph_frame :: XXX */
+ /* */
+ /* sfnt :: A pointer to the SFNT `driver' interface. */
+ /* */
+ /* psnames :: A pointer to the `PSNames' module */
+ /* interface. */
+ /* */
+ /* hdmx :: The face's horizontal device metrics */
+ /* (`hdmx' table). This table is optional in */
+ /* TrueType/OpenType fonts. */
+ /* */
+ /* gasp :: The grid-fitting and scaling properties */
+ /* table (`gasp'). This table is optional in */
+ /* TrueType/OpenType fonts. */
+ /* */
+ /* pclt :: XXX */
+ /* */
+ /* num_sbit_strikes :: The number of sbit strikes, i.e., bitmap */
+ /* sizes, embedded in this font. */
+ /* */
+ /* sbit_strikes :: An array of sbit strikes embedded in this */
+ /* font. This table is optional in a */
+ /* TrueType/OpenType font. */
+ /* */
+ /* num_sbit_scales :: The number of sbit scales for this font. */
+ /* */
+ /* sbit_scales :: Array of sbit scales embedded in this */
+ /* font. This table is optional in a */
+ /* TrueType/OpenType font. */
+ /* */
+ /* postscript_names :: A table used to store the Postscript names */
+ /* of the glyphs for this font. See the */
+ /* file `ttconfig.h' for comments on the */
+ /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES option. */
+ /* */
+ /* num_locations :: The number of glyph locations in this */
+ /* TrueType file. This should be */
+ /* identical to the number of glyphs. */
+ /* Ignored for Type 2 fonts. */
+ /* */
+ /* glyph_locations :: An array of longs. These are offsets to */
+ /* glyph data within the `glyf' table. */
+ /* Ignored for Type 2 font faces. */
+ /* */
+ /* font_program_size :: Size in bytecodes of the face's font */
+ /* program. 0 if none defined. Ignored for */
+ /* Type 2 fonts. */
+ /* */
+ /* font_program :: The face's font program (bytecode stream) */
+ /* executed at load time, also used during */
+ /* glyph rendering. Comes from the `fpgm' */
+ /* table. Ignored for Type 2 font fonts. */
+ /* */
+ /* cvt_program_size :: The size in bytecodes of the face's cvt */
+ /* program. Ignored for Type 2 fonts. */
+ /* */
+ /* cvt_program :: The face's cvt program (bytecode stream) */
+ /* executed each time an instance/size is */
+ /* changed/reset. Comes from the `prep' */
+ /* table. Ignored for Type 2 fonts. */
+ /* */
+ /* cvt_size :: Size of the control value table (in */
+ /* entries). Ignored for Type 2 fonts. */
+ /* */
+ /* cvt :: The face's original control value table. */
+ /* Coordinates are expressed in unscaled font */
+ /* units. Comes from the `cvt ' table. */
+ /* Ignored for Type 2 fonts. */
+ /* */
+ /* num_kern_pairs :: The number of kerning pairs present in the */
+ /* font file. The engine only loads the */
+ /* first horizontal format 0 kern table it */
+ /* finds in the font file. You should use */
+ /* the `ttxkern' structures if you want to */
+ /* access other kerning tables. Ignored */
+ /* for Type 2 fonts. */
+ /* */
+ /* kern_table_index :: The index of the kerning table in the font */
+ /* kerning directory. Only used by the */
+ /* ttxkern extension to avoid data */
+ /* duplication. Ignored for Type 2 fonts. */
+ /* */
+ /* interpreter :: A pointer to the TrueType bytecode */
+ /* interpreters field is also used to hook */
+ /* the debugger in `ttdebug'. */
+ /* */
+ /* extra :: XXX */
+ /* */
+ typedef struct TT_FaceRec_
+ {
+ FT_FaceRec root;
+
+ TTC_Header ttc_header;
+
+ FT_ULong format_tag;
+ FT_UShort num_tables;
+ TT_Table* dir_tables;
+
+ TT_Header header; /* TrueType header table */
+ TT_HoriHeader horizontal; /* TrueType horizontal header */
+
+ TT_MaxProfile max_profile;
+ FT_ULong max_components;
+
+ FT_Bool vertical_info;
+ TT_VertHeader vertical; /* TT Vertical header, if present */
+
+ FT_UShort num_names; /* number of name records */
+ TT_NameTable name_table; /* name table */
+
+ TT_OS2 os2; /* TrueType OS/2 table */
+ TT_Postscript postscript; /* TrueType Postscript table */
+
+ FT_Int num_charmaps;
+ TT_CharMap charmaps; /* array of TT_CharMapRec */
+
+ TT_Goto_Table_Func goto_table;
+
+ TT_Access_Glyph_Frame_Func access_glyph_frame;
+ TT_Load_Glyph_Element_Func read_glyph_header;
+ TT_Load_Glyph_Element_Func read_simple_glyph;
+ TT_Load_Glyph_Element_Func read_composite_glyph;
+ TT_Forget_Glyph_Frame_Func forget_glyph_frame;
+
+ /* a typeless pointer to the SFNT_Interface table used to load */
+ /* the basic TrueType tables in the face object */
+ void* sfnt;
+
+ /* a typeless pointer to the PSNames_Interface table used to */
+ /* handle glyph names <-> unicode & Mac values */
+ void* psnames;
+
+ /***********************************************************************/
+ /* */
+ /* Optional TrueType/OpenType tables */
+ /* */
+ /***********************************************************************/
+
+ /* horizontal device metrics */
+ TT_Hdmx hdmx;
+
+ /* grid-fitting and scaling table */
+ TT_Gasp gasp; /* the `gasp' table */
+
+ /* PCL 5 table */
+ TT_PCLT pclt;
+
+ /* embedded bitmaps support */
+ FT_Int num_sbit_strikes;
+ TT_SBit_Strike* sbit_strikes;
+
+ FT_Int num_sbit_scales;
+ TT_SBit_Scale* sbit_scales;
+
+ /* postscript names table */
+ TT_Post_Names postscript_names;
+
+
+ /***********************************************************************/
+ /* */
+ /* TrueType-specific fields (ignored by the OTF-Type2 driver) */
+ /* */
+ /***********************************************************************/
+
+ /* the glyph locations */
+ FT_UShort num_locations;
+ FT_Long* glyph_locations;
+
+ /* the font program, if any */
+ FT_ULong font_program_size;
+ FT_Byte* font_program;
+
+ /* the cvt program, if any */
+ FT_ULong cvt_program_size;
+ FT_Byte* cvt_program;
+
+ /* the original, unscaled, control value table */
+ FT_ULong cvt_size;
+ FT_Short* cvt;
+
+ /* the format 0 kerning table, if any */
+ FT_Int num_kern_pairs;
+ FT_Int kern_table_index;
+ TT_Kern_0_Pair* kern_pairs;
+
+ /* A pointer to the bytecode interpreter to use. This is also */
+ /* used to hook the debugger for the `ttdebug' utility. */
+ TT_Interpreter interpreter;
+
+
+ /***********************************************************************/
+ /* */
+ /* Other tables or fields. This is used by derivative formats like */
+ /* OpenType. */
+ /* */
+ /***********************************************************************/
+
+ FT_Generic extra;
+
+ } TT_FaceRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_GlyphZone */
+ /* */
+ /* <Description> */
+ /* A glyph zone is used to load, scale and hint glyph outline */
+ /* coordinates. */
+ /* */
+ /* <Fields> */
+ /* memory :: A handle to the memory manager. */
+ /* */
+ /* max_points :: The maximal size in points of the zone. */
+ /* */
+ /* max_contours :: Max size in links contours of thez one. */
+ /* */
+ /* n_points :: The current number of points in the zone. */
+ /* */
+ /* n_contours :: The current number of contours in the zone. */
+ /* */
+ /* org :: The original glyph coordinates (font */
+ /* units/scaled). */
+ /* */
+ /* cur :: The current glyph coordinates (scaled/hinted). */
+ /* */
+ /* tags :: The point control tags. */
+ /* */
+ /* contours :: The contours end points. */
+ /* */
+ typedef struct TT_GlyphZone_
+ {
+ FT_Memory memory;
+ FT_UShort max_points;
+ FT_UShort max_contours;
+ FT_UShort n_points; /* number of points in zone */
+ FT_Short n_contours; /* number of contours */
+
+ FT_Vector* org; /* original point coordinates */
+ FT_Vector* cur; /* current point coordinates */
+
+ FT_Byte* tags; /* current touch flags */
+ FT_UShort* contours; /* contour end points */
+
+ } TT_GlyphZone;
+
+
+ /* handle to execution context */
+ typedef struct TT_ExecContextRec_* TT_ExecContext;
+
+ /* glyph loader structure */
+ struct TT_Loader_
+ {
+ FT_Face face;
+ FT_Size size;
+ FT_GlyphSlot glyph;
+ FT_GlyphLoader* gloader;
+
+ FT_ULong load_flags;
+ FT_UInt glyph_index;
+
+ FT_Stream stream;
+ FT_Int byte_len;
+
+ FT_Short n_contours;
+ FT_BBox bbox;
+ FT_Int left_bearing;
+ FT_Int advance;
+ FT_Int linear;
+ FT_Bool linear_def;
+ FT_Bool preserve_pps;
+ FT_Vector pp1;
+ FT_Vector pp2;
+
+ FT_ULong glyf_offset;
+
+ /* the zone where we load our glyphs */
+ TT_GlyphZone base;
+ TT_GlyphZone zone;
+
+ TT_ExecContext exec;
+ FT_Byte* instructions;
+ FT_ULong ins_pos;
+
+ /* for possible extensibility in other formats */
+ void* other;
+
+ };
+
+
+FT_END_HEADER
+
+#endif /* __TTTYPES_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* t1tables.h */
+/* */
+/* Basic Type 1/Type 2 tables definitions and interface (specification */
+/* only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __T1TABLES_H__
+#define __T1TABLES_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* type1_tables */
+ /* */
+ /* <Title> */
+ /* Type 1 Tables */
+ /* */
+ /* <Abstract> */
+ /* Type 1 (PostScript) specific font tables. */
+ /* */
+ /* <Description> */
+ /* This section contains the definition of Type 1-specific tables, */
+ /* including structures related to other PostScript font formats. */
+ /* */
+ /*************************************************************************/
+
+
+ /* Note that we separate font data in T1_FontInfo and T1_Private */
+ /* structures in order to support Multiple Master fonts. */
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* T1_FontInfo */
+ /* */
+ /* <Description> */
+ /* A structure used to model a Type1/Type2 FontInfo dictionary. Note */
+ /* that for Multiple Master fonts, each instance has its own */
+ /* FontInfo. */
+ /* */
+ typedef struct T1_FontInfo
+ {
+ FT_String* version;
+ FT_String* notice;
+ FT_String* full_name;
+ FT_String* family_name;
+ FT_String* weight;
+ FT_Long italic_angle;
+ FT_Bool is_fixed_pitch;
+ FT_Short underline_position;
+ FT_UShort underline_thickness;
+
+ } T1_FontInfo;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* T1_Private */
+ /* */
+ /* <Description> */
+ /* A structure used to model a Type1/Type2 FontInfo dictionary. Note */
+ /* that for Multiple Master fonts, each instance has its own Private */
+ /* dict. */
+ /* */
+ typedef struct T1_Private
+ {
+ FT_Int unique_id;
+ FT_Int lenIV;
+
+ FT_Byte num_blue_values;
+ FT_Byte num_other_blues;
+ FT_Byte num_family_blues;
+ FT_Byte num_family_other_blues;
+
+ FT_Short blue_values[14];
+ FT_Short other_blues[10];
+
+ FT_Short family_blues [14];
+ FT_Short family_other_blues[10];
+
+ FT_Fixed blue_scale;
+ FT_Int blue_shift;
+ FT_Int blue_fuzz;
+
+ FT_UShort standard_width[1];
+ FT_UShort standard_height[1];
+
+ FT_Byte num_snap_widths;
+ FT_Byte num_snap_heights;
+ FT_Bool force_bold;
+ FT_Bool round_stem_up;
+
+ FT_Short snap_widths [13]; /* including std width */
+ FT_Short snap_heights[13]; /* including std height */
+
+ FT_Long language_group;
+ FT_Long password;
+
+ FT_Short min_feature[2];
+
+ } T1_Private;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Enum> */
+ /* T1_Blend_Flags */
+ /* */
+ /* <Description> */
+ /* A set of flags used to indicate which fields are present in a */
+ /* given blen dictionary (font info or private). Used to support */
+ /* Multiple Masters fonts. */
+ /* */
+ typedef enum
+ {
+ /*# 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 */
+ t1_blend_blue_values,
+ t1_blend_other_blues,
+ t1_blend_standard_width,
+ t1_blend_standard_height,
+ t1_blend_stem_snap_widths,
+ t1_blend_stem_snap_heights,
+ t1_blend_blue_scale,
+ t1_blend_blue_shift,
+ t1_blend_family_blues,
+ t1_blend_family_other_blues,
+ t1_blend_force_bold,
+
+ /*# never remove */
+ t1_blend_max
+
+ } T1_Blend_Flags;
+
+
+ /* maximum number of Multiple Masters designs, as defined in the spec */
+#define T1_MAX_MM_DESIGNS 16
+
+ /* maximum number of Multiple Masters axes, as defined in the spec */
+#define T1_MAX_MM_AXIS 4
+
+ /* maximum number of elements in a design map */
+#define T1_MAX_MM_MAP_POINTS 20
+
+
+ /* this structure is used to store the BlendDesignMap entry for an axis */
+ typedef struct T1_DesignMap_
+ {
+ FT_Byte num_points;
+ FT_Fixed* design_points;
+ FT_Fixed* blend_points;
+
+ } T1_DesignMap;
+
+
+ typedef struct T1_Blend_
+ {
+ FT_UInt num_designs;
+ FT_UInt num_axis;
+
+ FT_String* axis_names[T1_MAX_MM_AXIS];
+ FT_Fixed* design_pos[T1_MAX_MM_DESIGNS];
+ T1_DesignMap design_map[T1_MAX_MM_AXIS];
+
+ FT_Fixed* weight_vector;
+ FT_Fixed* default_weight_vector;
+
+ T1_FontInfo* font_infos[T1_MAX_MM_DESIGNS + 1];
+ T1_Private* privates [T1_MAX_MM_DESIGNS + 1];
+
+ FT_ULong blend_bitflags;
+
+ } T1_Blend;
+
+
+ typedef struct CID_FontDict_
+ {
+ T1_Private private_dict;
+
+ FT_UInt len_buildchar;
+ FT_Fixed forcebold_threshold;
+ FT_Pos stroke_width;
+ FT_Fixed expansion_factor;
+
+ FT_Byte paint_type;
+ FT_Byte font_type;
+ FT_Matrix font_matrix;
+ FT_Vector font_offset;
+
+ FT_UInt num_subrs;
+ FT_ULong subrmap_offset;
+ FT_Int sd_bytes;
+
+ } CID_FontDict;
+
+
+ typedef struct CID_Info_
+ {
+ FT_String* cid_font_name;
+ FT_Fixed cid_version;
+ FT_Int cid_font_type;
+
+ FT_String* registry;
+ FT_String* ordering;
+ FT_Int supplement;
+
+ T1_FontInfo font_info;
+ FT_BBox font_bbox;
+ FT_ULong uid_base;
+
+ FT_Int num_xuid;
+ FT_ULong xuid[16];
+
+
+ FT_ULong cidmap_offset;
+ FT_Int fd_bytes;
+ FT_Int gd_bytes;
+ FT_ULong cid_count;
+
+ FT_Int num_dicts;
+ CID_FontDict* font_dicts;
+
+ FT_ULong data_offset;
+
+ } CID_Info;
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __T1TABLES_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ttnameid.h */
+/* */
+/* TrueType name ID definitions (specification only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTNAMEID_H__
+#define __TTNAMEID_H__
+
+
+#include <ft2build.h>
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* Possible values for the `platform' identifier code in the name */
+ /* records of the TTF `name' table. */
+ /* */
+#define TT_PLATFORM_APPLE_UNICODE 0
+#define TT_PLATFORM_MACINTOSH 1
+#define TT_PLATFORM_ISO 2 /* deprecated */
+#define TT_PLATFORM_MICROSOFT 3
+#define TT_PLATFORM_CUSTOM 4
+
+ /* artificial values defined ad-hoc by FreeType */
+#define TT_PLATFORM_ADOBE 7
+
+
+ /*************************************************************************/
+ /* */
+ /* Possible values of the platform specific encoding identifier field in */
+ /* the name records of the TTF `name' table if the `platform' identifier */
+ /* code is TT_PLATFORM_APPLE_UNICODE. */
+ /* */
+#define TT_APPLE_ID_DEFAULT 0 /* Unicode 1.0 */
+#define TT_APPLE_ID_UNICODE_1_1 1 /* specify Hangul at U+34xx */
+#define TT_APPLE_ID_ISO_10646 2 /* deprecated */
+#define TT_APPLE_ID_UNICODE_2_0 3 /* or later */
+
+
+ /*************************************************************************/
+ /* */
+ /* Possible values of the platform specific encoding identifier field in */
+ /* the name records of the TTF `name' table if the `platform' identifier */
+ /* code is TT_PLATFORM_MACINTOSH. */
+ /* */
+#define TT_MAC_ID_ROMAN 0
+#define TT_MAC_ID_JAPANESE 1
+#define TT_MAC_ID_TRADITIONAL_CHINESE 2
+#define TT_MAC_ID_KOREAN 3
+#define TT_MAC_ID_ARABIC 4
+#define TT_MAC_ID_HEBREW 5
+#define TT_MAC_ID_GREEK 6
+#define TT_MAC_ID_RUSSIAN 7
+#define TT_MAC_ID_RSYMBOL 8
+#define TT_MAC_ID_DEVANAGARI 9
+#define TT_MAC_ID_GURMUKHI 10
+#define TT_MAC_ID_GUJARATI 11
+#define TT_MAC_ID_ORIYA 12
+#define TT_MAC_ID_BENGALI 13
+#define TT_MAC_ID_TAMIL 14
+#define TT_MAC_ID_TELUGU 15
+#define TT_MAC_ID_KANNADA 16
+#define TT_MAC_ID_MALAYALAM 17
+#define TT_MAC_ID_SINHALESE 18
+#define TT_MAC_ID_BURMESE 19
+#define TT_MAC_ID_KHMER 20
+#define TT_MAC_ID_THAI 21
+#define TT_MAC_ID_LAOTIAN 22
+#define TT_MAC_ID_GEORGIAN 23
+#define TT_MAC_ID_ARMENIAN 24
+#define TT_MAC_ID_MALDIVIAN 25
+#define TT_MAC_ID_SIMPLIFIED_CHINESE 25
+#define TT_MAC_ID_TIBETAN 26
+#define TT_MAC_ID_MONGOLIAN 27
+#define TT_MAC_ID_GEEZ 28
+#define TT_MAC_ID_SLAVIC 29
+#define TT_MAC_ID_VIETNAMESE 30
+#define TT_MAC_ID_SINDHI 31
+#define TT_MAC_ID_UNINTERP 32
+
+
+ /*************************************************************************/
+ /* */
+ /* Possible values of the platform specific encoding identifier field in */
+ /* the name records of the TTF `name' table if the `platform' identifier */
+ /* code is TT_PLATFORM_ISO. */
+ /* */
+ /* This use is now deprecated. */
+ /* */
+#define TT_ISO_ID_7BIT_ASCII 0
+#define TT_ISO_ID_10646 1
+#define TT_ISO_ID_8859_1 2
+
+
+ /*************************************************************************/
+ /* */
+ /* possible values of the platform specific encoding identifier field in */
+ /* the name records of the TTF `name' table if the `platform' identifier */
+ /* code is TT_PLATFORM_MICROSOFT. */
+ /* */
+#define TT_MS_ID_SYMBOL_CS 0
+#define TT_MS_ID_UNICODE_CS 1
+#define TT_MS_ID_SJIS 2
+#define TT_MS_ID_GB2312 3
+#define TT_MS_ID_BIG_5 4
+#define TT_MS_ID_WANSUNG 5
+#define TT_MS_ID_JOHAB 6
+#define TT_MS_ID_UCS_4 10
+
+
+ /*************************************************************************/
+ /* */
+ /* possible values of the platform specific encoding identifier field in */
+ /* the name records of the TTF `name' table if the `platform' identifier */
+ /* code is TT_PLATFORM_ADOBE. */
+ /* */
+ /* These are artificial values defined ad-hoc by FreeType. */
+ /* */
+#define TT_ADOBE_ID_STANDARD 0
+#define TT_ADOBE_ID_EXPERT 1
+#define TT_ADOBE_ID_CUSTOM 2
+
+
+ /*************************************************************************/
+ /* */
+ /* Possible values of the language identifier field in the name records */
+ /* of the TTF `name' table if the `platform' identifier code is */
+ /* TT_PLATFORM_MACINTOSH. */
+ /* */
+ /* The canonical source for the Apple assigned Language ID's is at */
+ /* */
+ /* http://fonts.apple.com/TTRefMan/RM06/Chap6name.html */
+ /* */
+#define TT_MAC_LANGID_ENGLISH 0
+#define TT_MAC_LANGID_FRENCH 1
+#define TT_MAC_LANGID_GERMAN 2
+#define TT_MAC_LANGID_ITALIAN 3
+#define TT_MAC_LANGID_DUTCH 4
+#define TT_MAC_LANGID_SWEDISH 5
+#define TT_MAC_LANGID_SPANISH 6
+#define TT_MAC_LANGID_DANISH 7
+#define TT_MAC_LANGID_PORTUGUESE 8
+#define TT_MAC_LANGID_NORWEGIAN 9
+#define TT_MAC_LANGID_HEBREW 10
+#define TT_MAC_LANGID_JAPANESE 11
+#define TT_MAC_LANGID_ARABIC 12
+#define TT_MAC_LANGID_FINNISH 13
+#define TT_MAC_LANGID_GREEK 14
+#define TT_MAC_LANGID_ICELANDIC 15
+#define TT_MAC_LANGID_MALTESE 16
+#define TT_MAC_LANGID_TURKISH 17
+#define TT_MAC_LANGID_CROATIAN 18
+#define TT_MAC_LANGID_CHINESE_TRADITIONAL 19
+#define TT_MAC_LANGID_URDU 20
+#define TT_MAC_LANGID_HINDI 21
+#define TT_MAC_LANGID_THAI 22
+#define TT_MAC_LANGID_KOREAN 23
+#define TT_MAC_LANGID_LITHUANIAN 24
+#define TT_MAC_LANGID_POLISH 25
+#define TT_MAC_LANGID_HUNGARIAN 26
+#define TT_MAC_LANGID_ESTONIAN 27
+#define TT_MAC_LANGID_LETTISH 28
+#define TT_MAC_LANGID_SAAMISK 29
+#define TT_MAC_LANGID_FAEROESE 30
+#define TT_MAC_LANGID_FARSI 31
+#define TT_MAC_LANGID_RUSSIAN 32
+#define TT_MAC_LANGID_CHINESE_SIMPLIFIED 33
+#define TT_MAC_LANGID_FLEMISH 34
+#define TT_MAC_LANGID_IRISH 35
+#define TT_MAC_LANGID_ALBANIAN 36
+#define TT_MAC_LANGID_ROMANIAN 37
+#define TT_MAC_LANGID_CZECH 38
+#define TT_MAC_LANGID_SLOVAK 39
+#define TT_MAC_LANGID_SLOVENIAN 40
+#define TT_MAC_LANGID_YIDDISH 41
+#define TT_MAC_LANGID_SERBIAN 42
+#define TT_MAC_LANGID_MACEDONIAN 43
+#define TT_MAC_LANGID_BULGARIAN 44
+#define TT_MAC_LANGID_UKRAINIAN 45
+#define TT_MAC_LANGID_BYELORUSSIAN 46
+#define TT_MAC_LANGID_UZBEK 47
+#define TT_MAC_LANGID_KAZAKH 48
+#define TT_MAC_LANGID_AZERBAIJANI 49
+#define TT_MAC_LANGID_AZERBAIJANI_CYRILLIC_SCRIPT 49
+#define TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT 50
+#define TT_MAC_LANGID_ARMENIAN 51
+#define TT_MAC_LANGID_GEORGIAN 52
+#define TT_MAC_LANGID_MOLDAVIAN 53
+#define TT_MAC_LANGID_KIRGHIZ 54
+#define TT_MAC_LANGID_TAJIKI 55
+#define TT_MAC_LANGID_TURKMEN 56
+#define TT_MAC_LANGID_MONGOLIAN 57
+#define TT_MAC_LANGID_MONGOLIAN_MONGOLIAN_SCRIPT 57
+#define TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT 58
+#define TT_MAC_LANGID_PASHTO 59
+#define TT_MAC_LANGID_KURDISH 60
+#define TT_MAC_LANGID_KASHMIRI 61
+#define TT_MAC_LANGID_SINDHI 62
+#define TT_MAC_LANGID_TIBETAN 63
+#define TT_MAC_LANGID_NEPALI 64
+#define TT_MAC_LANGID_SANSKRIT 65
+#define TT_MAC_LANGID_MARATHI 66
+#define TT_MAC_LANGID_BENGALI 67
+#define TT_MAC_LANGID_ASSAMESE 68
+#define TT_MAC_LANGID_GUJARATI 69
+#define TT_MAC_LANGID_PUNJABI 70
+#define TT_MAC_LANGID_ORIYA 71
+#define TT_MAC_LANGID_MALAYALAM 72
+#define TT_MAC_LANGID_KANNADA 73
+#define TT_MAC_LANGID_TAMIL 74
+#define TT_MAC_LANGID_TELUGU 75
+#define TT_MAC_LANGID_SINHALESE 76
+#define TT_MAC_LANGID_BURMESE 77
+#define TT_MAC_LANGID_KHMER 78
+#define TT_MAC_LANGID_LAO 79
+#define TT_MAC_LANGID_VIETNAMESE 80
+#define TT_MAC_LANGID_INDONESIAN 81
+#define TT_MAC_LANGID_TAGALOG 82
+#define TT_MAC_LANGID_MALAY_ROMAN_SCRIPT 83
+#define TT_MAC_LANGID_MALAY_ARABIC_SCRIPT 84
+#define TT_MAC_LANGID_AMHARIC 85
+#define TT_MAC_LANGID_TIGRINYA 86
+#define TT_MAC_LANGID_GALLA 87
+#define TT_MAC_LANGID_SOMALI 88
+#define TT_MAC_LANGID_SWAHILI 89
+#define TT_MAC_LANGID_RUANDA 90
+#define TT_MAC_LANGID_RUNDI 91
+#define TT_MAC_LANGID_CHEWA 92
+#define TT_MAC_LANGID_MALAGASY 93
+#define TT_MAC_LANGID_ESPERANTO 94
+#define TT_MAC_LANGID_WELSH 128
+#define TT_MAC_LANGID_BASQUE 129
+#define TT_MAC_LANGID_CATALAN 130
+#define TT_MAC_LANGID_LATIN 131
+#define TT_MAC_LANGID_QUECHUA 132
+#define TT_MAC_LANGID_GUARANI 133
+#define TT_MAC_LANGID_AYMARA 134
+#define TT_MAC_LANGID_TATAR 135
+#define TT_MAC_LANGID_UIGHUR 136
+#define TT_MAC_LANGID_DZONGKHA 137
+#define TT_MAC_LANGID_JAVANESE 138
+#define TT_MAC_LANGID_SUNDANESE 139
+
+
+#if 0 /* these seem to be errors that have been dropped */
+
+#define TT_MAC_LANGID_SCOTTISH_GAELIC 140
+#define TT_MAC_LANGID_IRISH_GAELIC 141
+
+#endif
+
+
+ /* The following codes are new as of 2000-03-10 */
+#define TT_MAC_LANGID_GALICIAN 140
+#define TT_MAC_LANGID_AFRIKAANS 141
+#define TT_MAC_LANGID_BRETON 142
+#define TT_MAC_LANGID_INUKTITUT 143
+#define TT_MAC_LANGID_SCOTTISH_GAELIC 144
+#define TT_MAC_LANGID_MANX_GAELIC 145
+#define TT_MAC_LANGID_IRISH_GAELIC 146
+#define TT_MAC_LANGID_TONGAN 147
+#define TT_MAC_LANGID_GREEK_POLYTONIC 148
+#define TT_MAC_LANGID_GREELANDIC 149
+#define TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT 150
+
+
+ /*************************************************************************/
+ /* */
+ /* Possible values of the language identifier field in the name records */
+ /* of the TTF `name' table if the `platform' identifier code is */
+ /* TT_PLATFORM_MICROSOFT. */
+ /* */
+ /* The canonical source for the MS assigned LCID's is at */
+ /* */
+ /* http://www.microsoft.com/typography/OTSPEC/lcid-cp.txt */
+ /* */
+#define TT_MS_LANGID_ARABIC_SAUDI_ARABIA 0x0401
+#define TT_MS_LANGID_ARABIC_IRAQ 0x0801
+#define TT_MS_LANGID_ARABIC_EGYPT 0x0c01
+#define TT_MS_LANGID_ARABIC_LIBYA 0x1001
+#define TT_MS_LANGID_ARABIC_ALGERIA 0x1401
+#define TT_MS_LANGID_ARABIC_MOROCCO 0x1801
+#define TT_MS_LANGID_ARABIC_TUNISIA 0x1c01
+#define TT_MS_LANGID_ARABIC_OMAN 0x2001
+#define TT_MS_LANGID_ARABIC_YEMEN 0x2401
+#define TT_MS_LANGID_ARABIC_SYRIA 0x2801
+#define TT_MS_LANGID_ARABIC_JORDAN 0x2c01
+#define TT_MS_LANGID_ARABIC_LEBANON 0x3001
+#define TT_MS_LANGID_ARABIC_KUWAIT 0x3401
+#define TT_MS_LANGID_ARABIC_UAE 0x3801
+#define TT_MS_LANGID_ARABIC_BAHRAIN 0x3c01
+#define TT_MS_LANGID_ARABIC_QATAR 0x4001
+#define TT_MS_LANGID_BULGARIAN_BULGARIA 0x0402
+#define TT_MS_LANGID_CATALAN_SPAIN 0x0403
+#define TT_MS_LANGID_CHINESE_TAIWAN 0x0404
+#define TT_MS_LANGID_CHINESE_PRC 0x0804
+#define TT_MS_LANGID_CHINESE_HONG_KONG 0x0c04
+#define TT_MS_LANGID_CHINESE_SINGAPORE 0x1004
+
+#if 1 /* this used to be this value (and it still is in many places) */
+#define TT_MS_LANGID_CHINESE_MACAU 0x1404
+#else /* but beware, Microsoft may change its mind...
+ the most recent Word reference has the following: :-( */
+#define TT_MS_LANGID_CHINESE_MACAU TT_MS_LANGID_CHINESE_HONG_KONG
+#endif
+
+#define TT_MS_LANGID_CZECH_CZECH_REPUBLIC 0x0405
+#define TT_MS_LANGID_DANISH_DENMARK 0x0406
+#define TT_MS_LANGID_GERMAN_GERMANY 0x0407
+#define TT_MS_LANGID_GERMAN_SWITZERLAND 0x0807
+#define TT_MS_LANGID_GERMAN_AUSTRIA 0x0c07
+#define TT_MS_LANGID_GERMAN_LUXEMBOURG 0x1007
+#define TT_MS_LANGID_GERMAN_LIECHTENSTEI 0x1407
+#define TT_MS_LANGID_GREEK_GREECE 0x0408
+#define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
+#define TT_MS_LANGID_ENGLISH_UNITED_KINGDOM 0x0809
+#define TT_MS_LANGID_ENGLISH_AUSTRALIA 0x0c09
+#define TT_MS_LANGID_ENGLISH_CANADA 0x1009
+#define TT_MS_LANGID_ENGLISH_NEW_ZEALAND 0x1409
+#define TT_MS_LANGID_ENGLISH_IRELAND 0x1809
+#define TT_MS_LANGID_ENGLISH_SOUTH_AFRICA 0x1c09
+#define TT_MS_LANGID_ENGLISH_JAMAICA 0x2009
+#define TT_MS_LANGID_ENGLISH_CARIBBEAN 0x2409
+#define TT_MS_LANGID_ENGLISH_BELIZE 0x2809
+#define TT_MS_LANGID_ENGLISH_TRINIDAD 0x2c09
+#define TT_MS_LANGID_ENGLISH_ZIMBABWE 0x3009
+#define TT_MS_LANGID_ENGLISH_PHILIPPINES 0x3409
+#define TT_MS_LANGID_SPANISH_SPAIN_TRADITIONAL_SORT 0x040a
+#define TT_MS_LANGID_SPANISH_MEXICO 0x080a
+#define TT_MS_LANGID_SPANISH_SPAIN_INTERNATIONAL_SORT 0x0c0a
+#define TT_MS_LANGID_SPANISH_GUATEMALA 0x100a
+#define TT_MS_LANGID_SPANISH_COSTA_RICA 0x140a
+#define TT_MS_LANGID_SPANISH_PANAMA 0x180a
+#define TT_MS_LANGID_SPANISH_DOMINICAN_REPUBLIC 0x1c0a
+#define TT_MS_LANGID_SPANISH_VENEZUELA 0x200a
+#define TT_MS_LANGID_SPANISH_COLOMBIA 0x240a
+#define TT_MS_LANGID_SPANISH_PERU 0x280a
+#define TT_MS_LANGID_SPANISH_ARGENTINA 0x2c0a
+#define TT_MS_LANGID_SPANISH_ECUADOR 0x300a
+#define TT_MS_LANGID_SPANISH_CHILE 0x340a
+#define TT_MS_LANGID_SPANISH_URUGUAY 0x380a
+#define TT_MS_LANGID_SPANISH_PARAGUAY 0x3c0a
+#define TT_MS_LANGID_SPANISH_BOLIVIA 0x400a
+#define TT_MS_LANGID_SPANISH_EL_SALVADOR 0x440a
+#define TT_MS_LANGID_SPANISH_HONDURAS 0x480a
+#define TT_MS_LANGID_SPANISH_NICARAGUA 0x4c0a
+#define TT_MS_LANGID_SPANISH_PUERTO_RICO 0x500a
+#define TT_MS_LANGID_FINNISH_FINLAND 0x040b
+#define TT_MS_LANGID_FRENCH_FRANCE 0x040c
+#define TT_MS_LANGID_FRENCH_BELGIUM 0x080c
+#define TT_MS_LANGID_FRENCH_CANADA 0x0c0c
+#define TT_MS_LANGID_FRENCH_SWITZERLAND 0x100c
+#define TT_MS_LANGID_FRENCH_LUXEMBOURG 0x140c
+#define TT_MS_LANGID_FRENCH_MONACO 0x180c
+#define TT_MS_LANGID_HEBREW_ISRAEL 0x040d
+#define TT_MS_LANGID_HUNGARIAN_HUNGARY 0x040e
+#define TT_MS_LANGID_ICELANDIC_ICELAND 0x040f
+#define TT_MS_LANGID_ITALIAN_ITALY 0x0410
+#define TT_MS_LANGID_ITALIAN_SWITZERLAND 0x0810
+#define TT_MS_LANGID_JAPANESE_JAPAN 0x0411
+#define TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA 0x0412
+#define TT_MS_LANGID_KOREAN_JOHAB_KOREA 0x0812
+#define TT_MS_LANGID_DUTCH_NETHERLANDS 0x0413
+#define TT_MS_LANGID_DUTCH_BELGIUM 0x0813
+#define TT_MS_LANGID_NORWEGIAN_NORWAY_BOKMAL 0x0414
+#define TT_MS_LANGID_NORWEGIAN_NORWAY_NYNORSK 0x0814
+#define TT_MS_LANGID_POLISH_POLAND 0x0415
+#define TT_MS_LANGID_PORTUGUESE_BRAZIL 0x0416
+#define TT_MS_LANGID_PORTUGUESE_PORTUGAL 0x0816
+#define TT_MS_LANGID_RHAETO_ROMANIC_SWITZERLAND 0x0417
+#define TT_MS_LANGID_ROMANIAN_ROMANIA 0x0418
+#define TT_MS_LANGID_MOLDAVIAN_MOLDAVIA 0x0818
+#define TT_MS_LANGID_RUSSIAN_RUSSIA 0x0419
+#define TT_MS_LANGID_RUSSIAN_MOLDAVIA 0x0819
+#define TT_MS_LANGID_CROATIAN_CROATIA 0x041a
+#define TT_MS_LANGID_SERBIAN_SERBIA_LATIN 0x081a
+#define TT_MS_LANGID_SERBIAN_SERBIA_CYRILLIC 0x0c1a
+#define TT_MS_LANGID_SLOVAK_SLOVAKIA 0x041b
+#define TT_MS_LANGID_ALBANIAN_ALBANIA 0x041c
+#define TT_MS_LANGID_SWEDISH_SWEDEN 0x041d
+#define TT_MS_LANGID_SWEDISH_FINLAND 0x081d
+#define TT_MS_LANGID_THAI_THAILAND 0x041e
+#define TT_MS_LANGID_TURKISH_TURKEY 0x041f
+#define TT_MS_LANGID_URDU_PAKISTAN 0x0420
+#define TT_MS_LANGID_INDONESIAN_INDONESIA 0x0421
+#define TT_MS_LANGID_UKRAINIAN_UKRAINE 0x0422
+#define TT_MS_LANGID_BELARUSIAN_BELARUS 0x0423
+#define TT_MS_LANGID_SLOVENE_SLOVENIA 0x0424
+#define TT_MS_LANGID_ESTONIAN_ESTONIA 0x0425
+#define TT_MS_LANGID_LATVIAN_LATVIA 0x0426
+#define TT_MS_LANGID_LITHUANIAN_LITHUANIA 0x0427
+#define TT_MS_LANGID_CLASSIC_LITHUANIAN_LITHUANIA 0x0827
+
+#if 0 /* this seems to be an error that have been dropped */
+#define TT_MS_LANGID_MAORI_NEW_ZEALAND 0x0428
+#endif
+
+#define TT_MS_LANGID_FARSI_IRAN 0x0429
+#define TT_MS_LANGID_VIETNAMESE_VIET_NAM 0x042a
+#define TT_MS_LANGID_ARMENIAN_ARMENIA 0x042b
+#define TT_MS_LANGID_AZERI_AZERBAIJAN_LATIN 0x042c
+#define TT_MS_LANGID_AZERI_AZERBAIJAN_CYRILLIC 0x082c
+#define TT_MS_LANGID_BASQUE_SPAIN 0x042d
+#define TT_MS_LANGID_SORBIAN_GERMANY 0x042e
+#define TT_MS_LANGID_MACEDONIAN_MACEDONIA 0x042f
+#define TT_MS_LANGID_SUTU_SOUTH_AFRICA 0x0430
+#define TT_MS_LANGID_TSONGA_SOUTH_AFRICA 0x0431
+#define TT_MS_LANGID_TSWANA_SOUTH_AFRICA 0x0432
+#define TT_MS_LANGID_VENDA_SOUTH_AFRICA 0x0433
+#define TT_MS_LANGID_XHOSA_SOUTH_AFRICA 0x0434
+#define TT_MS_LANGID_ZULU_SOUTH_AFRICA 0x0435
+#define TT_MS_LANGID_AFRIKAANS_SOUTH_AFRICA 0x0436
+#define TT_MS_LANGID_GEORGIAN_GEORGIA 0x0437
+#define TT_MS_LANGID_FAEROESE_FAEROE_ISLANDS 0x0438
+#define TT_MS_LANGID_HINDI_INDIA 0x0439
+#define TT_MS_LANGID_MALTESE_MALTA 0x043a
+#define TT_MS_LANGID_SAAMI_LAPONIA 0x043b
+
+#if 0 /* this seems to be a previous invertion */
+#define TT_MS_LANGID_IRISH_GAELIC_IRELAND 0x043c
+#define TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM 0x083c
+#else
+#define TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM 0x083c
+#define TT_MS_LANGID_IRISH_GAELIC_IRELAND 0x043c
+#endif
+
+#define TT_MS_LANGID_MALAY_MALAYSIA 0x043e
+#define TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM 0x083e
+#define TT_MS_LANGID_KAZAK_KAZAKSTAN 0x043f
+#define TT_MS_LANGID_SWAHILI_KENYA 0x0441
+#define TT_MS_LANGID_UZBEK_UZBEKISTAN_LATIN 0x0443
+#define TT_MS_LANGID_UZBEK_UZBEKISTAN_CYRILLIC 0x0843
+#define TT_MS_LANGID_TATAR_TATARSTAN 0x0444
+#define TT_MS_LANGID_BENGALI_INDIA 0x0445
+#define TT_MS_LANGID_PUNJABI_INDIA 0x0446
+#define TT_MS_LANGID_GUJARATI_INDIA 0x0447
+#define TT_MS_LANGID_ORIYA_INDIA 0x0448
+#define TT_MS_LANGID_TAMIL_INDIA 0x0449
+#define TT_MS_LANGID_TELUGU_INDIA 0x044a
+#define TT_MS_LANGID_KANNADA_INDIA 0x044b
+#define TT_MS_LANGID_MALAYALAM_INDIA 0x044c
+#define TT_MS_LANGID_ASSAMESE_INDIA 0x044d
+#define TT_MS_LANGID_MARATHI_INDIA 0x044e
+#define TT_MS_LANGID_SANSKRIT_INDIA 0x044f
+#define TT_MS_LANGID_KONKANI_INDIA 0x0457
+
+/* new as of 2001-01-01 */
+#define TT_MS_LANGID_ARABIC_GENERAL 0x0001
+#define TT_MS_LANGID_CHINESE_GENERAL 0x0004
+#define TT_MS_LANGID_ENGLISH_GENERAL 0x0009
+#define TT_MS_LANGID_FRENCH_WEST_INDIES 0x1c0c
+#define TT_MS_LANGID_FRENCH_REUNION 0x200c
+#define TT_MS_LANGID_FRENCH_CONGO 0x240c
+ /* which was formerly: */
+#define TT_MS_LANGID_FRENCH_ZAIRE TT_MS_LANGID_FRENCH_CONGO
+
+#define TT_MS_LANGID_FRENCH_SENEGAL 0x280c
+#define TT_MS_LANGID_FRENCH_CAMEROON 0x2c0c
+#define TT_MS_LANGID_FRENCH_COTE_D_IVOIRE 0x300c
+#define TT_MS_LANGID_FRENCH_MALI 0x340c
+#define TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA 0x101a
+#define TT_MS_LANGID_URDU_INDIA 0x0820
+#define TT_MS_LANGID_TAJIK_TAJIKISTAN 0x0428
+#define TT_MS_LANGID_YIDDISH_GERMANY 0x043d
+#define TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN 0x0440
+ /* alias declared in Windows 2000 */
+#define TT_MS_LANGID_KIRGHIZ_KIRGHIZ_REPUBLIC \
+ TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN
+
+#define TT_MS_LANGID_TURKMEN_TURKMENISTAN 0x0442
+#define TT_MS_LANGID_MONGOLIAN_MONGOLIA 0x0450
+#define TT_MS_LANGID_TIBETAN_BHUTAN 0x0451
+#define TT_MS_LANGID_WELSH_WALES 0x0452
+#define TT_MS_LANGID_KHMER_CAMBODIA 0x0453
+#define TT_MS_LANGID_LAO_LAOS 0x0454
+#define TT_MS_LANGID_BURMESE_MYANMAR 0x0455
+#define TT_MS_LANGID_GALICIAN_SPAIN 0x0456
+#define TT_MS_LANGID_MANIPURI_INDIA 0x0458
+#define TT_MS_LANGID_SINDHI_INDIA 0x0459
+#define TT_MS_LANGID_KASHMIRI_PAKISTAN 0x0460
+#define TT_MS_LANGID_KASHMIRI_INDIA 0x0860
+#define TT_MS_LANGID_NEPALI_NEPAL 0x0461
+#define TT_MS_LANGID_NEPALI_INDIA 0x0861
+#define TT_MS_LANGID_FRISIAN_NETHERLANDS 0x0462
+
+/* new as of 2001-03-01 (from Office Xp) */
+#define TT_MS_LANGID_SYRIAC_SYRIA 0x045a
+#define TT_MS_LANGID_SINHALESE_SRI_LANKA 0x045b
+#define TT_MS_LANGID_PASHTO_AFGHANISTAN 0x0463
+#define TT_MS_LANGID_ENGLISH_HONG_KONG 0x3c09
+#define TT_MS_LANGID_ENGLISH_INDIA 0x4009
+#define TT_MS_LANGID_ENGLISH_MALAYSIA 0x4409
+#define TT_MS_LANGID_ENGLISH_SINGAPORE 0x4809
+#define TT_MS_LANGID_CHEROKEE_UNITED_STATES 0x045c
+#define TT_MS_LANGID_INUKTITUT_CANADA 0x045d
+#define TT_MS_LANGID_AMHARIC_ETHIOPIA 0x045e
+#define TT_MS_LANGID_TAMAZIGHT_MOROCCO 0x045f
+#define TT_MS_LANGID_TAMAZIGHT_MOROCCO_LATIN 0x085f
+#define TT_MS_LANGID_FILIPINO_PHILIPPINES 0x0464
+#define TT_MS_LANGID_DHIVEHI_MALDIVES 0x0465
+ /* alias declared in Windows 2000 */
+#define TT_MS_LANGID_DIVEHI_MALDIVES TT_MS_LANGID_DHIVEHI_MALDIVES
+ /* language codes from 0x0466 to 0x0471 are unknown. */
+#define TT_MS_LANGID_OROMO_ETHIOPIA 0x0472
+#define TT_MS_LANGID_TIGRIGNA_ETHIOPIA 0x0473
+#define TT_MS_LANGID_TIGRIGNA_ERYTHREA 0x0873
+
+
+
+ /*************************************************************************/
+ /* */
+ /* Possible values of the `name' identifier field in the name records of */
+ /* the TTF `name' table. These values are platform independent. */
+ /* */
+#define TT_NAME_ID_COPYRIGHT 0
+#define TT_NAME_ID_FONT_FAMILY 1
+#define TT_NAME_ID_FONT_SUBFAMILY 2
+#define TT_NAME_ID_UNIQUE_ID 3
+#define TT_NAME_ID_FULL_NAME 4
+#define TT_NAME_ID_VERSION_STRING 5
+#define TT_NAME_ID_PS_NAME 6
+#define TT_NAME_ID_TRADEMARK 7
+
+/* the following values are from the OpenType spec */
+#define TT_NAME_ID_MANUFACTURER 8
+#define TT_NAME_ID_DESIGNER 9
+#define TT_NAME_ID_DESCRIPTION 10
+#define TT_NAME_ID_VENDOR_URL 11
+#define TT_NAME_ID_DESIGNER_URL 12
+#define TT_NAME_ID_LICENSE 13
+#define TT_NAME_ID_LICENSE_URL 14
+/* number 15 is reserved */
+#define TT_NAME_ID_PREFERRED_FAMILY 16
+#define TT_NAME_ID_PREFERRED_SUBFAMILY 17
+#define TT_NAME_ID_MAC_FULL_NAME 18
+
+/* The following code is new as of 2000-01-21 */
+#define TT_NAME_ID_SAMPLE_TEXT 19
+
+/* This is new in OpenType 1.3 */
+#define TT_NAME_ID_CID_FINDFONT_NAME 20
+
+
+ /*************************************************************************/
+ /* */
+ /* Bit mask values for the Unicode Ranges from the TTF `OS2 ' table. */
+ /* */
+ /* Updated 02-Jul-2000. */
+ /* */
+
+ /* General Scripts Area */
+
+ /* Bit 0 Basic Latin */
+#define TT_UCR_BASIC_LATIN (1L << 0) /* U+0020-U+007E */
+ /* Bit 1 C1 Controls and Latin-1 Supplement */
+#define TT_UCR_LATIN1_SUPPLEMENT (1L << 1) /* U+0080-U+00FF */
+ /* Bit 2 Latin Extended-A */
+#define TT_UCR_LATIN_EXTENDED_A (1L << 2) /* U+0100-U+017F */
+ /* Bit 3 Latin Extended-B */
+#define TT_UCR_LATIN_EXTENDED_B (1L << 3) /* U+0180-U+024F */
+ /* Bit 4 IPA Extensions */
+#define TT_UCR_IPA_EXTENSIONS (1L << 4) /* U+0250-U+02AF */
+ /* Bit 5 Spacing Modifier Letters */
+#define TT_UCR_SPACING_MODIFIER (1L << 5) /* U+02B0-U+02FF */
+ /* Bit 6 Combining Diacritical Marks */
+#define TT_UCR_COMBINING_DIACRITICS (1L << 6) /* U+0300-U+036F */
+ /* Bit 7 Greek and Coptic */
+#define TT_UCR_GREEK (1L << 7) /* U+0370-U+03FF */
+ /* Bit 8 is reserved (was: Greek Symbols and Coptic) */
+ /* Bit 9 Cyrillic */
+#define TT_UCR_CYRILLIC (1L << 9) /* U+0400-U+04FF */
+ /* Bit 10 Armenian */
+#define TT_UCR_ARMENIAN (1L << 10) /* U+0530-U+058F */
+ /* Bit 11 Hebrew */
+#define TT_UCR_HEBREW (1L << 11) /* U+0590-U+05FF */
+ /* Bit 12 is reserved (was: Hebrew Extended) */
+ /* Bit 13 Arabic */
+#define TT_UCR_ARABIC (1L << 13) /* U+0600-U+06FF */
+ /* Bit 14 is reserved (was: Arabic Extended) */
+ /* Bit 15 Devanagari */
+#define TT_UCR_DEVANAGARI (1L << 15) /* U+0900-U+097F */
+ /* Bit 16 Bengali */
+#define TT_UCR_BENGALI (1L << 16) /* U+0980-U+09FF */
+ /* Bit 17 Gurmukhi */
+#define TT_UCR_GURMUKHI (1L << 17) /* U+0A00-U+0A7F */
+ /* Bit 18 Gujarati */
+#define TT_UCR_GUJARATI (1L << 18) /* U+0A80-U+0AFF */
+ /* Bit 19 Oriya */
+#define TT_UCR_ORIYA (1L << 19) /* U+0B00-U+0B7F */
+ /* Bit 20 Tamil */
+#define TT_UCR_TAMIL (1L << 20) /* U+0B80-U+0BFF */
+ /* Bit 21 Telugu */
+#define TT_UCR_TELUGU (1L << 21) /* U+0C00-U+0C7F */
+ /* Bit 22 Kannada */
+#define TT_UCR_KANNADA (1L << 22) /* U+0C80-U+0CFF */
+ /* Bit 23 Malayalam */
+#define TT_UCR_MALAYALAM (1L << 23) /* U+0D00-U+0D7F */
+ /* Bit 24 Thai */
+#define TT_UCR_THAI (1L << 24) /* U+0E00-U+0E7F */
+ /* Bit 25 Lao */
+#define TT_UCR_LAO (1L << 25) /* U+0E80-U+0EFF */
+ /* Bit 26 Georgian */
+#define TT_UCR_GEORGIAN (1L << 26) /* U+10A0-U+10FF */
+ /* Bit 27 is reserved (was Georgian Extended) */
+ /* Bit 28 Hangul Jamo */
+#define TT_UCR_HANGUL_JAMO (1L << 28) /* U+1100-U+11FF */
+ /* Bit 29 Latin Extended Additional */
+#define TT_UCR_LATIN_EXTENDED_ADDITIONAL (1L << 29) /* U+1E00-U+1EFF */
+ /* Bit 30 Greek Extended */
+#define TT_UCR_GREEK_EXTENDED (1L << 30) /* U+1F00-U+1FFF */
+
+ /* Symbols Area */
+
+ /* Bit 31 General Punctuation */
+#define TT_UCR_GENERAL_PUNCTUATION (1L << 31) /* U+2000-U+206F */
+ /* Bit 32 Superscripts And Subscripts */
+#define TT_UCR_SUPERSCRIPTS_SUBSCRIPTS (1L << 0) /* U+2070-U+209F */
+ /* Bit 33 Currency Symbols */
+#define TT_UCR_CURRENCY_SYMBOLS (1L << 1) /* U+20A0-U+20CF */
+ /* Bit 34 Combining Diacritical Marks For Symbols */
+#define TT_UCR_COMBINING_DIACRITICS_SYMB (1L << 2) /* U+20D0-U+20FF */
+ /* Bit 35 Letterlike Symbols */
+#define TT_UCR_LETTERLIKE_SYMBOLS (1L << 3) /* U+2100-U+214F */
+ /* Bit 36 Number Forms */
+#define TT_UCR_NUMBER_FORMS (1L << 4) /* U+2150-U+218F */
+ /* Bit 37 Arrows */
+#define TT_UCR_ARROWS (1L << 5) /* U+2190-U+21FF */
+ /* Bit 38 Mathematical Operators */
+#define TT_UCR_MATHEMATICAL_OPERATORS (1L << 6) /* U+2200-U+22FF */
+ /* Bit 39 Miscellaneous Technical */
+#define TT_UCR_MISCELLANEOUS_TECHNICAL (1L << 7) /* U+2300-U+23FF */
+ /* Bit 40 Control Pictures */
+#define TT_UCR_CONTROL_PICTURES (1L << 8) /* U+2400-U+243F */
+ /* Bit 41 Optical Character Recognition */
+#define TT_UCR_OCR (1L << 9) /* U+2440-U+245F */
+ /* Bit 42 Enclosed Alphanumerics */
+#define TT_UCR_ENCLOSED_ALPHANUMERICS (1L << 10) /* U+2460-U+24FF */
+ /* Bit 43 Box Drawing */
+#define TT_UCR_BOX_DRAWING (1L << 11) /* U+2500-U+257F */
+ /* Bit 44 Block Elements */
+#define TT_UCR_BLOCK_ELEMENTS (1L << 12) /* U+2580-U+259F */
+ /* Bit 45 Geometric Shapes */
+#define TT_UCR_GEOMETRIC_SHAPES (1L << 13) /* U+25A0-U+25FF */
+ /* Bit 46 Miscellaneous Symbols */
+#define TT_UCR_MISCELLANEOUS_SYMBOLS (1L << 14) /* U+2600-U+26FF */
+ /* Bit 47 Dingbats */
+#define TT_UCR_DINGBATS (1L << 15) /* U+2700-U+27BF */
+
+ /* CJK Phonetics and Symbols Area */
+
+ /* Bit 48 CJK Symbols and Punctuation */
+#define TT_UCR_CJK_SYMBOLS (1L << 16) /* U+3000-U+303F */
+ /* Bit 49 Hiragana */
+#define TT_UCR_HIRAGANA (1L << 17) /* U+3040-U+309F */
+ /* Bit 50 Katakana */
+#define TT_UCR_KATAKANA (1L << 18) /* U+30A0-U+30FF */
+ /* Bit 51 Bopomofo + */
+ /* Bopomofo Extended */
+#define TT_UCR_BOPOMOFO (1L << 19) /* U+3100-U+312F */
+ /* U+31A0-U+31BF */
+ /* Bit 52 Hangul Compatibility Jamo */
+#define TT_UCR_HANGUL_COMPATIBILITY_JAMO (1L << 20) /* U+3130-U+318F */
+ /* Bit 53 Kanbun */
+#define TT_UCR_CJK_MISC (1L << 21) /* U+3190-U+319F */
+#define TT_UCR_KANBUN TT_UCR_CJK_MISC
+ /* Bit 54 Enclosed CJK Letters and Months */
+#define TT_UCR_ENCLOSED_CJK_LETTERS_MONTHS (1L << 22) /* U+3200-U+32FF */
+ /* Bit 55 CJK Compatibility */
+#define TT_UCR_CJK_COMPATIBILITY (1L << 23) /* U+3300-U+33FF */
+
+ /* Hangul Syllables Area */
+
+ /* Bit 56 Hangul */
+#define TT_UCR_HANGUL (1L << 24) /* U+AC00-U+D7A3 */
+
+ /* Surrogates Area */
+
+ /* Bit 57 High Surrogates + */
+ /* High Private Use Surrogates + */
+ /* Low Surrogates */
+#define TT_UCR_SURROGATES (1L << 25) /* U+D800-U+DB7F */
+ /* U+DB80-U+DBFF */
+ /* U+DC00-U+DFFF */
+ /* Bit 58 is reserved for Unicode SubRanges */
+
+ /* CJK Ideographs Area */
+
+ /* Bit 59 CJK Unified Ideographs + */
+ /* CJK Radicals Supplement + */
+ /* Kangxi Radicals + */
+ /* Ideographic Description Characters + */
+ /* CJK Unified Ideographs Extension A */
+#define TT_UCR_CJK_UNIFIED_IDEOGRAPHS (1L << 27) /* U+4E00-U+9FFF */
+ /* U+2E80-U+2EFF */
+ /* U+2F00-U+2FDF */
+ /* U+2FF0-U+2FFF */
+ /* U+3400-U+4DB5 */
+
+ /* Private Use Area */
+
+ /* Bit 60 Private Use */
+#define TT_UCR_PRIVATE_USE (1L << 28) /* U+E000-U+F8FF */
+
+ /* Compatibility Area and Specials */
+
+ /* Bit 61 CJK Compatibility Ideographs */
+#define TT_UCR_CJK_COMPATIBILITY_IDEOGRAPHS (1L << 29) /* U+F900-U+FAFF */
+ /* Bit 62 Alphabetic Presentation Forms */
+#define TT_UCR_ALPHABETIC_PRESENTATION_FORMS (1L << 30) /* U+FB00-U+FB4F */
+ /* Bit 63 Arabic Presentation Forms-A */
+#define TT_UCR_ARABIC_PRESENTATIONS_A (1L << 31) /* U+FB50-U+FDFF */
+ /* Bit 64 Combining Half Marks */
+#define TT_UCR_COMBINING_HALF_MARKS (1L << 0) /* U+FE20-U+FE2F */
+ /* Bit 65 CJK Compatibility Forms */
+#define TT_UCR_CJK_COMPATIBILITY_FORMS (1L << 1) /* U+FE30-U+FE4F */
+ /* Bit 66 Small Form Variants */
+#define TT_UCR_SMALL_FORM_VARIANTS (1L << 2) /* U+FE50-U+FE6F */
+ /* Bit 67 Arabic Presentation Forms-B */
+#define TT_UCR_ARABIC_PRESENTATIONS_B (1L << 3) /* U+FE70-U+FEFE */
+ /* Bit 68 Halfwidth and Fullwidth Forms */
+#define TT_UCR_HALFWIDTH_FULLWIDTH_FORMS (1L << 4) /* U+FF00-U+FFEF */
+ /* Bit 69 Specials */
+#define TT_UCR_SPECIALS (1L << 5) /* U+FFF0-U+FFFD */
+ /* Bit 70 Tibetan */
+#define TT_UCR_TIBETAN (1L << 6) /* U+0F00-U+0FFF */
+ /* Bit 71 Syriac */
+#define TT_UCR_SYRIAC (1L << 7) /* U+0700-U+074F */
+ /* Bit 72 Thaana */
+#define TT_UCR_THAANA (1L << 8) /* U+0780-U+07BF */
+ /* Bit 73 Sinhala */
+#define TT_UCR_SINHALA (1L << 9) /* U+0D80-U+0DFF */
+ /* Bit 74 Myanmar */
+#define TT_UCR_MYANMAR (1L << 10) /* U+1000-U+109F */
+ /* Bit 75 Ethiopic */
+#define TT_UCR_ETHIOPIC (1L << 11) /* U+1200-U+137F */
+ /* Bit 76 Cherokee */
+#define TT_UCR_CHEROKEE (1L << 12) /* U+13A0-U+13FF */
+ /* Bit 77 Unified Canadian Aboriginal Syllabics */
+#define TT_UCR_CANADIAN_ABORIGINAL_SYLLABICS (1L << 13) /* U+1400-U+167F */
+ /* Bit 78 Ogham */
+#define TT_UCR_OGHAM (1L << 14) /* U+1680-U+169F */
+ /* Bit 79 Runic */
+#define TT_UCR_RUNIC (1L << 15) /* U+16A0-U+16FF */
+ /* Bit 80 Khmer */
+#define TT_UCR_KHMER (1L << 16) /* U+1780-U+17FF */
+ /* Bit 81 Mongolian */
+#define TT_UCR_MONGOLIAN (1L << 17) /* U+1800-U+18AF */
+ /* Bit 82 Braille Patterns */
+#define TT_UCR_BRAILLE (1L << 18) /* U+2800-U+28FF */
+ /* Bit 83 Yi Syllables + */
+ /* Yi Radicals */
+#define TT_UCR_YI (1L << 19) /* U+A000-U+A48F */
+ /* U+A490-U+A4CF */
+
+
+ /*************************************************************************/
+ /* */
+ /* Some compilers have a very limited length of identifiers. */
+ /* */
+#if defined( __TURBOC__ ) && __TURBOC__ < 0x0410 || defined( __PACIFIC__ )
+#define HAVE_LIMIT_ON_IDENTS
+#endif
+
+
+#ifndef HAVE_LIMIT_ON_IDENTS
+
+
+ /*************************************************************************/
+ /* */
+ /* Here some alias #defines in order to be clearer. */
+ /* */
+ /* These are not always #defined to stay within the 31 character limit */
+ /* which some compilers have. */
+ /* */
+ /* Credits go to Dave Hoo <dhoo@flash.net> for pointing out that modern */
+ /* Borland compilers (read: from BC++ 3.1 on) can increase this limit. */
+ /* If you get a warning with such a compiler, use the -i40 switch. */
+ /* */
+#define TT_UCR_ARABIC_PRESENTATION_FORMS_A \
+ TT_UCR_ARABIC_PRESENTATIONS_A
+#define TT_UCR_ARABIC_PRESENTATION_FORMS_B \
+ TT_UCR_ARABIC_PRESENTATIONS_B
+
+#define TT_UCR_COMBINING_DIACRITICAL_MARKS \
+ TT_UCR_COMBINING_DIACRITICS
+#define TT_UCR_COMBINING_DIACRITICAL_MARKS_SYMB \
+ TT_UCR_COMBINING_DIACRITICS_SYMB
+
+
+#endif /* !HAVE_LIMIT_ON_IDENTS */
+
+
+FT_END_HEADER
+
+#endif /* __TTNAMEID_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* tttables.h */
+/* */
+/* Basic SFNT/TrueType tables definitions and interface */
+/* (specification only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTTABLES_H__
+#define __TTTABLES_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+
+FT_BEGIN_HEADER
+
+ /*************************************************************************/
+ /* */
+ /* <Section> */
+ /* truetype_tables */
+ /* */
+ /* <Title> */
+ /* TrueType Tables */
+ /* */
+ /* <Abstract> */
+ /* TrueType-specific table types and functions. */
+ /* */
+ /* <Description> */
+ /* This section contains the definition of TrueType-specific tables */
+ /* as well as some routines used to access and process them. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_Header */
+ /* */
+ /* <Description> */
+ /* A structure used to model a TrueType font header table. All */
+ /* fields follow the TrueType specification. */
+ /* */
+ typedef struct TT_Header_
+ {
+ FT_Fixed Table_Version;
+ FT_Fixed Font_Revision;
+
+ FT_Long CheckSum_Adjust;
+ FT_Long Magic_Number;
+
+ FT_UShort Flags;
+ FT_UShort Units_Per_EM;
+
+ FT_Long Created [2];
+ FT_Long Modified[2];
+
+ FT_Short xMin;
+ FT_Short yMin;
+ FT_Short xMax;
+ FT_Short yMax;
+
+ FT_UShort Mac_Style;
+ FT_UShort Lowest_Rec_PPEM;
+
+ FT_Short Font_Direction;
+ FT_Short Index_To_Loc_Format;
+ FT_Short Glyph_Data_Format;
+
+ } TT_Header;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_HoriHeader */
+ /* */
+ /* <Description> */
+ /* A structure used to model a TrueType horizontal header, the `hhea' */
+ /* table, as well as the corresponding horizontal metrics table, */
+ /* i.e., the `hmtx' table. */
+ /* */
+ /* <Fields> */
+ /* Version :: The table version. */
+ /* */
+ /* Ascender :: The font's ascender, i.e., the distance */
+ /* from the baseline to the top-most of all */
+ /* glyph points found in the font. */
+ /* */
+ /* This value is invalid in many fonts, as */
+ /* it is usually set by the font designer, */
+ /* and often reflects only a portion of the */
+ /* glyphs found in the font (maybe ASCII). */
+ /* */
+ /* You should use the `sTypoAscender' field */
+ /* of the OS/2 table instead if you want */
+ /* the correct one. */
+ /* */
+ /* Descender :: The font's descender, i.e., the distance */
+ /* from the baseline to the bottom-most of */
+ /* all glyph points found in the font. It */
+ /* is negative. */
+ /* */
+ /* This value is invalid in many fonts, as */
+ /* it is usually set by the font designer, */
+ /* and often reflects only a portion of the */
+ /* glyphs found in the font (maybe ASCII). */
+ /* */
+ /* You should use the `sTypoDescender' */
+ /* field of the OS/2 table instead if you */
+ /* want the correct one. */
+ /* */
+ /* Line_Gap :: The font's line gap, i.e., the distance */
+ /* to add to the ascender and descender to */
+ /* get the BTB, i.e., the */
+ /* baseline-to-baseline distance for the */
+ /* font. */
+ /* */
+ /* advance_Width_Max :: This field is the maximum of all advance */
+ /* widths found in the font. It can be */
+ /* used to compute the maximum width of an */
+ /* arbitrary string of text. */
+ /* */
+ /* min_Left_Side_Bearing :: The minimum left side bearing of all */
+ /* glyphs within the font. */
+ /* */
+ /* min_Right_Side_Bearing :: The minimum right side bearing of all */
+ /* glyphs within the font. */
+ /* */
+ /* xMax_Extent :: The maximum horizontal extent (i.e., the */
+ /* `width' of a glyph's bounding box) for */
+ /* all glyphs in the font. */
+ /* */
+ /* caret_Slope_Rise :: The rise coefficient of the cursor's */
+ /* slope of the cursor (slope=rise/run). */
+ /* */
+ /* caret_Slope_Run :: The run coefficient of the cursor's */
+ /* slope. */
+ /* */
+ /* Reserved :: 10 reserved bytes. */
+ /* */
+ /* metric_Data_Format :: Always 0. */
+ /* */
+ /* number_Of_HMetrics :: Number of HMetrics entries in the `hmtx' */
+ /* table -- this value can be smaller than */
+ /* the total number of glyphs in the font. */
+ /* */
+ /* long_metrics :: A pointer into the `hmtx' table. */
+ /* */
+ /* short_metrics :: A pointer into the `hmtx' table. */
+ /* */
+ /* <Note> */
+ /* IMPORTANT: The TT_HoriHeader and TT_VertHeader structures should */
+ /* be identical except for the names of their fields which */
+ /* are different. */
+ /* */
+ /* This ensures that a single function in the `ttload' */
+ /* module is able to read both the horizontal and vertical */
+ /* headers. */
+ /* */
+ typedef struct TT_HoriHeader_
+ {
+ FT_Fixed Version;
+ FT_Short Ascender;
+ FT_Short Descender;
+ FT_Short Line_Gap;
+
+ FT_UShort advance_Width_Max; /* advance width maximum */
+
+ FT_Short min_Left_Side_Bearing; /* minimum left-sb */
+ FT_Short min_Right_Side_Bearing; /* minimum right-sb */
+ FT_Short xMax_Extent; /* xmax extents */
+ FT_Short caret_Slope_Rise;
+ FT_Short caret_Slope_Run;
+ FT_Short caret_Offset;
+
+ FT_Short Reserved[4];
+
+ FT_Short metric_Data_Format;
+ FT_UShort number_Of_HMetrics;
+
+ /* The following fields are not defined by the TrueType specification */
+ /* but they are used to connect the metrics header to the relevant */
+ /* `HMTX' table. */
+
+ void* long_metrics;
+ void* short_metrics;
+
+ } TT_HoriHeader;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_VertHeader */
+ /* */
+ /* <Description> */
+ /* A structure used to model a TrueType vertical header, the `vhea' */
+ /* table, as well as the corresponding vertical metrics table, i.e., */
+ /* the `vmtx' table. */
+ /* */
+ /* <Fields> */
+ /* Version :: The table version. */
+ /* */
+ /* Ascender :: The font's ascender, i.e., the distance */
+ /* from the baseline to the top-most of */
+ /* all glyph points found in the font. */
+ /* */
+ /* This value is invalid in many fonts, as */
+ /* it is usually set by the font designer, */
+ /* and often reflects only a portion of */
+ /* the glyphs found in the font (maybe */
+ /* ASCII). */
+ /* */
+ /* You should use the `sTypoAscender' */
+ /* field of the OS/2 table instead if you */
+ /* want the correct one. */
+ /* */
+ /* Descender :: The font's descender, i.e., the */
+ /* distance from the baseline to the */
+ /* bottom-most of all glyph points found */
+ /* in the font. It is negative. */
+ /* */
+ /* This value is invalid in many fonts, as */
+ /* it is usually set by the font designer, */
+ /* and often reflects only a portion of */
+ /* the glyphs found in the font (maybe */
+ /* ASCII). */
+ /* */
+ /* You should use the `sTypoDescender' */
+ /* field of the OS/2 table instead if you */
+ /* want the correct one. */
+ /* */
+ /* Line_Gap :: The font's line gap, i.e., the distance */
+ /* to add to the ascender and descender to */
+ /* get the BTB, i.e., the */
+ /* baseline-to-baseline distance for the */
+ /* font. */
+ /* */
+ /* advance_Height_Max :: This field is the maximum of all */
+ /* advance heights found in the font. It */
+ /* can be used to compute the maximum */
+ /* height of an arbitrary string of text. */
+ /* */
+ /* min_Top_Side_Bearing :: The minimum top side bearing of all */
+ /* glyphs within the font. */
+ /* */
+ /* min_Bottom_Side_Bearing :: The minimum bottom side bearing of all */
+ /* glyphs within the font. */
+ /* */
+ /* yMax_Extent :: The maximum vertical extent (i.e., the */
+ /* `height' of a glyph's bounding box) for */
+ /* all glyphs in the font. */
+ /* */
+ /* caret_Slope_Rise :: The rise coefficient of the cursor's */
+ /* slope of the cursor (slope=rise/run). */
+ /* */
+ /* caret_Slope_Run :: The run coefficient of the cursor's */
+ /* slope. */
+ /* */
+ /* caret_Offset :: The cursor's offset for slanted fonts. */
+ /* This value is `reserved' in vmtx */
+ /* version 1.0. */
+ /* */
+ /* Reserved :: 8 reserved bytes. */
+ /* */
+ /* metric_Data_Format :: Always 0. */
+ /* */
+ /* number_Of_HMetrics :: Number of VMetrics entries in the */
+ /* `vmtx' table -- this value can be */
+ /* smaller than the total number of glyphs */
+ /* in the font. */
+ /* */
+ /* long_metrics :: A pointer into the `vmtx' table. */
+ /* */
+ /* short_metrics :: A pointer into the `vmtx' table. */
+ /* */
+ /* <Note> */
+ /* IMPORTANT: The TT_HoriHeader and TT_VertHeader structures should */
+ /* be identical except for the names of their fields which */
+ /* are different. */
+ /* */
+ /* This ensures that a single function in the `ttload' */
+ /* module is able to read both the horizontal and vertical */
+ /* headers. */
+ /* */
+ typedef struct TT_VertHeader_
+ {
+ FT_Fixed Version;
+ FT_Short Ascender;
+ FT_Short Descender;
+ FT_Short Line_Gap;
+
+ FT_UShort advance_Height_Max; /* advance height maximum */
+
+ FT_Short min_Top_Side_Bearing; /* minimum left-sb or top-sb */
+ FT_Short min_Bottom_Side_Bearing; /* minimum right-sb or bottom-sb */
+ FT_Short yMax_Extent; /* xmax or ymax extents */
+ FT_Short caret_Slope_Rise;
+ FT_Short caret_Slope_Run;
+ FT_Short caret_Offset;
+
+ FT_Short Reserved[4];
+
+ FT_Short metric_Data_Format;
+ FT_UShort number_Of_VMetrics;
+
+ /* The following fields are not defined by the TrueType specification */
+ /* but they're used to connect the metrics header to the relevant */
+ /* `HMTX' or `VMTX' table. */
+
+ void* long_metrics;
+ void* short_metrics;
+
+ } TT_VertHeader;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_OS2 */
+ /* */
+ /* <Description> */
+ /* A structure used to model a TrueType OS/2 table. This is the long */
+ /* table version. All fields comply to the TrueType specification. */
+ /* */
+ /* Note that we now support old Mac fonts which do not include an */
+ /* OS/2 table. In this case, the `version' field is always set to */
+ /* 0xFFFF. */
+ /* */
+ typedef struct TT_OS2_
+ {
+ FT_UShort version; /* 0x0001 - more or 0xFFFF */
+ FT_Short xAvgCharWidth;
+ FT_UShort usWeightClass;
+ FT_UShort usWidthClass;
+ FT_Short fsType;
+ FT_Short ySubscriptXSize;
+ FT_Short ySubscriptYSize;
+ FT_Short ySubscriptXOffset;
+ FT_Short ySubscriptYOffset;
+ FT_Short ySuperscriptXSize;
+ FT_Short ySuperscriptYSize;
+ FT_Short ySuperscriptXOffset;
+ FT_Short ySuperscriptYOffset;
+ FT_Short yStrikeoutSize;
+ FT_Short yStrikeoutPosition;
+ FT_Short sFamilyClass;
+
+ FT_Byte panose[10];
+
+ FT_ULong ulUnicodeRange1; /* Bits 0-31 */
+ FT_ULong ulUnicodeRange2; /* Bits 32-63 */
+ FT_ULong ulUnicodeRange3; /* Bits 64-95 */
+ FT_ULong ulUnicodeRange4; /* Bits 96-127 */
+
+ FT_Char achVendID[4];
+
+ FT_UShort fsSelection;
+ FT_UShort usFirstCharIndex;
+ FT_UShort usLastCharIndex;
+ FT_Short sTypoAscender;
+ FT_Short sTypoDescender;
+ FT_Short sTypoLineGap;
+ FT_UShort usWinAscent;
+ FT_UShort usWinDescent;
+
+ /* only version 1 tables: */
+
+ FT_ULong ulCodePageRange1; /* Bits 0-31 */
+ FT_ULong ulCodePageRange2; /* Bits 32-63 */
+
+ /* only version 2 tables: */
+
+ FT_Short sxHeight;
+ FT_Short sCapHeight;
+ FT_UShort usDefaultChar;
+ FT_UShort usBreakChar;
+ FT_UShort usMaxContext;
+
+ } TT_OS2;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_Postscript */
+ /* */
+ /* <Description> */
+ /* A structure used to model a TrueType Postscript table. All fields */
+ /* comply to the TrueType table. This structure does not reference */
+ /* the Postscript glyph names, which can be nevertheless accessed */
+ /* with the `ttpost' module. */
+ /* */
+ typedef struct TT_Postscript_
+ {
+ FT_Fixed FormatType;
+ FT_Fixed italicAngle;
+ FT_Short underlinePosition;
+ FT_Short underlineThickness;
+ FT_ULong isFixedPitch;
+ FT_ULong minMemType42;
+ FT_ULong maxMemType42;
+ FT_ULong minMemType1;
+ FT_ULong maxMemType1;
+
+ /* Glyph names follow in the file, but we don't */
+ /* load them by default. See the ttpost.c file. */
+
+ } TT_Postscript;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_PCLT */
+ /* */
+ /* <Description> */
+ /* A structure used to model a TrueType PCLT table. All fields */
+ /* comply to the TrueType table. */
+ /* */
+ typedef struct TT_PCLT_
+ {
+ FT_Fixed Version;
+ FT_ULong FontNumber;
+ FT_UShort Pitch;
+ FT_UShort xHeight;
+ FT_UShort Style;
+ FT_UShort TypeFamily;
+ FT_UShort CapHeight;
+ FT_UShort SymbolSet;
+ FT_Char TypeFace[16];
+ FT_Char CharacterComplement[8];
+ FT_Char FileName[6];
+ FT_Char StrokeWeight;
+ FT_Char WidthType;
+ FT_Byte SerifStyle;
+ FT_Byte Reserved;
+
+ } TT_PCLT;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_MaxProfile */
+ /* */
+ /* <Description> */
+ /* The maximum profile is a table containing many max values which */
+ /* can be used to pre-allocate arrays. This ensures that no memory */
+ /* allocation occurs during a glyph load. */
+ /* */
+ /* <Fields> */
+ /* version :: The version number. */
+ /* */
+ /* numGlyphs :: The number of glyphs in this TrueType */
+ /* font. */
+ /* */
+ /* maxPoints :: The maximum number of points in a */
+ /* non-composite TrueType glyph. See also */
+ /* the structure element */
+ /* `maxCompositePoints'. */
+ /* */
+ /* maxContours :: The maximum number of contours in a */
+ /* non-composite TrueType glyph. See also */
+ /* the structure element */
+ /* `maxCompositeContours'. */
+ /* */
+ /* maxCompositePoints :: The maximum number of points in a */
+ /* composite TrueType glyph. See also the */
+ /* structure element `maxPoints'. */
+ /* */
+ /* maxCompositeContours :: The maximum number of contours in a */
+ /* composite TrueType glyph. See also the */
+ /* structure element `maxContours'. */
+ /* */
+ /* maxZones :: The maximum number of zones used for */
+ /* glyph hinting. */
+ /* */
+ /* maxTwilightPoints :: The maximum number of points in the */
+ /* twilight zone used for glyph hinting. */
+ /* */
+ /* maxStorage :: The maximum number of elements in the */
+ /* storage area used for glyph hinting. */
+ /* */
+ /* maxFunctionDefs :: The maximum number of function */
+ /* definitions in the TrueType bytecode for */
+ /* this font. */
+ /* */
+ /* maxInstructionDefs :: The maximum number of instruction */
+ /* definitions in the TrueType bytecode for */
+ /* this font. */
+ /* */
+ /* maxStackElements :: The maximum number of stack elements used */
+ /* during bytecode interpretation. */
+ /* */
+ /* maxSizeOfInstructions :: The maximum number of TrueType opcodes */
+ /* used for glyph hinting. */
+ /* */
+ /* maxComponentElements :: An obscure value related to composite */
+ /* glyphs definitions. */
+ /* */
+ /* maxComponentDepth :: An obscure value related to composite */
+ /* glyphs definitions. Probably the maximum */
+ /* number of simple glyphs in a composite. */
+ /* */
+ /* <Note> */
+ /* This structure is only used during font loading. */
+ /* */
+ typedef struct TT_MaxProfile_
+ {
+ FT_Fixed version;
+ FT_UShort numGlyphs;
+ FT_UShort maxPoints;
+ FT_UShort maxContours;
+ FT_UShort maxCompositePoints;
+ FT_UShort maxCompositeContours;
+ FT_UShort maxZones;
+ FT_UShort maxTwilightPoints;
+ FT_UShort maxStorage;
+ FT_UShort maxFunctionDefs;
+ FT_UShort maxInstructionDefs;
+ FT_UShort maxStackElements;
+ FT_UShort maxSizeOfInstructions;
+ FT_UShort maxComponentElements;
+ FT_UShort maxComponentDepth;
+
+ } TT_MaxProfile;
+
+
+ /* */
+
+ typedef enum
+ {
+ ft_sfnt_head = 0,
+ ft_sfnt_maxp = 1,
+ ft_sfnt_os2 = 2,
+ ft_sfnt_hhea = 3,
+ ft_sfnt_vhea = 4,
+ ft_sfnt_post = 5,
+ ft_sfnt_pclt = 6,
+
+ sfnt_max /* don't remove */
+
+ } FT_Sfnt_Tag;
+
+
+ /* internal use only */
+ typedef void*
+ (*FT_Get_Sfnt_Table_Func)( FT_Face face,
+ FT_Sfnt_Tag tag );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* FT_Get_Sfnt_Table */
+ /* */
+ /* <Description> */
+ /* Returns a pointer to a given SFNT table within a face. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source. */
+ /* */
+ /* tag :: The index of the SFNT table. */
+ /* */
+ /* <Return> */
+ /* A type-less pointer to the table. This will be 0 in case of */
+ /* error, or if the corresponding table was not found *OR* loaded */
+ /* from the file. */
+ /* */
+ /* <Note> */
+ /* The table is owned by the face object and disappears with it. */
+ /* */
+ /* This function is only useful to access SFNT tables that are loaded */
+ /* by the sfnt/truetype/opentype drivers. See FT_Sfnt_Tag for a */
+ /* list. */
+ /* */
+ FT_EXPORT( void* )
+ FT_Get_Sfnt_Table( FT_Face face,
+ FT_Sfnt_Tag tag );
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __TTTABLES_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* tttags.h */
+/* */
+/* Tags for TrueType tables (specification only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTAGS_H__
+#define __TTAGS_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+
+FT_BEGIN_HEADER
+
+
+#define TTAG_cmap FT_MAKE_TAG( 'c', 'm', 'a', 'p' )
+#define TTAG_cvt FT_MAKE_TAG( 'c', 'v', 't', ' ' )
+#define TTAG_CFF FT_MAKE_TAG( 'C', 'F', 'F', ' ' )
+#define TTAG_DSIG FT_MAKE_TAG( 'D', 'S', 'I', 'G' )
+#define TTAG_bhed FT_MAKE_TAG( 'b', 'h', 'e', 'd' )
+#define TTAG_bdat FT_MAKE_TAG( 'b', 'd', 'a', 't' )
+#define TTAG_bloc FT_MAKE_TAG( 'b', 'l', 'o', 'c' )
+#define TTAG_EBDT FT_MAKE_TAG( 'E', 'B', 'D', 'T' )
+#define TTAG_EBLC FT_MAKE_TAG( 'E', 'B', 'L', 'C' )
+#define TTAG_EBSC FT_MAKE_TAG( 'E', 'B', 'S', 'C' )
+#define TTAG_fpgm FT_MAKE_TAG( 'f', 'p', 'g', 'm' )
+#define TTAG_fvar FT_MAKE_TAG( 'f', 'v', 'a', 'r' )
+#define TTAG_gasp FT_MAKE_TAG( 'g', 'a', 's', 'p' )
+#define TTAG_glyf FT_MAKE_TAG( 'g', 'l', 'y', 'f' )
+#define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' )
+#define TTAG_hdmx FT_MAKE_TAG( 'h', 'd', 'm', 'x' )
+#define TTAG_head FT_MAKE_TAG( 'h', 'e', 'a', 'd' )
+#define TTAG_hhea FT_MAKE_TAG( 'h', 'h', 'e', 'a' )
+#define TTAG_hmtx FT_MAKE_TAG( 'h', 'm', 't', 'x' )
+#define TTAG_kern FT_MAKE_TAG( 'k', 'e', 'r', 'n' )
+#define TTAG_loca FT_MAKE_TAG( 'l', 'o', 'c', 'a' )
+#define TTAG_LTSH FT_MAKE_TAG( 'L', 'T', 'S', 'H' )
+#define TTAG_maxp FT_MAKE_TAG( 'm', 'a', 'x', 'p' )
+#define TTAG_MMSD FT_MAKE_TAG( 'M', 'M', 'S', 'D' )
+#define TTAG_MMFX FT_MAKE_TAG( 'M', 'M', 'F', 'X' )
+#define TTAG_name FT_MAKE_TAG( 'n', 'a', 'm', 'e' )
+#define TTAG_OS2 FT_MAKE_TAG( 'O', 'S', '/', '2' )
+#define TTAG_OTTO FT_MAKE_TAG( 'O', 'T', 'T', 'O' )
+#define TTAG_PCLT FT_MAKE_TAG( 'P', 'C', 'L', 'T' )
+#define TTAG_post FT_MAKE_TAG( 'p', 'o', 's', 't' )
+#define TTAG_prep FT_MAKE_TAG( 'p', 'r', 'e', 'p' )
+#define TTAG_true FT_MAKE_TAG( 't', 'r', 'u', 'e' )
+#define TTAG_ttc FT_MAKE_TAG( 't', 't', 'c', ' ' )
+#define TTAG_ttcf FT_MAKE_TAG( 't', 't', 'c', 'f' )
+#define TTAG_VDMX FT_MAKE_TAG( 'V', 'D', 'M', 'X' )
+#define TTAG_vhea FT_MAKE_TAG( 'v', 'h', 'e', 'a' )
+#define TTAG_vmtx FT_MAKE_TAG( 'v', 'm', 't', 'x' )
+
+
+FT_END_HEADER
+
+#endif /* __TTAGS_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ft2build.h */
+/* */
+/* FreeType 2 build and setup macros. */
+/* (Generic version) */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file corresponds to the default "ft2build.h" file for */
+ /* FreeType 2. It uses the "freetype" include root. */
+ /* */
+ /* Note that specific platforms might use a different configuration. */
+ /* See builds/unix/ft2unix.h for an example. */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef __FT2_BUILD_GENERIC_H__
+#define __FT2_BUILD_GENERIC_H__
+
+#include <freetype/config/ftheader.h>
+
+#endif /* __FT2_BUILD_GENERIC_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftcerror.h */
+/* */
+/* Caching sub-system error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the caching sub-system error enumeration */
+ /* constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __FTCERROR_H__
+#define __FTCERROR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX FTC_Err_
+#define FT_ERR_BASE FT_Mod_Err_Cache
+
+#include FT_ERRORS_H
+
+#endif /* __FTCERROR_H__ */
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftgrays.h */
+/* */
+/* FreeType smooth renderer declaration */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTGRAYS_H__
+#define __FTGRAYS_H__
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+
+#ifdef _STANDALONE_
+#include "ftimage.h"
+#else
+#include <ft2build.h>
+#include FT_IMAGE_H
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* To make ftgrays.h independent from configuration files we check */
+ /* whether FT_EXPORT_VAR has been defined already. */
+ /* */
+ /* On some systems and compilers (Win32 mostly), an extra keyword is */
+ /* necessary to compile the library as a DLL. */
+ /* */
+#ifndef FT_EXPORT_VAR
+#define FT_EXPORT_VAR( x ) extern x
+#endif
+
+ FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_grays_raster;
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* __FTGRAYS_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftraster.h */
+/* */
+/* The FreeType glyph rasterizer (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used */
+/* modified and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTRASTER_H__
+#define __FTRASTER_H__
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include FT_IMAGE_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* Uncomment the following line if you are using ftraster.c as a */
+ /* standalone module, fully independent of FreeType. */
+ /* */
+/* #define _STANDALONE_ */
+
+ FT_EXPORT_VAR( const FT_Raster_Funcs ) ft_standard_raster;
+
+
+FT_END_HEADER
+
+#endif /* __FTRASTER_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftrend1.h */
+/* */
+/* The FreeType glyph rasterizer interface (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTREND1_H__
+#define __FTREND1_H__
+
+
+#include <ft2build.h>
+#include FT_RENDER_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_EXPORT_VAR( const FT_Renderer_Class ) ft_raster1_renderer_class;
+
+ /* this renderer is _NOT_ part of the default modules, you'll need */
+ /* to register it by hand in your application. It should only be */
+ /* used for backwards-compatibility with FT 1.x anyway. */
+ /* */
+ FT_EXPORT_VAR( const FT_Renderer_Class ) ft_raster5_renderer_class;
+
+
+FT_END_HEADER
+
+#endif /* __FTREND1_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftsmerrs.h */
+/* */
+/* smooth renderer error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the smooth renderer error enumeration */
+ /* constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __FTSMERRS_H__
+#define __FTSMERRS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX Smooth_Err_
+#define FT_ERR_BASE FT_Mod_Err_Smooth
+
+#include FT_ERRORS_H
+
+#endif /* __FTSMERRS_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ftsmooth.h */
+/* */
+/* Anti-aliasing renderer interface (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTSMOOTH_H__
+#define __FTSMOOTH_H__
+
+
+#include <ft2build.h>
+#include FT_RENDER_H
+
+
+FT_BEGIN_HEADER
+
+
+#ifndef FT_CONFIG_OPTION_NO_STD_RASTER
+ FT_EXPORT_VAR( const FT_Renderer_Class ) ft_std_renderer_class;
+#endif
+
+#ifndef FT_CONFIG_OPTION_NO_SMOOTH_RASTER
+ FT_EXPORT_VAR( const FT_Renderer_Class ) ft_smooth_renderer_class;
+#endif
+
+
+FT_END_HEADER
+
+#endif /* __FTSMOOTH_H__ */
+
+
+/* END */
--- /dev/null
+/* pcf.h
+
+ FreeType font driver for pcf fonts
+
+ Copyright (C) 2000-2001 by
+ Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#ifndef __PCF_H__
+#define __PCF_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+
+FT_BEGIN_HEADER
+
+ typedef struct PCF_TableRec_
+ {
+ FT_ULong type;
+ FT_ULong format;
+ FT_ULong size;
+ FT_ULong offset;
+
+ } PCF_TableRec, *PCF_Table;
+
+
+ typedef struct PCF_TocRec_
+ {
+ FT_ULong version;
+ FT_ULong count;
+ PCF_Table tables;
+
+ } PCF_TocRec, *PCF_Toc;
+
+
+ typedef struct PCF_ParseProperty_
+ {
+ FT_Long name;
+ FT_Byte isString;
+ FT_Long value;
+
+ } PCF_ParsePropertyRec, *PCF_ParseProperty;
+
+
+ typedef struct PCF_Property_
+ {
+ FT_String* name;
+ FT_Byte isString;
+
+ union
+ {
+ FT_String* atom;
+ FT_Long integer;
+ FT_ULong cardinal;
+
+ } value;
+
+ } PCF_PropertyRec, *PCF_Property;
+
+
+ typedef struct PCF_Compressed_Metric_
+ {
+ FT_Byte leftSideBearing;
+ FT_Byte rightSideBearing;
+ FT_Byte characterWidth;
+ FT_Byte ascent;
+ FT_Byte descent;
+
+ } PCF_Compressed_MetricRec, *PCF_Compressed_Metric;
+
+
+ typedef struct PCF_Metric_
+ {
+ FT_Short leftSideBearing;
+ FT_Short rightSideBearing;
+ FT_Short characterWidth;
+ FT_Short ascent;
+ FT_Short descent;
+ FT_Short attributes;
+ FT_ULong bits;
+
+ } PCF_MetricRec, *PCF_Metric;
+
+
+ typedef struct PCF_AccelRec_
+ {
+ FT_Byte noOverlap;
+ FT_Byte constantMetrics;
+ FT_Byte terminalFont;
+ FT_Byte constantWidth;
+ FT_Byte inkInside;
+ FT_Byte inkMetrics;
+ FT_Byte drawDirection;
+ FT_Long fontAscent;
+ FT_Long fontDescent;
+ FT_Long maxOverlap;
+ PCF_MetricRec minbounds;
+ PCF_MetricRec maxbounds;
+ PCF_MetricRec ink_minbounds;
+ PCF_MetricRec ink_maxbounds;
+
+ } PCF_AccelRec, *PCF_Accel;
+
+
+ typedef struct PCD_Encoding_
+ {
+ FT_Long enc;
+ FT_Short glyph;
+
+ } PCF_EncodingRec, *PCF_Encoding;
+
+
+ typedef struct PCF_FaceRec_
+ {
+ FT_FaceRec root;
+
+ char* charset_encoding;
+ char* charset_registry;
+
+ PCF_TocRec toc;
+ PCF_AccelRec accel;
+
+ int nprops;
+ PCF_Property properties;
+
+ FT_Long nmetrics;
+ PCF_Metric metrics;
+ FT_Long nencodings;
+ PCF_Encoding encodings;
+
+ FT_Short defaultChar;
+
+ FT_ULong bitmapsFormat;
+
+ FT_CharMap charmap_handle;
+ FT_CharMapRec charmap; /* a single charmap per face */
+
+ } PCF_FaceRec, *PCF_Face;
+
+
+ /* XXX hack */
+ FT_LOCAL FT_Error
+ PCF_Done_Face( PCF_Face face );
+
+
+ /* macros for pcf font format */
+
+#define LSBFirst 0
+#define MSBFirst 1
+
+#define PCF_FILE_VERSION ( ( 'p' << 24 ) | \
+ ( 'c' << 16 ) | \
+ ( 'f' << 8 ) | 1 )
+#define PCF_FORMAT_MASK 0xFFFFFF00L
+
+#define PCF_DEFAULT_FORMAT 0x00000000L
+#define PCF_INKBOUNDS 0x00000200L
+#define PCF_ACCEL_W_INKBOUNDS 0x00000100L
+#define PCF_COMPRESSED_METRICS 0x00000100L
+
+#define PCF_FORMAT_MATCH( a, b ) \
+ ( ( (a) & PCF_FORMAT_MASK ) == ( (b) & PCF_FORMAT_MASK ) )
+
+#define PCF_GLYPH_PAD_MASK ( 3 << 0 )
+#define PCF_BYTE_MASK ( 1 << 2 )
+#define PCF_BIT_MASK ( 1 << 3 )
+#define PCF_SCAN_UNIT_MASK ( 3 << 4 )
+
+#define PCF_BYTE_ORDER( f ) \
+ ( ( (f) & PCF_BYTE_MASK ) ? MSBFirst : LSBFirst )
+#define PCF_BIT_ORDER( f ) \
+ ( ( (f) & PCF_BIT_MASK ) ? MSBFirst : LSBFirst )
+#define PCF_GLYPH_PAD_INDEX( f ) \
+ ( (f) & PCF_GLYPH_PAD_MASK )
+#define PCF_GLYPH_PAD( f ) \
+ ( 1 << PCF_GLYPH_PAD_INDEX( f ) )
+#define PCF_SCAN_UNIT_INDEX( f ) \
+ ( ( (f) & PCF_SCAN_UNIT_MASK ) >> 4 )
+#define PCF_SCAN_UNIT( f ) \
+ ( 1 << PCF_SCAN_UNIT_INDEX( f ) )
+#define PCF_FORMAT_BITS( f ) \
+ ( (f) & ( PCF_GLYPH_PAD_MASK | \
+ PCF_BYTE_MASK | \
+ PCF_BIT_MASK | \
+ PCF_SCAN_UNIT_MASK ) )
+
+#define PCF_SIZE_TO_INDEX( s ) ( (s) == 4 ? 2 : (s) == 2 ? 1 : 0 )
+#define PCF_INDEX_TO_SIZE( b ) ( 1 << b )
+
+#define PCF_FORMAT( bit, byte, glyph, scan ) \
+ ( ( PCF_SIZE_TO_INDEX( scan ) << 4 ) | \
+ ( ( (bit) == MSBFirst ? 1 : 0 ) << 3 ) | \
+ ( ( (byte) == MSBFirst ? 1 : 0 ) << 2 ) | \
+ ( PCF_SIZE_TO_INDEX( glyph ) << 0 ) )
+
+#define PCF_PROPERTIES ( 1 << 0 )
+#define PCF_ACCELERATORS ( 1 << 1 )
+#define PCF_METRICS ( 1 << 2 )
+#define PCF_BITMAPS ( 1 << 3 )
+#define PCF_INK_METRICS ( 1 << 4 )
+#define PCF_BDF_ENCODINGS ( 1 << 5 )
+#define PCF_SWIDTHS ( 1 << 6 )
+#define PCF_GLYPH_NAMES ( 1 << 7 )
+#define PCF_BDF_ACCELERATORS ( 1 << 8 )
+
+#define GLYPHPADOPTIONS 4 /* I'm not sure about this */
+
+ FT_LOCAL FT_Error
+ pcf_load_font( FT_Stream,
+ PCF_Face );
+
+
+FT_END_HEADER
+
+#endif /* __PCF_H__ */
+
+
+/* END */
--- /dev/null
+/* pcfdriver.h
+
+ FreeType font driver for pcf fonts
+
+ Copyright 2000-2001 by
+ Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#ifndef __PCFDRIVER_H__
+#define __PCFDRIVER_H__
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+FT_BEGIN_HEADER
+
+ FT_EXPORT_VAR( const FT_Driver_Class ) pcf_driver_class;
+
+FT_END_HEADER
+
+
+#endif /* __PCFDRIVER_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* pcferror.h */
+/* */
+/* PCF error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the PCF error enumeration constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __PCFERROR_H__
+#define __PCFERROR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX PCF_Err_
+#define FT_ERR_BASE FT_Mod_Err_PCF
+
+#include FT_ERRORS_H
+
+#endif /* __PCFERROR_H__ */
+
+
+/* END */
--- /dev/null
+/* pcfutil.h
+
+ FreeType font driver for pcf fonts
+
+ Copyright 2000-2001 by
+ Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#ifndef __PCFUTIL_H__
+#define __PCFUTIL_H__
+
+
+#include <ft2build.h>
+
+
+ void
+ BitOrderInvert( unsigned char* buf,
+ int nbytes);
+
+ void
+ TwoByteSwap( unsigned char* buf,
+ int nbytes);
+
+ void
+ FourByteSwap( unsigned char* buf,
+ int nbytes);
+
+ int
+ RepadBitmap( char* pSrc,
+ char* pDst,
+ unsigned int srcPad,
+ unsigned int dstPad,
+ int width,
+ int height);
+
+#endif /* __PCFUTIL_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* psauxerr.h */
+/* */
+/* PS auxiliary module error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the PS auxiliary module error enumeration */
+ /* constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __PSAUXERR_H__
+#define __PSAUXERR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX PSaux_Err_
+#define FT_ERR_BASE FT_Mod_Err_PSaux
+
+#include FT_ERRORS_H
+
+#endif /* __PSAUXERR_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* psauxmod.h */
+/* */
+/* FreeType auxiliary PostScript module implementation (specification). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __PSAUXMOD_H__
+#define __PSAUXMOD_H__
+
+
+#include <ft2build.h>
+#include FT_MODULE_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_EXPORT_VAR( const FT_Module_Class ) psaux_driver_class;
+
+
+FT_END_HEADER
+
+#endif /* __PSAUXMOD_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* psmodule.h */
+/* */
+/* High-level PSNames module interface (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __PSMODULE_H__
+#define __PSMODULE_H__
+
+
+#include <ft2build.h>
+#include FT_MODULE_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_EXPORT_VAR( const FT_Module_Class ) psnames_module_class;
+
+
+FT_END_HEADER
+
+#endif /* __PSMODULE_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* psnamerr.h */
+/* */
+/* PS names module error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the PS names module error enumeration */
+ /* constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __PSNAMERR_H__
+#define __PSNAMERR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX PSnames_Err_
+#define FT_ERR_BASE FT_Mod_Err_PSnames
+
+#include FT_ERRORS_H
+
+#endif /* __PSNAMERR_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* psobjs.h */
+/* */
+/* Auxiliary functions for PostScript fonts (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __PSOBJS_H__
+#define __PSOBJS_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** T1_TABLE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_CALLBACK_TABLE
+ const PS_Table_Funcs ps_table_funcs;
+
+ FT_CALLBACK_TABLE
+ const T1_Parser_Funcs t1_parser_funcs;
+
+ FT_CALLBACK_TABLE
+ const T1_Builder_Funcs t1_builder_funcs;
+
+
+ FT_LOCAL FT_Error
+ PS_Table_New( PS_Table* table,
+ FT_Int count,
+ FT_Memory memory );
+
+ FT_LOCAL FT_Error
+ PS_Table_Add( PS_Table* table,
+ FT_Int index,
+ void* object,
+ FT_Int length );
+
+ FT_LOCAL void
+ PS_Table_Done( PS_Table* table );
+
+
+ FT_LOCAL void
+ PS_Table_Release( PS_Table* table );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** T1 PARSER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_LOCAL void
+ T1_Skip_Spaces( T1_Parser* parser );
+
+ FT_LOCAL void
+ T1_Skip_Alpha( T1_Parser* parser );
+
+ FT_LOCAL void
+ T1_ToToken( T1_Parser* parser,
+ T1_Token* token );
+
+ FT_LOCAL void
+ T1_ToTokenArray( T1_Parser* parser,
+ T1_Token* tokens,
+ FT_UInt max_tokens,
+ FT_Int* pnum_tokens );
+
+ FT_LOCAL FT_Error
+ T1_Load_Field( T1_Parser* parser,
+ const T1_Field* field,
+ void** objects,
+ FT_UInt max_objects,
+ FT_ULong* pflags );
+
+ FT_LOCAL FT_Error
+ T1_Load_Field_Table( T1_Parser* parser,
+ const T1_Field* field,
+ void** objects,
+ FT_UInt max_objects,
+ FT_ULong* pflags );
+
+ FT_LOCAL FT_Long
+ T1_ToInt( T1_Parser* parser );
+
+
+ FT_LOCAL FT_Fixed
+ T1_ToFixed( T1_Parser* parser,
+ FT_Int power_ten );
+
+
+ FT_LOCAL FT_Int
+ T1_ToCoordArray( T1_Parser* parser,
+ FT_Int max_coords,
+ FT_Short* coords );
+
+ FT_LOCAL FT_Int
+ T1_ToFixedArray( T1_Parser* parser,
+ FT_Int max_values,
+ FT_Fixed* values,
+ FT_Int power_ten );
+
+
+ FT_LOCAL void
+ T1_Init_Parser( T1_Parser* parser,
+ FT_Byte* base,
+ FT_Byte* limit,
+ FT_Memory memory );
+
+ FT_LOCAL void
+ T1_Done_Parser( T1_Parser* parser );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** T1 BUILDER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_LOCAL void
+ T1_Builder_Init( T1_Builder* builder,
+ FT_Face face,
+ FT_Size size,
+ FT_GlyphSlot glyph );
+
+ FT_LOCAL void
+ T1_Builder_Done( T1_Builder* builder );
+
+ FT_LOCAL FT_Error
+ T1_Builder_Check_Points( T1_Builder* builder,
+ FT_Int count );
+
+ FT_LOCAL void
+ T1_Builder_Add_Point( T1_Builder* builder,
+ FT_Pos x,
+ FT_Pos y,
+ FT_Byte flag );
+
+ FT_LOCAL FT_Error
+ T1_Builder_Add_Point1( T1_Builder* builder,
+ FT_Pos x,
+ FT_Pos y );
+
+ FT_LOCAL FT_Error
+ T1_Builder_Add_Contour( T1_Builder* builder );
+
+
+ FT_LOCAL FT_Error
+ T1_Builder_Start_Point( T1_Builder* builder,
+ FT_Pos x,
+ FT_Pos y );
+
+
+ FT_LOCAL void
+ T1_Builder_Close_Contour( T1_Builder* builder );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** OTHER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_LOCAL void
+ T1_Decrypt( FT_Byte* buffer,
+ FT_Offset length,
+ FT_UShort seed );
+
+
+FT_END_HEADER
+
+#endif /* __PSOBJS_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* c:\david\source\freetype\freetype2\src\psnames\pstables.h */
+/* */
+/* PostScript glyph names (specification only). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /* this file has been generated automatically -- do not edit! */
+
+
+ static const char* const ps_glyph_names[] =
+ {
+ ".notdef",
+ ".null",
+ "nonmarkingreturn",
+ "nonbreakingspace",
+ "apple",
+ ".notdef",
+ "space",
+ "exclam",
+ "quotedbl",
+ "numbersign",
+ "dollar",
+ "percent",
+ "ampersand",
+ "quoteright",
+ "parenleft",
+ "parenright",
+ "asterisk",
+ "plus",
+ "comma",
+ "hyphen",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "at",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "bracketleft",
+ "backslash",
+ "bracketright",
+ "asciicircum",
+ "underscore",
+ "quoteleft",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "braceleft",
+ "bar",
+ "braceright",
+ "asciitilde",
+ "exclamdown",
+ "cent",
+ "sterling",
+ "fraction",
+ "yen",
+ "florin",
+ "section",
+ "currency",
+ "quotesingle",
+ "quotedblleft",
+ "guillemotleft",
+ "guilsinglleft",
+ "guilsinglright",
+ "fi",
+ "fl",
+ "endash",
+ "dagger",
+ "daggerdbl",
+ "periodcentered",
+ "paragraph",
+ "bullet",
+ "quotesinglbase",
+ "quotedblbase",
+ "quotedblright",
+ "guillemotright",
+ "ellipsis",
+ "perthousand",
+ "questiondown",
+ "grave",
+ "acute",
+ "circumflex",
+ "tilde",
+ "macron",
+ "breve",
+ "dotaccent",
+ "dieresis",
+ "ring",
+ "cedilla",
+ "hungarumlaut",
+ "ogonek",
+ "caron",
+ "emdash",
+ "AE",
+ "ordfeminine",
+ "Lslash",
+ "Oslash",
+ "OE",
+ "ordmasculine",
+ "ae",
+ "dotlessi",
+ "lslash",
+ "oslash",
+ "oe",
+ "germandbls",
+ "onesuperior",
+ "logicalnot",
+ "mu",
+ "trademark",
+ "Eth",
+ "onehalf",
+ "plusminus",
+ "Thorn",
+ "onequarter",
+ "divide",
+ "brokenbar",
+ "degree",
+ "thorn",
+ "threequarters",
+ "twosuperior",
+ "registered",
+ "minus",
+ "eth",
+ "multiply",
+ "threesuperior",
+ "copyright",
+ "Aacute",
+ "Acircumflex",
+ "Adieresis",
+ "Agrave",
+ "Aring",
+ "Atilde",
+ "Ccedilla",
+ "Eacute",
+ "Ecircumflex",
+ "Edieresis",
+ "Egrave",
+ "Iacute",
+ "Icircumflex",
+ "Idieresis",
+ "Igrave",
+ "Ntilde",
+ "Oacute",
+ "Ocircumflex",
+ "Odieresis",
+ "Ograve",
+ "Otilde",
+ "Scaron",
+ "Uacute",
+ "Ucircumflex",
+ "Udieresis",
+ "Ugrave",
+ "Yacute",
+ "Ydieresis",
+ "Zcaron",
+ "aacute",
+ "acircumflex",
+ "adieresis",
+ "agrave",
+ "aring",
+ "atilde",
+ "ccedilla",
+ "eacute",
+ "ecircumflex",
+ "edieresis",
+ "egrave",
+ "iacute",
+ "icircumflex",
+ "idieresis",
+ "igrave",
+ "ntilde",
+ "oacute",
+ "ocircumflex",
+ "odieresis",
+ "ograve",
+ "otilde",
+ "scaron",
+ "uacute",
+ "ucircumflex",
+ "udieresis",
+ "ugrave",
+ "yacute",
+ "ydieresis",
+ "zcaron",
+ "exclamsmall",
+ "Hungarumlautsmall",
+ "dollaroldstyle",
+ "dollarsuperior",
+ "ampersandsmall",
+ "Acutesmall",
+ "parenleftsuperior",
+ "parenrightsuperior",
+ "twodotenleader",
+ "onedotenleader",
+ "zerooldstyle",
+ "oneoldstyle",
+ "twooldstyle",
+ "threeoldstyle",
+ "fouroldstyle",
+ "fiveoldstyle",
+ "sixoldstyle",
+ "sevenoldstyle",
+ "eightoldstyle",
+ "nineoldstyle",
+ "commasuperior",
+ "threequartersemdash",
+ "periodsuperior",
+ "questionsmall",
+ "asuperior",
+ "bsuperior",
+ "centsuperior",
+ "dsuperior",
+ "esuperior",
+ "isuperior",
+ "lsuperior",
+ "msuperior",
+ "nsuperior",
+ "osuperior",
+ "rsuperior",
+ "ssuperior",
+ "tsuperior",
+ "ff",
+ "ffi",
+ "ffl",
+ "parenleftinferior",
+ "parenrightinferior",
+ "Circumflexsmall",
+ "hyphensuperior",
+ "Gravesmall",
+ "Asmall",
+ "Bsmall",
+ "Csmall",
+ "Dsmall",
+ "Esmall",
+ "Fsmall",
+ "Gsmall",
+ "Hsmall",
+ "Ismall",
+ "Jsmall",
+ "Ksmall",
+ "Lsmall",
+ "Msmall",
+ "Nsmall",
+ "Osmall",
+ "Psmall",
+ "Qsmall",
+ "Rsmall",
+ "Ssmall",
+ "Tsmall",
+ "Usmall",
+ "Vsmall",
+ "Wsmall",
+ "Xsmall",
+ "Ysmall",
+ "Zsmall",
+ "colonmonetary",
+ "onefitted",
+ "rupiah",
+ "Tildesmall",
+ "exclamdownsmall",
+ "centoldstyle",
+ "Lslashsmall",
+ "Scaronsmall",
+ "Zcaronsmall",
+ "Dieresissmall",
+ "Brevesmall",
+ "Caronsmall",
+ "Dotaccentsmall",
+ "Macronsmall",
+ "figuredash",
+ "hypheninferior",
+ "Ogoneksmall",
+ "Ringsmall",
+ "Cedillasmall",
+ "questiondownsmall",
+ "oneeighth",
+ "threeeighths",
+ "fiveeighths",
+ "seveneighths",
+ "onethird",
+ "twothirds",
+ "zerosuperior",
+ "foursuperior",
+ "fivesuperior",
+ "sixsuperior",
+ "sevensuperior",
+ "eightsuperior",
+ "ninesuperior",
+ "zeroinferior",
+ "oneinferior",
+ "twoinferior",
+ "threeinferior",
+ "fourinferior",
+ "fiveinferior",
+ "sixinferior",
+ "seveninferior",
+ "eightinferior",
+ "nineinferior",
+ "centinferior",
+ "dollarinferior",
+ "periodinferior",
+ "commainferior",
+ "Agravesmall",
+ "Aacutesmall",
+ "Acircumflexsmall",
+ "Atildesmall",
+ "Adieresissmall",
+ "Aringsmall",
+ "AEsmall",
+ "Ccedillasmall",
+ "Egravesmall",
+ "Eacutesmall",
+ "Ecircumflexsmall",
+ "Edieresissmall",
+ "Igravesmall",
+ "Iacutesmall",
+ "Icircumflexsmall",
+ "Idieresissmall",
+ "Ethsmall",
+ "Ntildesmall",
+ "Ogravesmall",
+ "Oacutesmall",
+ "Ocircumflexsmall",
+ "Otildesmall",
+ "Odieresissmall",
+ "OEsmall",
+ "Oslashsmall",
+ "Ugravesmall",
+ "Uacutesmall",
+ "Ucircumflexsmall",
+ "Udieresissmall",
+ "Yacutesmall",
+ "Thornsmall",
+ "Ydieresissmall",
+ "001.000",
+ "001.001",
+ "001.002",
+ "001.003",
+ "Black",
+ "Bold",
+ "Book",
+ "Light",
+ "Medium",
+ "Regular",
+ "Roman",
+ "Semibold",
+
+#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
+
+ "AEacute",
+ "Abreve",
+ "Acute",
+ "Alpha",
+ "Alphatonos",
+ "Amacron",
+ "Aogonek",
+ "Aringacute",
+ "Beta",
+ "Cacute",
+ "Caron",
+ "Ccaron",
+ "Ccircumflex",
+ "Cdotaccent",
+ "Chi",
+ "Dcaron",
+ "Dcroat",
+ "Delta",
+ "Delta",
+ "Dieresis",
+ "DieresisAcute",
+ "DieresisGrave",
+ "Ebreve",
+ "Ecaron",
+ "Edotaccent",
+ "Emacron",
+ "Eng",
+ "Eogonek",
+ "Epsilon",
+ "Epsilontonos",
+ "Eta",
+ "Etatonos",
+ "Euro",
+ "Gamma",
+ "Gbreve",
+ "Gcaron",
+ "Gcircumflex",
+ "Gcommaaccent",
+ "Gdotaccent",
+ "Grave",
+ "H18533",
+ "H18543",
+ "H18551",
+ "H22073",
+ "Hbar",
+ "Hcircumflex",
+ "Hungarumlaut",
+ "IJ",
+ "Ibreve",
+ "Idotaccent",
+ "Ifraktur",
+ "Imacron",
+ "Iogonek",
+ "Iota",
+ "Iotadieresis",
+ "Iotatonos",
+ "Itilde",
+ "Jcircumflex",
+ "Kappa",
+ "Kcommaaccent",
+ "LL",
+ "Lacute",
+ "Lambda",
+ "Lcaron",
+ "Lcommaaccent",
+ "Ldot",
+ "Macron",
+ "Mu",
+ "Nacute",
+ "Ncaron",
+ "Ncommaaccent",
+ "Nu",
+ "Obreve",
+ "Ohorn",
+ "Ohungarumlaut",
+ "Omacron",
+ "Omega",
+ "Omega",
+ "Omegatonos",
+ "Omicron",
+ "Omicrontonos",
+ "Oslashacute",
+ "Phi",
+ "Pi",
+ "Psi",
+ "Racute",
+ "Rcaron",
+ "Rcommaaccent",
+ "Rfraktur",
+ "Rho",
+ "SF010000",
+ "SF020000",
+ "SF030000",
+ "SF040000",
+ "SF050000",
+ "SF060000",
+ "SF070000",
+ "SF080000",
+ "SF090000",
+ "SF100000",
+ "SF110000",
+ "SF190000",
+ "SF200000",
+ "SF210000",
+ "SF220000",
+ "SF230000",
+ "SF240000",
+ "SF250000",
+ "SF260000",
+ "SF270000",
+ "SF280000",
+ "SF360000",
+ "SF370000",
+ "SF380000",
+ "SF390000",
+ "SF400000",
+ "SF410000",
+ "SF420000",
+ "SF430000",
+ "SF440000",
+ "SF450000",
+ "SF460000",
+ "SF470000",
+ "SF480000",
+ "SF490000",
+ "SF500000",
+ "SF510000",
+ "SF520000",
+ "SF530000",
+ "SF540000",
+ "Sacute",
+ "Scedilla",
+ "Scedilla",
+ "Scircumflex",
+ "Scommaaccent",
+ "Sigma",
+ "Tau",
+ "Tbar",
+ "Tcaron",
+ "Tcommaaccent",
+ "Tcommaaccent",
+ "Theta",
+ "Ubreve",
+ "Uhorn",
+ "Uhungarumlaut",
+ "Umacron",
+ "Uogonek",
+ "Upsilon",
+ "Upsilon1",
+ "Upsilondieresis",
+ "Upsilontonos",
+ "Uring",
+ "Utilde",
+ "Wacute",
+ "Wcircumflex",
+ "Wdieresis",
+ "Wgrave",
+ "Xi",
+ "Ycircumflex",
+ "Ygrave",
+ "Zacute",
+ "Zdotaccent",
+ "Zeta",
+ "abreve",
+ "acutecomb",
+ "aeacute",
+ "afii00208",
+ "afii10017",
+ "afii10018",
+ "afii10019",
+ "afii10020",
+ "afii10021",
+ "afii10022",
+ "afii10023",
+ "afii10024",
+ "afii10025",
+ "afii10026",
+ "afii10027",
+ "afii10028",
+ "afii10029",
+ "afii10030",
+ "afii10031",
+ "afii10032",
+ "afii10033",
+ "afii10034",
+ "afii10035",
+ "afii10036",
+ "afii10037",
+ "afii10038",
+ "afii10039",
+ "afii10040",
+ "afii10041",
+ "afii10042",
+ "afii10043",
+ "afii10044",
+ "afii10045",
+ "afii10046",
+ "afii10047",
+ "afii10048",
+ "afii10049",
+ "afii10050",
+ "afii10051",
+ "afii10052",
+ "afii10053",
+ "afii10054",
+ "afii10055",
+ "afii10056",
+ "afii10057",
+ "afii10058",
+ "afii10059",
+ "afii10060",
+ "afii10061",
+ "afii10062",
+ "afii10063",
+ "afii10064",
+ "afii10065",
+ "afii10066",
+ "afii10067",
+ "afii10068",
+ "afii10069",
+ "afii10070",
+ "afii10071",
+ "afii10072",
+ "afii10073",
+ "afii10074",
+ "afii10075",
+ "afii10076",
+ "afii10077",
+ "afii10078",
+ "afii10079",
+ "afii10080",
+ "afii10081",
+ "afii10082",
+ "afii10083",
+ "afii10084",
+ "afii10085",
+ "afii10086",
+ "afii10087",
+ "afii10088",
+ "afii10089",
+ "afii10090",
+ "afii10091",
+ "afii10092",
+ "afii10093",
+ "afii10094",
+ "afii10095",
+ "afii10096",
+ "afii10097",
+ "afii10098",
+ "afii10099",
+ "afii10100",
+ "afii10101",
+ "afii10102",
+ "afii10103",
+ "afii10104",
+ "afii10105",
+ "afii10106",
+ "afii10107",
+ "afii10108",
+ "afii10109",
+ "afii10110",
+ "afii10145",
+ "afii10146",
+ "afii10147",
+ "afii10148",
+ "afii10192",
+ "afii10193",
+ "afii10194",
+ "afii10195",
+ "afii10196",
+ "afii10831",
+ "afii10832",
+ "afii10846",
+ "afii299",
+ "afii300",
+ "afii301",
+ "afii57381",
+ "afii57388",
+ "afii57392",
+ "afii57393",
+ "afii57394",
+ "afii57395",
+ "afii57396",
+ "afii57397",
+ "afii57398",
+ "afii57399",
+ "afii57400",
+ "afii57401",
+ "afii57403",
+ "afii57407",
+ "afii57409",
+ "afii57410",
+ "afii57411",
+ "afii57412",
+ "afii57413",
+ "afii57414",
+ "afii57415",
+ "afii57416",
+ "afii57417",
+ "afii57418",
+ "afii57419",
+ "afii57420",
+ "afii57421",
+ "afii57422",
+ "afii57423",
+ "afii57424",
+ "afii57425",
+ "afii57426",
+ "afii57427",
+ "afii57428",
+ "afii57429",
+ "afii57430",
+ "afii57431",
+ "afii57432",
+ "afii57433",
+ "afii57434",
+ "afii57440",
+ "afii57441",
+ "afii57442",
+ "afii57443",
+ "afii57444",
+ "afii57445",
+ "afii57446",
+ "afii57448",
+ "afii57449",
+ "afii57450",
+ "afii57451",
+ "afii57452",
+ "afii57453",
+ "afii57454",
+ "afii57455",
+ "afii57456",
+ "afii57457",
+ "afii57458",
+ "afii57470",
+ "afii57505",
+ "afii57506",
+ "afii57507",
+ "afii57508",
+ "afii57509",
+ "afii57511",
+ "afii57512",
+ "afii57513",
+ "afii57514",
+ "afii57519",
+ "afii57534",
+ "afii57636",
+ "afii57645",
+ "afii57658",
+ "afii57664",
+ "afii57665",
+ "afii57666",
+ "afii57667",
+ "afii57668",
+ "afii57669",
+ "afii57670",
+ "afii57671",
+ "afii57672",
+ "afii57673",
+ "afii57674",
+ "afii57675",
+ "afii57676",
+ "afii57677",
+ "afii57678",
+ "afii57679",
+ "afii57680",
+ "afii57681",
+ "afii57682",
+ "afii57683",
+ "afii57684",
+ "afii57685",
+ "afii57686",
+ "afii57687",
+ "afii57688",
+ "afii57689",
+ "afii57690",
+ "afii57694",
+ "afii57695",
+ "afii57700",
+ "afii57705",
+ "afii57716",
+ "afii57717",
+ "afii57718",
+ "afii57723",
+ "afii57793",
+ "afii57794",
+ "afii57795",
+ "afii57796",
+ "afii57797",
+ "afii57798",
+ "afii57799",
+ "afii57800",
+ "afii57801",
+ "afii57802",
+ "afii57803",
+ "afii57804",
+ "afii57806",
+ "afii57807",
+ "afii57839",
+ "afii57841",
+ "afii57842",
+ "afii57929",
+ "afii61248",
+ "afii61289",
+ "afii61352",
+ "afii61573",
+ "afii61574",
+ "afii61575",
+ "afii61664",
+ "afii63167",
+ "afii64937",
+ "aleph",
+ "alpha",
+ "alphatonos",
+ "amacron",
+ "angle",
+ "angleleft",
+ "angleright",
+ "anoteleia",
+ "aogonek",
+ "approxequal",
+ "aringacute",
+ "arrowboth",
+ "arrowdblboth",
+ "arrowdbldown",
+ "arrowdblleft",
+ "arrowdblright",
+ "arrowdblup",
+ "arrowdown",
+ "arrowhorizex",
+ "arrowleft",
+ "arrowright",
+ "arrowup",
+ "arrowupdn",
+ "arrowupdnbse",
+ "arrowvertex",
+ "asteriskmath",
+ "beta",
+ "block",
+ "braceex",
+ "braceleftbt",
+ "braceleftmid",
+ "bracelefttp",
+ "bracerightbt",
+ "bracerightmid",
+ "bracerighttp",
+ "bracketleftbt",
+ "bracketleftex",
+ "bracketlefttp",
+ "bracketrightbt",
+ "bracketrightex",
+ "bracketrighttp",
+ "cacute",
+ "carriagereturn",
+ "ccaron",
+ "ccircumflex",
+ "cdotaccent",
+ "chi",
+ "circle",
+ "circlemultiply",
+ "circleplus",
+ "club",
+ "commaaccent",
+ "congruent",
+ "copyrightsans",
+ "copyrightserif",
+ "cyrBreve",
+ "cyrFlex",
+ "cyrbreve",
+ "cyrflex",
+ "dblGrave",
+ "dblgrave",
+ "dcaron",
+ "dcroat",
+ "delta",
+ "diamond",
+ "dieresisacute",
+ "dieresisgrave",
+ "dieresistonos",
+ "dkshade",
+ "dnblock",
+ "dong",
+ "dotbelowcomb",
+ "dotlessj",
+ "dotmath",
+ "ebreve",
+ "ecaron",
+ "edotaccent",
+ "element",
+ "emacron",
+ "emptyset",
+ "eng",
+ "eogonek",
+ "epsilon",
+ "epsilontonos",
+ "equivalence",
+ "estimated",
+ "eta",
+ "etatonos",
+ "exclamdbl",
+ "existential",
+ "female",
+ "filledbox",
+ "filledrect",
+ "franc",
+ "gamma",
+ "gbreve",
+ "gcaron",
+ "gcircumflex",
+ "gcommaaccent",
+ "gdotaccent",
+ "gradient",
+ "gravecomb",
+ "greaterequal",
+ "hbar",
+ "hcircumflex",
+ "heart",
+ "hookabovecomb",
+ "house",
+ "ibreve",
+ "ij",
+ "imacron",
+ "infinity",
+ "integral",
+ "integralbt",
+ "integralex",
+ "integraltp",
+ "intersection",
+ "invbullet",
+ "invcircle",
+ "invsmileface",
+ "iogonek",
+ "iota",
+ "iotadieresis",
+ "iotadieresistonos",
+ "iotatonos",
+ "itilde",
+ "jcircumflex",
+ "kappa",
+ "kcommaaccent",
+ "kgreenlandic",
+ "lacute",
+ "lambda",
+ "lcaron",
+ "lcommaaccent",
+ "ldot",
+ "lessequal",
+ "lfblock",
+ "lira",
+ "ll",
+ "logicaland",
+ "logicalor",
+ "longs",
+ "lozenge",
+ "ltshade",
+ "male",
+ "minute",
+ "musicalnote",
+ "musicalnotedbl",
+ "nacute",
+ "napostrophe",
+ "ncaron",
+ "ncommaaccent",
+ "notelement",
+ "notequal",
+ "notsubset",
+ "nu",
+ "obreve",
+ "ohorn",
+ "ohungarumlaut",
+ "omacron",
+ "omega",
+ "omega1",
+ "omegatonos",
+ "omicron",
+ "omicrontonos",
+ "openbullet",
+ "orthogonal",
+ "oslashacute",
+ "parenleftbt",
+ "parenleftex",
+ "parenlefttp",
+ "parenrightbt",
+ "parenrightex",
+ "parenrighttp",
+ "partialdiff",
+ "perpendicular",
+ "peseta",
+ "phi",
+ "phi1",
+ "pi",
+ "prescription",
+ "product",
+ "propersubset",
+ "propersuperset",
+ "proportional",
+ "psi",
+ "quotereversed",
+ "racute",
+ "radical",
+ "radicalex",
+ "rcaron",
+ "rcommaaccent",
+ "reflexsubset",
+ "reflexsuperset",
+ "registersans",
+ "registerserif",
+ "revlogicalnot",
+ "rho",
+ "rtblock",
+ "sacute",
+ "scedilla",
+ "scedilla",
+ "scircumflex",
+ "scommaaccent",
+ "second",
+ "shade",
+ "sigma",
+ "sigma1",
+ "similar",
+ "smileface",
+ "spade",
+ "suchthat",
+ "summation",
+ "sun",
+ "tau",
+ "tbar",
+ "tcaron",
+ "tcommaaccent",
+ "tcommaaccent",
+ "therefore",
+ "theta",
+ "theta1",
+ "tildecomb",
+ "tonos",
+ "trademarksans",
+ "trademarkserif",
+ "triagdn",
+ "triaglf",
+ "triagrt",
+ "triagup",
+ "ubreve",
+ "uhorn",
+ "uhungarumlaut",
+ "umacron",
+ "underscoredbl",
+ "union",
+ "universal",
+ "uogonek",
+ "upblock",
+ "upsilon",
+ "upsilondieresis",
+ "upsilondieresistonos",
+ "upsilontonos",
+ "uring",
+ "utilde",
+ "wacute",
+ "wcircumflex",
+ "wdieresis",
+ "weierstrass",
+ "wgrave",
+ "xi",
+ "ycircumflex",
+ "ygrave",
+ "zacute",
+ "zdotaccent",
+ "zeta",
+
+#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
+
+ NULL
+ };
+
+
+ static const char* const * const sid_standard_names = ps_glyph_names + 5;
+
+
+#define NUM_SID_GLYPHS 391
+
+#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
+#define NUM_ADOBE_GLYPHS 1058
+#else
+#define NUM_ADOBE_GLYPHS 391
+#endif
+
+
+ static const unsigned short mac_standard_names[259] =
+ {
+ 5,
+ 0,
+ 1,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 109,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 64,
+ 65,
+ 66,
+ 67,
+ 68,
+ 69,
+ 129,
+ 71,
+ 72,
+ 73,
+ 74,
+ 75,
+ 76,
+ 77,
+ 78,
+ 79,
+ 80,
+ 81,
+ 82,
+ 83,
+ 84,
+ 85,
+ 86,
+ 87,
+ 88,
+ 89,
+ 90,
+ 91,
+ 92,
+ 93,
+ 94,
+ 95,
+ 96,
+ 97,
+ 98,
+ 99,
+ 100,
+ 178,
+ 180,
+ 182,
+ 183,
+ 191,
+ 194,
+ 200,
+ 205,
+ 208,
+ 206,
+ 207,
+ 210,
+ 209,
+ 211,
+ 212,
+ 215,
+ 213,
+ 214,
+ 216,
+ 219,
+ 217,
+ 218,
+ 220,
+ 221,
+ 224,
+ 222,
+ 223,
+ 225,
+ 227,
+ 230,
+ 228,
+ 229,
+ 117,
+ 166,
+ 102,
+ 103,
+ 107,
+ 121,
+ 120,
+ 154,
+ 170,
+ 175,
+ 158,
+ 130,
+ 136,
+ 2,
+ 143,
+ 146,
+ 3,
+ 161,
+ 4,
+ 5,
+ 105,
+ 157,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 144,
+ 148,
+ 11,
+ 149,
+ 152,
+ 128,
+ 101,
+ 156,
+ 12,
+ 106,
+ 13,
+ 14,
+ 111,
+ 125,
+ 126,
+ 15,
+ 179,
+ 181,
+ 196,
+ 147,
+ 153,
+ 116,
+ 142,
+ 110,
+ 124,
+ 70,
+ 13,
+ 164,
+ 16,
+ 232,
+ 203,
+ 104,
+ 108,
+ 112,
+ 113,
+ 114,
+ 115,
+ 118,
+ 119,
+ 122,
+ 123,
+ 127,
+ 177,
+ 184,
+ 176,
+ 185,
+ 186,
+ 187,
+ 188,
+ 189,
+ 190,
+ 192,
+ 193,
+ 17,
+ 195,
+ 198,
+ 199,
+ 201,
+ 150,
+ 131,
+ 132,
+ 133,
+ 134,
+ 135,
+ 137,
+ 138,
+ 139,
+ 140,
+ 141,
+ 145,
+ 151,
+ 197,
+ 226,
+ 204,
+ 233,
+ 165,
+ 159,
+ 172,
+ 202,
+ 231,
+ 162,
+ 167,
+ 171,
+ 173,
+ 155,
+ 169,
+ 174,
+ 160,
+ 163,
+ 168,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 0
+ };
+
+
+
+ static const unsigned short ps_names_to_unicode[1059] =
+ {
+ 0,
+ 0x0020,
+ 0x0021,
+ 0x0022,
+ 0x0023,
+ 0x0024,
+ 0x0025,
+ 0x0026,
+ 0x2019,
+ 0x0028,
+ 0x0029,
+ 0x002A,
+ 0x002B,
+ 0x002C,
+ 0x002D,
+ 0x002E,
+ 0x002F,
+ 0x0030,
+ 0x0031,
+ 0x0032,
+ 0x0033,
+ 0x0034,
+ 0x0035,
+ 0x0036,
+ 0x0037,
+ 0x0038,
+ 0x0039,
+ 0x003A,
+ 0x003B,
+ 0x003C,
+ 0x003D,
+ 0x003E,
+ 0x003F,
+ 0x0040,
+ 0x0041,
+ 0x0042,
+ 0x0043,
+ 0x0044,
+ 0x0045,
+ 0x0046,
+ 0x0047,
+ 0x0048,
+ 0x0049,
+ 0x004A,
+ 0x004B,
+ 0x004C,
+ 0x004D,
+ 0x004E,
+ 0x004F,
+ 0x0050,
+ 0x0051,
+ 0x0052,
+ 0x0053,
+ 0x0054,
+ 0x0055,
+ 0x0056,
+ 0x0057,
+ 0x0058,
+ 0x0059,
+ 0x005A,
+ 0x005B,
+ 0x005C,
+ 0x005D,
+ 0x005E,
+ 0x005F,
+ 0x2018,
+ 0x0061,
+ 0x0062,
+ 0x0063,
+ 0x0064,
+ 0x0065,
+ 0x0066,
+ 0x0067,
+ 0x0068,
+ 0x0069,
+ 0x006A,
+ 0x006B,
+ 0x006C,
+ 0x006D,
+ 0x006E,
+ 0x006F,
+ 0x0070,
+ 0x0071,
+ 0x0072,
+ 0x0073,
+ 0x0074,
+ 0x0075,
+ 0x0076,
+ 0x0077,
+ 0x0078,
+ 0x0079,
+ 0x007A,
+ 0x007B,
+ 0x007C,
+ 0x007D,
+ 0x007E,
+ 0x00A1,
+ 0x00A2,
+ 0x00A3,
+ 0x2044,
+ 0x00A5,
+ 0x0192,
+ 0x00A7,
+ 0x00A4,
+ 0x0027,
+ 0x201C,
+ 0x00AB,
+ 0x2039,
+ 0x203A,
+ 0xFB01,
+ 0xFB02,
+ 0x2013,
+ 0x2020,
+ 0x2021,
+ 0x00B7,
+ 0x00B6,
+ 0x2022,
+ 0x201A,
+ 0x201E,
+ 0x201D,
+ 0x00BB,
+ 0x2026,
+ 0x2030,
+ 0x00BF,
+ 0x0060,
+ 0x00B4,
+ 0x02C6,
+ 0x02DC,
+ 0x00AF,
+ 0x02D8,
+ 0x02D9,
+ 0x00A8,
+ 0x02DA,
+ 0x00B8,
+ 0x02DD,
+ 0x02DB,
+ 0x02C7,
+ 0x2014,
+ 0x00C6,
+ 0x00AA,
+ 0x0141,
+ 0x00D8,
+ 0x0152,
+ 0x00BA,
+ 0x00E6,
+ 0x0131,
+ 0x0142,
+ 0x00F8,
+ 0x0153,
+ 0x00DF,
+ 0x00B9,
+ 0x00AC,
+ 0x00B5,
+ 0x2122,
+ 0x00D0,
+ 0x00BD,
+ 0x00B1,
+ 0x00DE,
+ 0x00BC,
+ 0x00F7,
+ 0x00A6,
+ 0x00B0,
+ 0x00FE,
+ 0x00BE,
+ 0x00B2,
+ 0x00AE,
+ 0x2212,
+ 0x00F0,
+ 0x00D7,
+ 0x00B3,
+ 0x00A9,
+ 0x00C1,
+ 0x00C2,
+ 0x00C4,
+ 0x00C0,
+ 0x00C5,
+ 0x00C3,
+ 0x00C7,
+ 0x00C9,
+ 0x00CA,
+ 0x00CB,
+ 0x00C8,
+ 0x00CD,
+ 0x00CE,
+ 0x00CF,
+ 0x00CC,
+ 0x00D1,
+ 0x00D3,
+ 0x00D4,
+ 0x00D6,
+ 0x00D2,
+ 0x00D5,
+ 0x0160,
+ 0x00DA,
+ 0x00DB,
+ 0x00DC,
+ 0x00D9,
+ 0x00DD,
+ 0x0178,
+ 0x017D,
+ 0x00E1,
+ 0x00E2,
+ 0x00E4,
+ 0x00E0,
+ 0x00E5,
+ 0x00E3,
+ 0x00E7,
+ 0x00E9,
+ 0x00EA,
+ 0x00EB,
+ 0x00E8,
+ 0x00ED,
+ 0x00EE,
+ 0x00EF,
+ 0x00EC,
+ 0x00F1,
+ 0x00F3,
+ 0x00F4,
+ 0x00F6,
+ 0x00F2,
+ 0x00F5,
+ 0x0161,
+ 0x00FA,
+ 0x00FB,
+ 0x00FC,
+ 0x00F9,
+ 0x00FD,
+ 0x00FF,
+ 0x017E,
+ 0xF721,
+ 0xF6F8,
+ 0xF724,
+ 0xF6E4,
+ 0xF726,
+ 0xF7B4,
+ 0x207D,
+ 0x207E,
+ 0x2025,
+ 0x2024,
+ 0xF730,
+ 0xF731,
+ 0xF732,
+ 0xF733,
+ 0xF734,
+ 0xF735,
+ 0xF736,
+ 0xF737,
+ 0xF738,
+ 0xF739,
+ 0xF6E2,
+ 0xF6DE,
+ 0xF6E8,
+ 0xF73F,
+ 0xF6E9,
+ 0xF6EA,
+ 0xF6E0,
+ 0xF6EB,
+ 0xF6EC,
+ 0xF6ED,
+ 0xF6EE,
+ 0xF6EF,
+ 0x207F,
+ 0xF6F0,
+ 0xF6F1,
+ 0xF6F2,
+ 0xF6F3,
+ 0xFB00,
+ 0xFB03,
+ 0xFB04,
+ 0x208D,
+ 0x208E,
+ 0xF6F6,
+ 0xF6E6,
+ 0xF760,
+ 0xF761,
+ 0xF762,
+ 0xF763,
+ 0xF764,
+ 0xF765,
+ 0xF766,
+ 0xF767,
+ 0xF768,
+ 0xF769,
+ 0xF76A,
+ 0xF76B,
+ 0xF76C,
+ 0xF76D,
+ 0xF76E,
+ 0xF76F,
+ 0xF770,
+ 0xF771,
+ 0xF772,
+ 0xF773,
+ 0xF774,
+ 0xF775,
+ 0xF776,
+ 0xF777,
+ 0xF778,
+ 0xF779,
+ 0xF77A,
+ 0x20A1,
+ 0xF6DC,
+ 0xF6DD,
+ 0xF6FE,
+ 0xF7A1,
+ 0xF7A2,
+ 0xF6F9,
+ 0xF6FD,
+ 0xF6FF,
+ 0xF7A8,
+ 0xF6F4,
+ 0xF6F5,
+ 0xF6F7,
+ 0xF7AF,
+ 0x2012,
+ 0xF6E5,
+ 0xF6FB,
+ 0xF6FC,
+ 0xF7B8,
+ 0xF7BF,
+ 0x215B,
+ 0x215C,
+ 0x215D,
+ 0x215E,
+ 0x2153,
+ 0x2154,
+ 0x2070,
+ 0x2074,
+ 0x2075,
+ 0x2076,
+ 0x2077,
+ 0x2078,
+ 0x2079,
+ 0x2080,
+ 0x2081,
+ 0x2082,
+ 0x2083,
+ 0x2084,
+ 0x2085,
+ 0x2086,
+ 0x2087,
+ 0x2088,
+ 0x2089,
+ 0xF6DF,
+ 0xF6E3,
+ 0xF6E7,
+ 0xF6E1,
+ 0xF7E0,
+ 0xF7E1,
+ 0xF7E2,
+ 0xF7E3,
+ 0xF7E4,
+ 0xF7E5,
+ 0xF7E6,
+ 0xF7E7,
+ 0xF7E8,
+ 0xF7E9,
+ 0xF7EA,
+ 0xF7EB,
+ 0xF7EC,
+ 0xF7ED,
+ 0xF7EE,
+ 0xF7EF,
+ 0xF7F0,
+ 0xF7F1,
+ 0xF7F2,
+ 0xF7F3,
+ 0xF7F4,
+ 0xF7F5,
+ 0xF7F6,
+ 0xF6FA,
+ 0xF7F8,
+ 0xF7F9,
+ 0xF7FA,
+ 0xF7FB,
+ 0xF7FC,
+ 0xF7FD,
+ 0xF7FE,
+ 0xF7FF,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
+
+ 0x01FC,
+ 0x0102,
+ 0xF6C9,
+ 0x0391,
+ 0x0386,
+ 0x0100,
+ 0x0104,
+ 0x01FA,
+ 0x0392,
+ 0x0106,
+ 0xF6CA,
+ 0x010C,
+ 0x0108,
+ 0x010A,
+ 0x03A7,
+ 0x010E,
+ 0x0110,
+ 0x2206,
+ 0x2206,
+ 0xF6CB,
+ 0xF6CC,
+ 0xF6CD,
+ 0x0114,
+ 0x011A,
+ 0x0116,
+ 0x0112,
+ 0x014A,
+ 0x0118,
+ 0x0395,
+ 0x0388,
+ 0x0397,
+ 0x0389,
+ 0x20AC,
+ 0x0393,
+ 0x011E,
+ 0x01E6,
+ 0x011C,
+ 0x0122,
+ 0x0120,
+ 0xF6CE,
+ 0x25CF,
+ 0x25AA,
+ 0x25AB,
+ 0x25A1,
+ 0x0126,
+ 0x0124,
+ 0xF6CF,
+ 0x0132,
+ 0x012C,
+ 0x0130,
+ 0x2111,
+ 0x012A,
+ 0x012E,
+ 0x0399,
+ 0x03AA,
+ 0x038A,
+ 0x0128,
+ 0x0134,
+ 0x039A,
+ 0x0136,
+ 0xF6BF,
+ 0x0139,
+ 0x039B,
+ 0x013D,
+ 0x013B,
+ 0x013F,
+ 0xF6D0,
+ 0x039C,
+ 0x0143,
+ 0x0147,
+ 0x0145,
+ 0x039D,
+ 0x014E,
+ 0x01A0,
+ 0x0150,
+ 0x014C,
+ 0x2126,
+ 0x2126,
+ 0x038F,
+ 0x039F,
+ 0x038C,
+ 0x01FE,
+ 0x03A6,
+ 0x03A0,
+ 0x03A8,
+ 0x0154,
+ 0x0158,
+ 0x0156,
+ 0x211C,
+ 0x03A1,
+ 0x250C,
+ 0x2514,
+ 0x2510,
+ 0x2518,
+ 0x253C,
+ 0x252C,
+ 0x2534,
+ 0x251C,
+ 0x2524,
+ 0x2500,
+ 0x2502,
+ 0x2561,
+ 0x2562,
+ 0x2556,
+ 0x2555,
+ 0x2563,
+ 0x2551,
+ 0x2557,
+ 0x255D,
+ 0x255C,
+ 0x255B,
+ 0x255E,
+ 0x255F,
+ 0x255A,
+ 0x2554,
+ 0x2569,
+ 0x2566,
+ 0x2560,
+ 0x2550,
+ 0x256C,
+ 0x2567,
+ 0x2568,
+ 0x2564,
+ 0x2565,
+ 0x2559,
+ 0x2558,
+ 0x2552,
+ 0x2553,
+ 0x256B,
+ 0x256A,
+ 0x015A,
+ 0x015E,
+ 0x015E,
+ 0x015C,
+ 0x0218,
+ 0x03A3,
+ 0x03A4,
+ 0x0166,
+ 0x0164,
+ 0x0162,
+ 0x0162,
+ 0x0398,
+ 0x016C,
+ 0x01AF,
+ 0x0170,
+ 0x016A,
+ 0x0172,
+ 0x03A5,
+ 0x03D2,
+ 0x03AB,
+ 0x038E,
+ 0x016E,
+ 0x0168,
+ 0x1E82,
+ 0x0174,
+ 0x1E84,
+ 0x1E80,
+ 0x039E,
+ 0x0176,
+ 0x1EF2,
+ 0x0179,
+ 0x017B,
+ 0x0396,
+ 0x0103,
+ 0x0301,
+ 0x01FD,
+ 0x2015,
+ 0x0410,
+ 0x0411,
+ 0x0412,
+ 0x0413,
+ 0x0414,
+ 0x0415,
+ 0x0401,
+ 0x0416,
+ 0x0417,
+ 0x0418,
+ 0x0419,
+ 0x041A,
+ 0x041B,
+ 0x041C,
+ 0x041D,
+ 0x041E,
+ 0x041F,
+ 0x0420,
+ 0x0421,
+ 0x0422,
+ 0x0423,
+ 0x0424,
+ 0x0425,
+ 0x0426,
+ 0x0427,
+ 0x0428,
+ 0x0429,
+ 0x042A,
+ 0x042B,
+ 0x042C,
+ 0x042D,
+ 0x042E,
+ 0x042F,
+ 0x0490,
+ 0x0402,
+ 0x0403,
+ 0x0404,
+ 0x0405,
+ 0x0406,
+ 0x0407,
+ 0x0408,
+ 0x0409,
+ 0x040A,
+ 0x040B,
+ 0x040C,
+ 0x040E,
+ 0xF6C4,
+ 0xF6C5,
+ 0x0430,
+ 0x0431,
+ 0x0432,
+ 0x0433,
+ 0x0434,
+ 0x0435,
+ 0x0451,
+ 0x0436,
+ 0x0437,
+ 0x0438,
+ 0x0439,
+ 0x043A,
+ 0x043B,
+ 0x043C,
+ 0x043D,
+ 0x043E,
+ 0x043F,
+ 0x0440,
+ 0x0441,
+ 0x0442,
+ 0x0443,
+ 0x0444,
+ 0x0445,
+ 0x0446,
+ 0x0447,
+ 0x0448,
+ 0x0449,
+ 0x044A,
+ 0x044B,
+ 0x044C,
+ 0x044D,
+ 0x044E,
+ 0x044F,
+ 0x0491,
+ 0x0452,
+ 0x0453,
+ 0x0454,
+ 0x0455,
+ 0x0456,
+ 0x0457,
+ 0x0458,
+ 0x0459,
+ 0x045A,
+ 0x045B,
+ 0x045C,
+ 0x045E,
+ 0x040F,
+ 0x0462,
+ 0x0472,
+ 0x0474,
+ 0xF6C6,
+ 0x045F,
+ 0x0463,
+ 0x0473,
+ 0x0475,
+ 0xF6C7,
+ 0xF6C8,
+ 0x04D9,
+ 0x200E,
+ 0x200F,
+ 0x200D,
+ 0x066A,
+ 0x060C,
+ 0x0660,
+ 0x0661,
+ 0x0662,
+ 0x0663,
+ 0x0664,
+ 0x0665,
+ 0x0666,
+ 0x0667,
+ 0x0668,
+ 0x0669,
+ 0x061B,
+ 0x061F,
+ 0x0621,
+ 0x0622,
+ 0x0623,
+ 0x0624,
+ 0x0625,
+ 0x0626,
+ 0x0627,
+ 0x0628,
+ 0x0629,
+ 0x062A,
+ 0x062B,
+ 0x062C,
+ 0x062D,
+ 0x062E,
+ 0x062F,
+ 0x0630,
+ 0x0631,
+ 0x0632,
+ 0x0633,
+ 0x0634,
+ 0x0635,
+ 0x0636,
+ 0x0637,
+ 0x0638,
+ 0x0639,
+ 0x063A,
+ 0x0640,
+ 0x0641,
+ 0x0642,
+ 0x0643,
+ 0x0644,
+ 0x0645,
+ 0x0646,
+ 0x0648,
+ 0x0649,
+ 0x064A,
+ 0x064B,
+ 0x064C,
+ 0x064D,
+ 0x064E,
+ 0x064F,
+ 0x0650,
+ 0x0651,
+ 0x0652,
+ 0x0647,
+ 0x06A4,
+ 0x067E,
+ 0x0686,
+ 0x0698,
+ 0x06AF,
+ 0x0679,
+ 0x0688,
+ 0x0691,
+ 0x06BA,
+ 0x06D2,
+ 0x06D5,
+ 0x20AA,
+ 0x05BE,
+ 0x05C3,
+ 0x05D0,
+ 0x05D1,
+ 0x05D2,
+ 0x05D3,
+ 0x05D4,
+ 0x05D5,
+ 0x05D6,
+ 0x05D7,
+ 0x05D8,
+ 0x05D9,
+ 0x05DA,
+ 0x05DB,
+ 0x05DC,
+ 0x05DD,
+ 0x05DE,
+ 0x05DF,
+ 0x05E0,
+ 0x05E1,
+ 0x05E2,
+ 0x05E3,
+ 0x05E4,
+ 0x05E5,
+ 0x05E6,
+ 0x05E7,
+ 0x05E8,
+ 0x05E9,
+ 0x05EA,
+ 0xFB2A,
+ 0xFB2B,
+ 0xFB4B,
+ 0xFB1F,
+ 0x05F0,
+ 0x05F1,
+ 0x05F2,
+ 0xFB35,
+ 0x05B4,
+ 0x05B5,
+ 0x05B6,
+ 0x05BB,
+ 0x05B8,
+ 0x05B7,
+ 0x05B0,
+ 0x05B2,
+ 0x05B1,
+ 0x05B3,
+ 0x05C2,
+ 0x05C1,
+ 0x05B9,
+ 0x05BC,
+ 0x05BD,
+ 0x05BF,
+ 0x05C0,
+ 0x02BC,
+ 0x2105,
+ 0x2113,
+ 0x2116,
+ 0x202C,
+ 0x202D,
+ 0x202E,
+ 0x200C,
+ 0x066D,
+ 0x02BD,
+ 0x2135,
+ 0x03B1,
+ 0x03AC,
+ 0x0101,
+ 0x2220,
+ 0x2329,
+ 0x232A,
+ 0x0387,
+ 0x0105,
+ 0x2248,
+ 0x01FB,
+ 0x2194,
+ 0x21D4,
+ 0x21D3,
+ 0x21D0,
+ 0x21D2,
+ 0x21D1,
+ 0x2193,
+ 0xF8E7,
+ 0x2190,
+ 0x2192,
+ 0x2191,
+ 0x2195,
+ 0x21A8,
+ 0xF8E6,
+ 0x2217,
+ 0x03B2,
+ 0x2588,
+ 0xF8F4,
+ 0xF8F3,
+ 0xF8F2,
+ 0xF8F1,
+ 0xF8FE,
+ 0xF8FD,
+ 0xF8FC,
+ 0xF8F0,
+ 0xF8EF,
+ 0xF8EE,
+ 0xF8FB,
+ 0xF8FA,
+ 0xF8F9,
+ 0x0107,
+ 0x21B5,
+ 0x010D,
+ 0x0109,
+ 0x010B,
+ 0x03C7,
+ 0x25CB,
+ 0x2297,
+ 0x2295,
+ 0x2663,
+ 0xF6C3,
+ 0x2245,
+ 0xF8E9,
+ 0xF6D9,
+ 0xF6D1,
+ 0xF6D2,
+ 0xF6D4,
+ 0xF6D5,
+ 0xF6D3,
+ 0xF6D6,
+ 0x010F,
+ 0x0111,
+ 0x03B4,
+ 0x2666,
+ 0xF6D7,
+ 0xF6D8,
+ 0x0385,
+ 0x2593,
+ 0x2584,
+ 0x20AB,
+ 0x0323,
+ 0xF6BE,
+ 0x22C5,
+ 0x0115,
+ 0x011B,
+ 0x0117,
+ 0x2208,
+ 0x0113,
+ 0x2205,
+ 0x014B,
+ 0x0119,
+ 0x03B5,
+ 0x03AD,
+ 0x2261,
+ 0x212E,
+ 0x03B7,
+ 0x03AE,
+ 0x203C,
+ 0x2203,
+ 0x2640,
+ 0x25A0,
+ 0x25AC,
+ 0x20A3,
+ 0x03B3,
+ 0x011F,
+ 0x01E7,
+ 0x011D,
+ 0x0123,
+ 0x0121,
+ 0x2207,
+ 0x0300,
+ 0x2265,
+ 0x0127,
+ 0x0125,
+ 0x2665,
+ 0x0309,
+ 0x2302,
+ 0x012D,
+ 0x0133,
+ 0x012B,
+ 0x221E,
+ 0x222B,
+ 0x2321,
+ 0xF8F5,
+ 0x2320,
+ 0x2229,
+ 0x25D8,
+ 0x25D9,
+ 0x263B,
+ 0x012F,
+ 0x03B9,
+ 0x03CA,
+ 0x0390,
+ 0x03AF,
+ 0x0129,
+ 0x0135,
+ 0x03BA,
+ 0x0137,
+ 0x0138,
+ 0x013A,
+ 0x03BB,
+ 0x013E,
+ 0x013C,
+ 0x0140,
+ 0x2264,
+ 0x258C,
+ 0x20A4,
+ 0xF6C0,
+ 0x2227,
+ 0x2228,
+ 0x017F,
+ 0x25CA,
+ 0x2591,
+ 0x2642,
+ 0x2032,
+ 0x266A,
+ 0x266B,
+ 0x0144,
+ 0x0149,
+ 0x0148,
+ 0x0146,
+ 0x2209,
+ 0x2260,
+ 0x2284,
+ 0x03BD,
+ 0x014F,
+ 0x01A1,
+ 0x0151,
+ 0x014D,
+ 0x03C9,
+ 0x03D6,
+ 0x03CE,
+ 0x03BF,
+ 0x03CC,
+ 0x25E6,
+ 0x221F,
+ 0x01FF,
+ 0xF8ED,
+ 0xF8EC,
+ 0xF8EB,
+ 0xF8F8,
+ 0xF8F7,
+ 0xF8F6,
+ 0x2202,
+ 0x22A5,
+ 0x20A7,
+ 0x03C6,
+ 0x03D5,
+ 0x03C0,
+ 0x211E,
+ 0x220F,
+ 0x2282,
+ 0x2283,
+ 0x221D,
+ 0x03C8,
+ 0x201B,
+ 0x0155,
+ 0x221A,
+ 0xF8E5,
+ 0x0159,
+ 0x0157,
+ 0x2286,
+ 0x2287,
+ 0xF8E8,
+ 0xF6DA,
+ 0x2310,
+ 0x03C1,
+ 0x2590,
+ 0x015B,
+ 0x015F,
+ 0x015F,
+ 0x015D,
+ 0x0219,
+ 0x2033,
+ 0x2592,
+ 0x03C3,
+ 0x03C2,
+ 0x223C,
+ 0x263A,
+ 0x2660,
+ 0x220B,
+ 0x2211,
+ 0x263C,
+ 0x03C4,
+ 0x0167,
+ 0x0165,
+ 0x0163,
+ 0x0163,
+ 0x2234,
+ 0x03B8,
+ 0x03D1,
+ 0x0303,
+ 0x0384,
+ 0xF8EA,
+ 0xF6DB,
+ 0x25BC,
+ 0x25C4,
+ 0x25BA,
+ 0x25B2,
+ 0x016D,
+ 0x01B0,
+ 0x0171,
+ 0x016B,
+ 0x2017,
+ 0x222A,
+ 0x2200,
+ 0x0173,
+ 0x2580,
+ 0x03C5,
+ 0x03CB,
+ 0x03B0,
+ 0x03CD,
+ 0x016F,
+ 0x0169,
+ 0x1E83,
+ 0x0175,
+ 0x1E85,
+ 0x2118,
+ 0x1E81,
+ 0x03BE,
+ 0x0177,
+ 0x1EF3,
+ 0x017A,
+ 0x017C,
+ 0x03B6,
+
+#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
+ 0
+ };
+
+
+
+ static const unsigned short t1_standard_encoding[257] =
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ 52,
+ 53,
+ 54,
+ 55,
+ 56,
+ 57,
+ 58,
+ 59,
+ 60,
+ 61,
+ 62,
+ 63,
+ 64,
+ 65,
+ 66,
+ 67,
+ 68,
+ 69,
+ 70,
+ 71,
+ 72,
+ 73,
+ 74,
+ 75,
+ 76,
+ 77,
+ 78,
+ 79,
+ 80,
+ 81,
+ 82,
+ 83,
+ 84,
+ 85,
+ 86,
+ 87,
+ 88,
+ 89,
+ 90,
+ 91,
+ 92,
+ 93,
+ 94,
+ 95,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 96,
+ 97,
+ 98,
+ 99,
+ 100,
+ 101,
+ 102,
+ 103,
+ 104,
+ 105,
+ 106,
+ 107,
+ 108,
+ 109,
+ 110,
+ 0,
+ 111,
+ 112,
+ 113,
+ 114,
+ 0,
+ 115,
+ 116,
+ 117,
+ 118,
+ 119,
+ 120,
+ 121,
+ 122,
+ 0,
+ 123,
+ 0,
+ 124,
+ 125,
+ 126,
+ 127,
+ 128,
+ 129,
+ 130,
+ 131,
+ 0,
+ 132,
+ 133,
+ 0,
+ 134,
+ 135,
+ 136,
+ 137,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 138,
+ 0,
+ 139,
+ 0,
+ 0,
+ 0,
+ 0,
+ 140,
+ 141,
+ 142,
+ 143,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 144,
+ 0,
+ 0,
+ 0,
+ 145,
+ 0,
+ 0,
+ 146,
+ 147,
+ 148,
+ 149,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+
+ static const unsigned short t1_expert_encoding[257] =
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 229,
+ 230,
+ 0,
+ 231,
+ 232,
+ 233,
+ 234,
+ 235,
+ 236,
+ 237,
+ 238,
+ 13,
+ 14,
+ 15,
+ 99,
+ 239,
+ 240,
+ 241,
+ 242,
+ 243,
+ 244,
+ 245,
+ 246,
+ 247,
+ 248,
+ 27,
+ 28,
+ 249,
+ 250,
+ 251,
+ 252,
+ 0,
+ 253,
+ 254,
+ 255,
+ 256,
+ 257,
+ 0,
+ 0,
+ 0,
+ 258,
+ 0,
+ 0,
+ 259,
+ 260,
+ 261,
+ 262,
+ 0,
+ 0,
+ 263,
+ 264,
+ 265,
+ 0,
+ 266,
+ 109,
+ 110,
+ 267,
+ 268,
+ 269,
+ 0,
+ 270,
+ 271,
+ 272,
+ 273,
+ 274,
+ 275,
+ 276,
+ 277,
+ 278,
+ 279,
+ 280,
+ 281,
+ 282,
+ 283,
+ 284,
+ 285,
+ 286,
+ 287,
+ 288,
+ 289,
+ 290,
+ 291,
+ 292,
+ 293,
+ 294,
+ 295,
+ 296,
+ 297,
+ 298,
+ 299,
+ 300,
+ 301,
+ 302,
+ 303,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 304,
+ 305,
+ 306,
+ 0,
+ 0,
+ 307,
+ 308,
+ 309,
+ 310,
+ 311,
+ 0,
+ 312,
+ 0,
+ 0,
+ 313,
+ 0,
+ 0,
+ 314,
+ 315,
+ 0,
+ 0,
+ 316,
+ 317,
+ 318,
+ 0,
+ 0,
+ 0,
+ 158,
+ 155,
+ 163,
+ 319,
+ 320,
+ 321,
+ 322,
+ 323,
+ 324,
+ 325,
+ 0,
+ 0,
+ 326,
+ 150,
+ 164,
+ 169,
+ 327,
+ 328,
+ 329,
+ 330,
+ 331,
+ 332,
+ 333,
+ 334,
+ 335,
+ 336,
+ 337,
+ 338,
+ 339,
+ 340,
+ 341,
+ 342,
+ 343,
+ 344,
+ 345,
+ 346,
+ 347,
+ 348,
+ 349,
+ 350,
+ 351,
+ 352,
+ 353,
+ 354,
+ 355,
+ 356,
+ 357,
+ 358,
+ 359,
+ 360,
+ 361,
+ 362,
+ 363,
+ 364,
+ 365,
+ 366,
+ 367,
+ 368,
+ 369,
+ 370,
+ 371,
+ 372,
+ 373,
+ 374,
+ 375,
+ 376,
+ 377,
+ 378,
+ 0
+ };
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* rasterrs.h */
+/* */
+/* monochrome renderer error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the monochrome renderer error enumeration */
+ /* constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __RASTERRS_H__
+#define __RASTERRS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX Raster_Err_
+#define FT_ERR_BASE FT_Mod_Err_Raster
+
+#include FT_ERRORS_H
+
+#endif /* __RASTERRS_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* sfdriver.h */
+/* */
+/* High-level SFNT driver interface (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __SFDRIVER_H__
+#define __SFDRIVER_H__
+
+
+#include <ft2build.h>
+#include FT_MODULE_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_EXPORT_VAR( const FT_Module_Class ) sfnt_module_class;
+
+
+FT_END_HEADER
+
+#endif /* __SFDRIVER_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* sferrors.h */
+/* */
+/* SFNT error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the SFNT error enumeration constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __SFERRORS_H__
+#define __SFERRORS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX SFNT_Err_
+#define FT_ERR_BASE FT_Mod_Err_SFNT
+
+#include FT_ERRORS_H
+
+#endif /* __SFERRORS_H__ */
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* sfobjs.h */
+/* */
+/* SFNT object management (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __SFOBJS_H__
+#define __SFOBJS_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_SFNT_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_LOCAL FT_Error
+ SFNT_Init_Face( FT_Stream stream,
+ TT_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params );
+
+ FT_LOCAL FT_Error
+ SFNT_Load_Face( FT_Stream stream,
+ TT_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params );
+
+ FT_LOCAL void
+ SFNT_Done_Face( TT_Face face );
+
+
+FT_END_HEADER
+
+#endif /* __SFDRIVER_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* t1afm.h */
+/* */
+/* AFM support for Type 1 fonts (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __T1AFM_H__
+#define __T1AFM_H__
+
+#include <ft2build.h>
+#include "t1objs.h"
+
+
+FT_BEGIN_HEADER
+
+
+ typedef struct T1_Kern_Pair_
+ {
+ FT_UInt glyph1;
+ FT_UInt glyph2;
+ FT_Vector kerning;
+
+ } T1_Kern_Pair;
+
+
+ typedef struct T1_AFM_
+ {
+ FT_Int num_pairs;
+ T1_Kern_Pair* kern_pairs;
+
+ } T1_AFM;
+
+
+ FT_LOCAL FT_Error
+ T1_Read_AFM( FT_Face face,
+ FT_Stream stream );
+
+ FT_LOCAL void
+ T1_Done_AFM( FT_Memory memory,
+ T1_AFM* afm );
+
+ FT_LOCAL void
+ T1_Get_Kerning( T1_AFM* afm,
+ FT_UInt glyph1,
+ FT_UInt glyph2,
+ FT_Vector* kerning );
+
+
+FT_END_HEADER
+
+#endif /* __T1AFM_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* t1decode.h */
+/* */
+/* PostScript Type 1 decoding routines (specification). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __T1DECODE_H__
+#define __T1DECODE_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_CALLBACK_TABLE
+ const T1_Decoder_Funcs t1_decoder_funcs;
+
+
+ FT_LOCAL FT_Error
+ T1_Decoder_Parse_Glyph( T1_Decoder* decoder,
+ FT_UInt glyph_index );
+
+ FT_LOCAL FT_Error
+ T1_Decoder_Parse_Charstrings( T1_Decoder* decoder,
+ FT_Byte* base,
+ FT_UInt len );
+
+ FT_LOCAL FT_Error
+ T1_Decoder_Init( T1_Decoder* decoder,
+ FT_Face face,
+ FT_Size size,
+ FT_GlyphSlot slot,
+ FT_Byte** glyph_names,
+ T1_Blend* blend,
+ T1_Decoder_Callback parse_glyph );
+
+ FT_LOCAL void
+ T1_Decoder_Done( T1_Decoder* decoder );
+
+
+FT_END_HEADER
+
+#endif /* __T1DECODE_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* t1driver.h */
+/* */
+/* High-level Type 1 driver interface (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __T1DRIVER_H__
+#define __T1DRIVER_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_EXPORT_VAR( const FT_Driver_Class ) t1_driver_class;
+
+
+FT_END_HEADER
+
+#endif /* __T1DRIVER_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* t1errors.h */
+/* */
+/* Type 1 error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the Type 1 error enumeration constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __T1ERRORS_H__
+#define __T1ERRORS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX T1_Err_
+#define FT_ERR_BASE FT_Mod_Err_Type1
+
+#include FT_ERRORS_H
+
+#endif /* __T1ERRORS_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* t1gload.h */
+/* */
+/* Type 1 Glyph Loader (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __T1GLOAD_H__
+#define __T1GLOAD_H__
+
+
+#include <ft2build.h>
+#include "t1objs.h"
+
+
+FT_BEGIN_HEADER
+
+
+ FT_LOCAL FT_Error
+ T1_Compute_Max_Advance( T1_Face face,
+ FT_Int* max_advance );
+
+ FT_LOCAL FT_Error
+ T1_Load_Glyph( T1_GlyphSlot glyph,
+ T1_Size size,
+ FT_Int glyph_index,
+ FT_Int load_flags );
+
+
+FT_END_HEADER
+
+#endif /* __T1GLOAD_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* t1load.h */
+/* */
+/* Type 1 font loader (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __T1LOAD_H__
+#define __T1LOAD_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+#include FT_MULTIPLE_MASTERS_H
+
+#include "t1parse.h"
+
+
+FT_BEGIN_HEADER
+
+
+ typedef struct T1_Loader_
+ {
+ T1_ParserRec parser; /* parser used to read the stream */
+
+ FT_Int num_chars; /* number of characters in encoding */
+ PS_Table encoding_table; /* PS_Table used to store the */
+ /* encoding character names */
+
+ FT_Int num_glyphs;
+ PS_Table glyph_names;
+ PS_Table charstrings;
+ PS_Table swap_table; /* For moving .notdef glyph to index 0. */
+
+ FT_Int num_subrs;
+ PS_Table subrs;
+ FT_Bool fontdata;
+
+ } T1_Loader;
+
+
+ FT_LOCAL FT_Error
+ T1_Open_Face( T1_Face face );
+
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+
+ FT_LOCAL FT_Error
+ T1_Get_Multi_Master( T1_Face face,
+ FT_Multi_Master* master );
+
+ FT_LOCAL FT_Error
+ T1_Set_MM_Blend( T1_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords );
+
+ FT_LOCAL FT_Error
+ T1_Set_MM_Design( T1_Face face,
+ FT_UInt num_coords,
+ FT_Long* coords );
+
+ FT_LOCAL void
+ T1_Done_Blend( T1_Face face );
+
+#endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */
+
+
+FT_END_HEADER
+
+#endif /* __T1LOAD_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* t1objs.h */
+/* */
+/* Type 1 objects manager (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __T1OBJS_H__
+#define __T1OBJS_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_CONFIG_CONFIG_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+ /* The following structures must be defined by the hinter */
+ typedef struct T1_Size_Hints_ T1_Size_Hints;
+ typedef struct T1_Glyph_Hints_ T1_Glyph_Hints;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* T1_Driver */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 driver object. */
+ /* */
+ typedef struct T1_DriverRec_ *T1_Driver;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* T1_Size */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 size object. */
+ /* */
+ typedef struct T1_SizeRec_* T1_Size;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* T1_GlyphSlot */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 glyph slot object. */
+ /* */
+ typedef struct T1_GlyphSlotRec_* T1_GlyphSlot;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* T1_CharMap */
+ /* */
+ /* <Description> */
+ /* A handle to a Type 1 character mapping object. */
+ /* */
+ /* <Note> */
+ /* The Type 1 format doesn't use a charmap but an encoding table. */
+ /* The driver is responsible for making up charmap objects */
+ /* corresponding to these tables. */
+ /* */
+ typedef struct T1_CharMapRec_* T1_CharMap;
+
+
+ /*************************************************************************/
+ /* */
+ /* HERE BEGINS THE TYPE1 SPECIFIC STUFF */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* T1_SizeRec */
+ /* */
+ /* <Description> */
+ /* Type 1 size record. */
+ /* */
+ typedef struct T1_SizeRec_
+ {
+ FT_SizeRec root;
+ FT_Bool valid;
+ T1_Size_Hints* hints; /* defined in the hinter. This allows */
+ /* us to experiment with different */
+ /* hinting schemes without having to */
+ /* change `t1objs' each time. */
+ } T1_SizeRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* T1_GlyphSlotRec */
+ /* */
+ /* <Description> */
+ /* Type 1 glyph slot record. */
+ /* */
+ typedef struct T1_GlyphSlotRec_
+ {
+ FT_GlyphSlotRec root;
+
+ FT_Bool hint;
+ FT_Bool scaled;
+
+ FT_Int max_points;
+ FT_Int max_contours;
+
+ FT_Fixed x_scale;
+ FT_Fixed y_scale;
+
+ T1_Glyph_Hints* hints; /* defined in the hinter */
+
+ } T1_GlyphSlotRec;
+
+
+ FT_LOCAL FT_Error
+ T1_Init_Face( FT_Stream stream,
+ T1_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params );
+
+ FT_LOCAL void
+ T1_Done_Face( T1_Face face );
+
+ FT_LOCAL FT_Error
+ T1_Init_Driver( T1_Driver driver );
+
+ FT_LOCAL void
+ T1_Done_Driver( T1_Driver driver );
+
+
+FT_END_HEADER
+
+#endif /* __T1OBJS_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* t1parse.h */
+/* */
+/* Type 1 parser (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __T1PARSE_H__
+#define __T1PARSE_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_TYPE1_TYPES_H
+#include FT_INTERNAL_STREAM_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* T1_ParserRec */
+ /* */
+ /* <Description> */
+ /* A T1_ParserRec is an object used to parse a Type 1 fonts very */
+ /* quickly. */
+ /* */
+ /* <Fields> */
+ /* root :: The root parser. */
+ /* */
+ /* stream :: The current input stream. */
+ /* */
+ /* base_dict :: A pointer to the top-level dictionary. */
+ /* */
+ /* base_len :: The length in bytes of the top dictionary. */
+ /* */
+ /* private_dict :: A pointer to the private dictionary. */
+ /* */
+ /* private_len :: The length in bytes of the private dictionary. */
+ /* */
+ /* in_pfb :: A boolean. Indicates that we are handling a PFB */
+ /* file. */
+ /* */
+ /* in_memory :: A boolean. Indicates a memory-based stream. */
+ /* */
+ /* single_block :: A boolean. Indicates that the private dictionary */
+ /* is stored in lieu of the base dictionary. */
+ /* */
+ typedef struct T1_ParserRec_
+ {
+ T1_Parser root;
+ FT_Stream stream;
+
+ FT_Byte* base_dict;
+ FT_Int base_len;
+
+ FT_Byte* private_dict;
+ FT_Int private_len;
+
+ FT_Byte in_pfb;
+ FT_Byte in_memory;
+ FT_Byte single_block;
+
+ } T1_ParserRec;
+
+
+#define T1_Add_Table( p, i, o, l ) (p)->funcs.add( (p), i, o, l )
+#define T1_Done_Table( p ) \
+ do \
+ { \
+ if ( (p)->funcs.done ) \
+ (p)->funcs.done( p ); \
+ } while ( 0 )
+#define T1_Release_Table( p ) \
+ do \
+ { \
+ if ( (p)->funcs.release ) \
+ (p)->funcs.release( p ); \
+ } while ( 0 )
+
+
+#define T1_Skip_Spaces( p ) (p)->root.funcs.skip_spaces( &(p)->root )
+#define T1_Skip_Alpha( p ) (p)->root.funcs.skip_alpha ( &(p)->root )
+
+#define T1_ToInt( p ) (p)->root.funcs.to_int( &(p)->root )
+#define T1_ToFixed( p, t ) (p)->root.funcs.to_fixed( &(p)->root, t )
+
+#define T1_ToCoordArray( p, m, c ) \
+ (p)->root.funcs.to_coord_array( &(p)->root, m, c )
+#define T1_ToFixedArray( p, m, f, t ) \
+ (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t )
+#define T1_ToToken( p, t ) \
+ (p)->root.funcs.to_token( &(p)->root, t )
+#define T1_ToTokenArray( p, t, m, c ) \
+ (p)->root.funcs.to_token_array( &(p)->root, t, m, c )
+
+#define T1_Load_Field( p, f, o, m, pf ) \
+ (p)->root.funcs.load_field( &(p)->root, f, o, m, pf )
+#define T1_Load_Field_Table( p, f, o, m, pf ) \
+ (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf )
+
+
+ FT_LOCAL FT_Error
+ T1_New_Parser( T1_ParserRec* parser,
+ FT_Stream stream,
+ FT_Memory memory,
+ PSAux_Interface* psaux );
+
+ FT_LOCAL FT_Error
+ T1_Get_Private_Dict( T1_ParserRec* parser,
+ PSAux_Interface* psaux );
+
+ FT_LOCAL void
+ T1_Finalize_Parser( T1_ParserRec* parser );
+
+
+FT_END_HEADER
+
+#endif /* __T1PARSE_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* t1tokens.h */
+/* */
+/* Type 1 tokenizer (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE T1_FontInfo
+#undef T1CODE
+#define T1CODE t1_field_font_info
+
+ T1_FIELD_STRING( "version", version )
+ T1_FIELD_STRING( "Notice", notice )
+ T1_FIELD_STRING( "FullName", full_name )
+ T1_FIELD_STRING( "FamilyName", family_name )
+ T1_FIELD_STRING( "Weight", weight )
+
+ T1_FIELD_NUM ( "ItalicAngle", italic_angle )
+ T1_FIELD_BOOL ( "isFixedPitch", is_fixed_pitch )
+ T1_FIELD_NUM ( "UnderlinePosition", underline_position )
+ T1_FIELD_NUM ( "UnderlineThickness", underline_thickness )
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE T1_Private
+#undef T1CODE
+#define T1CODE t1_field_private
+
+ T1_FIELD_NUM ( "UniqueID", unique_id )
+ T1_FIELD_NUM ( "lenIV", lenIV )
+ T1_FIELD_NUM ( "LanguageGroup", language_group )
+ T1_FIELD_NUM ( "password", password )
+
+ T1_FIELD_FIXED ( "BlueScale", blue_scale )
+ T1_FIELD_NUM ( "BlueShift", blue_shift )
+ T1_FIELD_NUM ( "BlueFuzz", blue_fuzz )
+
+ T1_FIELD_NUM_TABLE ( "BlueValues", blue_values, 14 )
+ T1_FIELD_NUM_TABLE ( "OtherBlues", other_blues, 10 )
+ T1_FIELD_NUM_TABLE ( "FamilyBlues", family_blues, 14 )
+ T1_FIELD_NUM_TABLE ( "FamilyOtherBlues", family_other_blues, 10 )
+
+ T1_FIELD_NUM_TABLE2( "StdHW", standard_width, 1 )
+ T1_FIELD_NUM_TABLE2( "StdVW", standard_height, 1 )
+ T1_FIELD_NUM_TABLE2( "MinFeature", min_feature, 2 )
+
+ T1_FIELD_NUM_TABLE ( "StemSnapH", snap_widths, 12 )
+ T1_FIELD_NUM_TABLE ( "StemSnapV", snap_heights, 12 )
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE T1_Font
+#undef T1CODE
+#define T1CODE t1_field_font_dict
+
+ T1_FIELD_NUM( "PaintType", paint_type )
+ T1_FIELD_NUM( "FontType", font_type )
+ T1_FIELD_NUM( "StrokeWidth", stroke_width )
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ttcmap.h */
+/* */
+/* TrueType character mapping table (cmap) support (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTCMAP_H__
+#define __TTCMAP_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_LOCAL FT_Error
+ TT_CharMap_Load( TT_Face face,
+ TT_CMapTable* cmap,
+ FT_Stream input );
+
+ FT_LOCAL FT_Error
+ TT_CharMap_Free( TT_Face face,
+ TT_CMapTable* cmap );
+
+
+FT_END_HEADER
+
+#endif /* __TTCMAP_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ttdriver.h */
+/* */
+/* High-level TrueType driver interface (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTDRIVER_H__
+#define __TTDRIVER_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_EXPORT_VAR( const FT_Driver_Class ) tt_driver_class;
+
+
+FT_END_HEADER
+
+#endif /* __TTDRIVER_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* tterrors.h */
+/* */
+/* TrueType error codes (specification only). */
+/* */
+/* Copyright 2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the TrueType error enumeration */
+ /* constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __TTERRORS_H__
+#define __TTERRORS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX TT_Err_
+#define FT_ERR_BASE FT_Mod_Err_TrueType
+
+#include FT_ERRORS_H
+
+#endif /* __TTERRORS_H__ */
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ttgload.h */
+/* */
+/* TrueType Glyph Loader (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTGLOAD_H__
+#define __TTGLOAD_H__
+
+
+#include <ft2build.h>
+#include "ttobjs.h"
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+#include "ttinterp.h"
+#endif
+
+
+FT_BEGIN_HEADER
+
+
+ FT_LOCAL void
+ TT_Get_Metrics( TT_HoriHeader* header,
+ FT_UInt index,
+ FT_Short* bearing,
+ FT_UShort* advance );
+
+ FT_LOCAL void
+ TT_Init_Glyph_Loading( TT_Face face );
+
+ FT_LOCAL FT_Error
+ TT_Load_Glyph( TT_Size size,
+ TT_GlyphSlot glyph,
+ FT_UShort glyph_index,
+ FT_UInt load_flags );
+
+
+FT_END_HEADER
+
+#endif /* __TTGLOAD_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ttinterp.h */
+/* */
+/* TrueType bytecode interpreter (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTINTERP_H__
+#define __TTINTERP_H__
+
+
+#include <ft2build.h>
+#include "ttobjs.h"
+
+
+FT_BEGIN_HEADER
+
+
+#ifndef TT_CONFIG_OPTION_STATIC_INTEPRETER /* indirect implementation */
+
+#define EXEC_OP_ TT_ExecContext exc,
+#define EXEC_OP TT_ExecContext exc
+#define EXEC_ARG_ exc,
+#define EXEC_ARG exc
+
+#else /* static implementation */
+
+#define EXEC_OP_ /* void */
+#define EXEC_OP /* void */
+#define EXEC_ARG_ /* void */
+#define EXEC_ARG /* void */
+
+#endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */
+
+
+ /*************************************************************************/
+ /* */
+ /* Rounding mode constants. */
+ /* */
+#define TT_Round_Off 5
+#define TT_Round_To_Half_Grid 0
+#define TT_Round_To_Grid 1
+#define TT_Round_To_Double_Grid 2
+#define TT_Round_Up_To_Grid 4
+#define TT_Round_Down_To_Grid 3
+#define TT_Round_Super 6
+#define TT_Round_Super_45 7
+
+
+ /*************************************************************************/
+ /* */
+ /* Function types used by the interpreter, depending on various modes */
+ /* (e.g. the rounding mode, whether to render a vertical or horizontal */
+ /* line etc). */
+ /* */
+ /*************************************************************************/
+
+ /* Rounding function */
+ typedef FT_F26Dot6
+ (*TT_Round_Func)( EXEC_OP_ FT_F26Dot6 distance,
+ FT_F26Dot6 compensation );
+
+ /* Point displacement along the freedom vector routine */
+ typedef void
+ (*TT_Move_Func)( EXEC_OP_ TT_GlyphZone* zone,
+ FT_UShort point,
+ FT_F26Dot6 distance );
+
+ /* Distance projection along one of the projection vectors */
+ typedef FT_F26Dot6
+ (*TT_Project_Func)( EXEC_OP_ FT_Vector* v1,
+ FT_Vector* v2 );
+
+ /* reading a cvt value. Take care of non-square pixels if necessary */
+ typedef FT_F26Dot6
+ (*TT_Get_CVT_Func)( EXEC_OP_ FT_ULong index );
+
+ /* setting or moving a cvt value. Take care of non-square pixels */
+ /* if necessary */
+ typedef void
+ (*TT_Set_CVT_Func)( EXEC_OP_ FT_ULong index,
+ FT_F26Dot6 value );
+
+
+ /*************************************************************************/
+ /* */
+ /* This structure defines a call record, used to manage function calls. */
+ /* */
+ typedef struct TT_CallRec_
+ {
+ FT_Int Caller_Range;
+ FT_Long Caller_IP;
+ FT_Long Cur_Count;
+ FT_Long Cur_Restart;
+
+ } TT_CallRec, *TT_CallStack;
+
+
+ /*************************************************************************/
+ /* */
+ /* The main structure for the interpreter which collects all necessary */
+ /* variables and states. */
+ /* */
+ typedef struct TT_ExecContextRec_
+ {
+ TT_Face face;
+ TT_Size size;
+ FT_Memory memory;
+
+ /* instructions state */
+
+ FT_Error error; /* last execution error */
+
+ FT_Long top; /* top of exec. stack */
+
+ FT_UInt stackSize; /* size of exec. stack */
+ FT_Long* stack; /* current exec. stack */
+
+ FT_Long args;
+ FT_UInt new_top; /* new top after exec. */
+
+ TT_GlyphZone zp0, /* zone records */
+ zp1,
+ zp2,
+ pts,
+ twilight;
+
+ FT_Size_Metrics metrics;
+ TT_Size_Metrics tt_metrics; /* size metrics */
+
+ TT_GraphicsState GS; /* current graphics state */
+
+ FT_Int curRange; /* current code range number */
+ FT_Byte* code; /* current code range */
+ FT_Long IP; /* current instruction pointer */
+ FT_Long codeSize; /* size of current range */
+
+ FT_Byte opcode; /* current opcode */
+ FT_Int length; /* length of current opcode */
+
+ FT_Bool step_ins; /* true if the interpreter must */
+ /* increment IP after ins. exec */
+ FT_Long cvtSize;
+ FT_Long* cvt;
+
+ FT_UInt glyphSize; /* glyph instructions buffer size */
+ FT_Byte* glyphIns; /* glyph instructions buffer */
+
+ FT_UInt numFDefs; /* number of function defs */
+ FT_UInt maxFDefs; /* maximum number of function defs */
+ TT_DefArray FDefs; /* table of FDefs entries */
+
+ FT_UInt numIDefs; /* number of instruction defs */
+ FT_UInt maxIDefs; /* maximum number of ins defs */
+ TT_DefArray IDefs; /* table of IDefs entries */
+
+ FT_UInt maxFunc; /* maximum function index */
+ FT_UInt maxIns; /* maximum instruction index */
+
+ FT_Int callTop, /* top of call stack during execution */
+ callSize; /* size of call stack */
+ TT_CallStack callStack; /* call stack */
+
+ FT_UShort maxPoints; /* capacity of this context's `pts' */
+ FT_Short maxContours; /* record, expressed in points and */
+ /* contours. */
+
+ TT_CodeRangeTable codeRangeTable; /* table of valid code ranges */
+ /* useful for the debugger */
+
+ FT_UShort storeSize; /* size of current storage */
+ FT_Long* storage; /* storage area */
+
+ FT_F26Dot6 period; /* values used for the */
+ FT_F26Dot6 phase; /* `SuperRounding' */
+ FT_F26Dot6 threshold;
+
+#if 0
+ /* this seems to be unused */
+ FT_Int cur_ppem; /* ppem along the current proj vector */
+#endif
+
+ FT_Bool instruction_trap; /* If `True', the interpreter will */
+ /* exit after each instruction */
+
+ TT_GraphicsState default_GS; /* graphics state resulting from */
+ /* the prep program */
+ FT_Bool is_composite; /* true if the glyph is composite */
+ FT_Bool pedantic_hinting; /* true for pedantic interpretation */
+
+ /* latest interpreter additions */
+
+ FT_Long F_dot_P; /* dot product of freedom and projection */
+ /* vectors */
+ TT_Round_Func func_round; /* current rounding function */
+
+ TT_Project_Func func_project, /* current projection function */
+ func_dualproj, /* current dual proj. function */
+ func_freeProj; /* current freedom proj. func */
+
+ TT_Move_Func func_move; /* current point move function */
+
+ TT_Get_CVT_Func func_read_cvt; /* read a cvt entry */
+ TT_Set_CVT_Func func_write_cvt; /* write a cvt entry (in pixels) */
+ TT_Set_CVT_Func func_move_cvt; /* incr a cvt entry (in pixels) */
+
+ FT_ULong loadSize;
+ TT_SubGlyph_Stack loadStack; /* loading subglyph stack */
+
+ } TT_ExecContextRec;
+
+
+ extern const TT_GraphicsState tt_default_graphics_state;
+
+
+ FT_LOCAL FT_Error
+ TT_Goto_CodeRange( TT_ExecContext exec,
+ FT_Int range,
+ FT_Long IP );
+
+ FT_LOCAL FT_Error
+ TT_Set_CodeRange( TT_ExecContext exec,
+ FT_Int range,
+ void* base,
+ FT_Long length );
+
+ FT_LOCAL FT_Error
+ TT_Clear_CodeRange( TT_ExecContext exec,
+ FT_Int range );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_New_Context */
+ /* */
+ /* <Description> */
+ /* Queries the face context for a given font. Note that there is */
+ /* now a _single_ execution context in the TrueType driver which is */
+ /* shared among faces. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* <Return> */
+ /* A handle to the execution context. Initialized for `face'. */
+ /* */
+ /* <Note> */
+ /* Only the glyph loader and debugger should call this function. */
+ /* */
+ FT_EXPORT( TT_ExecContext )
+ TT_New_Context( TT_Face face );
+
+
+ FT_LOCAL FT_Error
+ TT_Done_Context( TT_ExecContext exec );
+
+ FT_LOCAL FT_Error
+ TT_Destroy_Context( TT_ExecContext exec,
+ FT_Memory memory );
+
+ FT_LOCAL FT_Error
+ TT_Load_Context( TT_ExecContext exec,
+ TT_Face face,
+ TT_Size size );
+
+ FT_LOCAL FT_Error
+ TT_Save_Context( TT_ExecContext exec,
+ TT_Size ins );
+
+ FT_LOCAL FT_Error
+ TT_Run_Context( TT_ExecContext exec,
+ FT_Bool debug );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_RunIns */
+ /* */
+ /* <Description> */
+ /* Executes one or more instruction in the execution context. This */
+ /* is the main function of the TrueType opcode interpreter. */
+ /* */
+ /* <Input> */
+ /* exec :: A handle to the target execution context. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Only the object manager and debugger should call this function. */
+ /* */
+ /* This function is publicly exported because it is directly */
+ /* invoked by the TrueType debugger. */
+ /* */
+ FT_EXPORT( FT_Error )
+ TT_RunIns( TT_ExecContext exec );
+
+
+FT_END_HEADER
+
+#endif /* __TTINTERP_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ttload.h */
+/* */
+/* Load the basic TrueType tables, i.e., tables that can be either in */
+/* TTF or OTF fonts (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTLOAD_H__
+#define __TTLOAD_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_LOCAL TT_Table*
+ TT_LookUp_Table( TT_Face face,
+ FT_ULong tag );
+
+ FT_LOCAL FT_Error
+ TT_Goto_Table( TT_Face face,
+ FT_ULong tag,
+ FT_Stream stream,
+ FT_ULong* length );
+
+
+ FT_LOCAL FT_Error
+ TT_Load_SFNT_Header( TT_Face face,
+ FT_Stream stream,
+ FT_Long face_index,
+ SFNT_Header* sfnt );
+
+ FT_LOCAL FT_Error
+ TT_Load_Directory( TT_Face face,
+ FT_Stream stream,
+ SFNT_Header* sfnt );
+
+ FT_LOCAL FT_Error
+ TT_Load_Any( TT_Face face,
+ FT_ULong tag,
+ FT_Long offset,
+ FT_Byte* buffer,
+ FT_ULong* length );
+
+
+ FT_LOCAL FT_Error
+ TT_Load_Header( TT_Face face,
+ FT_Stream stream );
+
+
+ FT_LOCAL FT_Error
+ TT_Load_Metrics_Header( TT_Face face,
+ FT_Stream stream,
+ FT_Bool vertical );
+
+
+ FT_LOCAL FT_Error
+ TT_Load_CMap( TT_Face face,
+ FT_Stream stream );
+
+
+ FT_LOCAL FT_Error
+ TT_Load_MaxProfile( TT_Face face,
+ FT_Stream stream );
+
+
+ FT_LOCAL FT_Error
+ TT_Load_Names( TT_Face face,
+ FT_Stream stream );
+
+
+ FT_LOCAL FT_Error
+ TT_Load_OS2( TT_Face face,
+ FT_Stream stream );
+
+
+ FT_LOCAL FT_Error
+ TT_Load_PostScript( TT_Face face,
+ FT_Stream stream );
+
+
+ FT_LOCAL FT_Error
+ TT_Load_Hdmx( TT_Face face,
+ FT_Stream stream );
+
+ FT_LOCAL FT_Error
+ TT_Load_PCLT( TT_Face face,
+ FT_Stream stream );
+
+ FT_LOCAL void
+ TT_Free_Names( TT_Face face );
+
+
+ FT_LOCAL void
+ TT_Free_Hdmx ( TT_Face face );
+
+
+ FT_LOCAL FT_Error
+ TT_Load_Kern( TT_Face face,
+ FT_Stream stream );
+
+
+ FT_LOCAL FT_Error
+ TT_Load_Gasp( TT_Face face,
+ FT_Stream stream );
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ FT_LOCAL FT_Error
+ TT_Load_Bitmap_Header( TT_Face face,
+ FT_Stream stream );
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+
+FT_END_HEADER
+
+#endif /* __TTLOAD_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ttobjs.h */
+/* */
+/* Objects manager (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTOBJS_H__
+#define __TTOBJS_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* TT_Driver */
+ /* */
+ /* <Description> */
+ /* A handle to a TrueType driver object. */
+ /* */
+ typedef struct TT_DriverRec_* TT_Driver;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* TT_Instance */
+ /* */
+ /* <Description> */
+ /* A handle to a TrueType size object. */
+ /* */
+ typedef struct TT_SizeRec_* TT_Size;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Type> */
+ /* TT_GlyphSlot */
+ /* */
+ /* <Description> */
+ /* A handle to a TrueType glyph slot object. */
+ /* */
+ /* <Note> */
+ /* This is a direct typedef of FT_GlyphSlot, as there is nothing */
+ /* specific about the TrueType glyph slot. */
+ /* */
+ typedef FT_GlyphSlot TT_GlyphSlot;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Struct> */
+ /* TT_GraphicsState */
+ /* */
+ /* <Description> */
+ /* The TrueType graphics state used during bytecode interpretation. */
+ /* */
+ typedef struct TT_GraphicsState_
+ {
+ FT_UShort rp0;
+ FT_UShort rp1;
+ FT_UShort rp2;
+
+ FT_UnitVector dualVector;
+ FT_UnitVector projVector;
+ FT_UnitVector freeVector;
+
+ FT_Long loop;
+ FT_F26Dot6 minimum_distance;
+ FT_Int round_state;
+
+ FT_Bool auto_flip;
+ FT_F26Dot6 control_value_cutin;
+ FT_F26Dot6 single_width_cutin;
+ FT_F26Dot6 single_width_value;
+ FT_Short delta_base;
+ FT_Short delta_shift;
+
+ FT_Byte instruct_control;
+ FT_Bool scan_control;
+ FT_Int scan_type;
+
+ FT_UShort gep0;
+ FT_UShort gep1;
+ FT_UShort gep2;
+
+ } TT_GraphicsState;
+
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ FT_LOCAL void
+ TT_Done_GlyphZone( TT_GlyphZone* zone );
+
+ FT_LOCAL FT_Error
+ TT_New_GlyphZone( FT_Memory memory,
+ FT_UShort maxPoints,
+ FT_Short maxContours,
+ TT_GlyphZone* zone );
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+
+
+ /*************************************************************************/
+ /* */
+ /* EXECUTION SUBTABLES */
+ /* */
+ /* These sub-tables relate to instruction execution. */
+ /* */
+ /*************************************************************************/
+
+
+#define TT_MAX_CODE_RANGES 3
+
+
+ /*************************************************************************/
+ /* */
+ /* There can only be 3 active code ranges at once: */
+ /* - the Font Program */
+ /* - the CVT Program */
+ /* - a glyph's instructions set */
+ /* */
+ typedef enum TT_CodeRange_Tag_
+ {
+ tt_coderange_none = 0,
+ tt_coderange_font,
+ tt_coderange_cvt,
+ tt_coderange_glyph
+
+ } TT_CodeRange_Tag;
+
+
+ typedef struct TT_CodeRange_
+ {
+ FT_Byte* base;
+ FT_ULong size;
+
+ } TT_CodeRange;
+
+ typedef TT_CodeRange TT_CodeRangeTable[TT_MAX_CODE_RANGES];
+
+
+ /*************************************************************************/
+ /* */
+ /* Defines a function/instruction definition record. */
+ /* */
+ typedef struct TT_DefRecord_
+ {
+ FT_Int range; /* in which code range is it located? */
+ FT_Long start; /* where does it start? */
+ FT_UInt opc; /* function #, or instruction code */
+ FT_Bool active; /* is it active? */
+
+ } TT_DefRecord, *TT_DefArray;
+
+
+ /*************************************************************************/
+ /* */
+ /* Subglyph transformation record. */
+ /* */
+ typedef struct TT_Transform_
+ {
+ FT_Fixed xx, xy; /* transformation matrix coefficients */
+ FT_Fixed yx, yy;
+ FT_F26Dot6 ox, oy; /* offsets */
+
+ } TT_Transform;
+
+
+ /*************************************************************************/
+ /* */
+ /* Subglyph loading record. Used to load composite components. */
+ /* */
+ typedef struct TT_SubglyphRec_
+ {
+ FT_Long index; /* subglyph index; initialized with -1 */
+ FT_Bool is_scaled; /* is the subglyph scaled? */
+ FT_Bool is_hinted; /* should it be hinted? */
+ FT_Bool preserve_pps; /* preserve phantom points? */
+
+ FT_Long file_offset;
+
+ FT_BBox bbox;
+ FT_Pos left_bearing;
+ FT_Pos advance;
+
+ TT_GlyphZone zone;
+
+ FT_Long arg1; /* first argument */
+ FT_Long arg2; /* second argument */
+
+ FT_UShort element_flag; /* current load element flag */
+
+ TT_Transform transform; /* transformation matrix */
+
+ FT_Vector pp1, pp2; /* phantom points */
+
+ } TT_SubGlyphRec, *TT_SubGlyph_Stack;
+
+
+ /*************************************************************************/
+ /* */
+ /* A note regarding non-squared pixels: */
+ /* */
+ /* (This text will probably go into some docs at some time; for now, it */
+ /* is kept here to explain some definitions in the TIns_Metrics */
+ /* record). */
+ /* */
+ /* The CVT is a one-dimensional array containing values that control */
+ /* certain important characteristics in a font, like the height of all */
+ /* capitals, all lowercase letter, default spacing or stem width/height. */
+ /* */
+ /* These values are found in FUnits in the font file, and must be scaled */
+ /* to pixel coordinates before being used by the CVT and glyph programs. */
+ /* Unfortunately, when using distinct x and y resolutions (or distinct x */
+ /* and y pointsizes), there are two possible scalings. */
+ /* */
+ /* A first try was to implement a `lazy' scheme where all values were */
+ /* scaled when first used. However, while some values are always used */
+ /* in the same direction, some others are used under many different */
+ /* circumstances and orientations. */
+ /* */
+ /* I have found a simpler way to do the same, and it even seems to work */
+ /* in most of the cases: */
+ /* */
+ /* - All CVT values are scaled to the maximum ppem size. */
+ /* */
+ /* - When performing a read or write in the CVT, a ratio factor is used */
+ /* to perform adequate scaling. Example: */
+ /* */
+ /* x_ppem = 14 */
+ /* y_ppem = 10 */
+ /* */
+ /* We choose ppem = x_ppem = 14 as the CVT scaling size. All cvt */
+ /* entries are scaled to it. */
+ /* */
+ /* x_ratio = 1.0 */
+ /* y_ratio = y_ppem/ppem (< 1.0) */
+ /* */
+ /* We compute the current ratio like: */
+ /* */
+ /* - If projVector is horizontal, */
+ /* ratio = x_ratio = 1.0 */
+ /* */
+ /* - if projVector is vertical, */
+ /* ratio = y_ratio */
+ /* */
+ /* - else, */
+ /* ratio = sqrt( (proj.x * x_ratio) ^ 2 + (proj.y * y_ratio) ^ 2 ) */
+ /* */
+ /* Reading a cvt value returns */
+ /* ratio * cvt[index] */
+ /* */
+ /* Writing a cvt value in pixels: */
+ /* cvt[index] / ratio */
+ /* */
+ /* The current ppem is simply */
+ /* ratio * ppem */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* Metrics used by the TrueType size and context objects. */
+ /* */
+ typedef struct TT_Size_Metrics_
+ {
+ /* for non-square pixels */
+ FT_Long x_ratio;
+ FT_Long y_ratio;
+
+ FT_UShort ppem; /* maximum ppem size */
+ FT_Long ratio; /* current ratio */
+ FT_Fixed scale;
+
+ FT_F26Dot6 compensations[4]; /* device-specific compensations */
+
+ FT_Bool valid;
+
+ FT_Bool rotated; /* `is the glyph rotated?'-flag */
+ FT_Bool stretched; /* `is the glyph stretched?'-flag */
+
+ } TT_Size_Metrics;
+
+
+ /*************************************************************************/
+ /* */
+ /* TrueType size class. */
+ /* */
+ typedef struct TT_SizeRec_
+ {
+ FT_SizeRec root;
+
+ TT_Size_Metrics ttmetrics;
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ FT_UInt strike_index; /* 0xFFFF to indicate invalid */
+ FT_Size_Metrics strike_metrics; /* current strike's metrics */
+
+#endif
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ FT_UInt num_function_defs; /* number of function definitions */
+ FT_UInt max_function_defs;
+ TT_DefArray function_defs; /* table of function definitions */
+
+ FT_UInt num_instruction_defs; /* number of ins. definitions */
+ FT_UInt max_instruction_defs;
+ TT_DefArray instruction_defs; /* table of ins. definitions */
+
+ FT_UInt max_func;
+ FT_UInt max_ins;
+
+ TT_CodeRangeTable codeRangeTable;
+
+ TT_GraphicsState GS;
+
+ FT_ULong cvt_size; /* the scaled control value table */
+ FT_Long* cvt;
+
+ FT_UShort storage_size; /* The storage area is now part of */
+ FT_Long* storage; /* the instance */
+
+ TT_GlyphZone twilight; /* The instance's twilight zone */
+
+ /* debugging variables */
+
+ /* When using the debugger, we must keep the */
+ /* execution context tied to the instance */
+ /* object rather than asking it on demand. */
+
+ FT_Bool debug;
+ TT_ExecContext context;
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+ } TT_SizeRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* TrueType driver class. */
+ /* */
+ typedef struct TT_DriverRec_
+ {
+ FT_DriverRec root;
+ TT_ExecContext context; /* execution context */
+ TT_GlyphZone zone; /* glyph loader points zone */
+
+ void* extension_component;
+
+ } TT_DriverRec;
+
+
+ /*************************************************************************/
+ /* */
+ /* Face functions */
+ /* */
+ FT_LOCAL FT_Error
+ TT_Init_Face( FT_Stream stream,
+ TT_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params );
+
+ FT_LOCAL void
+ TT_Done_Face( TT_Face face );
+
+
+ /*************************************************************************/
+ /* */
+ /* Size functions */
+ /* */
+ FT_LOCAL FT_Error
+ TT_Init_Size( TT_Size size );
+
+ FT_LOCAL void
+ TT_Done_Size( TT_Size size );
+
+ FT_LOCAL FT_Error
+ TT_Reset_Size( TT_Size size );
+
+
+ /*************************************************************************/
+ /* */
+ /* Driver functions */
+ /* */
+ FT_LOCAL FT_Error
+ TT_Init_Driver( TT_Driver driver );
+
+ FT_LOCAL void
+ TT_Done_Driver( TT_Driver driver );
+
+
+FT_END_HEADER
+
+#endif /* __TTOBJS_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ttpload.h */
+/* */
+/* TrueType glyph data/program tables loader (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTPLOAD_H__
+#define __TTPLOAD_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_LOCAL FT_Error
+ TT_Load_Locations( TT_Face face,
+ FT_Stream stream );
+
+ FT_LOCAL FT_Error
+ TT_Load_CVT( TT_Face face,
+ FT_Stream stream );
+
+ FT_LOCAL FT_Error
+ TT_Load_Programs( TT_Face face,
+ FT_Stream stream );
+
+
+FT_END_HEADER
+
+#endif /* __TTPLOAD_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ttpost.h */
+/* */
+/* Postcript name table processing for TrueType and OpenType fonts */
+/* (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTPOST_H__
+#define __TTPOST_H__
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_LOCAL FT_Error
+ TT_Get_PS_Name( TT_Face face,
+ FT_UInt index,
+ FT_String** PSname );
+
+ FT_LOCAL void
+ TT_Free_Post_Names( TT_Face face );
+
+
+FT_END_HEADER
+
+#endif /* __TTPOST_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ttsbit.h */
+/* */
+/* TrueType and OpenType embedded bitmap support (specification). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __TTSBIT_H__
+#define __TTSBIT_H__
+
+
+#include <ft2build.h>
+#include "ttload.h"
+
+
+FT_BEGIN_HEADER
+
+
+ FT_LOCAL FT_Error
+ TT_Load_SBit_Strikes( TT_Face face,
+ FT_Stream stream );
+
+ FT_LOCAL void
+ TT_Free_SBit_Strikes( TT_Face face );
+
+
+ FT_LOCAL FT_Error
+ TT_Set_SBit_Strike( TT_Face face,
+ FT_Int x_ppem,
+ FT_Int y_ppem,
+ FT_ULong *astrike_index );
+
+ FT_LOCAL FT_Error
+ TT_Load_SBit_Image( TT_Face face,
+ FT_ULong strike_index,
+ FT_UInt glyph_index,
+ FT_UInt load_flags,
+ FT_Stream stream,
+ FT_Bitmap *map,
+ TT_SBit_Metrics *metrics );
+
+
+FT_END_HEADER
+
+#endif /* __TTSBIT_H__ */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* winfnt.h */
+/* */
+/* FreeType font driver for Windows FNT/FON files */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __WINFNT_H__
+#define __WINFNT_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+
+FT_BEGIN_HEADER
+
+
+ FT_EXPORT_VAR( const FT_Driver_Class ) winfnt_driver_class;
+
+
+FT_END_HEADER
+
+
+#endif /* __WINFNT_H__ */
+
+
+/* END */
--- /dev/null
+
+FreeType comes with two licenses from which you can choose the one which
+fits your needs best:
+
+ . The FreeType License, in file `docs/FTL.txt'.
+
+ . The GNU General Public License, in file `docs/GPL.txt'.
+
+The contributed PCF driver comes with a license similar to that of X Windows
+which is compatible to the above two licenses (see file src/pcf/readme).
--- /dev/null
+/* pcf.c
+
+ FreeType font driver for pcf fonts
+
+ Copyright 2000-2001 by
+ Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+
+#include <ft2build.h>
+#include "pcfutil.c"
+#include "pcfread.c"
+#include "pcfdriver.c"
+
+/* END */
--- /dev/null
+/* pcfdriver.c
+
+ FreeType font driver for pcf files
+
+ Copyright (C) 2000-2001 by
+ Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#include <ft2build.h>
+
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "pcf.h"
+#include "pcfdriver.h"
+#include "pcfutil.h"
+
+#include "pcferror.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_pcfdriver
+
+
+ FT_LOCAL_DEF FT_Error
+ PCF_Done_Face( PCF_Face face )
+ {
+ FT_Memory memory = FT_FACE_MEMORY( face );
+ PCF_Property tmp = face->properties;
+ int i;
+
+
+ FREE( face->encodings );
+ FREE( face->metrics );
+
+ for ( i = 0; i < face->nprops; i++ )
+ {
+ FREE( tmp->name );
+ if ( tmp->isString )
+ FREE( tmp->value );
+ }
+ FREE( face->properties );
+
+ FT_TRACE4(( "DONE_FACE!!!\n" ));
+
+ return PCF_Err_Ok;
+ }
+
+
+ static FT_Error
+ PCF_Init_Face( FT_Stream stream,
+ PCF_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ FT_Error error = PCF_Err_Ok;
+
+ FT_UNUSED( num_params );
+ FT_UNUSED( params );
+ FT_UNUSED( face_index );
+
+
+ error = pcf_load_font( stream, face );
+ if ( error )
+ goto Fail;
+
+ return PCF_Err_Ok;
+
+ Fail:
+ FT_TRACE2(( "[not a valid PCF file]\n" ));
+ PCF_Done_Face( face );
+
+ return PCF_Err_Unknown_File_Format; /* error */
+ }
+
+
+ static FT_Error
+ PCF_Set_Pixel_Size( FT_Size size )
+ {
+ PCF_Face face = (PCF_Face)FT_SIZE_FACE( size );
+
+
+ FT_TRACE4(( "rec %d - pres %d\n", size->metrics.y_ppem,
+ face->root.available_sizes->height ));
+
+ if ( size->metrics.y_ppem == face->root.available_sizes->height )
+ {
+ size->metrics.ascender = face->accel.fontAscent << 6;
+ size->metrics.descender = face->accel.fontDescent * (-64);
+#if 0
+ size->metrics.height = face->accel.maxbounds.ascent << 6;
+#endif
+ size->metrics.height = size->metrics.ascender -
+ size->metrics.descender;
+
+ return PCF_Err_Ok;
+ }
+ else
+ {
+ FT_TRACE4(( "size WRONG\n" ));
+ return PCF_Err_Invalid_Pixel_Size;
+ }
+ }
+
+
+ static FT_Error
+ PCF_Load_Glyph( FT_GlyphSlot slot,
+ FT_Size size,
+ FT_UInt glyph_index,
+ FT_Int load_flags )
+ {
+ PCF_Face face = (PCF_Face)FT_SIZE_FACE( size );
+ FT_Error error = PCF_Err_Ok;
+ FT_Memory memory = FT_FACE(face)->memory;
+ FT_Bitmap* bitmap = &slot->bitmap;
+ PCF_Metric metric;
+ int bytes;
+
+ FT_Stream stream = face->root.stream;
+
+ FT_UNUSED( load_flags );
+
+
+ FT_TRACE4(( "load_glyph %d ---", glyph_index ));
+
+ if ( !face )
+ {
+ error = PCF_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ metric = face->metrics + glyph_index;
+
+ bitmap->rows = metric->ascent + metric->descent;
+ bitmap->width = metric->rightSideBearing - metric->leftSideBearing;
+ bitmap->num_grays = 1;
+ bitmap->pixel_mode = ft_pixel_mode_mono;
+
+ FT_TRACE6(( "BIT_ORDER %d ; BYTE_ORDER %d ; GLYPH_PAD %d\n",
+ PCF_BIT_ORDER( face->bitmapsFormat ),
+ PCF_BYTE_ORDER( face->bitmapsFormat ),
+ PCF_GLYPH_PAD( face->bitmapsFormat ) ));
+
+ switch ( PCF_GLYPH_PAD( face->bitmapsFormat ) )
+ {
+ case 1:
+ bitmap->pitch = ( bitmap->width + 7 ) >> 3;
+ break;
+
+ case 2:
+ bitmap->pitch = ( ( bitmap->width + 15 ) >> 4 ) << 1;
+ break;
+
+ case 4:
+ bitmap->pitch = ( ( bitmap->width + 31 ) >> 5 ) << 2;
+ break;
+
+ case 8:
+ bitmap->pitch = ( ( bitmap->width + 63 ) >> 6 ) << 3;
+ break;
+
+ default:
+ return PCF_Err_Invalid_File_Format;
+ }
+
+ /* XXX: to do: are there cases that need repadding the bitmap? */
+ bytes = bitmap->pitch * bitmap->rows;
+
+ if ( ALLOC( bitmap->buffer, bytes ) )
+ goto Exit;
+
+ if ( FILE_Seek( metric->bits ) ||
+ FILE_Read( bitmap->buffer, bytes ) )
+ goto Exit;
+
+ if ( PCF_BIT_ORDER( face->bitmapsFormat ) != MSBFirst )
+ BitOrderInvert( bitmap->buffer,bytes );
+
+ if ( ( PCF_BYTE_ORDER( face->bitmapsFormat ) !=
+ PCF_BIT_ORDER( face->bitmapsFormat ) ) )
+ {
+ switch ( PCF_SCAN_UNIT( face->bitmapsFormat ) )
+ {
+ case 1:
+ break;
+
+ case 2:
+ TwoByteSwap( bitmap->buffer, bytes );
+ break;
+
+ case 4:
+ FourByteSwap( bitmap->buffer, bytes );
+ break;
+ }
+ }
+
+ slot->bitmap_left = metric->leftSideBearing;
+ slot->bitmap_top = metric->ascent;
+
+ slot->metrics.horiAdvance = metric->characterWidth << 6 ;
+ slot->metrics.horiBearingX = metric->rightSideBearing << 6 ;
+ slot->metrics.horiBearingY = metric->ascent << 6 ;
+ slot->metrics.width = metric->characterWidth << 6 ;
+ slot->metrics.height = bitmap->rows << 6;
+
+ slot->linearHoriAdvance = (FT_Fixed)bitmap->width << 16;
+ slot->format = ft_glyph_format_bitmap;
+ slot->flags = ft_glyph_own_bitmap;
+
+ FT_TRACE4(( " --- ok\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_UInt
+ PCF_Get_Char_Index( FT_CharMap charmap,
+ FT_Long char_code )
+ {
+ PCF_Face face = (PCF_Face)charmap->face;
+ PCF_Encoding en_table = face->encodings;
+ int low, high, mid;
+
+
+ FT_TRACE4(( "get_char_index %ld\n", char_code ));
+
+ low = 0;
+ high = face->nencodings - 1;
+ while ( low <= high )
+ {
+ mid = ( low + high ) / 2;
+ if ( char_code < en_table[mid].enc )
+ high = mid - 1;
+ else if ( char_code > en_table[mid].enc )
+ low = mid + 1;
+ else
+ return en_table[mid].glyph;
+ }
+
+ return 0;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Driver_Class pcf_driver_class =
+ {
+ {
+ ft_module_font_driver,
+ sizeof ( FT_DriverRec ),
+
+ "pcf",
+ 0x10000L,
+ 0x20000L,
+
+ 0,
+
+ (FT_Module_Constructor)0,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) 0
+ },
+
+ sizeof( PCF_FaceRec ),
+ sizeof( FT_SizeRec ),
+ sizeof( FT_GlyphSlotRec ),
+
+ (FTDriver_initFace) PCF_Init_Face,
+ (FTDriver_doneFace) PCF_Done_Face,
+ (FTDriver_initSize) 0,
+ (FTDriver_doneSize) 0,
+ (FTDriver_initGlyphSlot)0,
+ (FTDriver_doneGlyphSlot)0,
+
+ (FTDriver_setCharSizes) PCF_Set_Pixel_Size,
+ (FTDriver_setPixelSizes)PCF_Set_Pixel_Size,
+
+ (FTDriver_loadGlyph) PCF_Load_Glyph,
+ (FTDriver_getCharIndex) PCF_Get_Char_Index,
+
+ (FTDriver_getKerning) 0,
+ (FTDriver_attachFile) 0,
+ (FTDriver_getAdvances) 0
+ };
+
+
+#ifdef FT_CONFIG_OPTION_DYNAMIC_DRIVERS
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* getDriverClass */
+ /* */
+ /* <Description> */
+ /* This function is used when compiling the TrueType driver as a */
+ /* shared library (`.DLL' or `.so'). It will be used by the */
+ /* high-level library of FreeType to retrieve the address of the */
+ /* driver's generic interface. */
+ /* */
+ /* It shouldn't be implemented in a static build, as each driver must */
+ /* have the same function as an exported entry point. */
+ /* */
+ /* <Return> */
+ /* The address of the TrueType's driver generic interface. The */
+ /* format-specific interface can then be retrieved through the method */
+ /* interface->get_format_interface. */
+ /* */
+ FT_EXPORT_DEF( const FT_Driver_Class* )
+ getDriverClass( void )
+ {
+ return &pcf_driver_class;
+ }
+
+
+#endif /* FT_CONFIG_OPTION_DYNAMIC_DRIVERS */
+
+
+/* END */
--- /dev/null
+/* pcfread.c
+
+ FreeType font driver for pcf fonts
+
+ Copyright 2000-2001 by
+ Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#include <ft2build.h>
+
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "pcf.h"
+#include "pcfdriver.h"
+
+#include "pcferror.h"
+
+#include <string.h> /* strlen(), strcpy() */
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_pcfread
+
+
+#if defined( FT_DEBUG_LEVEL_TRACE )
+ static char* tableNames[] =
+ {
+ "prop", "accl", "mtrcs", "bmps", "imtrcs",
+ "enc", "swidth", "names", "accel"
+ };
+#endif
+
+
+ static
+ const FT_Frame_Field pcf_toc_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_TocRec
+
+ FT_FRAME_START( 8 ),
+ FT_FRAME_ULONG_LE( version ),
+ FT_FRAME_ULONG_LE( count ),
+ FT_FRAME_END
+ };
+
+
+ static
+ const FT_Frame_Field pcf_table_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_TableRec
+
+ FT_FRAME_START( 16 ),
+ FT_FRAME_ULONG_LE( type ),
+ FT_FRAME_ULONG_LE( format ),
+ FT_FRAME_ULONG_LE( size ),
+ FT_FRAME_ULONG_LE( offset ),
+ FT_FRAME_END
+ };
+
+
+ static FT_Error
+ pcf_read_TOC( FT_Stream stream,
+ PCF_Face face )
+ {
+ FT_Error error;
+ PCF_Toc toc = &face->toc;
+ PCF_Table tables;
+
+ FT_Memory memory = FT_FACE(face)->memory;
+ unsigned int i;
+
+
+ if ( FILE_Seek ( 0 ) ||
+ READ_Fields ( pcf_toc_header, toc ) )
+ return PCF_Err_Cannot_Open_Resource;
+
+ if ( toc->version != PCF_FILE_VERSION )
+ return PCF_Err_Invalid_File_Format;
+
+ if ( ALLOC( face->toc.tables, toc->count * sizeof ( PCF_TableRec ) ) )
+ return PCF_Err_Out_Of_Memory;
+
+ tables = face->toc.tables;
+ for ( i = 0; i < toc->count; i++ )
+ {
+ if ( READ_Fields( pcf_table_header, tables ) )
+ goto Exit;
+ tables++;
+ }
+
+#if defined( FT_DEBUG_LEVEL_TRACE )
+
+ {
+ unsigned int i,j;
+ char* name = "?";
+
+
+ FT_TRACE4(( "Tables count: %ld\n", face->toc.count ));
+ tables = face->toc.tables;
+ for ( i = 0; i < toc->count; i++ )
+ {
+ for( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] ); j++ )
+ if ( tables[i].type == (unsigned int)( 1 << j ) )
+ name=tableNames[j];
+ FT_TRACE4(( "Table %d: type=%-6s format=0x%04lX "
+ "size=0x%06lX (%8ld) offset=0x%04lX\n",
+ i, name,
+ tables[i].format,
+ tables[i].size, tables[i].size,
+ tables[i].offset ));
+ }
+ }
+
+#endif
+
+ return PCF_Err_Ok;
+
+ Exit:
+ FREE( face->toc.tables );
+ return error;
+ }
+
+
+ static
+ const FT_Frame_Field pcf_metric_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_MetricRec
+
+ FT_FRAME_START( 12 ),
+ FT_FRAME_SHORT_LE( leftSideBearing ),
+ FT_FRAME_SHORT_LE( rightSideBearing ),
+ FT_FRAME_SHORT_LE( characterWidth ),
+ FT_FRAME_SHORT_LE( ascent ),
+ FT_FRAME_SHORT_LE( descent ),
+ FT_FRAME_SHORT_LE( attributes ),
+ FT_FRAME_END
+ };
+
+
+ static
+ const FT_Frame_Field pcf_metric_msb_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_MetricRec
+
+ FT_FRAME_START( 12 ),
+ FT_FRAME_SHORT( leftSideBearing ),
+ FT_FRAME_SHORT( rightSideBearing ),
+ FT_FRAME_SHORT( characterWidth ),
+ FT_FRAME_SHORT( ascent ),
+ FT_FRAME_SHORT( descent ),
+ FT_FRAME_SHORT( attributes ),
+ FT_FRAME_END
+ };
+
+
+ static
+ const FT_Frame_Field pcf_compressed_metric_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_Compressed_MetricRec
+
+ FT_FRAME_START( 5 ),
+ FT_FRAME_BYTE( leftSideBearing ),
+ FT_FRAME_BYTE( rightSideBearing ),
+ FT_FRAME_BYTE( characterWidth ),
+ FT_FRAME_BYTE( ascent ),
+ FT_FRAME_BYTE( descent ),
+ FT_FRAME_END
+ };
+
+
+ static FT_Error
+ pcf_parse_metric( FT_Stream stream,
+ const FT_Frame_Field* header,
+ PCF_Metric metric )
+ {
+ FT_Error error = PCF_Err_Ok;
+
+
+ if ( READ_Fields( header, metric ) )
+ return error;
+
+ return PCF_Err_Ok;
+ }
+
+
+ static FT_Error
+ pcf_parse_compressed_metric( FT_Stream stream,
+ PCF_Metric metric )
+ {
+ PCF_Compressed_MetricRec compr_metric;
+ FT_Error error = PCF_Err_Ok;
+
+
+ if ( READ_Fields( pcf_compressed_metric_header, &compr_metric ) )
+ return error;
+
+ metric->leftSideBearing =
+ (FT_Short)( compr_metric.leftSideBearing - 0x80 );
+ metric->rightSideBearing =
+ (FT_Short)( compr_metric.rightSideBearing - 0x80 );
+ metric->characterWidth =
+ (FT_Short)( compr_metric.characterWidth - 0x80 );
+ metric->ascent =
+ (FT_Short)( compr_metric.ascent - 0x80 );
+ metric->descent =
+ (FT_Short)( compr_metric.descent - 0x80 );
+ metric->attributes = 0;
+
+ return PCF_Err_Ok;
+ }
+
+
+ static FT_Error
+ pcf_get_metric( FT_Stream stream,
+ FT_ULong format,
+ PCF_Metric metric )
+ {
+ FT_Error error = PCF_Err_Ok;
+
+
+ if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+ {
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ error = pcf_parse_metric( stream, pcf_metric_msb_header, metric );
+ else
+ error = pcf_parse_metric( stream, pcf_metric_header, metric );
+ }
+ else
+ error = pcf_parse_compressed_metric( stream, metric );
+
+ return error;
+ }
+
+
+ static FT_Error
+ pcfSeekToType( FT_Stream stream,
+ PCF_Table tables,
+ int ntables,
+ FT_ULong type,
+ FT_ULong* formatp,
+ FT_ULong* sizep )
+ {
+ FT_Error error;
+ int i;
+
+
+ for ( i = 0; i < ntables; i++ )
+ if ( tables[i].type == type )
+ {
+ if ( stream->pos > tables[i].offset )
+ return PCF_Err_Invalid_Stream_Skip;
+ if ( FILE_Skip( tables[i].offset - stream->pos ) )
+ return PCF_Err_Invalid_Stream_Skip;
+ *sizep = tables[i].size; /* unused - to be removed */
+ *formatp = tables[i].format;
+ return PCF_Err_Ok;
+ }
+
+ return PCF_Err_Invalid_File_Format;
+ }
+
+
+ static FT_Bool
+ pcfHasType( PCF_Table tables,
+ int ntables,
+ FT_ULong type )
+ {
+ int i;
+
+
+ for ( i = 0; i < ntables; i++ )
+ if ( tables[i].type == type )
+ return TRUE;
+
+ return FALSE;
+ }
+
+
+ static
+ const FT_Frame_Field pcf_property_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_ParsePropertyRec
+
+ FT_FRAME_START( 9 ),
+ FT_FRAME_LONG_LE( name ),
+ FT_FRAME_BYTE ( isString ),
+ FT_FRAME_LONG_LE( value ),
+ FT_FRAME_END
+ };
+
+
+ static
+ const FT_Frame_Field pcf_property_msb_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_ParsePropertyRec
+
+ FT_FRAME_START( 9 ),
+ FT_FRAME_LONG( name ),
+ FT_FRAME_BYTE( isString ),
+ FT_FRAME_LONG( value ),
+ FT_FRAME_END
+ };
+
+
+ static PCF_Property
+ find_property( PCF_Face face,
+ const FT_String* prop )
+ {
+ PCF_Property properties = face->properties;
+ FT_Bool found = 0;
+ int i;
+
+
+ for ( i = 0 ; i < face->nprops && !found; i++ )
+ {
+ if ( !strcmp( properties[i].name, prop ) )
+ found = 1;
+ }
+
+ if ( found )
+ return properties + i - 1;
+ else
+ return NULL;
+ }
+
+
+ static FT_Error
+ pcf_get_properties( FT_Stream stream,
+ PCF_Face face )
+ {
+ PCF_ParseProperty props = 0;
+ PCF_Property properties = 0;
+ int nprops, i;
+ FT_ULong format, size;
+ FT_Error error;
+ FT_Memory memory = FT_FACE(face)->memory;
+ FT_ULong string_size;
+ FT_String* strings = 0;
+
+
+ error = pcfSeekToType( stream,
+ face->toc.tables,
+ face->toc.count,
+ PCF_PROPERTIES,
+ &format,
+ &size );
+ if ( error )
+ goto Bail;
+
+ if ( READ_ULongLE( format ) )
+ goto Bail;
+
+ FT_TRACE4(( "get_prop: format = %ld\n", format ));
+
+ if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+ goto Bail;
+
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ (void)READ_ULong( nprops );
+ else
+ (void)READ_ULongLE( nprops );
+ if ( error )
+ goto Bail;
+
+ FT_TRACE4(( "get_prop: nprop = %d\n", nprops ));
+
+ if ( ALLOC( props, nprops * sizeof ( PCF_ParsePropertyRec ) ) )
+ goto Bail;
+
+ for ( i = 0; i < nprops; i++ )
+ {
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ {
+ if ( READ_Fields( pcf_property_msb_header, props + i ) )
+ goto Bail;
+ }
+ else
+ {
+ if ( READ_Fields( pcf_property_header, props + i ) )
+ goto Bail;
+ }
+ }
+
+ /* pad the property array */
+ /* */
+ /* clever here - nprops is the same as the number of odd-units read, */
+ /* as only isStringProp are odd length (Keith Packard) */
+ /* */
+ if ( nprops & 3 )
+ {
+ i = 4 - ( nprops & 3 );
+ FT_Skip_Stream( stream, i );
+ }
+
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ (void)READ_ULong( string_size );
+ else
+ (void)READ_ULongLE( string_size );
+ if ( error )
+ goto Bail;
+
+ FT_TRACE4(( "get_prop: string_size = %ld\n", string_size ));
+
+ if ( ALLOC( strings, string_size * sizeof ( char ) ) )
+ goto Bail;
+
+ error = FT_Read_Stream( stream, (FT_Byte*)strings, string_size );
+ if ( error )
+ goto Bail;
+
+ if ( ALLOC( properties, nprops * sizeof ( PCF_PropertyRec ) ) )
+ goto Bail;
+
+ for ( i = 0; i < nprops; i++ )
+ {
+ /* XXX: make atom */
+ if ( ALLOC( properties[i].name,
+ ( strlen( strings + props[i].name ) + 1 ) *
+ sizeof ( char ) ) )
+ goto Bail;
+ strcpy( properties[i].name,strings + props[i].name );
+
+ properties[i].isString = props[i].isString;
+
+ if ( props[i].isString )
+ {
+ if ( ALLOC( properties[i].value.atom,
+ ( strlen( strings + props[i].value ) + 1 ) *
+ sizeof ( char ) ) )
+ goto Bail;
+ strcpy( properties[i].value.atom, strings + props[i].value );
+ }
+ else
+ properties[i].value.integer = props[i].value;
+ }
+
+ face->properties = properties;
+ face->nprops = nprops;
+
+ FREE( props );
+ FREE( strings );
+
+ return PCF_Err_Ok;
+
+ Bail:
+ FREE( props );
+ FREE( strings );
+
+ return error;
+ }
+
+
+ static FT_Error
+ pcf_get_metrics( FT_Stream stream,
+ PCF_Face face )
+ {
+ FT_Error error = PCF_Err_Ok;
+ FT_Memory memory = FT_FACE(face)->memory;
+ FT_ULong format = 0;
+ FT_ULong size = 0;
+ PCF_Metric metrics = 0;
+ int i;
+ int nmetrics = -1;
+
+
+ error = pcfSeekToType( stream,
+ face->toc.tables,
+ face->toc.count,
+ PCF_METRICS,
+ &format,
+ &size );
+ if ( error )
+ return error;
+
+ error = READ_ULongLE( format );
+
+ if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
+ !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )
+ return PCF_Err_Invalid_File_Format;
+
+ if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+ {
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ (void)READ_ULong( nmetrics );
+ else
+ (void)READ_ULongLE( nmetrics );
+ }
+ else
+ {
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ (void)READ_UShort( nmetrics );
+ else
+ (void)READ_UShortLE( nmetrics );
+ }
+ if ( error || nmetrics == -1 )
+ return PCF_Err_Invalid_File_Format;
+
+ face->nmetrics = nmetrics;
+
+ if ( ALLOC( face->metrics, nmetrics * sizeof ( PCF_MetricRec ) ) )
+ return PCF_Err_Out_Of_Memory;
+
+ metrics = face->metrics;
+ for ( i = 0; i < nmetrics; i++ )
+ {
+ pcf_get_metric( stream, format, metrics + i );
+
+ metrics[i].bits = 0;
+
+ FT_TRACE4(( "%d : width=%d, "
+ "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n",
+ i,
+ ( metrics + i )->characterWidth,
+ ( metrics + i )->leftSideBearing,
+ ( metrics + i )->rightSideBearing,
+ ( metrics + i )->ascent,
+ ( metrics + i )->descent,
+ ( metrics + i )->attributes ));
+
+ if ( error )
+ break;
+ }
+
+ if ( error )
+ FREE( face->metrics );
+ return error;
+ }
+
+
+ static FT_Error
+ pcf_get_bitmaps( FT_Stream stream,
+ PCF_Face face )
+ {
+ FT_Error error = PCF_Err_Ok;
+ FT_Memory memory = FT_FACE(face)->memory;
+ FT_Long* offsets;
+ FT_Long bitmapSizes[GLYPHPADOPTIONS];
+ FT_ULong format, size;
+ int nbitmaps, i, sizebitmaps = 0;
+ char* bitmaps;
+
+
+ error = pcfSeekToType( stream,
+ face->toc.tables,
+ face->toc.count,
+ PCF_BITMAPS,
+ &format,
+ &size );
+ if ( error )
+ return error;
+
+ error = FT_Access_Frame( stream, 8 );
+ if ( error )
+ return error;
+ format = GET_ULongLE();
+ if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+ return PCF_Err_Invalid_File_Format;
+
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ nbitmaps = GET_ULong();
+ else
+ nbitmaps = GET_ULongLE();
+ FT_Forget_Frame( stream );
+ if ( nbitmaps != face->nmetrics )
+ return PCF_Err_Invalid_File_Format;
+
+ if ( ALLOC( offsets, nbitmaps * sizeof ( FT_ULong ) ) )
+ return error;
+
+ if ( error )
+ goto Bail;
+ for ( i = 0; i < nbitmaps; i++ )
+ {
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ (void)READ_Long( offsets[i] );
+ else
+ (void)READ_LongLE( offsets[i] );
+
+ FT_TRACE4(( "bitmap %d is at offset %ld\n", i, offsets[i] ));
+ }
+ if ( error )
+ goto Bail;
+
+ if ( error )
+ goto Bail;
+ for ( i = 0; i < GLYPHPADOPTIONS; i++ )
+ {
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ (void)READ_Long( bitmapSizes[i] );
+ else
+ (void)READ_LongLE( bitmapSizes[i] );
+ if ( error )
+ goto Bail;
+
+ sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
+
+ FT_TRACE4(( "padding %d implies a size of %ld\n", i, bitmapSizes[i] ));
+ }
+
+ FT_TRACE4(( " %d bitmaps, padding index %ld\n",
+ nbitmaps,
+ PCF_GLYPH_PAD_INDEX( format ) ));
+ FT_TRACE4(( "bitmap size = %d\n", sizebitmaps ));
+
+ for ( i = 0; i < nbitmaps; i++ )
+ face->metrics[i].bits = stream->pos + offsets[i];
+
+ face->bitmapsFormat = format;
+
+ FREE ( offsets );
+ return error;
+
+ Bail:
+ FREE ( offsets );
+ FREE ( bitmaps );
+ return error;
+ }
+
+
+ static FT_Error
+ pcf_get_encodings( FT_Stream stream,
+ PCF_Face face )
+ {
+ FT_Error error = PCF_Err_Ok;
+ FT_Memory memory = FT_FACE(face)->memory;
+ FT_ULong format, size;
+ int firstCol, lastCol;
+ int firstRow, lastRow;
+ int nencoding, encodingOffset;
+ int i, j;
+ PCF_Encoding tmpEncoding, encoding = 0;
+
+
+ error = pcfSeekToType( stream,
+ face->toc.tables,
+ face->toc.count,
+ PCF_BDF_ENCODINGS,
+ &format,
+ &size );
+ if ( error )
+ return error;
+
+ error = FT_Access_Frame( stream, 14 );
+ if ( error )
+ return error;
+ format = GET_ULongLE();
+ if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+ return PCF_Err_Invalid_File_Format;
+
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ {
+ firstCol = GET_Short();
+ lastCol = GET_Short();
+ firstRow = GET_Short();
+ lastRow = GET_Short();
+ face->defaultChar = GET_Short();
+ }
+ else
+ {
+ firstCol = GET_ShortLE();
+ lastCol = GET_ShortLE();
+ firstRow = GET_ShortLE();
+ lastRow = GET_ShortLE();
+ face->defaultChar = GET_ShortLE();
+ }
+
+ FT_Forget_Frame( stream );
+
+ FT_TRACE4(( "enc: firstCol %d, lastCol %d, firstRow %d, lastRow %d\n",
+ firstCol, lastCol, firstRow, lastRow ));
+
+ nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 );
+
+ if ( ALLOC( tmpEncoding, nencoding * sizeof ( PCF_EncodingRec ) ) )
+ return PCF_Err_Out_Of_Memory;
+
+ error = FT_Access_Frame( stream, 2 * nencoding );
+ if ( error )
+ goto Bail;
+
+ for ( i = 0, j = 0 ; i < nencoding; i++ )
+ {
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ encodingOffset = GET_Short();
+ else
+ encodingOffset = GET_ShortLE();
+
+ if ( encodingOffset != -1 )
+ {
+ tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) +
+ firstRow ) * 256 ) +
+ ( ( i % ( lastCol - firstCol + 1 ) ) +
+ firstCol );
+
+ tmpEncoding[j].glyph = (FT_Short)encodingOffset;
+ j++;
+ }
+
+ FT_TRACE4(( "enc n. %d ; Uni %ld ; Glyph %d\n",
+ i, tmpEncoding[j - 1].enc, encodingOffset ));
+ }
+ FT_Forget_Frame( stream );
+
+ if ( ALLOC( encoding, (--j) * sizeof ( PCF_EncodingRec ) ) )
+ goto Bail;
+
+ for ( i = 0; i < j; i++ )
+ {
+ encoding[i].enc = tmpEncoding[i].enc;
+ encoding[i].glyph = tmpEncoding[i].glyph;
+ }
+
+ face->nencodings = j;
+ face->encodings = encoding;
+ FREE( tmpEncoding );
+
+ return error;
+
+ Bail:
+ FREE( encoding );
+ FREE( tmpEncoding );
+ return error;
+ }
+
+
+ static
+ const FT_Frame_Field pcf_accel_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_AccelRec
+
+ FT_FRAME_START( 20 ),
+ FT_FRAME_BYTE ( noOverlap ),
+ FT_FRAME_BYTE ( constantMetrics ),
+ FT_FRAME_BYTE ( terminalFont ),
+ FT_FRAME_BYTE ( constantWidth ),
+ FT_FRAME_BYTE ( inkInside ),
+ FT_FRAME_BYTE ( inkMetrics ),
+ FT_FRAME_BYTE ( drawDirection ),
+ FT_FRAME_SKIP_BYTES( 1 ),
+ FT_FRAME_LONG_LE ( fontAscent ),
+ FT_FRAME_LONG_LE ( fontDescent ),
+ FT_FRAME_LONG_LE ( maxOverlap ),
+ FT_FRAME_END
+ };
+
+
+ static
+ const FT_Frame_Field pcf_accel_msb_header[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PCF_AccelRec
+
+ FT_FRAME_START( 20 ),
+ FT_FRAME_BYTE ( noOverlap ),
+ FT_FRAME_BYTE ( constantMetrics ),
+ FT_FRAME_BYTE ( terminalFont ),
+ FT_FRAME_BYTE ( constantWidth ),
+ FT_FRAME_BYTE ( inkInside ),
+ FT_FRAME_BYTE ( inkMetrics ),
+ FT_FRAME_BYTE ( drawDirection ),
+ FT_FRAME_SKIP_BYTES( 1 ),
+ FT_FRAME_LONG ( fontAscent ),
+ FT_FRAME_LONG ( fontDescent ),
+ FT_FRAME_LONG ( maxOverlap ),
+ FT_FRAME_END
+ };
+
+
+ static FT_Error
+ pcf_get_accel( FT_Stream stream,
+ PCF_Face face,
+ FT_ULong type )
+ {
+ FT_ULong format, size;
+ FT_Error error = PCF_Err_Ok;
+ PCF_Accel accel = &face->accel;
+
+
+ error = pcfSeekToType( stream,
+ face->toc.tables,
+ face->toc.count,
+ type,
+ &format,
+ &size );
+ if ( error )
+ goto Bail;
+
+ error = READ_ULongLE( format );
+ if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) &&
+ !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
+ goto Bail;
+
+ if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+ {
+ if ( READ_Fields( pcf_accel_msb_header, accel ) )
+ goto Bail;
+ }
+ else
+ {
+ if ( READ_Fields( pcf_accel_header, accel ) )
+ goto Bail;
+ }
+
+ error = pcf_get_metric( stream, format, &(accel->minbounds) );
+ if ( error )
+ goto Bail;
+ error = pcf_get_metric( stream, format, &(accel->maxbounds) );
+ if ( error )
+ goto Bail;
+
+ if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
+ {
+ error = pcf_get_metric( stream, format, &(accel->ink_minbounds) );
+ if ( error )
+ goto Bail;
+ error = pcf_get_metric( stream, format, &(accel->ink_maxbounds) );
+ if ( error )
+ goto Bail;
+ }
+ else
+ {
+ accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */
+ accel->ink_maxbounds = accel->maxbounds;
+ }
+ return error;
+
+ Bail:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF FT_Error
+ pcf_load_font( FT_Stream stream,
+ PCF_Face face )
+ {
+ FT_Error error = PCF_Err_Ok;
+ FT_Memory memory = FT_FACE(face)->memory;
+ FT_Bool hasBDFAccelerators;
+
+
+ error = pcf_read_TOC( stream, face );
+ if ( error )
+ return error;
+
+ error = pcf_get_properties( stream, face );
+ if ( error )
+ return error;;
+
+ /* Use the old accelerators if no BDF accelerators are in the file. */
+ hasBDFAccelerators = pcfHasType( face->toc.tables,
+ face->toc.count,
+ PCF_BDF_ACCELERATORS );
+ if ( !hasBDFAccelerators )
+ {
+ error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
+ if ( error )
+ goto Bail;
+ }
+
+ /* metrics */
+ error = pcf_get_metrics( stream, face );
+ if ( error )
+ goto Bail;
+
+ /* bitmaps */
+ error = pcf_get_bitmaps( stream, face );
+ if ( error )
+ goto Bail;
+
+ /* encodings */
+ error = pcf_get_encodings( stream, face );
+ if ( error )
+ goto Bail;
+
+ /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
+ if ( hasBDFAccelerators )
+ {
+ error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
+ if ( error )
+ goto Bail;
+ }
+
+ /* XXX: TO DO: inkmetrics and glyph_names are missing */
+
+ /* now construct the face object */
+ {
+ FT_Face root = FT_FACE( face );
+ PCF_Property prop;
+
+
+ root->num_faces = 1;
+ root->face_index = 0;
+ root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
+ FT_FACE_FLAG_HORIZONTAL |
+ FT_FACE_FLAG_FAST_GLYPHS;
+
+ if ( face->accel.constantWidth )
+ root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+ root->style_flags = 0;
+ prop = find_property( face, "SLANT" );
+ if ( prop != NULL )
+ if ( prop->isString )
+ if ( ( *(prop->value.atom) == 'O' ) ||
+ ( *(prop->value.atom) == 'I' ) )
+ root->style_flags |= FT_STYLE_FLAG_ITALIC;
+
+ prop = find_property( face, "WEIGHT_NAME" );
+ if ( prop != NULL )
+ if ( prop->isString )
+ if ( *(prop->value.atom) == 'B' )
+ root->style_flags |= FT_STYLE_FLAG_BOLD;
+
+ root->style_name = (char *)"Regular";
+
+ if ( root->style_flags & FT_STYLE_FLAG_BOLD ) {
+ if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
+ root->style_name = (char *)"Bold Italic";
+ else
+ root->style_name = (char *)"Bold";
+ }
+ else if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
+ root->style_name = (char *)"Italic";
+
+ prop = find_property( face, "FAMILY_NAME" );
+ if ( prop != NULL )
+ {
+ if ( prop->isString )
+ {
+ int l = strlen( prop->value.atom ) + 1;
+
+
+ if ( ALLOC( root->family_name, l * sizeof ( char ) ) )
+ goto Bail;
+ strcpy( root->family_name, prop->value.atom );
+ }
+ }
+ else
+ root->family_name = 0;
+
+ root->num_glyphs = face->nmetrics;
+
+ root->num_fixed_sizes = 1;
+ if ( ALLOC_ARRAY( root->available_sizes, 1, FT_Bitmap_Size ) )
+ goto Bail;
+
+ prop = find_property( face, "PIXEL_SIZE" );
+ if ( prop != NULL )
+ {
+ PCF_Property xres = 0, yres = 0;
+
+
+ xres = find_property( face, "RESOLUTION_X" );
+ yres = find_property( face, "RESOLUTION_Y" );
+ if ( ( xres != NULL ) && ( yres != NULL ) )
+ {
+ root->available_sizes->width =
+ (FT_Short)( prop->value.integer * 75 / xres->value.integer );
+ root->available_sizes->height =
+ (FT_Short)( prop->value.integer * 75 / yres->value.integer );
+ }
+ }
+ else
+ { /* XXX */
+#if 0
+ printf( "PCF Warning: Pixel Size undefined, assuming 12\n");
+#endif
+ root->available_sizes->width = 12;
+ root->available_sizes->height = 12;
+ }
+
+ /* XXX: charmaps */
+ root->charmaps = &face->charmap_handle;
+ root->num_charmaps = 1;
+
+ {
+ PCF_Property charset_registry = 0, charset_encoding = 0;
+
+
+ charset_registry = find_property( face, "CHARSET_REGISTRY" );
+ charset_encoding = find_property( face, "CHARSET_ENCODING" );
+
+ if ( ( charset_registry != NULL ) &&
+ ( charset_encoding != NULL ) )
+ {
+ if ( ( charset_registry->isString ) &&
+ ( charset_encoding->isString ) )
+ {
+ if ( ALLOC( face->charset_encoding,
+ ( strlen( charset_encoding->value.atom ) + 1 ) *
+ sizeof ( char ) ) )
+ goto Bail;
+ if ( ALLOC( face->charset_registry,
+ ( strlen( charset_registry->value.atom ) + 1 ) *
+ sizeof ( char ) ) )
+ goto Bail;
+ strcpy( face->charset_registry, charset_registry->value.atom );
+ strcpy( face->charset_encoding, charset_encoding->value.atom );
+
+#if 0
+ if ( !strcmp( charset_registry, "ISO10646" ) )
+ {
+ face->charmap.encoding = ft_encoding_unicode;
+ face->charmap.platform_id = 3;
+ face->charmap.encoding_id = 1;
+ face->charmap.face = root;
+ face->charmap_handle
+
+ return PCF_Err_Ok;
+ }
+#endif
+ }
+ }
+ }
+
+ face->charmap.encoding = ft_encoding_none;
+ face->charmap.platform_id = 0;
+ face->charmap.encoding_id = 0;
+ face->charmap.face = root;
+ face->charmap_handle = &face->charmap;
+ root->charmap = face->charmap_handle;
+ }
+ return PCF_Err_Ok;
+
+ Bail:
+ PCF_Done_Face( face );
+ return PCF_Err_Invalid_File_Format;
+ }
+
+
+/* END */
--- /dev/null
+/*
+
+Copyright 1990, 1994, 1998 The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/* $XFree86: xc/lib/font/util/utilbitmap.c,v 1.3 1999/08/22 08:58:58 dawes Exp $ */
+
+/*
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+
+#include <ft2build.h>
+#include "pcfutil.h"
+
+
+ /* Utility functions for reformatting font bitmaps */
+
+ static const unsigned char _reverse_byte[0x100] =
+ {
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+ };
+
+ /*
+ * Invert bit order within each BYTE of an array.
+ */
+
+ void
+ BitOrderInvert( unsigned char* buf,
+ int nbytes )
+ {
+ const unsigned char* rev = _reverse_byte;
+
+
+ for ( ; --nbytes >= 0; buf++ )
+ *buf = rev[*buf];
+ }
+
+
+ /*
+ * Invert byte order within each 16-bits of an array.
+ */
+
+ void
+ TwoByteSwap( unsigned char* buf,
+ int nbytes )
+ {
+ unsigned char c;
+
+
+ for ( ; nbytes > 0; nbytes -= 2, buf += 2 )
+ {
+ c = buf[0];
+ buf[0] = buf[1];
+ buf[1] = c;
+ }
+ }
+
+ /*
+ * Invert byte order within each 32-bits of an array.
+ */
+
+ void
+ FourByteSwap( unsigned char* buf,
+ int nbytes )
+ {
+ unsigned char c;
+
+
+ for ( ; nbytes > 0; nbytes -= 4, buf += 4 )
+ {
+ c = buf[0];
+ buf[0] = buf[3];
+ buf[3] = c;
+
+ c = buf[1];
+ buf[1] = buf[2];
+ buf[2] = c;
+ }
+ }
+
+
+ /*
+ * Repad a bitmap.
+ */
+
+ int
+ RepadBitmap( char* pSrc,
+ char* pDst,
+ unsigned int srcPad,
+ unsigned int dstPad,
+ int width,
+ int height )
+ {
+ int srcWidthBytes, dstWidthBytes;
+ int row, col;
+ char *pTmpSrc, *pTmpDst;
+
+
+ switch ( srcPad )
+ {
+ case 1:
+ srcWidthBytes = ( width + 7 ) >> 3;
+ break;
+
+ case 2:
+ srcWidthBytes = ( ( width + 15 ) >> 4 ) << 1;
+ break;
+
+ case 4:
+ srcWidthBytes = ( ( width + 31 ) >> 5 ) << 2;
+ break;
+
+ case 8:
+ srcWidthBytes = ( ( width + 63 ) >> 6 ) << 3;
+ break;
+
+ default:
+ return 0;
+ }
+
+ switch ( dstPad )
+ {
+ case 1:
+ dstWidthBytes = ( width + 7 ) >> 3;
+ break;
+
+ case 2:
+ dstWidthBytes = ( ( width + 15 ) >> 4 ) << 1;
+ break;
+
+ case 4:
+ dstWidthBytes = ( ( width + 31 ) >> 5 ) << 2;
+ break;
+
+ case 8:
+ dstWidthBytes = ( ( width + 63 ) >> 6 ) << 3;
+ break;
+
+ default:
+ return 0;
+ }
+
+ width = srcWidthBytes;
+ if ( width > dstWidthBytes )
+ width = dstWidthBytes;
+
+ pTmpSrc= pSrc;
+ pTmpDst= pDst;
+
+ for ( row = 0; row < height; row++ )
+ {
+ for ( col = 0; col < width; col++ )
+ *pTmpDst++ = *pTmpSrc++;
+
+ while ( col < dstWidthBytes )
+ {
+ *pTmpDst++ = '\0';
+ col++;
+ }
+ pTmpSrc += srcWidthBytes - width;
+ }
+
+ return dstWidthBytes * height;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* psaux.c */
+/* */
+/* FreeType auxiliary PostScript driver component (body only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "psobjs.c"
+#include "psauxmod.c"
+#include "t1decode.c"
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* psauxmod.c */
+/* */
+/* FreeType auxiliary PostScript module implementation (body). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "psauxmod.h"
+#include "psobjs.h"
+#include "t1decode.h"
+
+
+ FT_CALLBACK_TABLE_DEF
+ const PS_Table_Funcs ps_table_funcs =
+ {
+ PS_Table_New,
+ PS_Table_Done,
+ PS_Table_Add,
+ PS_Table_Release
+ };
+
+
+ FT_CALLBACK_TABLE_DEF
+ const T1_Parser_Funcs t1_parser_funcs =
+ {
+ T1_Init_Parser,
+ T1_Done_Parser,
+ T1_Skip_Spaces,
+ T1_Skip_Alpha,
+ T1_ToInt,
+ T1_ToFixed,
+ T1_ToCoordArray,
+ T1_ToFixedArray,
+ T1_ToToken,
+ T1_ToTokenArray,
+ T1_Load_Field,
+ T1_Load_Field_Table
+ };
+
+
+ FT_CALLBACK_TABLE_DEF
+ const T1_Builder_Funcs t1_builder_funcs =
+ {
+ T1_Builder_Init,
+ T1_Builder_Done,
+ T1_Builder_Check_Points,
+ T1_Builder_Add_Point,
+ T1_Builder_Add_Point1,
+ T1_Builder_Add_Contour,
+ T1_Builder_Start_Point,
+ T1_Builder_Close_Contour
+ };
+
+
+ FT_CALLBACK_TABLE_DEF
+ const T1_Decoder_Funcs t1_decoder_funcs =
+ {
+ T1_Decoder_Init,
+ T1_Decoder_Done,
+ T1_Decoder_Parse_Charstrings
+ };
+
+
+ static
+ const PSAux_Interface psaux_interface =
+ {
+ &ps_table_funcs,
+ &t1_parser_funcs,
+ &t1_builder_funcs,
+ &t1_decoder_funcs,
+
+ T1_Decrypt
+ };
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Module_Class psaux_module_class =
+ {
+ 0,
+ sizeof( FT_ModuleRec ),
+ "psaux",
+ 0x10000L,
+ 0x20000L,
+
+ &psaux_interface, /* module-specific interface */
+
+ (FT_Module_Constructor)0,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) 0
+ };
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* psmodule.c */
+/* */
+/* PSNames module implementation (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "psmodule.h"
+#include "pstables.h"
+
+#include "psnamerr.h"
+
+#include <stdlib.h> /* for qsort() */
+#include <string.h> /* for strcmp(), strncpy() */
+
+
+#ifndef FT_CONFIG_OPTION_NO_POSTSCRIPT_NAMES
+
+
+#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
+
+
+ /* return the Unicode value corresponding to a given glyph. Note that */
+ /* we do deal with glyph variants by detecting a non-initial dot in */
+ /* the name, as in `A.swash' or `e.final', etc. */
+ /* */
+ static FT_ULong
+ PS_Unicode_Value( const char* glyph_name )
+ {
+ FT_Int n;
+ char first = glyph_name[0];
+ char temp[64];
+
+
+ /* if the name begins with `uni', then the glyph name may be a */
+ /* hard-coded unicode character code. */
+ if ( glyph_name[0] == 'u' &&
+ glyph_name[1] == 'n' &&
+ glyph_name[2] == 'i' )
+ {
+ /* determine whether the next four characters following are */
+ /* hexadecimal. */
+
+ /* XXX: Add code to deal with ligatures, i.e. glyph names like */
+ /* `uniXXXXYYYYZZZZ'... */
+
+ FT_Int count;
+ FT_ULong value = 0;
+ const char* p = glyph_name + 3;
+
+
+ for ( count = 4; count > 0; count--, p++ )
+ {
+ char c = *p;
+ unsigned int d;
+
+
+ d = (unsigned char)c - '0';
+ if ( d >= 10 )
+ {
+ d = (unsigned char)c - 'A';
+ if ( d >= 6 )
+ d = 16;
+ else
+ d += 10;
+ }
+
+ /* exit if a non-uppercase hexadecimal character was found */
+ if ( d >= 16 )
+ break;
+
+ value = ( value << 4 ) + d;
+ }
+ if ( count == 0 )
+ return value;
+ }
+
+ /* look for a non-initial dot in the glyph name in order to */
+ /* sort-out variants like `A.swash', `e.final', etc. */
+ {
+ const char* p;
+ int len;
+
+
+ p = glyph_name;
+
+ while ( *p && *p != '.' )
+ p++;
+
+ len = (int)( p - glyph_name );
+
+ if ( *p && len < 64 )
+ {
+ strncpy( temp, glyph_name, len );
+ temp[len] = 0;
+ glyph_name = temp;
+ }
+ }
+
+ /* now, look up the glyph in the Adobe Glyph List */
+ for ( n = 0; n < NUM_ADOBE_GLYPHS; n++ )
+ {
+ const char* name = sid_standard_names[n];
+
+
+ if ( first == name[0] && strcmp( glyph_name, name ) == 0 )
+ return ps_names_to_unicode[n];
+ }
+
+ /* not found, there is probably no Unicode value for this glyph name */
+ return 0;
+ }
+
+
+ /* qsort callback to sort the unicode map */
+ FT_CALLBACK_DEF( int )
+ compare_uni_maps( const void* a,
+ const void* b )
+ {
+ PS_UniMap* map1 = (PS_UniMap*)a;
+ PS_UniMap* map2 = (PS_UniMap*)b;
+
+
+ return ( map1->unicode - map2->unicode );
+ }
+
+
+ /* Builds a table that maps Unicode values to glyph indices */
+ static FT_Error
+ PS_Build_Unicode_Table( FT_Memory memory,
+ FT_UInt num_glyphs,
+ const char** glyph_names,
+ PS_Unicodes* table )
+ {
+ FT_Error error;
+
+
+ /* we first allocate the table */
+ table->num_maps = 0;
+ table->maps = 0;
+
+ if ( !ALLOC_ARRAY( table->maps, num_glyphs, PS_UniMap ) )
+ {
+ FT_UInt n;
+ FT_UInt count;
+ PS_UniMap* map;
+ FT_ULong uni_char;
+
+
+ map = table->maps;
+
+ for ( n = 0; n < num_glyphs; n++ )
+ {
+ const char* gname = glyph_names[n];
+
+
+ if ( gname )
+ {
+ uni_char = PS_Unicode_Value( gname );
+
+ if ( uni_char != 0 && uni_char != 0xFFFF )
+ {
+ map->unicode = uni_char;
+ map->glyph_index = n;
+ map++;
+ }
+ }
+ }
+
+ /* now, compress the table a bit */
+ count = (FT_UInt)( map - table->maps );
+
+ if ( count > 0 && REALLOC( table->maps,
+ num_glyphs * sizeof ( PS_UniMap ),
+ count * sizeof ( PS_UniMap ) ) )
+ count = 0;
+
+ if ( count == 0 )
+ {
+ FREE( table->maps );
+ if ( !error )
+ error = PSnames_Err_Invalid_Argument; /* no unicode chars here! */
+ }
+ else
+ /* sort the table in increasing order of unicode values */
+ qsort( table->maps, count, sizeof ( PS_UniMap ), compare_uni_maps );
+
+ table->num_maps = count;
+ }
+
+ return error;
+ }
+
+
+ static FT_UInt
+ PS_Lookup_Unicode( PS_Unicodes* table,
+ FT_ULong unicode )
+ {
+ PS_UniMap *min, *max, *mid;
+
+
+ /* perform a binary search on the table */
+
+ min = table->maps;
+ max = min + table->num_maps - 1;
+
+ while ( min <= max )
+ {
+ mid = min + ( max - min ) / 2;
+ if ( mid->unicode == unicode )
+ return mid->glyph_index;
+
+ if ( min == max )
+ break;
+
+ if ( mid->unicode < unicode )
+ min = mid + 1;
+ else
+ max = mid - 1;
+ }
+
+ return 0xFFFF;
+ }
+
+
+#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
+
+
+ static const char*
+ PS_Macintosh_Name( FT_UInt name_index )
+ {
+ if ( name_index >= 258 )
+ name_index = 0;
+
+ return ps_glyph_names[mac_standard_names[name_index]];
+ }
+
+
+ static const char*
+ PS_Standard_Strings( FT_UInt sid )
+ {
+ return ( sid < NUM_SID_GLYPHS ? sid_standard_names[sid] : 0 );
+ }
+
+
+ static
+ const PSNames_Interface psnames_interface =
+ {
+#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
+
+ (PS_Unicode_Value_Func) PS_Unicode_Value,
+ (PS_Build_Unicodes_Func) PS_Build_Unicode_Table,
+ (PS_Lookup_Unicode_Func) PS_Lookup_Unicode,
+
+#else
+
+ 0,
+ 0,
+ 0,
+
+#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
+
+ (PS_Macintosh_Name_Func) PS_Macintosh_Name,
+ (PS_Adobe_Std_Strings_Func)PS_Standard_Strings,
+
+ t1_standard_encoding,
+ t1_expert_encoding
+ };
+
+
+#endif /* !FT_CONFIG_OPTION_NO_POSTSCRIPT_NAMES */
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Module_Class psnames_module_class =
+ {
+ 0, /* this is not a font driver, nor a renderer */
+ sizeof( FT_ModuleRec ),
+
+ "psnames", /* driver name */
+ 0x10000L, /* driver version */
+ 0x20000L, /* driver requires FreeType 2 or above */
+
+#ifdef FT_CONFIG_OPTION_NO_POSTSCRIPT_NAMES
+ 0,
+#else
+ (void*)&psnames_interface, /* module specific interface */
+#endif
+
+ (FT_Module_Constructor)0,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) 0
+ };
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* psnames.c */
+/* */
+/* FreeType PSNames module component (body only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "psmodule.c"
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* psobjs.c */
+/* */
+/* Auxiliary functions for PostScript fonts (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+#include FT_INTERNAL_DEBUG_H
+
+#include "psobjs.h"
+
+#include "psauxerr.h"
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** PS_TABLE *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* PS_Table_New */
+ /* */
+ /* <Description> */
+ /* Initializes a PS_Table. */
+ /* */
+ /* <InOut> */
+ /* table :: The address of the target table. */
+ /* */
+ /* <Input> */
+ /* count :: The table size = the maximum number of elements. */
+ /* */
+ /* memory :: The memory object to use for all subsequent */
+ /* reallocations. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ PS_Table_New( PS_Table* table,
+ FT_Int count,
+ FT_Memory memory )
+ {
+ FT_Error error;
+
+
+ table->memory = memory;
+ if ( ALLOC_ARRAY( table->elements, count, FT_Byte* ) ||
+ ALLOC_ARRAY( table->lengths, count, FT_Byte* ) )
+ goto Exit;
+
+ table->max_elems = count;
+ table->init = 0xDEADBEEFUL;
+ table->num_elems = 0;
+ table->block = 0;
+ table->capacity = 0;
+ table->cursor = 0;
+ table->funcs = ps_table_funcs;
+
+ Exit:
+ if ( error )
+ FREE( table->elements );
+
+ return error;
+ }
+
+
+ static void
+ shift_elements( PS_Table* table,
+ FT_Byte* old_base )
+ {
+ FT_Long delta = (FT_Long)( table->block - old_base );
+ FT_Byte** offset = table->elements;
+ FT_Byte** limit = offset + table->max_elems;
+
+
+ for ( ; offset < limit; offset++ )
+ {
+ if ( offset[0] )
+ offset[0] += delta;
+ }
+ }
+
+
+ static FT_Error
+ reallocate_t1_table( PS_Table* table,
+ FT_Long new_size )
+ {
+ FT_Memory memory = table->memory;
+ FT_Byte* old_base = table->block;
+ FT_Error error;
+
+
+ /* allocate new base block */
+ if ( ALLOC( table->block, new_size ) )
+ return error;
+
+ /* copy elements and shift offsets */
+ if (old_base )
+ {
+ MEM_Copy( table->block, old_base, table->capacity );
+ shift_elements( table, old_base );
+ FREE( old_base );
+ }
+
+ table->capacity = new_size;
+
+ return PSaux_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* PS_Table_Add */
+ /* */
+ /* <Description> */
+ /* Adds an object to a PS_Table, possibly growing its memory block. */
+ /* */
+ /* <InOut> */
+ /* table :: The target table. */
+ /* */
+ /* <Input> */
+ /* index :: The index of the object in the table. */
+ /* */
+ /* object :: The address of the object to copy in memory. */
+ /* */
+ /* length :: The length in bytes of the source object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. An error is returned if a */
+ /* reallocation fails. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ PS_Table_Add( PS_Table* table,
+ FT_Int index,
+ void* object,
+ FT_Int length )
+ {
+ if ( index < 0 || index > table->max_elems )
+ {
+ FT_ERROR(( "PS_Table_Add: invalid index\n" ));
+ return PSaux_Err_Invalid_Argument;
+ }
+
+ /* grow the base block if needed */
+ if ( table->cursor + length > table->capacity )
+ {
+ FT_Error error;
+ FT_Offset new_size = table->capacity;
+ FT_Long in_offset;
+
+
+ in_offset = (FT_Long)((FT_Byte*)object - table->block);
+ if ( (FT_ULong)in_offset >= table->capacity )
+ in_offset = -1;
+
+ while ( new_size < table->cursor + length )
+ new_size += 1024;
+
+ error = reallocate_t1_table( table, new_size );
+ if ( error )
+ return error;
+
+ if ( in_offset >= 0 )
+ object = table->block + in_offset;
+ }
+
+ /* add the object to the base block and adjust offset */
+ table->elements[index] = table->block + table->cursor;
+ table->lengths [index] = length;
+ MEM_Copy( table->block + table->cursor, object, length );
+
+ table->cursor += length;
+ return PSaux_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* PS_Table_Done */
+ /* */
+ /* <Description> */
+ /* Finalizes a PS_Table (i.e., reallocate it to its current cursor). */
+ /* */
+ /* <InOut> */
+ /* table :: The target table. */
+ /* */
+ /* <Note> */
+ /* This function does NOT release the heap's memory block. It is up */
+ /* to the caller to clean it, or reference it in its own structures. */
+ /* */
+ FT_LOCAL_DEF void
+ PS_Table_Done( PS_Table* table )
+ {
+ FT_Memory memory = table->memory;
+ FT_Error error;
+ FT_Byte* old_base = table->block;
+
+
+ /* should never fail, because rec.cursor <= rec.size */
+ if ( !old_base )
+ return;
+
+ if ( ALLOC( table->block, table->cursor ) )
+ return;
+ MEM_Copy( table->block, old_base, table->cursor );
+ shift_elements( table, old_base );
+
+ table->capacity = table->cursor;
+ FREE( old_base );
+ }
+
+
+ FT_LOCAL_DEF void
+ PS_Table_Release( PS_Table* table )
+ {
+ FT_Memory memory = table->memory;
+
+
+ if ( (FT_ULong)table->init == 0xDEADBEEFUL )
+ {
+ FREE( table->block );
+ FREE( table->elements );
+ FREE( table->lengths );
+ table->init = 0;
+ }
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** T1 PARSER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#define IS_T1_WHITESPACE( c ) ( (c) == ' ' || (c) == '\t' )
+#define IS_T1_LINESPACE( c ) ( (c) == '\r' || (c) == '\n' )
+
+#define IS_T1_SPACE( c ) ( IS_T1_WHITESPACE( c ) || IS_T1_LINESPACE( c ) )
+
+
+ FT_LOCAL_DEF void
+ T1_Skip_Spaces( T1_Parser* parser )
+ {
+ FT_Byte* cur = parser->cursor;
+ FT_Byte* limit = parser->limit;
+
+
+ while ( cur < limit )
+ {
+ FT_Byte c = *cur;
+
+
+ if ( !IS_T1_SPACE( c ) )
+ break;
+ cur++;
+ }
+ parser->cursor = cur;
+ }
+
+
+ FT_LOCAL_DEF void
+ T1_Skip_Alpha( T1_Parser* parser )
+ {
+ FT_Byte* cur = parser->cursor;
+ FT_Byte* limit = parser->limit;
+
+
+ while ( cur < limit )
+ {
+ FT_Byte c = *cur;
+
+
+ if ( IS_T1_SPACE( c ) )
+ break;
+ cur++;
+ }
+ parser->cursor = cur;
+ }
+
+
+ FT_LOCAL_DEF void
+ T1_ToToken( T1_Parser* parser,
+ T1_Token* token )
+ {
+ FT_Byte* cur;
+ FT_Byte* limit;
+ FT_Byte starter, ender;
+ FT_Int embed;
+
+
+ token->type = t1_token_none;
+ token->start = 0;
+ token->limit = 0;
+
+ /* first of all, skip space */
+ T1_Skip_Spaces( parser );
+
+ cur = parser->cursor;
+ limit = parser->limit;
+
+ if ( cur < limit )
+ {
+ switch ( *cur )
+ {
+ /************* check for strings ***********************/
+ case '(':
+ token->type = t1_token_string;
+ ender = ')';
+ goto Lookup_Ender;
+
+ /************* check for programs/array ****************/
+ case '{':
+ token->type = t1_token_array;
+ ender = '}';
+ goto Lookup_Ender;
+
+ /************* check for table/array ******************/
+ case '[':
+ token->type = t1_token_array;
+ ender = ']';
+
+ Lookup_Ender:
+ embed = 1;
+ starter = *cur++;
+ token->start = cur;
+ while ( cur < limit )
+ {
+ if ( *cur == starter )
+ embed++;
+ else if ( *cur == ender )
+ {
+ embed--;
+ if ( embed <= 0 )
+ {
+ token->limit = cur++;
+ break;
+ }
+ }
+ cur++;
+ }
+ break;
+
+ /* **************** otherwise, it's any token **********/
+ default:
+ token->start = cur++;
+ token->type = t1_token_any;
+ while ( cur < limit && !IS_T1_SPACE( *cur ) )
+ cur++;
+
+ token->limit = cur;
+ }
+
+ if ( !token->limit )
+ {
+ token->start = 0;
+ token->type = t1_token_none;
+ }
+
+ parser->cursor = cur;
+ }
+ }
+
+
+ FT_LOCAL_DEF void
+ T1_ToTokenArray( T1_Parser* parser,
+ T1_Token* tokens,
+ FT_UInt max_tokens,
+ FT_Int* pnum_tokens )
+ {
+ T1_Token master;
+
+
+ *pnum_tokens = -1;
+
+ T1_ToToken( parser, &master );
+ if ( master.type == t1_token_array )
+ {
+ FT_Byte* old_cursor = parser->cursor;
+ FT_Byte* old_limit = parser->limit;
+ T1_Token* cur = tokens;
+ T1_Token* limit = cur + max_tokens;
+
+
+ parser->cursor = master.start;
+ parser->limit = master.limit;
+
+ while ( parser->cursor < parser->limit )
+ {
+ T1_Token token;
+
+
+ T1_ToToken( parser, &token );
+ if ( !token.type )
+ break;
+
+ if ( cur < limit )
+ *cur = token;
+
+ cur++;
+ }
+
+ *pnum_tokens = (FT_Int)( cur - tokens );
+
+ parser->cursor = old_cursor;
+ parser->limit = old_limit;
+ }
+ }
+
+
+ static FT_Long
+ t1_toint( FT_Byte** cursor,
+ FT_Byte* limit )
+ {
+ FT_Long result = 0;
+ FT_Byte* cur = *cursor;
+ FT_Byte c = '\0', d;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ c = *cur;
+ d = (FT_Byte)( c - '0' );
+ if ( d < 10 )
+ break;
+
+ if ( c == '-' )
+ {
+ cur++;
+ break;
+ }
+ }
+
+ if ( cur < limit )
+ {
+ do
+ {
+ d = (FT_Byte)( cur[0] - '0' );
+ if ( d >= 10 )
+ break;
+
+ result = result * 10 + d;
+ cur++;
+
+ } while ( cur < limit );
+
+ if ( c == '-' )
+ result = -result;
+ }
+
+ *cursor = cur;
+ return result;
+ }
+
+
+ static FT_Long
+ t1_tofixed( FT_Byte** cursor,
+ FT_Byte* limit,
+ FT_Long power_ten )
+ {
+ FT_Byte* cur = *cursor;
+ FT_Long num, divider, result;
+ FT_Int sign = 0;
+ FT_Byte d;
+
+
+ if ( cur >= limit )
+ return 0;
+
+ /* first of all, check the sign */
+ if ( *cur == '-' )
+ {
+ sign = 1;
+ cur++;
+ }
+
+ /* then, read the integer part, if any */
+ if ( *cur != '.' )
+ result = t1_toint( &cur, limit ) << 16;
+ else
+ result = 0;
+
+ num = 0;
+ divider = 1;
+
+ if ( cur >= limit )
+ goto Exit;
+
+ /* read decimal part, if any */
+ if ( *cur == '.' && cur + 1 < limit )
+ {
+ cur++;
+
+ for (;;)
+ {
+ d = (FT_Byte)( *cur - '0' );
+ if ( d >= 10 )
+ break;
+
+ if ( divider < 10000000L )
+ {
+ num = num * 10 + d;
+ divider *= 10;
+ }
+
+ cur++;
+ if ( cur >= limit )
+ break;
+ }
+ }
+
+ /* read exponent, if any */
+ if ( cur + 1 < limit && ( *cur == 'e' || *cur == 'E' ) )
+ {
+ cur++;
+ power_ten += t1_toint( &cur, limit );
+ }
+
+ Exit:
+ /* raise to power of ten if needed */
+ while ( power_ten > 0 )
+ {
+ result = result * 10;
+ num = num * 10;
+ power_ten--;
+ }
+
+ while ( power_ten < 0 )
+ {
+ result = result / 10;
+ divider = divider * 10;
+ power_ten++;
+ }
+
+ if ( num )
+ result += FT_DivFix( num, divider );
+
+ if ( sign )
+ result = -result;
+
+ *cursor = cur;
+ return result;
+ }
+
+
+ static FT_Int
+ t1_tocoordarray( FT_Byte** cursor,
+ FT_Byte* limit,
+ FT_Int max_coords,
+ FT_Short* coords )
+ {
+ FT_Byte* cur = *cursor;
+ FT_Int count = 0;
+ FT_Byte c, ender;
+
+
+ if ( cur >= limit )
+ goto Exit;
+
+ /* check for the beginning of an array; if not, only one number will */
+ /* be read */
+ c = *cur;
+ ender = 0;
+
+ if ( c == '[' )
+ ender = ']';
+
+ if ( c == '{' )
+ ender = '}';
+
+ if ( ender )
+ cur++;
+
+ /* now, read the coordinates */
+ for ( ; cur < limit; )
+ {
+ /* skip whitespace in front of data */
+ for (;;)
+ {
+ c = *cur;
+ if ( c != ' ' && c != '\t' )
+ break;
+
+ cur++;
+ if ( cur >= limit )
+ goto Exit;
+ }
+
+ if ( count >= max_coords || c == ender )
+ break;
+
+ coords[count] = (FT_Short)( t1_tofixed( &cur, limit, 0 ) >> 16 );
+ count++;
+
+ if ( !ender )
+ break;
+ }
+
+ Exit:
+ *cursor = cur;
+ return count;
+ }
+
+
+ static FT_Int
+ t1_tofixedarray( FT_Byte** cursor,
+ FT_Byte* limit,
+ FT_Int max_values,
+ FT_Fixed* values,
+ FT_Int power_ten )
+ {
+ FT_Byte* cur = *cursor;
+ FT_Int count = 0;
+ FT_Byte c, ender;
+
+
+ if ( cur >= limit ) goto Exit;
+
+ /* check for the beginning of an array. If not, only one number will */
+ /* be read */
+ c = *cur;
+ ender = 0;
+
+ if ( c == '[' )
+ ender = ']';
+
+ if ( c == '{' )
+ ender = '}';
+
+ if ( ender )
+ cur++;
+
+ /* now, read the values */
+ for ( ; cur < limit; )
+ {
+ /* skip whitespace in front of data */
+ for (;;)
+ {
+ c = *cur;
+ if ( c != ' ' && c != '\t' )
+ break;
+
+ cur++;
+ if ( cur >= limit )
+ goto Exit;
+ }
+
+ if ( count >= max_values || c == ender )
+ break;
+
+ values[count] = t1_tofixed( &cur, limit, power_ten );
+ count++;
+
+ if ( !ender )
+ break;
+ }
+
+ Exit:
+ *cursor = cur;
+ return count;
+ }
+
+
+#if 0
+
+ static FT_String*
+ t1_tostring( FT_Byte** cursor,
+ FT_Byte* limit,
+ FT_Memory memory )
+ {
+ FT_Byte* cur = *cursor;
+ FT_Int len = 0;
+ FT_Int count;
+ FT_String* result;
+ FT_Error error;
+
+
+ /* XXX: some stupid fonts have a `Notice' or `Copyright' string */
+ /* that simply doesn't begin with an opening parenthesis, even */
+ /* though they have a closing one! E.g. "amuncial.pfb" */
+ /* */
+ /* We must deal with these ill-fated cases there. Note that */
+ /* these fonts didn't work with the old Type 1 driver as the */
+ /* notice/copyright was not recognized as a valid string token */
+ /* and made the old token parser commit errors. */
+
+ while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) )
+ cur++;
+ if ( cur + 1 >= limit )
+ return 0;
+
+ if ( *cur == '(' )
+ cur++; /* skip the opening parenthesis, if there is one */
+
+ *cursor = cur;
+ count = 0;
+
+ /* then, count its length */
+ for ( ; cur < limit; cur++ )
+ {
+ if ( *cur == '(' )
+ count++;
+
+ else if ( *cur == ')' )
+ {
+ count--;
+ if ( count < 0 )
+ break;
+ }
+ }
+
+ len = cur - *cursor;
+ if ( cur >= limit || ALLOC( result, len + 1 ) )
+ return 0;
+
+ /* now copy the string */
+ MEM_Copy( result, *cursor, len );
+ result[len] = '\0';
+ *cursor = cur;
+ return result;
+ }
+
+#endif /* 0 */
+
+
+ static int
+ t1_tobool( FT_Byte** cursor,
+ FT_Byte* limit )
+ {
+ FT_Byte* cur = *cursor;
+ FT_Bool result = 0;
+
+
+ /* return 1 if we find `true', 0 otherwise */
+ if ( cur + 3 < limit &&
+ cur[0] == 't' &&
+ cur[1] == 'r' &&
+ cur[2] == 'u' &&
+ cur[3] == 'e' )
+ {
+ result = 1;
+ cur += 5;
+ }
+ else if ( cur + 4 < limit &&
+ cur[0] == 'f' &&
+ cur[1] == 'a' &&
+ cur[2] == 'l' &&
+ cur[3] == 's' &&
+ cur[4] == 'e' )
+ {
+ result = 0;
+ cur += 6;
+ }
+
+ *cursor = cur;
+ return result;
+ }
+
+
+ /* Load a simple field (i.e. non-table) into the current list of objects */
+ FT_LOCAL_DEF FT_Error
+ T1_Load_Field( T1_Parser* parser,
+ const T1_Field* field,
+ void** objects,
+ FT_UInt max_objects,
+ FT_ULong* pflags )
+ {
+ T1_Token token;
+ FT_Byte* cur;
+ FT_Byte* limit;
+ FT_UInt count;
+ FT_UInt index;
+ FT_Error error;
+
+
+ T1_ToToken( parser, &token );
+ if ( !token.type )
+ goto Fail;
+
+ count = 1;
+ index = 0;
+ cur = token.start;
+ limit = token.limit;
+
+ if ( token.type == t1_token_array )
+ {
+ /* if this is an array, and we have no blend, an error occurs */
+ if ( max_objects == 0 )
+ goto Fail;
+
+ count = max_objects;
+ index = 1;
+ }
+
+ for ( ; count > 0; count--, index++ )
+ {
+ FT_Byte* q = (FT_Byte*)objects[index] + field->offset;
+ FT_Long val;
+ FT_String* string;
+
+
+ switch ( field->type )
+ {
+ case t1_field_bool:
+ val = t1_tobool( &cur, limit );
+ goto Store_Integer;
+
+ case t1_field_fixed:
+ val = t1_tofixed( &cur, limit, 3 );
+ goto Store_Integer;
+
+ case t1_field_integer:
+ val = t1_toint( &cur, limit );
+
+ Store_Integer:
+ switch ( field->size )
+ {
+ case 1:
+ *(FT_Byte*)q = (FT_Byte)val;
+ break;
+
+ case 2:
+ *(FT_UShort*)q = (FT_UShort)val;
+ break;
+
+ case 4:
+ *(FT_UInt32*)q = (FT_UInt32)val;
+ break;
+
+ default: /* for 64-bit systems */
+ *(FT_Long*)q = val;
+ }
+ break;
+
+ case t1_field_string:
+ {
+ FT_Memory memory = parser->memory;
+ FT_UInt len = (FT_UInt)( limit - cur );
+
+
+ if ( *(FT_String**)q )
+ /* with synthetic fonts, it's possible to find a field twice */
+ break;
+
+ if ( ALLOC( string, len + 1 ) )
+ goto Exit;
+
+ MEM_Copy( string, cur, len );
+ string[len] = 0;
+
+ *(FT_String**)q = string;
+ }
+ break;
+
+ default:
+ /* an error occured */
+ goto Fail;
+ }
+ }
+
+#if 0 /* obsolete - keep for reference */
+ if ( pflags )
+ *pflags |= 1L << field->flag_bit;
+#else
+ FT_UNUSED( pflags );
+#endif
+
+ error = PSaux_Err_Ok;
+
+ Exit:
+ return error;
+
+ Fail:
+ error = PSaux_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+
+#define T1_MAX_TABLE_ELEMENTS 32
+
+
+ FT_LOCAL_DEF FT_Error
+ T1_Load_Field_Table( T1_Parser* parser,
+ const T1_Field* field,
+ void** objects,
+ FT_UInt max_objects,
+ FT_ULong* pflags )
+ {
+ T1_Token elements[T1_MAX_TABLE_ELEMENTS];
+ T1_Token* token;
+ FT_Int num_elements;
+ FT_Error error = 0;
+ FT_Byte* old_cursor;
+ FT_Byte* old_limit;
+ T1_Field fieldrec = *(T1_Field*)field;
+
+#if 1
+ fieldrec.type = t1_field_integer;
+ if ( field->type == t1_field_fixed_array )
+ fieldrec.type = t1_field_fixed;
+#endif
+
+ T1_ToTokenArray( parser, elements, 32, &num_elements );
+ if ( num_elements < 0 )
+ goto Fail;
+
+ if ( num_elements > T1_MAX_TABLE_ELEMENTS )
+ num_elements = T1_MAX_TABLE_ELEMENTS;
+
+ old_cursor = parser->cursor;
+ old_limit = parser->limit;
+
+ /* we store the elements count */
+ *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) =
+ (FT_Byte)num_elements;
+
+ /* we now load each element, adjusting the field.offset on each one */
+ token = elements;
+ for ( ; num_elements > 0; num_elements--, token++ )
+ {
+ parser->cursor = token->start;
+ parser->limit = token->limit;
+ T1_Load_Field( parser, &fieldrec, objects, max_objects, 0 );
+ fieldrec.offset += fieldrec.size;
+ }
+
+#if 0 /* obsolete -- keep for reference */
+ if ( pflags )
+ *pflags |= 1L << field->flag_bit;
+#else
+ FT_UNUSED( pflags );
+#endif
+
+ parser->cursor = old_cursor;
+ parser->limit = old_limit;
+
+ Exit:
+ return error;
+
+ Fail:
+ error = PSaux_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+
+ FT_LOCAL_DEF FT_Long
+ T1_ToInt( T1_Parser* parser )
+ {
+ return t1_toint( &parser->cursor, parser->limit );
+ }
+
+
+ FT_LOCAL_DEF FT_Fixed
+ T1_ToFixed( T1_Parser* parser,
+ FT_Int power_ten )
+ {
+ return t1_tofixed( &parser->cursor, parser->limit, power_ten );
+ }
+
+
+ FT_LOCAL_DEF FT_Int
+ T1_ToCoordArray( T1_Parser* parser,
+ FT_Int max_coords,
+ FT_Short* coords )
+ {
+ return t1_tocoordarray( &parser->cursor, parser->limit,
+ max_coords, coords );
+ }
+
+
+ FT_LOCAL_DEF FT_Int
+ T1_ToFixedArray( T1_Parser* parser,
+ FT_Int max_values,
+ FT_Fixed* values,
+ FT_Int power_ten )
+ {
+ return t1_tofixedarray( &parser->cursor, parser->limit,
+ max_values, values, power_ten );
+ }
+
+
+#if 0
+
+ FT_LOCAL_DEF FT_String*
+ T1_ToString( T1_Parser* parser )
+ {
+ return t1_tostring( &parser->cursor, parser->limit, parser->memory );
+ }
+
+
+ FT_LOCAL_DEF FT_Bool
+ T1_ToBool( T1_Parser* parser )
+ {
+ return t1_tobool( &parser->cursor, parser->limit );
+ }
+
+#endif /* 0 */
+
+
+ FT_LOCAL_DEF void
+ T1_Init_Parser( T1_Parser* parser,
+ FT_Byte* base,
+ FT_Byte* limit,
+ FT_Memory memory )
+ {
+ parser->error = 0;
+ parser->base = base;
+ parser->limit = limit;
+ parser->cursor = base;
+ parser->memory = memory;
+ parser->funcs = t1_parser_funcs;
+ }
+
+
+ FT_LOCAL_DEF void
+ T1_Done_Parser( T1_Parser* parser )
+ {
+ FT_UNUSED( parser );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** T1 BUILDER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* T1_Builder_Init */
+ /* */
+ /* <Description> */
+ /* Initializes a given glyph builder. */
+ /* */
+ /* <InOut> */
+ /* builder :: A pointer to the glyph builder to initialize. */
+ /* */
+ /* <Input> */
+ /* face :: The current face object. */
+ /* */
+ /* size :: The current size object. */
+ /* */
+ /* glyph :: The current glyph object. */
+ /* */
+ FT_LOCAL_DEF void
+ T1_Builder_Init( T1_Builder* builder,
+ FT_Face face,
+ FT_Size size,
+ FT_GlyphSlot glyph )
+ {
+ builder->path_begun = 0;
+ builder->load_points = 1;
+
+ builder->face = face;
+ builder->glyph = glyph;
+ builder->memory = face->memory;
+
+ if ( glyph )
+ {
+ FT_GlyphLoader* loader = glyph->internal->loader;
+
+
+ builder->loader = loader;
+ builder->base = &loader->base.outline;
+ builder->current = &loader->current.outline;
+ FT_GlyphLoader_Rewind( loader );
+ }
+
+ if ( size )
+ {
+ builder->scale_x = size->metrics.x_scale;
+ builder->scale_y = size->metrics.y_scale;
+ }
+
+ builder->pos_x = 0;
+ builder->pos_y = 0;
+
+ builder->left_bearing.x = 0;
+ builder->left_bearing.y = 0;
+ builder->advance.x = 0;
+ builder->advance.y = 0;
+
+ builder->funcs = t1_builder_funcs;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* T1_Builder_Done */
+ /* */
+ /* <Description> */
+ /* Finalizes a given glyph builder. Its contents can still be used */
+ /* after the call, but the function saves important information */
+ /* within the corresponding glyph slot. */
+ /* */
+ /* <Input> */
+ /* builder :: A pointer to the glyph builder to finalize. */
+ /* */
+ FT_LOCAL_DEF void
+ T1_Builder_Done( T1_Builder* builder )
+ {
+ FT_GlyphSlot glyph = builder->glyph;
+
+
+ if ( glyph )
+ glyph->outline = *builder->base;
+ }
+
+
+ /* check that there is enough room for `count' more points */
+ FT_LOCAL_DEF FT_Error
+ T1_Builder_Check_Points( T1_Builder* builder,
+ FT_Int count )
+ {
+ return FT_GlyphLoader_Check_Points( builder->loader, count, 0 );
+ }
+
+
+ /* add a new point, do not check space */
+ FT_LOCAL_DEF void
+ T1_Builder_Add_Point( T1_Builder* builder,
+ FT_Pos x,
+ FT_Pos y,
+ FT_Byte flag )
+ {
+ FT_Outline* outline = builder->current;
+
+
+ if ( builder->load_points )
+ {
+ FT_Vector* point = outline->points + outline->n_points;
+ FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points;
+
+
+ if ( builder->shift )
+ {
+ x >>= 16;
+ y >>= 16;
+ }
+ point->x = x;
+ point->y = y;
+ *control = (FT_Byte)( flag ? FT_Curve_Tag_On : FT_Curve_Tag_Cubic );
+
+ builder->last = *point;
+ }
+ outline->n_points++;
+ }
+
+
+ /* check space for a new on-curve point, then add it */
+ FT_LOCAL_DEF FT_Error
+ T1_Builder_Add_Point1( T1_Builder* builder,
+ FT_Pos x,
+ FT_Pos y )
+ {
+ FT_Error error;
+
+
+ error = T1_Builder_Check_Points( builder, 1 );
+ if ( !error )
+ T1_Builder_Add_Point( builder, x, y, 1 );
+
+ return error;
+ }
+
+
+ /* check room for a new contour, then add it */
+ FT_LOCAL_DEF FT_Error
+ T1_Builder_Add_Contour( T1_Builder* builder )
+ {
+ FT_Outline* outline = builder->current;
+ FT_Error error;
+
+
+ if ( !builder->load_points )
+ {
+ outline->n_contours++;
+ return PSaux_Err_Ok;
+ }
+
+ error = FT_GlyphLoader_Check_Points( builder->loader, 0, 1 );
+ if ( !error )
+ {
+ if ( outline->n_contours > 0 )
+ outline->contours[outline->n_contours - 1] =
+ (short)( outline->n_points - 1 );
+
+ outline->n_contours++;
+ }
+
+ return error;
+ }
+
+
+ /* if a path was begun, add its first on-curve point */
+ FT_LOCAL_DEF FT_Error
+ T1_Builder_Start_Point( T1_Builder* builder,
+ FT_Pos x,
+ FT_Pos y )
+ {
+ FT_Error error = 0;
+
+
+ /* test whether we are building a new contour */
+ if ( !builder->path_begun )
+ {
+ builder->path_begun = 1;
+ error = T1_Builder_Add_Contour( builder );
+ if ( !error )
+ error = T1_Builder_Add_Point1( builder, x, y );
+ }
+ return error;
+ }
+
+
+ /* close the current contour */
+ FT_LOCAL_DEF void
+ T1_Builder_Close_Contour( T1_Builder* builder )
+ {
+ FT_Outline* outline = builder->current;
+
+
+ /* XXXX: We must not include the last point in the path if it */
+ /* is located on the first point. */
+ if ( outline->n_points > 1 )
+ {
+ FT_Int first = 0;
+ FT_Vector* p1 = outline->points + first;
+ FT_Vector* p2 = outline->points + outline->n_points - 1;
+ FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1;
+
+
+ if ( outline->n_contours > 1 )
+ {
+ first = outline->contours[outline->n_contours - 2] + 1;
+ p1 = outline->points + first;
+ }
+
+ /* `delete' last point only if it coincides with the first */
+ /* point and it is not a control point (which can happen). */
+ if ( p1->x == p2->x && p1->y == p2->y )
+ if ( *control == FT_Curve_Tag_On )
+ outline->n_points--;
+ }
+
+ if ( outline->n_contours > 0 )
+ outline->contours[outline->n_contours - 1] =
+ (short)( outline->n_points - 1 );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** OTHER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_LOCAL_DEF void
+ T1_Decrypt( FT_Byte* buffer,
+ FT_Offset length,
+ FT_UShort seed )
+ {
+ while ( length > 0 )
+ {
+ FT_Byte plain;
+
+
+ plain = (FT_Byte)( *buffer ^ ( seed >> 8 ) );
+ seed = (FT_UShort)( ( *buffer + seed ) * 52845U + 22719 );
+ *buffer++ = plain;
+ length--;
+ }
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* raster.c */
+/* */
+/* FreeType monochrome rasterer module component (body only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "ftraster.c"
+#include "ftrend1.c"
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* sfdriver.c */
+/* */
+/* High-level SFNT driver interface (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_SFNT_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "sfdriver.h"
+#include "ttload.h"
+#include "ttcmap.h"
+#include "sfobjs.h"
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+#include "ttsbit.h"
+#endif
+
+#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+#include "ttpost.h"
+#endif
+
+#include <string.h> /* for strcmp() */
+
+
+ static void*
+ get_sfnt_table( TT_Face face,
+ FT_Sfnt_Tag tag )
+ {
+ void* table;
+
+
+ switch ( tag )
+ {
+ case ft_sfnt_head:
+ table = &face->header;
+ break;
+
+ case ft_sfnt_hhea:
+ table = &face->horizontal;
+ break;
+
+ case ft_sfnt_vhea:
+ table = face->vertical_info ? &face->vertical : 0;
+ break;
+
+ case ft_sfnt_os2:
+ table = face->os2.version == 0xFFFF ? 0 : &face->os2;
+ break;
+
+ case ft_sfnt_post:
+ table = &face->postscript;
+ break;
+
+ case ft_sfnt_maxp:
+ table = &face->max_profile;
+ break;
+
+ case ft_sfnt_pclt:
+ table = face->pclt.Version ? &face->pclt : 0;
+ break;
+
+ default:
+ table = 0;
+ }
+
+ return table;
+ }
+
+
+#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+
+
+ static FT_Error
+ get_sfnt_glyph_name( TT_Face face,
+ FT_UInt glyph_index,
+ FT_Pointer buffer,
+ FT_UInt buffer_max )
+ {
+ FT_String* gname;
+ FT_Error error;
+
+
+ error = TT_Get_PS_Name( face, glyph_index, &gname );
+ if ( !error && buffer_max > 0 )
+ {
+ FT_UInt len = (FT_UInt)( strlen( gname ) );
+
+
+ if ( len >= buffer_max )
+ len = buffer_max - 1;
+
+ MEM_Copy( buffer, gname, len );
+ ((FT_Byte*)buffer)[len] = 0;
+ }
+
+ return error;
+ }
+
+
+ static const char*
+ get_sfnt_postscript_name( TT_Face face )
+ {
+ FT_Int n;
+
+ /* shouldn't happen, but just in case to avoid memory leaks */
+ if ( face->root.internal->postscript_name )
+ return face->root.internal->postscript_name;
+
+ /* scan the name table to see if we have a Postscript name here, either */
+ /* in Macintosh or Windows platform encodings.. */
+ for ( n = 0; n < face->num_names; n++ )
+ {
+ TT_NameRec* name = face->name_table.names + n;
+
+ if ( name->nameID == 6 )
+ {
+ if ( ( name->platformID == 3 &&
+ name->encodingID == 1 &&
+ name->languageID == 0x409 ) ||
+
+ ( name->platformID == 1 &&
+ name->encodingID == 0 &&
+ name->languageID == 0 ) )
+ {
+ FT_UInt len = name->stringLength;
+ FT_Error error;
+ FT_Memory memory = face->root.memory;
+ FT_String* result;
+
+ if ( !ALLOC( result, len+1 ) )
+ {
+ memcpy( result, name->string, len );
+ result[len] = '\0';
+
+ face->root.internal->postscript_name = result;
+ }
+ return result;
+ }
+ }
+ }
+
+ return NULL;
+ }
+
+
+#endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
+
+
+ FT_CALLBACK_DEF( FT_Module_Interface )
+ SFNT_Get_Interface( FT_Module module,
+ const char* interface )
+ {
+ FT_UNUSED( module );
+
+ if ( strcmp( interface, "get_sfnt" ) == 0 )
+ return (FT_Module_Interface)get_sfnt_table;
+
+#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+ if ( strcmp( interface, "glyph_name" ) == 0 )
+ return (FT_Module_Interface)get_sfnt_glyph_name;
+#endif
+
+ if ( strcmp( interface, "postscript_name" ) == 0 )
+ return (FT_Module_Interface)get_sfnt_postscript_name;
+
+ return 0;
+ }
+
+
+ static
+ const SFNT_Interface sfnt_interface =
+ {
+ TT_Goto_Table,
+
+ SFNT_Init_Face,
+ SFNT_Load_Face,
+ SFNT_Done_Face,
+ SFNT_Get_Interface,
+
+ TT_Load_Any,
+ TT_Load_SFNT_Header,
+ TT_Load_Directory,
+
+ TT_Load_Header,
+ TT_Load_Metrics_Header,
+ TT_Load_CMap,
+ TT_Load_MaxProfile,
+ TT_Load_OS2,
+ TT_Load_PostScript,
+
+ TT_Load_Names,
+ TT_Free_Names,
+
+ TT_Load_Hdmx,
+ TT_Free_Hdmx,
+
+ TT_Load_Kern,
+ TT_Load_Gasp,
+ TT_Load_PCLT,
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ /* see `ttload.h' */
+ TT_Load_Bitmap_Header,
+
+ /* see `ttsbit.h' */
+ TT_Set_SBit_Strike,
+ TT_Load_SBit_Strikes,
+ TT_Load_SBit_Image,
+ TT_Free_SBit_Strikes,
+
+#else /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+
+ /* see `ttpost.h' */
+ TT_Get_PS_Name,
+ TT_Free_Post_Names,
+
+#else /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
+
+ 0,
+ 0,
+
+#endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
+
+ /* see `ttcmap.h' */
+ TT_CharMap_Load,
+ TT_CharMap_Free,
+ };
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Module_Class sfnt_module_class =
+ {
+ 0, /* not a font driver or renderer */
+ sizeof( FT_ModuleRec ),
+
+ "sfnt", /* driver name */
+ 0x10000L, /* driver version 1.0 */
+ 0x20000L, /* driver requires FreeType 2.0 or higher */
+
+ (const void*)&sfnt_interface, /* module specific interface */
+
+ (FT_Module_Constructor)0,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) SFNT_Get_Interface
+ };
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* sfnt.c */
+/* */
+/* Single object library component. */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "ttload.c"
+#include "ttcmap.c"
+#include "sfobjs.c"
+#include "sfdriver.c"
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+#include "ttsbit.c"
+#endif
+
+#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+#include "ttpost.c"
+#endif
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* sfobjs.c */
+/* */
+/* SFNT object management (base). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "sfobjs.h"
+#include "ttload.h"
+#include FT_INTERNAL_SFNT_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_TRUETYPE_IDS_H
+#include FT_TRUETYPE_TAGS_H
+
+#include "sferrors.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_sfobjs
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Get_Name */
+ /* */
+ /* <Description> */
+ /* Returns a given ENGLISH name record in ASCII. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* nameid :: The name id of the name record to return. */
+ /* */
+ /* <Return> */
+ /* Character string. NULL if no name is present. */
+ /* */
+ static FT_String*
+ Get_Name( TT_Face face,
+ FT_UShort nameid )
+ {
+ FT_Memory memory = face->root.memory;
+ FT_UShort n;
+ TT_NameRec* rec;
+ FT_Bool wide_chars = 1;
+
+
+ rec = face->name_table.names;
+ for ( n = 0; n < face->name_table.numNameRecords; n++, rec++ )
+ {
+ if ( rec->nameID == nameid )
+ {
+ /* found the name -- now create an ASCII string from it */
+ FT_Bool found = 0;
+
+
+ /* test for Microsoft English language */
+ if ( rec->platformID == TT_PLATFORM_MICROSOFT &&
+ rec->encodingID <= TT_MS_ID_UNICODE_CS &&
+ ( rec->languageID & 0x3FF ) == 0x009 )
+ found = 1;
+
+ /* test for Apple Unicode encoding */
+ else if ( rec->platformID == TT_PLATFORM_APPLE_UNICODE )
+ found = 1;
+
+ /* test for Apple Roman */
+ else if ( rec->platformID == TT_PLATFORM_MACINTOSH &&
+ rec->languageID == TT_MAC_ID_ROMAN )
+ {
+ found = 1;
+ wide_chars = 0;
+ }
+
+ /* found a Unicode name */
+ if ( found )
+ {
+ FT_String* string;
+ FT_UInt len;
+
+
+ if ( wide_chars )
+ {
+ FT_UInt m;
+
+
+ len = (FT_UInt)rec->stringLength / 2;
+ if ( MEM_Alloc( string, len + 1 ) )
+ return NULL;
+
+ for ( m = 0; m < len; m ++ )
+ string[m] = rec->string[2 * m + 1];
+ }
+ else
+ {
+ len = rec->stringLength;
+ if ( MEM_Alloc( string, len + 1 ) )
+ return NULL;
+
+ MEM_Copy( string, rec->string, len );
+ }
+
+ string[len] = '\0';
+ return string;
+ }
+ }
+ }
+
+ return NULL;
+ }
+
+
+ static FT_Encoding
+ find_encoding( int platform_id,
+ int encoding_id )
+ {
+ typedef struct TEncoding
+ {
+ int platform_id;
+ int encoding_id;
+ FT_Encoding encoding;
+
+ } TEncoding;
+
+ static
+ const TEncoding tt_encodings[] =
+ {
+ { TT_PLATFORM_ISO, -1, ft_encoding_unicode },
+
+ { TT_PLATFORM_APPLE_UNICODE, -1, ft_encoding_unicode },
+
+ { TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, ft_encoding_apple_roman },
+
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, ft_encoding_symbol },
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_UCS_4, ft_encoding_unicode },
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, ft_encoding_unicode },
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, ft_encoding_sjis },
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_GB2312, ft_encoding_gb2312 },
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, ft_encoding_big5 },
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, ft_encoding_wansung },
+ { TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, ft_encoding_johab }
+ };
+
+ const TEncoding *cur, *limit;
+
+
+ cur = tt_encodings;
+ limit = cur + sizeof ( tt_encodings ) / sizeof ( tt_encodings[0] );
+
+ for ( ; cur < limit; cur++ )
+ {
+ if ( cur->platform_id == platform_id )
+ {
+ if ( cur->encoding_id == encoding_id ||
+ cur->encoding_id == -1 )
+ return cur->encoding;
+ }
+ }
+
+ return ft_encoding_none;
+ }
+
+
+ FT_LOCAL_DEF FT_Error
+ SFNT_Init_Face( FT_Stream stream,
+ TT_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ FT_Error error;
+ FT_Library library = face->root.driver->root.library;
+ SFNT_Interface* sfnt;
+ SFNT_Header sfnt_header;
+
+ /* for now, parameters are unused */
+ FT_UNUSED( num_params );
+ FT_UNUSED( params );
+
+ sfnt = (SFNT_Interface*)face->sfnt;
+ if ( !sfnt )
+ {
+ sfnt = (SFNT_Interface*)FT_Get_Module_Interface( library, "sfnt" );
+ if ( !sfnt )
+ {
+ error = SFNT_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ face->sfnt = sfnt;
+ face->goto_table = sfnt->goto_table;
+ }
+
+ if ( !face->psnames )
+ {
+ face->psnames = (PSNames_Interface*)
+ FT_Get_Module_Interface( library, "psnames" );
+ }
+
+ /* check that we have a valid TrueType file */
+ error = sfnt->load_sfnt_header( face, stream, face_index, &sfnt_header );
+ if ( error )
+ goto Exit;
+
+ face->format_tag = sfnt_header.format_tag;
+ face->num_tables = sfnt_header.num_tables;
+
+ /* Load font directory */
+ error = sfnt->load_directory( face, stream, &sfnt_header );
+ if ( error )
+ goto Exit;
+
+ face->root.num_faces = face->ttc_header.count;
+ if ( face->root.num_faces < 1 )
+ face->root.num_faces = 1;
+
+ Exit:
+ return error;
+ }
+
+
+#undef LOAD_
+#define LOAD_( x ) ( ( error = sfnt->load_##x( face, stream ) ) \
+ != SFNT_Err_Ok )
+
+
+ FT_LOCAL_DEF FT_Error
+ SFNT_Load_Face( FT_Stream stream,
+ TT_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ FT_Error error;
+ FT_Bool has_outline;
+ FT_Bool is_apple_sbit;
+
+ SFNT_Interface* sfnt = (SFNT_Interface*)face->sfnt;
+
+ FT_UNUSED( face_index );
+ FT_UNUSED( num_params );
+ FT_UNUSED( params );
+
+
+ /* Load tables */
+
+ /* We now support two SFNT-based bitmapped font formats. They */
+ /* are recognized easily as they do not include a `glyf' */
+ /* table. */
+ /* */
+ /* The first format comes from Apple, and uses a table named */
+ /* `bhed' instead of `head' to store the font header (using */
+ /* the same format). It also doesn't include horizontal and */
+ /* vertical metrics tables (i.e. `hhea' and `vhea' tables are */
+ /* missing). */
+ /* */
+ /* The other format comes from Microsoft, and is used with */
+ /* WinCE/PocketPC. It looks like a standard TTF, except that */
+ /* it doesn't contain outlines. */
+ /* */
+
+ /* do we have outlines in there? */
+ has_outline = FT_BOOL( ( TT_LookUp_Table( face, TTAG_glyf ) != 0 ) ||
+ ( TT_LookUp_Table( face, TTAG_CFF ) != 0 ) );
+ is_apple_sbit = 0;
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ /* if this font doesn't contain outlines, we try to load */
+ /* a `bhed' table */
+ if ( !has_outline )
+ is_apple_sbit = FT_BOOL( !LOAD_( bitmap_header ) );
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+ /* load the font header (`head' table) if this isn't an Apple */
+ /* sbit font file */
+ if ( !is_apple_sbit && LOAD_( header ) )
+ goto Exit;
+
+ /* load other tables */
+ if ( LOAD_( max_profile ) ||
+ LOAD_( charmaps ) ||
+ LOAD_( names ) ||
+ LOAD_( psnames ) )
+ goto Exit;
+
+ /* do not load the metrics headers and tables if this is an Apple */
+ /* sbit font file */
+ if ( !is_apple_sbit )
+ {
+ /* load the `hhea' and `hmtx' tables at once */
+ error = sfnt->load_metrics( face, stream, 0 );
+ if ( error )
+ goto Exit;
+
+ /* try to load the `vhea' and `vmtx' tables at once */
+ error = sfnt->load_metrics( face, stream, 1 );
+ if ( error )
+ goto Exit;
+
+ if ( LOAD_( os2 ) )
+ goto Exit;
+ }
+
+ /* the optional tables */
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ /* embedded bitmap support. */
+ if ( sfnt->load_sbits && LOAD_( sbits ) )
+ {
+ /* return an error if this font file has no outlines */
+ if ( error == SFNT_Err_Table_Missing && has_outline )
+ error = SFNT_Err_Ok;
+ else
+ goto Exit;
+ }
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+ if ( LOAD_( hdmx ) ||
+ LOAD_( gasp ) ||
+ LOAD_( kerning ) ||
+ LOAD_( pclt ) )
+ goto Exit;
+
+#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
+ if ( ( error = TT_Extension_Create( face ) ) != SFNT_Err_Ok )
+ goto Exit;
+#endif
+
+ face->root.family_name = Get_Name( face, TT_NAME_ID_FONT_FAMILY );
+ face->root.style_name = Get_Name( face, TT_NAME_ID_FONT_SUBFAMILY );
+
+ /* now set up root fields */
+ {
+ FT_Face root = &face->root;
+ FT_Int flags = 0;
+ TT_CharMap charmap;
+ FT_Int n;
+ FT_Memory memory;
+
+
+ memory = root->memory;
+
+ /*********************************************************************/
+ /* */
+ /* Compute face flags. */
+ /* */
+ if ( has_outline == TRUE )
+ flags = FT_FACE_FLAG_SCALABLE; /* scalable outlines */
+
+ flags |= FT_FACE_FLAG_SFNT | /* SFNT file format */
+ FT_FACE_FLAG_HORIZONTAL; /* horizontal data */
+
+#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+ /* might need more polish to detect the presence of a Postscript */
+ /* name table in the font */
+ flags |= FT_FACE_FLAG_GLYPH_NAMES;
+#endif
+
+ /* fixed width font? */
+ if ( face->postscript.isFixedPitch )
+ flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+ /* vertical information? */
+ if ( face->vertical_info )
+ flags |= FT_FACE_FLAG_VERTICAL;
+
+ /* kerning available ? */
+ if ( face->kern_pairs )
+ flags |= FT_FACE_FLAG_KERNING;
+
+ root->face_flags = flags;
+
+ /*********************************************************************/
+ /* */
+ /* Compute style flags. */
+ /* */
+ flags = 0;
+ if ( has_outline == TRUE && face->os2.version != 0xFFFF )
+ {
+ /* we have an OS/2 table; use the `fsSelection' field */
+ if ( face->os2.fsSelection & 1 )
+ flags |= FT_STYLE_FLAG_ITALIC;
+
+ if ( face->os2.fsSelection & 32 )
+ flags |= FT_STYLE_FLAG_BOLD;
+ }
+ else
+ {
+ /* this is an old Mac font, use the header field */
+ if ( face->header.Mac_Style & 1 )
+ flags |= FT_STYLE_FLAG_BOLD;
+
+ if ( face->header.Mac_Style & 2 )
+ flags |= FT_STYLE_FLAG_ITALIC;
+ }
+
+ root->style_flags = flags;
+
+ /*********************************************************************/
+ /* */
+ /* Polish the charmaps. */
+ /* */
+ /* Try to set the charmap encoding according to the platform & */
+ /* encoding ID of each charmap. */
+ /* */
+ charmap = face->charmaps;
+ root->num_charmaps = face->num_charmaps;
+
+ /* allocate table of pointers */
+ if ( ALLOC_ARRAY( root->charmaps, root->num_charmaps, FT_CharMap ) )
+ goto Exit;
+
+ for ( n = 0; n < root->num_charmaps; n++, charmap++ )
+ {
+ FT_Int platform = charmap->cmap.platformID;
+ FT_Int encoding = charmap->cmap.platformEncodingID;
+
+
+ charmap->root.face = (FT_Face)face;
+ charmap->root.platform_id = (FT_UShort)platform;
+ charmap->root.encoding_id = (FT_UShort)encoding;
+ charmap->root.encoding = find_encoding( platform, encoding );
+
+ /* now, set root->charmap with a unicode charmap */
+ /* wherever available */
+ if ( !root->charmap &&
+ charmap->root.encoding == ft_encoding_unicode )
+ root->charmap = (FT_CharMap)charmap;
+
+ root->charmaps[n] = (FT_CharMap)charmap;
+ }
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ if ( face->num_sbit_strikes )
+ {
+ root->face_flags |= FT_FACE_FLAG_FIXED_SIZES;
+
+#if 0
+ /* I don't know criteria whether layout is horizontal or vertical */
+ if ( has_outline.... )
+ {
+ ...
+ root->face_flags |= FT_FACE_FLAG_VERTICAL;
+ }
+#endif
+ root->num_fixed_sizes = face->num_sbit_strikes;
+
+ if ( ALLOC_ARRAY( root->available_sizes,
+ face->num_sbit_strikes,
+ FT_Bitmap_Size ) )
+ goto Exit;
+
+ for ( n = 0 ; n < face->num_sbit_strikes ; n++ )
+ {
+ root->available_sizes[n].width =
+ face->sbit_strikes[n].x_ppem;
+
+ root->available_sizes[n].height =
+ face->sbit_strikes[n].y_ppem;
+ }
+ }
+ else
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+ {
+ root->num_fixed_sizes = 0;
+ root->available_sizes = 0;
+ }
+
+ /*********************************************************************/
+ /* */
+ /* Set up metrics. */
+ /* */
+ if ( has_outline == TRUE )
+ {
+ /* XXX What about if outline header is missing */
+ /* (e.g. sfnt wrapped outline)? */
+ root->bbox.xMin = face->header.xMin;
+ root->bbox.yMin = face->header.yMin;
+ root->bbox.xMax = face->header.xMax;
+ root->bbox.yMax = face->header.yMax;
+ root->units_per_EM = face->header.Units_Per_EM;
+
+
+ /* XXX: Computing the ascender/descender/height is very different */
+ /* from what the specification tells you. Apparently, we */
+ /* must be careful because */
+ /* */
+ /* - not all fonts have an OS/2 table; in this case, we take */
+ /* the values in the horizontal header. However, these */
+ /* values very often are not reliable. */
+ /* */
+ /* - otherwise, the correct typographic values are in the */
+ /* sTypoAscender, sTypoDescender & sTypoLineGap fields. */
+ /* */
+ /* However, certains fonts have these fields set to 0. */
+ /* Rather, they have usWinAscent & usWinDescent correctly */
+ /* set (but with different values). */
+ /* */
+ /* As an example, Arial Narrow is implemented through four */
+ /* files ARIALN.TTF, ARIALNI.TTF, ARIALNB.TTF & ARIALNBI.TTF */
+ /* */
+ /* Strangely, all fonts have the same values in their */
+ /* sTypoXXX fields, except ARIALNB which sets them to 0. */
+ /* */
+ /* On the other hand, they all have different */
+ /* usWinAscent/Descent values -- as a conclusion, the OS/2 */
+ /* table cannot be used to compute the text height reliably! */
+ /* */
+
+ /* The ascender/descender/height are computed from the OS/2 table */
+ /* when found. Otherwise, they're taken from the horizontal */
+ /* header. */
+ /* */
+
+ root->ascender = face->horizontal.Ascender;
+ root->descender = face->horizontal.Descender;
+
+ root->height = (FT_Short)( root->ascender - root->descender +
+ face->horizontal.Line_Gap );
+
+ /* if the line_gap is 0, we add an extra 15% to the text height -- */
+ /* this computation is based on various versions of Times New Roman */
+ if ( face->horizontal.Line_Gap == 0 )
+ root->height = (FT_Short)( ( root->height * 115 + 50 ) / 100 );
+
+#if 0
+
+ /* some fonts have the OS/2 "sTypoAscender", "sTypoDescender" & */
+ /* "sTypoLineGap" fields set to 0, like ARIALNB.TTF */
+ if ( face->os2.version != 0xFFFF && root->ascender )
+ {
+ FT_Int height;
+
+
+ root->ascender = face->os2.sTypoAscender;
+ root->descender = -face->os2.sTypoDescender;
+
+ height = root->ascender + root->descender + face->os2.sTypoLineGap;
+ if ( height > root->height )
+ root->height = height;
+ }
+
+#endif /* 0 */
+
+ root->max_advance_width = face->horizontal.advance_Width_Max;
+
+ root->max_advance_height = (FT_Short)( face->vertical_info
+ ? face->vertical.advance_Height_Max
+ : root->height );
+
+ root->underline_position = face->postscript.underlinePosition;
+ root->underline_thickness = face->postscript.underlineThickness;
+
+ /* root->max_points -- already set up */
+ /* root->max_contours -- already set up */
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+#undef LOAD_
+
+
+ FT_LOCAL_DEF void
+ SFNT_Done_Face( TT_Face face )
+ {
+ FT_Memory memory = face->root.memory;
+ SFNT_Interface* sfnt = (SFNT_Interface*)face->sfnt;
+
+
+ if ( sfnt )
+ {
+ /* destroy the postscript names table if it is loaded */
+ if ( sfnt->free_psnames )
+ sfnt->free_psnames( face );
+
+ /* destroy the embedded bitmaps table if it is loaded */
+ if ( sfnt->free_sbits )
+ sfnt->free_sbits( face );
+ }
+
+ /* freeing the kerning table */
+ FREE( face->kern_pairs );
+ face->num_kern_pairs = 0;
+
+ /* freeing the collection table */
+ FREE( face->ttc_header.offsets );
+ face->ttc_header.count = 0;
+
+ /* freeing table directory */
+ FREE( face->dir_tables );
+ face->num_tables = 0;
+
+ /* freeing the character mapping tables */
+ if ( sfnt && sfnt->load_charmaps )
+ {
+ FT_UShort n;
+
+
+ for ( n = 0; n < face->num_charmaps; n++ )
+ sfnt->free_charmap( face, &face->charmaps[n].cmap );
+ }
+
+ FREE( face->charmaps );
+ face->num_charmaps = 0;
+
+ FREE( face->root.charmaps );
+ face->root.num_charmaps = 0;
+ face->root.charmap = 0;
+
+ /* freeing the horizontal metrics */
+ FREE( face->horizontal.long_metrics );
+ FREE( face->horizontal.short_metrics );
+
+ /* freeing the vertical ones, if any */
+ if ( face->vertical_info )
+ {
+ FREE( face->vertical.long_metrics );
+ FREE( face->vertical.short_metrics );
+ face->vertical_info = 0;
+ }
+
+ /* freeing the gasp table */
+ FREE( face->gasp.gaspRanges );
+ face->gasp.numRanges = 0;
+
+ /* freeing the name table */
+ sfnt->free_names( face );
+
+ /* freeing the hdmx table */
+ sfnt->free_hdmx( face );
+
+ /* freeing family and style name */
+ FREE( face->root.family_name );
+ FREE( face->root.style_name );
+
+ /* freeing sbit size table */
+ face->root.num_fixed_sizes = 0;
+ if ( face->root.available_sizes )
+ FREE( face->root.available_sizes );
+
+ face->sfnt = 0;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* smooth.c */
+/* */
+/* FreeType anti-aliasing rasterer module component (body only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "ftgrays.c"
+#include "ftsmooth.c"
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* t1afm.c */
+/* */
+/* AFM support for Type 1 fonts (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "t1afm.h"
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+#include <stdlib.h> /* for qsort() */
+#include <string.h> /* for strcmp() */
+#include <ctype.h> /* for isalnum() */
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_t1afm
+
+
+ FT_LOCAL_DEF void
+ T1_Done_AFM( FT_Memory memory,
+ T1_AFM* afm )
+ {
+ FREE( afm->kern_pairs );
+ afm->num_pairs = 0;
+ FREE( afm );
+ }
+
+
+#undef IS_KERN_PAIR
+#define IS_KERN_PAIR( p ) ( p[0] == 'K' && p[1] == 'P' )
+
+#define IS_ALPHANUM( c ) ( isalnum( c ) || \
+ c == '_' || \
+ c == '.' )
+
+
+ /* read a glyph name and return the equivalent glyph index */
+ static FT_UInt
+ afm_atoindex( FT_Byte** start,
+ FT_Byte* limit,
+ T1_Font* type1 )
+ {
+ FT_Byte* p = *start;
+ FT_Int len;
+ FT_UInt result = 0;
+ char temp[64];
+
+
+ /* skip whitespace */
+ while ( ( *p == ' ' || *p == '\t' || *p == ':' || *p == ';' ) &&
+ p < limit )
+ p++;
+ *start = p;
+
+ /* now, read glyph name */
+ while ( IS_ALPHANUM( *p ) && p < limit )
+ p++;
+
+ len = (FT_Int)( p - *start );
+
+ if ( len > 0 && len < 64 )
+ {
+ FT_Int n;
+
+
+ /* copy glyph name to intermediate array */
+ MEM_Copy( temp, *start, len );
+ temp[len] = 0;
+
+ /* lookup glyph name in face array */
+ for ( n = 0; n < type1->num_glyphs; n++ )
+ {
+ char* gname = (char*)type1->glyph_names[n];
+
+
+ if ( gname && gname[0] == temp[0] && strcmp( gname, temp ) == 0 )
+ {
+ result = n;
+ break;
+ }
+ }
+ }
+ *start = p;
+ return result;
+ }
+
+
+ /* read an integer */
+ static int
+ afm_atoi( FT_Byte** start,
+ FT_Byte* limit )
+ {
+ FT_Byte* p = *start;
+ int sum = 0;
+ int sign = 1;
+
+
+ /* skip everything that is not a number */
+ while ( p < limit && !isdigit( *p ) )
+ {
+ sign = 1;
+ if ( *p == '-' )
+ sign = -1;
+
+ p++;
+ }
+
+ while ( p < limit && isdigit( *p ) )
+ {
+ sum = sum * 10 + ( *p - '0' );
+ p++;
+ }
+ *start = p;
+
+ return sum * sign;
+ }
+
+
+#undef KERN_INDEX
+#define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)g1 << 16 ) | g2 )
+
+
+ /* compare two kerning pairs */
+ FT_CALLBACK_DEF( int )
+ compare_kern_pairs( const void* a,
+ const void* b )
+ {
+ T1_Kern_Pair* pair1 = (T1_Kern_Pair*)a;
+ T1_Kern_Pair* pair2 = (T1_Kern_Pair*)b;
+
+ FT_ULong index1 = KERN_INDEX( pair1->glyph1, pair1->glyph2 );
+ FT_ULong index2 = KERN_INDEX( pair2->glyph1, pair2->glyph2 );
+
+
+ return ( index1 - index2 );
+ }
+
+
+ /* parse an AFM file -- for now, only read the kerning pairs */
+ FT_LOCAL_DEF FT_Error
+ T1_Read_AFM( FT_Face t1_face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+ FT_Byte* start;
+ FT_Byte* limit;
+ FT_Byte* p;
+ FT_Int count = 0;
+ T1_Kern_Pair* pair;
+ T1_Font* type1 = &((T1_Face)t1_face)->type1;
+ T1_AFM* afm = 0;
+
+
+ if ( ACCESS_Frame( stream->size ) )
+ return error;
+
+ start = (FT_Byte*)stream->cursor;
+ limit = (FT_Byte*)stream->limit;
+ p = start;
+
+ /* we are now going to count the occurences of `KP' or `KPX' in */
+ /* the AFM file */
+ count = 0;
+ for ( p = start; p < limit - 3; p++ )
+ {
+ if ( IS_KERN_PAIR( p ) )
+ count++;
+ }
+
+ /* Actually, kerning pairs are simply optional! */
+ if ( count == 0 )
+ goto Exit;
+
+ /* allocate the pairs */
+ if ( ALLOC( afm, sizeof ( *afm ) ) ||
+ ALLOC_ARRAY( afm->kern_pairs, count, T1_Kern_Pair ) )
+ goto Exit;
+
+ /* now, read each kern pair */
+ pair = afm->kern_pairs;
+ afm->num_pairs = count;
+
+ /* save in face object */
+ ((T1_Face)t1_face)->afm_data = afm;
+
+ t1_face->face_flags |= FT_FACE_FLAG_KERNING;
+
+ for ( p = start; p < limit - 3; p++ )
+ {
+ if ( IS_KERN_PAIR( p ) )
+ {
+ FT_Byte* q;
+
+
+ /* skip keyword (KP or KPX) */
+ q = p + 2;
+ if ( *q == 'X' )
+ q++;
+
+ pair->glyph1 = afm_atoindex( &q, limit, type1 );
+ pair->glyph2 = afm_atoindex( &q, limit, type1 );
+ pair->kerning.x = afm_atoi( &q, limit );
+
+ pair->kerning.y = 0;
+ if ( p[2] != 'X' )
+ pair->kerning.y = afm_atoi( &q, limit );
+
+ pair++;
+ }
+ }
+
+ /* now, sort the kern pairs according to their glyph indices */
+ qsort( afm->kern_pairs, count, sizeof ( T1_Kern_Pair ),
+ compare_kern_pairs );
+
+ Exit:
+ if ( error )
+ FREE( afm );
+
+ FORGET_Frame();
+
+ return error;
+ }
+
+
+ /* find the kerning for a given glyph pair */
+ FT_LOCAL_DEF void
+ T1_Get_Kerning( T1_AFM* afm,
+ FT_UInt glyph1,
+ FT_UInt glyph2,
+ FT_Vector* kerning )
+ {
+ T1_Kern_Pair *min, *mid, *max;
+ FT_ULong index = KERN_INDEX( glyph1, glyph2 );
+
+
+ /* simple binary search */
+ min = afm->kern_pairs;
+ max = min + afm->num_pairs - 1;
+
+ while ( min <= max )
+ {
+ FT_ULong midi;
+
+
+ mid = min + ( max - min ) / 2;
+ midi = KERN_INDEX( mid->glyph1, mid->glyph2 );
+
+ if ( midi == index )
+ {
+ *kerning = mid->kerning;
+ return;
+ }
+
+ if ( midi < index )
+ min = mid + 1;
+ else
+ max = mid - 1;
+ }
+
+ kerning->x = 0;
+ kerning->y = 0;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* t1decode.c */
+/* */
+/* PostScript Type 1 decoding routines (body). */
+/* */
+/* Copyright 2000-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_OUTLINE_H
+
+#include "t1decode.h"
+#include "psobjs.h"
+
+#include "psauxerr.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_t1decode
+
+
+ typedef enum T1_Operator_
+ {
+ op_none = 0,
+ op_endchar,
+ op_hsbw,
+ op_seac,
+ op_sbw,
+ op_closepath,
+ op_hlineto,
+ op_hmoveto,
+ op_hvcurveto,
+ op_rlineto,
+ op_rmoveto,
+ op_rrcurveto,
+ op_vhcurveto,
+ op_vlineto,
+ op_vmoveto,
+ op_dotsection,
+ op_hstem,
+ op_hstem3,
+ op_vstem,
+ op_vstem3,
+ op_div,
+ op_callothersubr,
+ op_callsubr,
+ op_pop,
+ op_return,
+ op_setcurrentpoint,
+
+ op_max /* never remove this one */
+
+ } T1_Operator;
+
+ static
+ const FT_Int t1_args_count[op_max] =
+ {
+ 0, /* none */
+ 0, /* endchar */
+ 2, /* hsbw */
+ 5, /* seac */
+ 4, /* sbw */
+ 0, /* closepath */
+ 1, /* hlineto */
+ 1, /* hmoveto */
+ 4, /* hvcurveto */
+ 2, /* rlineto */
+ 2, /* rmoveto */
+ 6, /* rrcurveto */
+ 4, /* vhcurveto */
+ 1, /* vlineto */
+ 1, /* vmoveto */
+ 0, /* dotsection */
+ 2, /* hstem */
+ 6, /* hstem3 */
+ 2, /* vstem */
+ 6, /* vstem3 */
+ 2, /* div */
+ -1, /* callothersubr */
+ 1, /* callsubr */
+ 0, /* pop */
+ 0, /* return */
+ 2 /* setcurrentpoint */
+ };
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* t1_lookup_glyph_by_stdcharcode */
+ /* */
+ /* <Description> */
+ /* Looks up a given glyph by its StandardEncoding charcode. Used to */
+ /* implement the SEAC Type 1 operator. */
+ /* */
+ /* <Input> */
+ /* face :: The current face object. */
+ /* */
+ /* charcode :: The character code to look for. */
+ /* */
+ /* <Return> */
+ /* A glyph index in the font face. Returns -1 if the corresponding */
+ /* glyph wasn't found. */
+ /* */
+ static FT_Int
+ t1_lookup_glyph_by_stdcharcode( T1_Decoder* decoder,
+ FT_Int charcode )
+ {
+ FT_UInt n;
+ const FT_String* glyph_name;
+ PSNames_Interface* psnames = decoder->psnames;
+
+
+ /* check range of standard char code */
+ if ( charcode < 0 || charcode > 255 )
+ return -1;
+
+ glyph_name = psnames->adobe_std_strings(
+ psnames->adobe_std_encoding[charcode]);
+
+ for ( n = 0; n < decoder->num_glyphs; n++ )
+ {
+ FT_String* name = (FT_String*)decoder->glyph_names[n];
+
+
+ if ( name && strcmp( name,glyph_name ) == 0 )
+ return n;
+ }
+
+ return -1;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* t1operator_seac */
+ /* */
+ /* <Description> */
+ /* Implements the `seac' Type 1 operator for a Type 1 decoder. */
+ /* */
+ /* <Input> */
+ /* decoder :: The current CID decoder. */
+ /* */
+ /* asb :: The accent's side bearing. */
+ /* */
+ /* adx :: The horizontal offset of the accent. */
+ /* */
+ /* ady :: The vertical offset of the accent. */
+ /* */
+ /* bchar :: The base character's StandardEncoding charcode. */
+ /* */
+ /* achar :: The accent character's StandardEncoding charcode. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ t1operator_seac( T1_Decoder* decoder,
+ FT_Pos asb,
+ FT_Pos adx,
+ FT_Pos ady,
+ FT_Int bchar,
+ FT_Int achar )
+ {
+ FT_Error error;
+ FT_Int bchar_index, achar_index, n_base_points;
+ FT_Outline* base = decoder->builder.base;
+ FT_Vector left_bearing, advance;
+
+
+ /* seac weirdness */
+ adx += decoder->builder.left_bearing.x;
+
+ /* `glyph_names' is set to 0 for CID fonts which do not */
+ /* include an encoding. How can we deal with these? */
+ if ( decoder->glyph_names == 0 )
+ {
+ FT_ERROR(( "t1operator_seac:" ));
+ FT_ERROR(( " glyph names table not available in this font!\n" ));
+ return PSaux_Err_Syntax_Error;
+ }
+
+ bchar_index = t1_lookup_glyph_by_stdcharcode( decoder, bchar );
+ achar_index = t1_lookup_glyph_by_stdcharcode( decoder, achar );
+
+ if ( bchar_index < 0 || achar_index < 0 )
+ {
+ FT_ERROR(( "t1operator_seac:" ));
+ FT_ERROR(( " invalid seac character code arguments\n" ));
+ return PSaux_Err_Syntax_Error;
+ }
+
+ /* if we are trying to load a composite glyph, do not load the */
+ /* accent character and return the array of subglyphs. */
+ if ( decoder->builder.no_recurse )
+ {
+ FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph;
+ FT_GlyphLoader* loader = glyph->internal->loader;
+ FT_SubGlyph* subg;
+
+
+ /* reallocate subglyph array if necessary */
+ error = FT_GlyphLoader_Check_Subglyphs( loader, 2 );
+ if ( error )
+ goto Exit;
+
+ subg = loader->current.subglyphs;
+
+ /* subglyph 0 = base character */
+ subg->index = bchar_index;
+ subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES |
+ FT_SUBGLYPH_FLAG_USE_MY_METRICS;
+ subg->arg1 = 0;
+ subg->arg2 = 0;
+ subg++;
+
+ /* subglyph 1 = accent character */
+ subg->index = achar_index;
+ subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES;
+ subg->arg1 = adx - asb;
+ subg->arg2 = ady;
+
+ /* set up remaining glyph fields */
+ glyph->num_subglyphs = 2;
+ glyph->subglyphs = loader->base.subglyphs;
+ glyph->format = ft_glyph_format_composite;
+
+ loader->current.num_subglyphs = 2;
+ }
+
+ /* First load `bchar' in builder */
+ /* now load the unscaled outline */
+
+ FT_GlyphLoader_Prepare( decoder->builder.loader ); /* prepare loader */
+
+ error = T1_Decoder_Parse_Glyph( decoder, bchar_index );
+ if ( error )
+ goto Exit;
+
+ n_base_points = base->n_points;
+
+ /* save the left bearing and width of the base character */
+ /* as they will be erased by the next load. */
+
+ left_bearing = decoder->builder.left_bearing;
+ advance = decoder->builder.advance;
+
+ decoder->builder.left_bearing.x = 0;
+ decoder->builder.left_bearing.y = 0;
+
+ /* Now load `achar' on top of */
+ /* the base outline */
+ error = T1_Decoder_Parse_Glyph( decoder, achar_index );
+ if ( error )
+ goto Exit;
+
+ /* restore the left side bearing and */
+ /* advance width of the base character */
+
+ decoder->builder.left_bearing = left_bearing;
+ decoder->builder.advance = advance;
+
+ /* Finally, move the accent */
+ if ( decoder->builder.load_points )
+ {
+ FT_Outline dummy;
+
+
+ dummy.n_points = (short)( base->n_points - n_base_points );
+ dummy.points = base->points + n_base_points;
+
+ FT_Outline_Translate( &dummy, adx - asb, ady );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* T1_Decoder_Parse_Charstrings */
+ /* */
+ /* <Description> */
+ /* Parses a given Type 1 charstrings program. */
+ /* */
+ /* <Input> */
+ /* decoder :: The current Type 1 decoder. */
+ /* */
+ /* charstring_base :: The base address of the charstring stream. */
+ /* */
+ /* charstring_len :: The length in bytes of the charstring stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ T1_Decoder_Parse_Charstrings( T1_Decoder* decoder,
+ FT_Byte* charstring_base,
+ FT_UInt charstring_len )
+ {
+ FT_Error error;
+ T1_Decoder_Zone* zone;
+ FT_Byte* ip;
+ FT_Byte* limit;
+ T1_Builder* builder = &decoder->builder;
+ FT_Pos x, y;
+
+
+ /* we don't want to touch the source code -- use macro trick */
+#define start_point T1_Builder_Start_Point
+#define check_points T1_Builder_Check_Points
+#define add_point T1_Builder_Add_Point
+#define add_point1 T1_Builder_Add_Point1
+#define add_contour T1_Builder_Add_Contour
+#define close_contour T1_Builder_Close_Contour
+
+ /* First of all, initialize the decoder */
+ decoder->top = decoder->stack;
+ decoder->zone = decoder->zones;
+ zone = decoder->zones;
+
+ builder->path_begun = 0;
+
+ zone->base = charstring_base;
+ limit = zone->limit = charstring_base + charstring_len;
+ ip = zone->cursor = zone->base;
+
+ error = PSaux_Err_Ok;
+
+ x = builder->pos_x;
+ y = builder->pos_y;
+
+ /* now, execute loop */
+ while ( ip < limit )
+ {
+ FT_Long* top = decoder->top;
+ T1_Operator op = op_none;
+ FT_Long value = 0;
+
+
+ /*********************************************************************/
+ /* */
+ /* Decode operator or operand */
+ /* */
+ /* */
+
+ /* first of all, decompress operator or value */
+ switch ( *ip++ )
+ {
+ case 1:
+ op = op_hstem;
+ break;
+
+ case 3:
+ op = op_vstem;
+ break;
+ case 4:
+ op = op_vmoveto;
+ break;
+ case 5:
+ op = op_rlineto;
+ break;
+ case 6:
+ op = op_hlineto;
+ break;
+ case 7:
+ op = op_vlineto;
+ break;
+ case 8:
+ op = op_rrcurveto;
+ break;
+ case 9:
+ op = op_closepath;
+ break;
+ case 10:
+ op = op_callsubr;
+ break;
+ case 11:
+ op = op_return;
+ break;
+
+ case 13:
+ op = op_hsbw;
+ break;
+ case 14:
+ op = op_endchar;
+ break;
+
+ case 21:
+ op = op_rmoveto;
+ break;
+ case 22:
+ op = op_hmoveto;
+ break;
+
+ case 30:
+ op = op_vhcurveto;
+ break;
+ case 31:
+ op = op_hvcurveto;
+ break;
+
+ case 12:
+ if ( ip > limit )
+ {
+ FT_ERROR(( "T1_Decoder_Parse_CharStrings: "
+ "invalid escape (12+EOF)\n" ));
+ goto Syntax_Error;
+ }
+
+ switch ( *ip++ )
+ {
+ case 0:
+ op = op_dotsection;
+ break;
+ case 1:
+ op = op_vstem3;
+ break;
+ case 2:
+ op = op_hstem3;
+ break;
+ case 6:
+ op = op_seac;
+ break;
+ case 7:
+ op = op_sbw;
+ break;
+ case 12:
+ op = op_div;
+ break;
+ case 16:
+ op = op_callothersubr;
+ break;
+ case 17:
+ op = op_pop;
+ break;
+ case 33:
+ op = op_setcurrentpoint;
+ break;
+
+ default:
+ FT_ERROR(( "T1_Decoder_Parse_CharStrings: "
+ "invalid escape (12+%d)\n",
+ ip[-1] ));
+ goto Syntax_Error;
+ }
+ break;
+
+ case 255: /* four bytes integer */
+ if ( ip + 4 > limit )
+ {
+ FT_ERROR(( "T1_Decoder_Parse_CharStrings: "
+ "unexpected EOF in integer\n" ));
+ goto Syntax_Error;
+ }
+
+ value = (FT_Int32)( ((FT_Long)ip[0] << 24) |
+ ((FT_Long)ip[1] << 16) |
+ ((FT_Long)ip[2] << 8 ) |
+ ip[3] );
+ ip += 4;
+ break;
+
+ default:
+ if ( ip[-1] >= 32 )
+ {
+ if ( ip[-1] < 247 )
+ value = (FT_Long)ip[-1] - 139;
+ else
+ {
+ if ( ++ip > limit )
+ {
+ FT_ERROR(( "T1_Decoder_Parse_CharStrings: " ));
+ FT_ERROR(( "unexpected EOF in integer\n" ));
+ goto Syntax_Error;
+ }
+
+ if ( ip[-2] < 251 )
+ value = ( ( (FT_Long)ip[-2] - 247 ) << 8 ) + ip[-1] + 108;
+ else
+ value = -( ( ( (FT_Long)ip[-2] - 251 ) << 8 ) + ip[-1] + 108 );
+ }
+ }
+ else
+ {
+ FT_ERROR(( "T1_Decoder_Parse_CharStrings: "
+ "invalid byte (%d)\n", ip[-1] ));
+ goto Syntax_Error;
+ }
+ }
+
+ /*********************************************************************/
+ /* */
+ /* Push value on stack, or process operator */
+ /* */
+ /* */
+ if ( op == op_none )
+ {
+ if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS )
+ {
+ FT_ERROR(( "T1_Decoder_Parse_CharStrings: stack overflow!\n" ));
+ goto Syntax_Error;
+ }
+
+ FT_TRACE4(( " %ld", value ));
+
+ *top++ = value;
+ decoder->top = top;
+ }
+ else if ( op == op_callothersubr ) /* callothersubr */
+ {
+ FT_TRACE4(( " callothersubr" ));
+
+ if ( top - decoder->stack < 2 )
+ goto Stack_Underflow;
+
+ top -= 2;
+ switch ( top[1] )
+ {
+ case 1: /* start flex feature */
+ if ( top[0] != 0 )
+ goto Unexpected_OtherSubr;
+
+ decoder->flex_state = 1;
+ decoder->num_flex_vectors = 0;
+ if ( start_point( builder, x, y ) ||
+ check_points( builder, 6 ) )
+ goto Memory_Error;
+ break;
+
+ case 2: /* add flex vectors */
+ {
+ FT_Int index;
+
+ if ( top[0] != 0 )
+ goto Unexpected_OtherSubr;
+
+ /* note that we should not add a point for index 0; */
+ /* this will move our current position to the flex */
+ /* point without adding any point to the outline */
+ index = decoder->num_flex_vectors++;
+ if ( index > 0 && index < 7 )
+ add_point( builder,
+ x,
+ y,
+ (FT_Byte)( index == 3 || index == 6 ) );
+ }
+ break;
+
+ case 0: /* end flex feature */
+ if ( top[0] != 3 )
+ goto Unexpected_OtherSubr;
+
+ if ( decoder->flex_state == 0 ||
+ decoder->num_flex_vectors != 7 )
+ {
+ FT_ERROR(( "T1_Decoder_Parse_CharStrings: "
+ "unexpected flex end\n" ));
+ goto Syntax_Error;
+ }
+
+ /* now consume the remaining `pop pop setcurpoint' */
+ if ( ip + 6 > limit ||
+ ip[0] != 12 || ip[1] != 17 || /* pop */
+ ip[2] != 12 || ip[3] != 17 || /* pop */
+ ip[4] != 12 || ip[5] != 33 ) /* setcurpoint */
+ {
+ FT_ERROR(( "T1_Decoder_Parse_CharStrings: "
+ "invalid flex charstring\n" ));
+ goto Syntax_Error;
+ }
+
+ ip += 6;
+ decoder->flex_state = 0;
+ break;
+
+ case 3: /* change hints */
+ if ( top[0] != 1 )
+ goto Unexpected_OtherSubr;
+
+ /* eat the following `pop' */
+ if ( ip + 2 > limit )
+ {
+ FT_ERROR(( "T1_Decoder_Parse_CharStrings: "
+ "invalid escape (12+%d)\n", ip[-1] ));
+ goto Syntax_Error;
+ }
+
+ if ( ip[0] != 12 || ip[1] != 17 )
+ {
+ FT_ERROR(( "T1_Decoder_Parse_CharStrings: " ));
+ FT_ERROR(( "`pop' expected, found (%d %d)\n", ip[0], ip[1] ));
+ goto Syntax_Error;
+ }
+ ip += 2;
+ break;
+
+ case 12:
+ case 13:
+ /* counter control hints, clear stack */
+ top = decoder->stack;
+ break;
+
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18: /* multiple masters */
+ {
+ T1_Blend* blend = decoder->blend;
+ FT_UInt num_points, nn, mm;
+ FT_Long* delta;
+ FT_Long* values;
+
+
+ if ( !blend )
+ {
+ FT_ERROR(( "T1_Decoder_Parse_CharStrings: " ));
+ FT_ERROR(( "unexpected multiple masters operator!\n" ));
+ goto Syntax_Error;
+ }
+
+ num_points = top[1] - 13 + ( top[1] == 18 );
+ if ( top[0] != (FT_Int)( num_points * blend->num_designs ) )
+ {
+ FT_ERROR(( "T1_Decoder_Parse_CharStrings: " ));
+ FT_ERROR(( "incorrect number of mm arguments\n" ));
+ goto Syntax_Error;
+ }
+
+ top -= blend->num_designs*num_points;
+ if ( top < decoder->stack )
+ goto Stack_Underflow;
+
+ /* we want to compute: */
+ /* */
+ /* a0*w0 + a1*w1 + ... + ak*wk */
+ /* */
+ /* but we only have the a0, a1-a0, a2-a0, .. ak-a0 */
+ /* however, given that w0 + w1 + ... + wk == 1, we can */
+ /* rewrite it easily as: */
+ /* */
+ /* a0 + (a1-a0)*w1 + (a2-a0)*w2 + .. + (ak-a0)*wk */
+ /* */
+ /* where k == num_designs-1 */
+ /* */
+ /* I guess that's why it's written in this `compact' */
+ /* form. */
+ /* */
+ delta = top + num_points;
+ values = top;
+ for ( nn = 0; nn < num_points; nn++ )
+ {
+ FT_Int tmp = values[0];
+
+
+ for ( mm = 1; mm < blend->num_designs; mm++ )
+ tmp += FT_MulFix( *delta++, blend->weight_vector[mm] );
+
+ *values++ = tmp;
+ }
+ /* note that `top' will be incremented later by calls to `pop' */
+ break;
+ }
+
+ default:
+ Unexpected_OtherSubr:
+ FT_ERROR(( "T1_Decoder_Parse_CharStrings: "
+ "invalid othersubr [%d %d]!\n", top[0], top[1] ));
+ goto Syntax_Error;
+ }
+ decoder->top = top;
+ }
+ else /* general operator */
+ {
+ FT_Int num_args = t1_args_count[op];
+
+
+ if ( top - decoder->stack < num_args )
+ goto Stack_Underflow;
+
+ top -= num_args;
+
+ switch ( op )
+ {
+ case op_endchar:
+ FT_TRACE4(( " endchar" ));
+
+ close_contour( builder );
+
+ /* add current outline to the glyph slot */
+ FT_GlyphLoader_Add( builder->loader );
+
+ /* return now! */
+ FT_TRACE4(( "\n\n" ));
+ return PSaux_Err_Ok;
+
+ case op_hsbw:
+ FT_TRACE4(( " hsbw" ));
+
+ builder->left_bearing.x += top[0];
+ builder->advance.x = top[1];
+ builder->advance.y = 0;
+
+ builder->last.x = x = top[0];
+ builder->last.y = y = 0;
+
+ /* the `metrics_only' indicates that we only want to compute */
+ /* the glyph's metrics (lsb + advance width), not load the */
+ /* rest of it; so exit immediately */
+ if ( builder->metrics_only )
+ return PSaux_Err_Ok;
+
+ break;
+
+ case op_seac:
+ /* return immediately after the processing */
+ return t1operator_seac( decoder, top[0], top[1],
+ top[2], top[3], top[4] );
+
+ case op_sbw:
+ FT_TRACE4(( " sbw" ));
+
+ builder->left_bearing.x += top[0];
+ builder->left_bearing.y += top[1];
+ builder->advance.x = top[2];
+ builder->advance.y = top[3];
+
+ builder->last.x = x = top[0];
+ builder->last.y = y = top[1];
+
+ /* the `metrics_only' indicates that we only want to compute */
+ /* the glyph's metrics (lsb + advance width), not load the */
+ /* rest of it; so exit immediately */
+ if ( builder->metrics_only )
+ return PSaux_Err_Ok;
+
+ break;
+
+ case op_closepath:
+ FT_TRACE4(( " closepath" ));
+
+ close_contour( builder );
+ builder->path_begun = 0;
+ break;
+
+ case op_hlineto:
+ FT_TRACE4(( " hlineto" ));
+
+ if ( start_point( builder, x, y ) )
+ goto Memory_Error;
+
+ x += top[0];
+ goto Add_Line;
+
+ case op_hmoveto:
+ FT_TRACE4(( " hmoveto" ));
+
+ x += top[0];
+ if ( !decoder->flex_state )
+ builder->path_begun = 0;
+ break;
+
+ case op_hvcurveto:
+ FT_TRACE4(( " hvcurveto" ));
+
+ if ( start_point( builder, x, y ) ||
+ check_points( builder, 3 ) )
+ goto Memory_Error;
+
+ x += top[0];
+ add_point( builder, x, y, 0 );
+ x += top[1];
+ y += top[2];
+ add_point( builder, x, y, 0 );
+ y += top[3];
+ add_point( builder, x, y, 1 );
+ break;
+
+ case op_rlineto:
+ FT_TRACE4(( " rlineto" ));
+
+ if ( start_point( builder, x, y ) )
+ goto Memory_Error;
+
+ x += top[0];
+ y += top[1];
+
+ Add_Line:
+ if ( add_point1( builder, x, y ) )
+ goto Memory_Error;
+ break;
+
+ case op_rmoveto:
+ FT_TRACE4(( " rmoveto" ));
+
+ x += top[0];
+ y += top[1];
+ if ( !decoder->flex_state )
+ builder->path_begun = 0;
+ break;
+
+ case op_rrcurveto:
+ FT_TRACE4(( " rcurveto" ));
+
+ if ( start_point( builder, x, y ) ||
+ check_points( builder, 3 ) )
+ goto Memory_Error;
+
+ x += top[0];
+ y += top[1];
+ add_point( builder, x, y, 0 );
+
+ x += top[2];
+ y += top[3];
+ add_point( builder, x, y, 0 );
+
+ x += top[4];
+ y += top[5];
+ add_point( builder, x, y, 1 );
+ break;
+
+ case op_vhcurveto:
+ FT_TRACE4(( " vhcurveto" ));
+
+ if ( start_point( builder, x, y ) ||
+ check_points( builder, 3 ) )
+ goto Memory_Error;
+
+ y += top[0];
+ add_point( builder, x, y, 0 );
+ x += top[1];
+ y += top[2];
+ add_point( builder, x, y, 0 );
+ x += top[3];
+ add_point( builder, x, y, 1 );
+ break;
+
+ case op_vlineto:
+ FT_TRACE4(( " vlineto" ));
+
+ if ( start_point( builder, x, y ) )
+ goto Memory_Error;
+
+ y += top[0];
+ goto Add_Line;
+
+ case op_vmoveto:
+ FT_TRACE4(( " vmoveto" ));
+
+ y += top[0];
+ if ( !decoder->flex_state )
+ builder->path_begun = 0;
+ break;
+
+ case op_div:
+ FT_TRACE4(( " div" ));
+
+ if ( top[1] )
+ {
+ *top = top[0] / top[1];
+ ++top;
+ }
+ else
+ {
+ FT_ERROR(( "T1_Decoder_Parse_CharStrings: division by 0\n" ));
+ goto Syntax_Error;
+ }
+ break;
+
+ case op_callsubr:
+ {
+ FT_Int index;
+
+
+ FT_TRACE4(( " callsubr" ));
+
+ index = top[0];
+ if ( index < 0 || index >= (FT_Int)decoder->num_subrs )
+ {
+ FT_ERROR(( "T1_Decoder_Parse_CharStrings: "
+ "invalid subrs index\n" ));
+ goto Syntax_Error;
+ }
+
+ if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS )
+ {
+ FT_ERROR(( "T1_Decoder_Parse_CharStrings: "
+ "too many nested subrs\n" ));
+ goto Syntax_Error;
+ }
+
+ zone->cursor = ip; /* save current instruction pointer */
+
+ zone++;
+
+ /* The Type 1 driver stores subroutines without the seed bytes. */
+ /* The CID driver stores subroutines with seed bytes. This */
+ /* case is taken care of when decoder->subrs_len == 0. */
+ zone->base = decoder->subrs[index];
+
+ if ( decoder->subrs_len )
+ zone->limit = zone->base + decoder->subrs_len[index];
+ else
+ {
+ /* We are using subroutines from a CID font. We must adjust */
+ /* for the seed bytes. */
+ zone->base += ( decoder->lenIV >= 0 ? decoder->lenIV : 0 );
+ zone->limit = decoder->subrs[index + 1];
+ }
+
+ zone->cursor = zone->base;
+
+ if ( !zone->base )
+ {
+ FT_ERROR(( "T1_Decoder_Parse_CharStrings: "
+ "invoking empty subrs!\n" ));
+ goto Syntax_Error;
+ }
+
+ decoder->zone = zone;
+ ip = zone->base;
+ limit = zone->limit;
+ break;
+ }
+
+ case op_pop:
+ FT_TRACE4(( " pop" ));
+
+ /* theoretically, the arguments are already on the stack */
+ top++;
+ break;
+
+ case op_return:
+ FT_TRACE4(( " return" ));
+
+ if ( zone <= decoder->zones )
+ {
+ FT_ERROR(( "T1_Decoder_Parse_CharStrings: unexpected return\n" ));
+ goto Syntax_Error;
+ }
+
+ zone--;
+ ip = zone->cursor;
+ limit = zone->limit;
+ decoder->zone = zone;
+ break;
+
+ case op_dotsection:
+ FT_TRACE4(( " dotsection" ));
+
+ break;
+
+ case op_hstem:
+ FT_TRACE4(( " hstem" ));
+
+ break;
+
+ case op_hstem3:
+ FT_TRACE4(( " hstem3" ));
+
+ break;
+
+ case op_vstem:
+ FT_TRACE4(( " vstem" ));
+
+ break;
+
+ case op_vstem3:
+ FT_TRACE4(( " vstem3" ));
+
+ break;
+
+ case op_setcurrentpoint:
+ FT_TRACE4(( " setcurrentpoint" ));
+
+ FT_ERROR(( "T1_Decoder_Parse_CharStrings: " ));
+ FT_ERROR(( "unexpected `setcurrentpoint'\n" ));
+ goto Syntax_Error;
+
+ default:
+ FT_ERROR(( "T1_Decoder_Parse_CharStrings: "
+ "unhandled opcode %d\n", op ));
+ goto Syntax_Error;
+ }
+
+ decoder->top = top;
+
+ } /* general operator processing */
+
+ } /* while ip < limit */
+
+ FT_TRACE4(( "..end..\n\n" ));
+ return error;
+
+ Syntax_Error:
+ return PSaux_Err_Syntax_Error;
+
+ Stack_Underflow:
+ return PSaux_Err_Stack_Underflow;
+
+ Memory_Error:
+ return builder->error;
+ }
+
+
+ FT_LOCAL_DEF FT_Error
+ T1_Decoder_Parse_Glyph( T1_Decoder* decoder,
+ FT_UInt glyph )
+ {
+ return decoder->parse_callback( decoder, glyph );
+ }
+
+
+ FT_LOCAL_DEF FT_Error
+ T1_Decoder_Init( T1_Decoder* decoder,
+ FT_Face face,
+ FT_Size size,
+ FT_GlyphSlot slot,
+ FT_Byte** glyph_names,
+ T1_Blend* blend,
+ T1_Decoder_Callback parse_callback )
+ {
+ MEM_Set( decoder, 0, sizeof ( *decoder ) );
+
+ /* retrieve PSNames interface from list of current modules */
+ {
+ PSNames_Interface* psnames = 0;
+
+
+ psnames = (PSNames_Interface*)FT_Get_Module_Interface(
+ FT_FACE_LIBRARY(face), "psnames" );
+ if ( !psnames )
+ {
+ FT_ERROR(( "T1_Decoder_Init: " ));
+ FT_ERROR(( "the `psnames' module is not available\n" ));
+ return PSaux_Err_Unimplemented_Feature;
+ }
+
+ decoder->psnames = psnames;
+ }
+ T1_Builder_Init( &decoder->builder, face, size, slot );
+
+ decoder->num_glyphs = face->num_glyphs;
+ decoder->glyph_names = glyph_names;
+ decoder->blend = blend;
+ decoder->parse_callback = parse_callback;
+
+ decoder->funcs = t1_decoder_funcs;
+
+ return 0;
+ }
+
+
+ FT_LOCAL_DEF void
+ T1_Decoder_Done( T1_Decoder* decoder )
+ {
+ T1_Builder_Done( &decoder->builder );
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* t1driver.c */
+/* */
+/* Type 1 driver interface (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "t1driver.h"
+#include "t1gload.h"
+#include "t1load.h"
+
+#include "t1errors.h"
+
+#ifndef T1_CONFIG_OPTION_NO_AFM
+#include "t1afm.h"
+#endif
+
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+#include <string.h> /* for strcmp() */
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_t1driver
+
+
+ static FT_Error
+ t1_get_glyph_name( T1_Face face,
+ FT_UInt glyph_index,
+ FT_Pointer buffer,
+ FT_UInt buffer_max )
+ {
+ FT_String* gname;
+
+
+ gname = face->type1.glyph_names[glyph_index];
+
+ if ( buffer_max > 0 )
+ {
+ FT_UInt len = (FT_UInt)( strlen( gname ) );
+
+
+ if (len >= buffer_max)
+ len = buffer_max - 1;
+
+ MEM_Copy( buffer, gname, len );
+ ((FT_Byte*)buffer)[len] = 0;
+ }
+
+ return T1_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* t1_get_name_index */
+ /* */
+ /* <Description> */
+ /* Uses the Type 1 font's `glyph_names' table to find a given glyph */
+ /* name's glyph index. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* glyph_name :: The glyph name. */
+ /* */
+ /* <Return> */
+ /* Glyph index. 0 means `undefined character code'. */
+ /* */
+ static FT_UInt
+ t1_get_name_index( T1_Face face,
+ FT_String* glyph_name )
+ {
+ FT_Int i;
+ FT_String* gname;
+
+
+ for ( i = 0; i < face->type1.num_glyphs; i++ )
+ {
+ gname = face->type1.glyph_names[i];
+
+ if ( !strcmp( glyph_name, gname ) )
+ return (FT_UInt)i;
+ }
+
+ return 0;
+ }
+
+
+ static const char*
+ t1_get_ps_name( T1_Face face )
+ {
+ return (const char*) face->type1.font_name;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Get_Interface */
+ /* */
+ /* <Description> */
+ /* Each driver can provide one or more extensions to the base */
+ /* FreeType API. These can be used to access format specific */
+ /* features (e.g., all TrueType/OpenType resources share a common */
+ /* file structure and common tables which can be accessed through the */
+ /* `sfnt' interface), or more simply generic ones (e.g., the */
+ /* `postscript names' interface which can be used to retrieve the */
+ /* PostScript name of a given glyph index). */
+ /* */
+ /* <InOut> */
+ /* driver :: A handle to a driver object. */
+ /* */
+ /* <Input> */
+ /* interface :: A string designing the interface. Examples are */
+ /* `sfnt', `post_names', `charmaps', etc. */
+ /* */
+ /* <Return> */
+ /* A typeless pointer to the extension's interface (normally a table */
+ /* of function pointers). Returns NULL if the requested extension */
+ /* isn't available (i.e., wasn't compiled in the driver at build */
+ /* time). */
+ /* */
+ static FT_Module_Interface
+ Get_Interface( FT_Driver driver,
+ const FT_String* interface )
+ {
+ FT_UNUSED( driver );
+ FT_UNUSED( interface );
+
+ if ( strcmp( (const char*)interface, "glyph_name" ) == 0 )
+ return (FT_Module_Interface)t1_get_glyph_name;
+
+ if ( strcmp( (const char*)interface, "name_index" ) == 0 )
+ return (FT_Module_Interface)t1_get_name_index;
+
+ if ( strcmp( (const char*)interface, "postscript_name" ) == 0 )
+ return (FT_Module_Interface)t1_get_ps_name;
+
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+ if ( strcmp( (const char*)interface, "get_mm" ) == 0 )
+ return (FT_Module_Interface)T1_Get_Multi_Master;
+
+ if ( strcmp( (const char*)interface, "set_mm_design") == 0 )
+ return (FT_Module_Interface)T1_Set_MM_Design;
+
+ if ( strcmp( (const char*)interface, "set_mm_blend") == 0 )
+ return (FT_Module_Interface)T1_Set_MM_Blend;
+#endif
+ return 0;
+ }
+
+
+#ifndef T1_CONFIG_OPTION_NO_AFM
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Get_Kerning */
+ /* */
+ /* <Description> */
+ /* A driver method used to return the kerning vector between two */
+ /* glyphs of the same face. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* left_glyph :: The index of the left glyph in the kern pair. */
+ /* */
+ /* right_glyph :: The index of the right glyph in the kern pair. */
+ /* */
+ /* <Output> */
+ /* kerning :: The kerning vector. This is in font units for */
+ /* scalable formats, and in pixels for fixed-sizes */
+ /* formats. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Only horizontal layouts (left-to-right & right-to-left) are */
+ /* supported by this function. Other layouts, or more sophisticated */
+ /* kernings are out of scope of this method (the basic driver */
+ /* interface is meant to be simple). */
+ /* */
+ /* They can be implemented by format-specific interfaces. */
+ /* */
+ static FT_Error
+ Get_Kerning( T1_Face face,
+ FT_UInt left_glyph,
+ FT_UInt right_glyph,
+ FT_Vector* kerning )
+ {
+ T1_AFM* afm;
+
+
+ kerning->x = 0;
+ kerning->y = 0;
+
+ afm = (T1_AFM*)face->afm_data;
+ if ( afm )
+ T1_Get_Kerning( afm, left_glyph, right_glyph, kerning );
+
+ return T1_Err_Ok;
+ }
+
+
+#endif /* T1_CONFIG_OPTION_NO_AFM */
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Get_Char_Index */
+ /* */
+ /* <Description> */
+ /* Uses a charmap to return a given character code's glyph index. */
+ /* */
+ /* <Input> */
+ /* charmap :: A handle to the source charmap object. */
+ /* charcode :: The character code. */
+ /* */
+ /* <Return> */
+ /* Glyph index. 0 means `undefined character code'. */
+ /* */
+ static FT_UInt
+ Get_Char_Index( FT_CharMap charmap,
+ FT_Long charcode )
+ {
+ T1_Face face;
+ FT_UInt result = 0;
+ PSNames_Interface* psnames;
+
+
+ face = (T1_Face)charmap->face;
+ psnames = (PSNames_Interface*)face->psnames;
+ if ( psnames )
+ switch ( charmap->encoding )
+ {
+ /*******************************************************************/
+ /* */
+ /* Unicode encoding support */
+ /* */
+ case ft_encoding_unicode:
+ /* use the `PSNames' module to synthetize the Unicode charmap */
+ result = psnames->lookup_unicode( &face->unicode_map,
+ (FT_ULong)charcode );
+
+ /* the function returns 0xFFFF if the Unicode charcode has */
+ /* no corresponding glyph */
+ if ( result == 0xFFFF )
+ result = 0;
+ goto Exit;
+
+ /*******************************************************************/
+ /* */
+ /* Custom Type 1 encoding */
+ /* */
+ case ft_encoding_adobe_custom:
+ {
+ T1_Encoding* encoding = &face->type1.encoding;
+
+
+ if ( charcode >= encoding->code_first &&
+ charcode <= encoding->code_last )
+ result = encoding->char_index[charcode];
+ goto Exit;
+ }
+
+ /*******************************************************************/
+ /* */
+ /* Adobe Standard & Expert encoding support */
+ /* */
+ default:
+ if ( charcode < 256 )
+ {
+ FT_UInt code;
+ FT_Int n;
+ const char* glyph_name;
+
+
+ code = psnames->adobe_std_encoding[charcode];
+ if ( charmap->encoding == ft_encoding_adobe_expert )
+ code = psnames->adobe_expert_encoding[charcode];
+
+ glyph_name = psnames->adobe_std_strings( code );
+ if ( !glyph_name )
+ break;
+
+ for ( n = 0; n < face->type1.num_glyphs; n++ )
+ {
+ const char* gname = face->type1.glyph_names[n];
+
+
+ if ( gname && gname[0] == glyph_name[0] &&
+ strcmp( gname, glyph_name ) == 0 )
+ {
+ result = n;
+ break;
+ }
+ }
+ }
+ }
+ Exit:
+ return result;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Driver_Class t1_driver_class =
+ {
+ {
+ ft_module_font_driver | ft_module_driver_scalable,
+ sizeof( FT_DriverRec ),
+
+ "type1",
+ 0x10000L,
+ 0x20000L,
+
+ 0, /* format interface */
+
+ (FT_Module_Constructor)T1_Init_Driver,
+ (FT_Module_Destructor) T1_Done_Driver,
+ (FT_Module_Requester) Get_Interface,
+ },
+
+ sizeof( T1_FaceRec ),
+ sizeof( T1_SizeRec ),
+ sizeof( T1_GlyphSlotRec ),
+
+ (FTDriver_initFace) T1_Init_Face,
+ (FTDriver_doneFace) T1_Done_Face,
+ (FTDriver_initSize) 0,
+ (FTDriver_doneSize) 0,
+ (FTDriver_initGlyphSlot)0,
+ (FTDriver_doneGlyphSlot)0,
+
+ (FTDriver_setCharSizes) 0,
+ (FTDriver_setPixelSizes)0,
+ (FTDriver_loadGlyph) T1_Load_Glyph,
+ (FTDriver_getCharIndex) Get_Char_Index,
+
+#ifdef T1_CONFIG_OPTION_NO_AFM
+ (FTDriver_getKerning) 0,
+ (FTDriver_attachFile) 0,
+#else
+ (FTDriver_getKerning) Get_Kerning,
+ (FTDriver_attachFile) T1_Read_AFM,
+#endif
+ (FTDriver_getAdvances) 0
+ };
+
+
+#ifdef FT_CONFIG_OPTION_DYNAMIC_DRIVERS
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* getDriverClass */
+ /* */
+ /* <Description> */
+ /* This function is used when compiling the TrueType driver as a */
+ /* shared library (`.DLL' or `.so'). It will be used by the */
+ /* high-level library of FreeType to retrieve the address of the */
+ /* driver's generic interface. */
+ /* */
+ /* It shouldn't be implemented in a static build, as each driver must */
+ /* have the same function as an exported entry point. */
+ /* */
+ /* <Return> */
+ /* The address of the TrueType's driver generic interface. The */
+ /* format-specific interface can then be retrieved through the method */
+ /* interface->get_format_interface. */
+ /* */
+ FT_EXPORT_DEF( const FT_Driver_Class* )
+ getDriverClass( void )
+ {
+ return &t1_driver_class;
+ }
+
+
+#endif /* FT_CONFIG_OPTION_DYNAMIC_DRIVERS */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* t1gload.c */
+/* */
+/* Type 1 Glyph Loader (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "t1gload.h"
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_OUTLINE_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+#include "t1errors.h"
+
+#include <string.h> /* for strcmp() */
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_t1gload
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********** *********/
+ /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/
+ /********** *********/
+ /********** The following code is in charge of computing *********/
+ /********** the maximum advance width of the font. It *********/
+ /********** quickly processes each glyph charstring to *********/
+ /********** extract the value from either a `sbw' or `seac' *********/
+ /********** operator. *********/
+ /********** *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ T1_Parse_Glyph( T1_Decoder* decoder,
+ FT_UInt glyph_index )
+ {
+ T1_Face face = (T1_Face)decoder->builder.face;
+ T1_Font* type1 = &face->type1;
+
+
+ decoder->font_matrix = type1->font_matrix;
+ decoder->font_offset = type1->font_offset;
+
+ return decoder->funcs.parse_charstrings(
+ decoder,
+ type1->charstrings [glyph_index],
+ type1->charstrings_len[glyph_index] );
+ }
+
+
+ FT_LOCAL_DEF FT_Error
+ T1_Compute_Max_Advance( T1_Face face,
+ FT_Int* max_advance )
+ {
+ FT_Error error;
+ T1_Decoder decoder;
+ FT_Int glyph_index;
+ T1_Font* type1 = &face->type1;
+ PSAux_Interface* psaux = (PSAux_Interface*)face->psaux;
+
+
+ *max_advance = 0;
+
+ /* initialize load decoder */
+ error = psaux->t1_decoder_funcs->init( &decoder,
+ (FT_Face)face,
+ 0, /* size */
+ 0, /* glyph slot */
+ (FT_Byte**)type1->glyph_names,
+ face->blend,
+ T1_Parse_Glyph );
+ if ( error )
+ return error;
+
+ decoder.builder.metrics_only = 1;
+ decoder.builder.load_points = 0;
+
+ decoder.num_subrs = type1->num_subrs;
+ decoder.subrs = type1->subrs;
+ decoder.subrs_len = type1->subrs_len;
+
+ /* for each glyph, parse the glyph charstring and extract */
+ /* the advance width */
+ for ( glyph_index = 0; glyph_index < type1->num_glyphs; glyph_index++ )
+ {
+ /* now get load the unscaled outline */
+ error = T1_Parse_Glyph( &decoder, glyph_index );
+ /* ignore the error if one occured - skip to next glyph */
+ }
+
+ *max_advance = decoder.builder.advance.x;
+ return T1_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /********** *********/
+ /********** UNHINTED GLYPH LOADER *********/
+ /********** *********/
+ /********** The following code is in charge of loading a *********/
+ /********** single outline. It completely ignores hinting *********/
+ /********** and is used when FT_LOAD_NO_HINTING is set. *********/
+ /********** *********/
+ /********** The Type 1 hinter is located in `t1hint.c' *********/
+ /********** *********/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_LOCAL_DEF FT_Error
+ T1_Load_Glyph( T1_GlyphSlot glyph,
+ T1_Size size,
+ FT_Int glyph_index,
+ FT_Int load_flags )
+ {
+ FT_Error error;
+ T1_Decoder decoder;
+ T1_Face face = (T1_Face)glyph->root.face;
+ FT_Bool hinting;
+ T1_Font* type1 = &face->type1;
+ PSAux_Interface* psaux = (PSAux_Interface*)face->psaux;
+ const T1_Decoder_Funcs* decoder_funcs = psaux->t1_decoder_funcs;
+
+ FT_Matrix font_matrix;
+ FT_Vector font_offset;
+
+ if ( load_flags & FT_LOAD_NO_RECURSE )
+ load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+
+ glyph->x_scale = size->root.metrics.x_scale;
+ glyph->y_scale = size->root.metrics.y_scale;
+
+ glyph->root.outline.n_points = 0;
+ glyph->root.outline.n_contours = 0;
+
+ hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 &&
+ ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
+
+ glyph->root.format = ft_glyph_format_outline;
+
+ error = decoder_funcs->init( &decoder,
+ (FT_Face)face,
+ (FT_Size)size,
+ (FT_GlyphSlot)glyph,
+ (FT_Byte**)type1->glyph_names,
+ face->blend,
+ T1_Parse_Glyph );
+ if ( error )
+ goto Exit;
+
+ decoder.builder.no_recurse = FT_BOOL(
+ ( load_flags & FT_LOAD_NO_RECURSE ) != 0 );
+
+ decoder.num_subrs = type1->num_subrs;
+ decoder.subrs = type1->subrs;
+ decoder.subrs_len = type1->subrs_len;
+
+
+ /* now load the unscaled outline */
+ error = T1_Parse_Glyph( &decoder, glyph_index );
+ if ( error )
+ goto Exit;
+
+ font_matrix = decoder.font_matrix;
+ font_offset = decoder.font_offset;
+
+ /* save new glyph tables */
+ decoder_funcs->done( &decoder );
+
+ /* now, set the metrics -- this is rather simple, as */
+ /* the left side bearing is the xMin, and the top side */
+ /* bearing the yMax */
+ if ( !error )
+ {
+ glyph->root.outline.flags &= ft_outline_owner;
+ glyph->root.outline.flags |= ft_outline_reverse_fill;
+
+ /* for composite glyphs, return only left side bearing and */
+ /* advance width */
+ if ( load_flags & FT_LOAD_NO_RECURSE )
+ {
+ FT_Slot_Internal internal = glyph->root.internal;
+
+
+ glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x;
+ glyph->root.metrics.horiAdvance = decoder.builder.advance.x;
+ internal->glyph_matrix = font_matrix;
+ internal->glyph_delta = font_offset;
+ internal->glyph_transformed = 1;
+ }
+ else
+ {
+ FT_BBox cbox;
+ FT_Glyph_Metrics* metrics = &glyph->root.metrics;
+
+
+ /* copy the _unscaled_ advance width */
+ metrics->horiAdvance = decoder.builder.advance.x;
+ glyph->root.linearHoriAdvance = decoder.builder.advance.x;
+ glyph->root.internal->glyph_transformed = 0;
+
+ /* make up vertical metrics */
+ metrics->vertBearingX = 0;
+ metrics->vertBearingY = 0;
+ metrics->vertAdvance = 0;
+
+ glyph->root.linearVertAdvance = 0;
+
+ glyph->root.format = ft_glyph_format_outline;
+
+ if ( size && size->root.metrics.y_ppem < 24 )
+ glyph->root.outline.flags |= ft_outline_high_precision;
+
+ /* apply the font matrix */
+ FT_Outline_Transform( &glyph->root.outline, &font_matrix );
+
+ FT_Outline_Translate( &glyph->root.outline,
+ font_offset.x,
+ font_offset.y );
+
+#if 0
+
+ glyph->root.outline.second_pass = TRUE;
+ glyph->root.outline.high_precision = size->root.metrics.y_ppem < 24;
+ glyph->root.outline.dropout_mode = 2;
+
+#endif /* 0 */
+
+ if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 )
+ {
+ /* scale the outline and the metrics */
+ FT_Int n;
+ FT_Outline* cur = decoder.builder.base;
+ FT_Vector* vec = cur->points;
+ FT_Fixed x_scale = glyph->x_scale;
+ FT_Fixed y_scale = glyph->y_scale;
+
+
+ /* First of all, scale the points */
+ for ( n = cur->n_points; n > 0; n--, vec++ )
+ {
+ vec->x = FT_MulFix( vec->x, x_scale );
+ vec->y = FT_MulFix( vec->y, y_scale );
+ }
+
+ FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
+
+ /* Then scale the metrics */
+ metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
+ metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
+
+ metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale );
+ metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale );
+ }
+
+ /* compute the other metrics */
+ FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
+
+ /* grid fit the bounding box if necessary */
+ if ( hinting )
+ {
+ cbox.xMin &= -64;
+ cbox.yMin &= -64;
+ cbox.xMax = ( cbox.xMax+63 ) & -64;
+ cbox.yMax = ( cbox.yMax+63 ) & -64;
+ }
+
+ metrics->width = cbox.xMax - cbox.xMin;
+ metrics->height = cbox.yMax - cbox.yMin;
+
+ metrics->horiBearingX = cbox.xMin;
+ metrics->horiBearingY = cbox.yMax;
+ }
+
+ /* Set control data to the glyph charstrings. Note that this is */
+ /* _not_ zero-terminated. */
+ glyph->root.control_data = type1->charstrings [glyph_index];
+ glyph->root.control_len = type1->charstrings_len[glyph_index];
+ }
+
+ Exit:
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* t1load.c */
+/* */
+/* Type 1 font loader (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This is the new and improved Type 1 data loader for FreeType 2. The */
+ /* old loader has several problems: it is slow, complex, difficult to */
+ /* maintain, and contains incredible hacks to make it accept some */
+ /* ill-formed Type 1 fonts without hiccup-ing. Moreover, about 5% of */
+ /* the Type 1 fonts on my machine still aren't loaded correctly by it. */
+ /* */
+ /* This version is much simpler, much faster and also easier to read and */
+ /* maintain by a great order of magnitude. The idea behind it is to */
+ /* _not_ try to read the Type 1 token stream with a state machine (i.e. */
+ /* a Postscript-like interpreter) but rather to perform simple pattern */
+ /* matching. */
+ /* */
+ /* Indeed, nearly all data definitions follow a simple pattern like */
+ /* */
+ /* ... /Field <data> ... */
+ /* */
+ /* where <data> can be a number, a boolean, a string, or an array of */
+ /* numbers. There are a few exceptions, namely the encoding, font name, */
+ /* charstrings, and subrs; they are handled with a special pattern */
+ /* matching routine. */
+ /* */
+ /* All other common cases are handled very simply. The matching rules */
+ /* are defined in the file `t1tokens.h' through the use of several */
+ /* macros calls PARSE_XXX. */
+ /* */
+ /* This file is included twice here; the first time to generate parsing */
+ /* callback functions, the second to generate a table of keywords (with */
+ /* pointers to the associated callback). */
+ /* */
+ /* The function `parse_dict' simply scans *linearly* a given dictionary */
+ /* (either the top-level or private one) and calls the appropriate */
+ /* callback when it encounters an immediate keyword. */
+ /* */
+ /* This is by far the fastest way one can find to parse and read all */
+ /* data. */
+ /* */
+ /* This led to tremendous code size reduction. Note that later, the */
+ /* glyph loader will also be _greatly_ simplified, and the automatic */
+ /* hinter will replace the clumsy `t1hinter'. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_CONFIG_CONFIG_H
+#include FT_MULTIPLE_MASTERS_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+
+#include "t1load.h"
+
+#include "t1errors.h"
+
+#include <string.h> /* for strncmp(), strcmp() */
+#include <ctype.h> /* for isalnum() */
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_t1load
+
+
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** MULTIPLE MASTERS SUPPORT *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static FT_Error
+ t1_allocate_blend( T1_Face face,
+ FT_UInt num_designs,
+ FT_UInt num_axis )
+ {
+ T1_Blend* blend;
+ FT_Memory memory = face->root.memory;
+ FT_Error error = 0;
+
+
+ blend = face->blend;
+ if ( !blend )
+ {
+ if ( ALLOC( blend, sizeof ( *blend ) ) )
+ goto Exit;
+
+ face->blend = blend;
+ }
+
+ /* allocate design data if needed */
+ if ( num_designs > 0 )
+ {
+ if ( blend->num_designs == 0 )
+ {
+ FT_UInt nn;
+
+
+ /* allocate the blend `private' and `font_info' dictionaries */
+ if ( ALLOC_ARRAY( blend->font_infos[1], num_designs, T1_FontInfo ) ||
+ ALLOC_ARRAY( blend->privates[1], num_designs, T1_Private ) ||
+ ALLOC_ARRAY( blend->weight_vector, num_designs * 2, FT_Fixed ) )
+ goto Exit;
+
+ blend->default_weight_vector = blend->weight_vector + num_designs;
+
+ blend->font_infos[0] = &face->type1.font_info;
+ blend->privates [0] = &face->type1.private_dict;
+
+ for ( nn = 2; nn <= num_designs; nn++ )
+ {
+ blend->privates[nn] = blend->privates [nn - 1] + 1;
+ blend->font_infos[nn] = blend->font_infos[nn - 1] + 1;
+ }
+
+ blend->num_designs = num_designs;
+ }
+ else if ( blend->num_designs != num_designs )
+ goto Fail;
+ }
+
+ /* allocate axis data if needed */
+ if ( num_axis > 0 )
+ {
+ if ( blend->num_axis != 0 && blend->num_axis != num_axis )
+ goto Fail;
+
+ blend->num_axis = num_axis;
+ }
+
+ /* allocate the blend design pos table if needed */
+ num_designs = blend->num_designs;
+ num_axis = blend->num_axis;
+ if ( num_designs && num_axis && blend->design_pos[0] == 0 )
+ {
+ FT_UInt n;
+
+
+ if ( ALLOC_ARRAY( blend->design_pos[0],
+ num_designs * num_axis, FT_Fixed ) )
+ goto Exit;
+
+ for ( n = 1; n < num_designs; n++ )
+ blend->design_pos[n] = blend->design_pos[0] + num_axis * n;
+ }
+
+ Exit:
+ return error;
+
+ Fail:
+ error = -1;
+ goto Exit;
+ }
+
+
+ FT_LOCAL_DEF FT_Error
+ T1_Get_Multi_Master( T1_Face face,
+ FT_Multi_Master* master )
+ {
+ T1_Blend* blend = face->blend;
+ FT_UInt n;
+ FT_Error error;
+
+
+ error = T1_Err_Invalid_Argument;
+
+ if ( blend )
+ {
+ master->num_axis = blend->num_axis;
+ master->num_designs = blend->num_designs;
+
+ for ( n = 0; n < blend->num_axis; n++ )
+ {
+ FT_MM_Axis* axis = master->axis + n;
+ T1_DesignMap* map = blend->design_map + n;
+
+
+ axis->name = blend->axis_names[n];
+ axis->minimum = map->design_points[0];
+ axis->maximum = map->design_points[map->num_points - 1];
+ }
+ error = 0;
+ }
+ return error;
+ }
+
+
+ FT_LOCAL_DEF FT_Error
+ T1_Set_MM_Blend( T1_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords )
+ {
+ T1_Blend* blend = face->blend;
+ FT_Error error;
+ FT_UInt n, m;
+
+
+ error = T1_Err_Invalid_Argument;
+
+ if ( blend && blend->num_axis == num_coords )
+ {
+ /* recompute the weight vector from the blend coordinates */
+ error = T1_Err_Ok;
+
+ for ( n = 0; n < blend->num_designs; n++ )
+ {
+ FT_Fixed result = 0x10000L; /* 1.0 fixed */
+
+
+ for ( m = 0; m < blend->num_axis; m++ )
+ {
+ FT_Fixed factor;
+
+
+ /* get current blend axis position */
+ factor = coords[m];
+ if ( factor < 0 ) factor = 0;
+ if ( factor > 0x10000L ) factor = 0x10000L;
+
+ if ( ( n & ( 1 << m ) ) == 0 )
+ factor = 0x10000L - factor;
+
+ result = FT_MulFix( result, factor );
+ }
+ blend->weight_vector[n] = result;
+ }
+
+ error = T1_Err_Ok;
+ }
+ return error;
+ }
+
+
+ FT_LOCAL_DEF FT_Error
+ T1_Set_MM_Design( T1_Face face,
+ FT_UInt num_coords,
+ FT_Long* coords )
+ {
+ T1_Blend* blend = face->blend;
+ FT_Error error;
+ FT_UInt n, p;
+
+
+ error = T1_Err_Invalid_Argument;
+ if ( blend && blend->num_axis == num_coords )
+ {
+ /* compute the blend coordinates through the blend design map */
+ FT_Fixed final_blends[T1_MAX_MM_DESIGNS];
+
+
+ for ( n = 0; n < blend->num_axis; n++ )
+ {
+ FT_Long design = coords[n];
+ FT_Fixed the_blend;
+ T1_DesignMap* map = blend->design_map + n;
+ FT_Fixed* designs = map->design_points;
+ FT_Fixed* blends = map->blend_points;
+ FT_Int before = -1, after = -1;
+
+ for ( p = 0; p < (FT_UInt)map->num_points; p++ )
+ {
+ FT_Fixed p_design = designs[p];
+
+
+ /* exact match ? */
+ if ( design == p_design )
+ {
+ the_blend = blends[p];
+ goto Found;
+ }
+
+ if ( design < p_design )
+ {
+ after = p;
+ break;
+ }
+
+ before = p;
+ }
+
+ /* now, interpolate if needed */
+ if ( before < 0 )
+ the_blend = blends[0];
+
+ else if ( after < 0 )
+ the_blend = blends[map->num_points - 1];
+
+ else
+ the_blend = FT_MulDiv( design - designs[before],
+ blends [after] - blends [before],
+ designs[after] - designs[before] );
+
+ Found:
+ final_blends[n] = the_blend;
+ }
+
+ error = T1_Set_MM_Blend( face, num_coords, final_blends );
+ }
+
+ return error;
+ }
+
+
+ FT_LOCAL_DEF void
+ T1_Done_Blend( T1_Face face )
+ {
+ FT_Memory memory = face->root.memory;
+ T1_Blend* blend = face->blend;
+
+
+ if ( blend )
+ {
+ FT_UInt num_designs = blend->num_designs;
+ FT_UInt num_axis = blend->num_axis;
+ FT_UInt n;
+
+
+ /* release design pos table */
+ FREE( blend->design_pos[0] );
+ for ( n = 1; n < num_designs; n++ )
+ blend->design_pos[n] = 0;
+
+ /* release blend `private' and `font info' dictionaries */
+ FREE( blend->privates[1] );
+ FREE( blend->font_infos[1] );
+
+ for ( n = 0; n < num_designs; n++ )
+ {
+ blend->privates [n] = 0;
+ blend->font_infos[n] = 0;
+ }
+
+ /* release weight vectors */
+ FREE( blend->weight_vector );
+ blend->default_weight_vector = 0;
+
+ /* release axis names */
+ for ( n = 0; n < num_axis; n++ )
+ FREE( blend->axis_names[n] );
+
+ /* release design map */
+ for ( n = 0; n < num_axis; n++ )
+ {
+ T1_DesignMap* dmap = blend->design_map + n;
+
+
+ FREE( dmap->design_points );
+ dmap->num_points = 0;
+ }
+
+ FREE( face->blend );
+ }
+ }
+
+
+ static void
+ parse_blend_axis_types( T1_Face face,
+ T1_Loader* loader )
+ {
+ T1_Token axis_tokens[ T1_MAX_MM_AXIS ];
+ FT_Int n, num_axis;
+ FT_Error error = 0;
+ T1_Blend* blend;
+ FT_Memory memory;
+
+
+ /* take an array of objects */
+ T1_ToTokenArray( &loader->parser, axis_tokens,
+ T1_MAX_MM_AXIS, &num_axis );
+ if ( num_axis <= 0 || num_axis > T1_MAX_MM_AXIS )
+ {
+ FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n",
+ num_axis ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* allocate blend if necessary */
+ error = t1_allocate_blend( face, 0, (FT_UInt)num_axis );
+ if ( error )
+ goto Exit;
+
+ blend = face->blend;
+ memory = face->root.memory;
+
+ /* each token is an immediate containing the name of the axis */
+ for ( n = 0; n < num_axis; n++ )
+ {
+ T1_Token* token = axis_tokens + n;
+ FT_Byte* name;
+ FT_Int len;
+
+ /* skip first slash, if any */
+ if (token->start[0] == '/')
+ token->start++;
+
+ len = (FT_Int)( token->limit - token->start );
+ if ( len <= 0 )
+ {
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ if ( ALLOC( blend->axis_names[n], len + 1 ) )
+ goto Exit;
+
+ name = (FT_Byte*)blend->axis_names[n];
+ MEM_Copy( name, token->start, len );
+ name[len] = 0;
+ }
+
+ Exit:
+ loader->parser.root.error = error;
+ }
+
+
+ static void
+ parse_blend_design_positions( T1_Face face,
+ T1_Loader* loader )
+ {
+ T1_Token design_tokens[ T1_MAX_MM_DESIGNS ];
+ FT_Int num_designs;
+ FT_Int num_axis;
+ T1_ParserRec* parser = &loader->parser;
+
+ FT_Error error = 0;
+ T1_Blend* blend;
+
+
+ /* get the array of design tokens - compute number of designs */
+ T1_ToTokenArray( parser, design_tokens, T1_MAX_MM_DESIGNS, &num_designs );
+ if ( num_designs <= 0 || num_designs > T1_MAX_MM_DESIGNS )
+ {
+ FT_ERROR(( "parse_blend_design_positions:" ));
+ FT_ERROR(( " incorrect number of designs: %d\n",
+ num_designs ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ {
+ FT_Byte* old_cursor = parser->root.cursor;
+ FT_Byte* old_limit = parser->root.limit;
+ FT_UInt n;
+
+
+ blend = face->blend;
+ num_axis = 0; /* make compiler happy */
+
+ for ( n = 0; n < (FT_UInt)num_designs; n++ )
+ {
+ T1_Token axis_tokens[ T1_MAX_MM_DESIGNS ];
+ T1_Token* token;
+ FT_Int axis, n_axis;
+
+
+ /* read axis/coordinates tokens */
+ token = design_tokens + n;
+ parser->root.cursor = token->start - 1;
+ parser->root.limit = token->limit + 1;
+ T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis );
+
+ if ( n == 0 )
+ {
+ num_axis = n_axis;
+ error = t1_allocate_blend( face, num_designs, num_axis );
+ if ( error )
+ goto Exit;
+ blend = face->blend;
+ }
+ else if ( n_axis != num_axis )
+ {
+ FT_ERROR(( "parse_blend_design_positions: incorrect table\n" ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* now, read each axis token into the design position */
+ for ( axis = 0; axis < n_axis; axis++ )
+ {
+ T1_Token* token2 = axis_tokens + axis;
+
+
+ parser->root.cursor = token2->start;
+ parser->root.limit = token2->limit;
+ blend->design_pos[n][axis] = T1_ToFixed( parser, 0 );
+ }
+ }
+
+ loader->parser.root.cursor = old_cursor;
+ loader->parser.root.limit = old_limit;
+ }
+
+ Exit:
+ loader->parser.root.error = error;
+ }
+
+
+ static void
+ parse_blend_design_map( T1_Face face,
+ T1_Loader* loader )
+ {
+ FT_Error error = 0;
+ T1_ParserRec* parser = &loader->parser;
+ T1_Blend* blend;
+ T1_Token axis_tokens[ T1_MAX_MM_AXIS ];
+ FT_Int n, num_axis;
+ FT_Byte* old_cursor;
+ FT_Byte* old_limit;
+ FT_Memory memory = face->root.memory;
+
+
+ T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &num_axis );
+ if ( num_axis <= 0 || num_axis > T1_MAX_MM_AXIS )
+ {
+ FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n",
+ num_axis ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+ old_cursor = parser->root.cursor;
+ old_limit = parser->root.limit;
+
+ error = t1_allocate_blend( face, 0, num_axis );
+ if ( error )
+ goto Exit;
+ blend = face->blend;
+
+ /* now, read each axis design map */
+ for ( n = 0; n < num_axis; n++ )
+ {
+ T1_DesignMap* map = blend->design_map + n;
+ T1_Token* token;
+ FT_Int p, num_points;
+
+
+ token = axis_tokens + n;
+ parser->root.cursor = token->start;
+ parser->root.limit = token->limit;
+
+ /* count the number of map points */
+ {
+ FT_Byte* ptr = token->start;
+ FT_Byte* limit = token->limit;
+
+
+ num_points = 0;
+ for ( ; ptr < limit; ptr++ )
+ if ( ptr[0] == '[' )
+ num_points++;
+ }
+ if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS )
+ {
+ FT_ERROR(( "parse_blend_design_map: incorrect table\n" ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* allocate design map data */
+ if ( ALLOC_ARRAY( map->design_points, num_points * 2, FT_Fixed ) )
+ goto Exit;
+ map->blend_points = map->design_points + num_points;
+ map->num_points = (FT_Byte)num_points;
+
+ for ( p = 0; p < num_points; p++ )
+ {
+ map->design_points[p] = T1_ToInt( parser );
+ map->blend_points [p] = T1_ToFixed( parser, 0 );
+ }
+ }
+
+ parser->root.cursor = old_cursor;
+ parser->root.limit = old_limit;
+
+ Exit:
+ parser->root.error = error;
+ }
+
+
+ static void
+ parse_weight_vector( T1_Face face,
+ T1_Loader* loader )
+ {
+ FT_Error error = 0;
+ T1_ParserRec* parser = &loader->parser;
+ T1_Blend* blend = face->blend;
+ T1_Token master;
+ FT_UInt n;
+ FT_Byte* old_cursor;
+ FT_Byte* old_limit;
+
+
+ if ( !blend || blend->num_designs == 0 )
+ {
+ FT_ERROR(( "parse_weight_vector: too early!\n" ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ T1_ToToken( parser, &master );
+ if ( master.type != t1_token_array )
+ {
+ FT_ERROR(( "parse_weight_vector: incorrect format!\n" ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ old_cursor = parser->root.cursor;
+ old_limit = parser->root.limit;
+
+ parser->root.cursor = master.start;
+ parser->root.limit = master.limit;
+
+ for ( n = 0; n < blend->num_designs; n++ )
+ {
+ blend->default_weight_vector[n] =
+ blend->weight_vector[n] = T1_ToFixed( parser, 0 );
+ }
+
+ parser->root.cursor = old_cursor;
+ parser->root.limit = old_limit;
+
+ Exit:
+ parser->root.error = error;
+ }
+
+
+ /* the keyword `/shareddict' appears in some multiple master fonts */
+ /* with a lot of Postscript garbage behind it (that's completely out */
+ /* of spec!); we detect it and terminate the parsing */
+ /* */
+ static void
+ parse_shared_dict( T1_Face face,
+ T1_Loader* loader )
+ {
+ T1_ParserRec* parser = &loader->parser;
+
+ FT_UNUSED( face );
+
+
+ parser->root.cursor = parser->root.limit;
+ parser->root.error = 0;
+ }
+
+#endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** TYPE 1 SYMBOL PARSING *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* First of all, define the token field static variables. This is a set */
+ /* of T1_Field variables used later. */
+ /* */
+ /*************************************************************************/
+
+
+ static FT_Error
+ t1_load_keyword( T1_Face face,
+ T1_Loader* loader,
+ T1_Field* field )
+ {
+ FT_Error error;
+ void* dummy_object;
+ void** objects;
+ FT_UInt max_objects;
+ T1_Blend* blend = face->blend;
+
+
+ /* if the keyword has a dedicated callback, call it */
+ if ( field->type == t1_field_callback )
+ {
+ field->reader( (FT_Face)face, loader );
+ error = loader->parser.root.error;
+ goto Exit;
+ }
+
+ /* now, the keyword is either a simple field, or a table of fields; */
+ /* we are now going to take care of it */
+ switch ( field->location )
+ {
+ case t1_field_font_info:
+ dummy_object = &face->type1.font_info;
+ objects = &dummy_object;
+ max_objects = 0;
+
+ if ( blend )
+ {
+ objects = (void**)blend->font_infos;
+ max_objects = blend->num_designs;
+ }
+ break;
+
+ case t1_field_private:
+ dummy_object = &face->type1.private_dict;
+ objects = &dummy_object;
+ max_objects = 0;
+
+ if ( blend )
+ {
+ objects = (void**)blend->privates;
+ max_objects = blend->num_designs;
+ }
+ break;
+
+ default:
+ dummy_object = &face->type1;
+ objects = &dummy_object;
+ max_objects = 0;
+ }
+
+ if ( field->type == t1_field_integer_array ||
+ field->type == t1_field_fixed_array )
+ error = T1_Load_Field_Table( &loader->parser, field,
+ objects, max_objects, 0 );
+ else
+ error = T1_Load_Field( &loader->parser, field,
+ objects, max_objects, 0 );
+
+ Exit:
+ return error;
+ }
+
+
+ static int
+ is_space( FT_Byte c )
+ {
+ return ( c == ' ' || c == '\t' || c == '\r' || c == '\n' );
+ }
+
+
+ static int
+ is_alpha( FT_Byte c )
+ {
+ /* Note: we must accept "+" as a valid character, as it is used in */
+ /* embedded type1 fonts in PDF documents. */
+ /* */
+ return ( isalnum( c ) || c == '.' || c == '_' || c == '-' || c == '+' );
+ }
+
+
+ static int
+ read_binary_data( T1_ParserRec* parser,
+ FT_Int* size,
+ FT_Byte** base )
+ {
+ FT_Byte* cur;
+ FT_Byte* limit = parser->root.limit;
+
+
+ /* the binary data has the following format */
+ /* */
+ /* `size' [white*] RD white ....... ND */
+ /* */
+
+ T1_Skip_Spaces( parser );
+ cur = parser->root.cursor;
+
+ if ( cur < limit && (FT_Byte)( *cur - '0' ) < 10 )
+ {
+ *size = T1_ToInt( parser );
+
+ T1_Skip_Spaces( parser );
+ T1_Skip_Alpha ( parser ); /* `RD' or `-|' or something else */
+
+ /* there is only one whitespace char after the */
+ /* `RD' or `-|' token */
+ *base = parser->root.cursor + 1;
+
+ parser->root.cursor += *size + 1;
+ return 1;
+ }
+
+ FT_ERROR(( "read_binary_data: invalid size field\n" ));
+ parser->root.error = T1_Err_Invalid_File_Format;
+ return 0;
+ }
+
+
+ /* we will now define the routines used to handle */
+ /* the `/Encoding', `/Subrs', and `/CharStrings' */
+ /* dictionaries */
+
+ static void
+ parse_font_name( T1_Face face,
+ T1_Loader* loader )
+ {
+ T1_ParserRec* parser = &loader->parser;
+ FT_Error error;
+ FT_Memory memory = parser->root.memory;
+ FT_Int len;
+ FT_Byte* cur;
+ FT_Byte* cur2;
+ FT_Byte* limit;
+
+
+ T1_Skip_Spaces( parser );
+
+ cur = parser->root.cursor;
+ limit = parser->root.limit;
+
+ if ( cur >= limit - 1 || *cur != '/' )
+ return;
+
+ cur++;
+ cur2 = cur;
+ while ( cur2 < limit && is_alpha( *cur2 ) )
+ cur2++;
+
+ len = (FT_Int)( cur2 - cur );
+ if ( len > 0 )
+ {
+ if ( ALLOC( face->type1.font_name, len + 1 ) )
+ {
+ parser->root.error = error;
+ return;
+ }
+
+ MEM_Copy( face->type1.font_name, cur, len );
+ face->type1.font_name[len] = '\0';
+ }
+ parser->root.cursor = cur2;
+ }
+
+
+ static void
+ parse_font_bbox( T1_Face face,
+ T1_Loader* loader )
+ {
+ T1_ParserRec* parser = &loader->parser;
+ FT_Fixed temp[4];
+ FT_BBox* bbox = &face->type1.font_bbox;
+
+
+ (void)T1_ToFixedArray( parser, 4, temp, 0 );
+ bbox->xMin = FT_RoundFix( temp[0] );
+ bbox->yMin = FT_RoundFix( temp[1] );
+ bbox->xMax = FT_RoundFix( temp[2] );
+ bbox->yMax = FT_RoundFix( temp[3] );
+ }
+
+
+ static void
+ parse_font_matrix( T1_Face face,
+ T1_Loader* loader )
+ {
+ T1_ParserRec* parser = &loader->parser;
+ FT_Matrix* matrix = &face->type1.font_matrix;
+ FT_Vector* offset = &face->type1.font_offset;
+ FT_Face root = (FT_Face)&face->root;
+ FT_Fixed temp[6];
+ FT_Fixed temp_scale;
+
+
+ if ( matrix->xx || matrix->yx )
+ /* with synthetic fonts, it's possible we get here twice */
+ return;
+
+ (void)T1_ToFixedArray( parser, 6, temp, 3 );
+
+ temp_scale = ABS( temp[3] );
+
+ /* Set Units per EM based on FontMatrix values. We set the value to */
+ /* 1000 / temp_scale, because temp_scale was already multiplied by */
+ /* 1000 (in t1_tofixed, from psobjs.c). */
+
+ root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L,
+ temp_scale ) >> 16 );
+
+ /* we need to scale the values by 1.0/temp_scale */
+ if ( temp_scale != 0x10000L )
+ {
+ temp[0] = FT_DivFix( temp[0], temp_scale );
+ temp[1] = FT_DivFix( temp[1], temp_scale );
+ temp[2] = FT_DivFix( temp[2], temp_scale );
+ temp[4] = FT_DivFix( temp[4], temp_scale );
+ temp[5] = FT_DivFix( temp[5], temp_scale );
+ temp[3] = 0x10000L;
+ }
+
+ matrix->xx = temp[0];
+ matrix->yx = temp[1];
+ matrix->xy = temp[2];
+ matrix->yy = temp[3];
+
+ /* note that the offsets must be expressed in integer font units */
+ offset->x = temp[4] >> 16;
+ offset->y = temp[5] >> 16;
+ }
+
+
+ static void
+ parse_encoding( T1_Face face,
+ T1_Loader* loader )
+ {
+ T1_ParserRec* parser = &loader->parser;
+ FT_Byte* cur = parser->root.cursor;
+ FT_Byte* limit = parser->root.limit;
+
+ PSAux_Interface* psaux = (PSAux_Interface*)face->psaux;
+
+
+ /* skip whitespace */
+ while ( is_space( *cur ) )
+ {
+ cur++;
+ if ( cur >= limit )
+ {
+ FT_ERROR(( "parse_encoding: out of bounds!\n" ));
+ parser->root.error = T1_Err_Invalid_File_Format;
+ return;
+ }
+ }
+
+ /* if we have a number, then the encoding is an array, */
+ /* and we must load it now */
+ if ( (FT_Byte)( *cur - '0' ) < 10 )
+ {
+ T1_Encoding* encode = &face->type1.encoding;
+ FT_Int count, n;
+ PS_Table* char_table = &loader->encoding_table;
+ FT_Memory memory = parser->root.memory;
+ FT_Error error;
+
+
+ /* read the number of entries in the encoding, should be 256 */
+ count = T1_ToInt( parser );
+ if ( parser->root.error )
+ return;
+
+ /* we use a T1_Table to store our charnames */
+ encode->num_chars = count;
+ if ( ALLOC_ARRAY( encode->char_index, count, FT_Short ) ||
+ ALLOC_ARRAY( encode->char_name, count, FT_String* ) ||
+ ( error = psaux->ps_table_funcs->init(
+ char_table, count, memory ) ) != 0 )
+ {
+ parser->root.error = error;
+ return;
+ }
+
+ /* We need to `zero' out encoding_table.elements */
+ for ( n = 0; n < count; n++ )
+ {
+ char* notdef = (char *)".notdef";
+
+
+ T1_Add_Table( char_table, n, notdef, 8 );
+ }
+
+ /* Now, we will need to read a record of the form */
+ /* ... charcode /charname ... for each entry in our table */
+ /* */
+ /* We simply look for a number followed by an immediate */
+ /* name. Note that this ignores correctly the sequence */
+ /* that is often seen in type1 fonts: */
+ /* */
+ /* 0 1 255 { 1 index exch /.notdef put } for dup */
+ /* */
+ /* used to clean the encoding array before anything else. */
+ /* */
+ /* We stop when we encounter a `def'. */
+
+ cur = parser->root.cursor;
+ limit = parser->root.limit;
+ n = 0;
+
+ for ( ; cur < limit; )
+ {
+ FT_Byte c;
+
+
+ c = *cur;
+
+ /* we stop when we encounter a `def' */
+ if ( c == 'd' && cur + 3 < limit )
+ {
+ if ( cur[1] == 'e' &&
+ cur[2] == 'f' &&
+ is_space(cur[-1]) &&
+ is_space(cur[3]) )
+ {
+ FT_TRACE6(( "encoding end\n" ));
+ break;
+ }
+ }
+
+ /* otherwise, we must find a number before anything else */
+ if ( (FT_Byte)( c - '0' ) < 10 )
+ {
+ FT_Int charcode;
+
+
+ parser->root.cursor = cur;
+ charcode = T1_ToInt( parser );
+ cur = parser->root.cursor;
+
+ /* skip whitespace */
+ while ( cur < limit && is_space( *cur ) )
+ cur++;
+
+ if ( cur < limit && *cur == '/' )
+ {
+ /* bingo, we have an immediate name -- it must be a */
+ /* character name */
+ FT_Byte* cur2 = cur + 1;
+ FT_Int len;
+
+
+ while ( cur2 < limit && is_alpha( *cur2 ) )
+ cur2++;
+
+ len = (FT_Int)( cur2 - cur - 1 );
+
+ parser->root.error = T1_Add_Table( char_table, charcode,
+ cur + 1, len + 1 );
+ char_table->elements[charcode][len] = '\0';
+ if ( parser->root.error )
+ return;
+
+ cur = cur2;
+ }
+ }
+ else
+ cur++;
+ }
+
+ face->type1.encoding_type = t1_encoding_array;
+ parser->root.cursor = cur;
+ }
+ /* Otherwise, we should have either `StandardEncoding' or */
+ /* `ExpertEncoding' */
+ else
+ {
+ if ( cur + 17 < limit &&
+ strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
+ face->type1.encoding_type = t1_encoding_standard;
+
+ else if ( cur + 15 < limit &&
+ strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
+ face->type1.encoding_type = t1_encoding_expert;
+
+ else
+ {
+ FT_ERROR(( "parse_encoding: invalid token!\n" ));
+ parser->root.error = T1_Err_Invalid_File_Format;
+ }
+ }
+ }
+
+
+ static void
+ parse_subrs( T1_Face face,
+ T1_Loader* loader )
+ {
+ T1_ParserRec* parser = &loader->parser;
+ PS_Table* table = &loader->subrs;
+ FT_Memory memory = parser->root.memory;
+ FT_Error error;
+ FT_Int n;
+
+ PSAux_Interface* psaux = (PSAux_Interface*)face->psaux;
+
+
+ loader->num_subrs = T1_ToInt( parser );
+ if ( parser->root.error )
+ return;
+
+ /* position the parser right before the `dup' of the first subr */
+ T1_Skip_Spaces( parser );
+ T1_Skip_Alpha( parser ); /* `array' */
+ T1_Skip_Spaces( parser );
+
+ /* initialize subrs array */
+ error = psaux->ps_table_funcs->init( table, loader->num_subrs, memory );
+ if ( error )
+ goto Fail;
+
+ /* the format is simple: */
+ /* */
+ /* `index' + binary data */
+ /* */
+
+ for ( n = 0; n < loader->num_subrs; n++ )
+ {
+ FT_Int index, size;
+ FT_Byte* base;
+
+
+ /* If the next token isn't `dup', we are also done. This */
+ /* happens when there are `holes' in the Subrs array. */
+ if ( strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 )
+ break;
+
+ index = T1_ToInt( parser );
+
+ if ( !read_binary_data( parser, &size, &base ) )
+ return;
+
+ /* The binary string is followed by one token, e.g. `NP' */
+ /* (bound to `noaccess put') or by two separate tokens: */
+ /* `noaccess' & `put'. We position the parser right */
+ /* before the next `dup', if any. */
+ T1_Skip_Spaces( parser );
+ T1_Skip_Alpha( parser ); /* `NP' or `I' or `noaccess' */
+ T1_Skip_Spaces( parser );
+
+ if ( strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 )
+ {
+ T1_Skip_Alpha( parser ); /* skip `put' */
+ T1_Skip_Spaces( parser );
+ }
+
+ /* some fonts use a value of -1 for lenIV to indicate that */
+ /* the charstrings are unencoded */
+ /* */
+ /* thanks to Tom Kacvinsky for pointing this out */
+ /* */
+ if ( face->type1.private_dict.lenIV >= 0 )
+ {
+ psaux->t1_decrypt( base, size, 4330 );
+ size -= face->type1.private_dict.lenIV;
+ base += face->type1.private_dict.lenIV;
+ }
+
+ error = T1_Add_Table( table, index, base, size );
+ if ( error )
+ goto Fail;
+ }
+ return;
+
+ Fail:
+ parser->root.error = error;
+ }
+
+
+ static void
+ parse_charstrings( T1_Face face,
+ T1_Loader* loader )
+ {
+ T1_ParserRec* parser = &loader->parser;
+ PS_Table* code_table = &loader->charstrings;
+ PS_Table* name_table = &loader->glyph_names;
+ PS_Table* swap_table = &loader->swap_table;
+ FT_Memory memory = parser->root.memory;
+ FT_Error error;
+
+ PSAux_Interface* psaux = (PSAux_Interface*)face->psaux;
+
+ FT_Byte* cur;
+ FT_Byte* limit = parser->root.limit;
+ FT_Int n;
+ FT_UInt notdef_index = 0;
+ FT_Byte notdef_found = 0;
+
+
+ if ( loader->num_glyphs )
+ /* with synthetic fonts, it's possible we get here twice */
+ return;
+
+ loader->num_glyphs = T1_ToInt( parser );
+ if ( parser->root.error )
+ return;
+
+ /* initialize tables (leaving room for addition of .notdef, */
+ /* if necessary). */
+
+ error = psaux->ps_table_funcs->init( code_table,
+ loader->num_glyphs + 1,
+ memory );
+ if ( error )
+ goto Fail;
+
+ error = psaux->ps_table_funcs->init( name_table,
+ loader->num_glyphs + 1,
+ memory );
+ if ( error )
+ goto Fail;
+
+ /* Initialize table for swapping index notdef_index and */
+ /* index 0 names and codes (if necessary). */
+
+ error = psaux->ps_table_funcs->init( swap_table, 4, memory );
+
+ if ( error )
+ goto Fail;
+
+
+ n = 0;
+ for (;;)
+ {
+ FT_Int size;
+ FT_Byte* base;
+
+
+ /* the format is simple: */
+ /* `/glyphname' + binary data */
+ /* */
+ /* note that we stop when we find a `def' */
+ /* */
+ T1_Skip_Spaces( parser );
+
+ cur = parser->root.cursor;
+ if ( cur >= limit )
+ break;
+
+ /* we stop when we find a `def' or `end' keyword */
+ if ( *cur == 'd' &&
+ cur + 3 < limit &&
+ cur[1] == 'e' &&
+ cur[2] == 'f' )
+ break;
+
+ if ( *cur == 'e' &&
+ cur + 3 < limit &&
+ cur[1] == 'n' &&
+ cur[2] == 'd' )
+ break;
+
+ if ( *cur != '/' )
+ T1_Skip_Alpha( parser );
+ else
+ {
+ FT_Byte* cur2 = cur + 1;
+ FT_Int len;
+
+
+ while ( cur2 < limit && is_alpha( *cur2 ) )
+ cur2++;
+ len = (FT_Int)( cur2 - cur - 1 );
+
+ error = T1_Add_Table( name_table, n, cur + 1, len + 1 );
+ if ( error )
+ goto Fail;
+
+ /* add a trailing zero to the name table */
+ name_table->elements[n][len] = '\0';
+
+ /* record index of /.notdef */
+ if ( strcmp( (const char*)".notdef",
+ (const char*)(name_table->elements[n]) ) == 0 )
+ {
+ notdef_index = n;
+ notdef_found = 1;
+ }
+
+ parser->root.cursor = cur2;
+ if ( !read_binary_data( parser, &size, &base ) )
+ return;
+
+ if ( face->type1.private_dict.lenIV >= 0 )
+ {
+ psaux->t1_decrypt( base, size, 4330 );
+ size -= face->type1.private_dict.lenIV;
+ base += face->type1.private_dict.lenIV;
+ }
+
+ error = T1_Add_Table( code_table, n, base, size );
+ if ( error )
+ goto Fail;
+
+ n++;
+ if ( n >= loader->num_glyphs )
+ break;
+ }
+ }
+
+ loader->num_glyphs = n;
+
+ /* if /.notdef is found but does not occupy index 0, do our magic. */
+ if ( strcmp( (const char*)".notdef",
+ (const char*)name_table->elements[0] ) &&
+ notdef_found )
+ {
+ /* Swap glyph in index 0 with /.notdef glyph. First, add index 0 */
+ /* name and code entries to swap_table. Then place notdef_index name */
+ /* and code entries into swap_table. Then swap name and code */
+ /* entries at indices notdef_index and 0 using values stored in */
+ /* swap_table. */
+
+ /* Index 0 name */
+ error = T1_Add_Table( swap_table, 0,
+ name_table->elements[0],
+ name_table->lengths [0] );
+ if ( error )
+ goto Fail;
+
+ /* Index 0 code */
+ error = T1_Add_Table( swap_table, 1,
+ code_table->elements[0],
+ code_table->lengths [0] );
+ if ( error )
+ goto Fail;
+
+ /* Index notdef_index name */
+ error = T1_Add_Table( swap_table, 2,
+ name_table->elements[notdef_index],
+ name_table->lengths [notdef_index] );
+ if ( error )
+ goto Fail;
+
+ /* Index notdef_index code */
+ error = T1_Add_Table( swap_table, 3,
+ code_table->elements[notdef_index],
+ code_table->lengths [notdef_index] );
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( name_table, notdef_index,
+ swap_table->elements[0],
+ swap_table->lengths [0] );
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( code_table, notdef_index,
+ swap_table->elements[1],
+ swap_table->lengths [1] );
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( name_table, 0,
+ swap_table->elements[2],
+ swap_table->lengths [2] );
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( code_table, 0,
+ swap_table->elements[3],
+ swap_table->lengths [3] );
+ if ( error )
+ goto Fail;
+
+ }
+ else if ( !notdef_found )
+ {
+
+ /* notdef_index is already 0, or /.notdef is undefined in */
+ /* charstrings dictionary. Worry about /.notdef undefined. */
+ /* We take index 0 and add it to the end of the table(s) */
+ /* and add our own /.notdef glyph to index 0. */
+
+ /* 0 333 hsbw endchar */
+ FT_Byte notdef_glyph[] = {0x8B, 0xF7, 0xE1, 0x0D, 0x0E};
+ char* notdef_name = (char *)".notdef";
+
+
+ error = T1_Add_Table( swap_table, 0,
+ name_table->elements[0],
+ name_table->lengths [0] );
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( swap_table, 1,
+ code_table->elements[0],
+ code_table->lengths [0] );
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( name_table, 0, notdef_name, 8 );
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( code_table, 0, notdef_glyph, 5 );
+
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( name_table, n,
+ swap_table->elements[0],
+ swap_table->lengths [0] );
+ if ( error )
+ goto Fail;
+
+ error = T1_Add_Table( code_table, n,
+ swap_table->elements[1],
+ swap_table->lengths [1] );
+ if ( error )
+ goto Fail;
+
+ /* we added a glyph. */
+ loader->num_glyphs = n + 1;
+
+ }
+
+
+ return;
+
+ Fail:
+ parser->root.error = error;
+ }
+
+
+ static
+ const T1_Field t1_keywords[] =
+ {
+
+#include "t1tokens.h"
+
+ /* now add the special functions... */
+ T1_FIELD_CALLBACK( "FontName", parse_font_name )
+ T1_FIELD_CALLBACK( "FontBBox", parse_font_bbox )
+ T1_FIELD_CALLBACK( "FontMatrix", parse_font_matrix )
+ T1_FIELD_CALLBACK( "Encoding", parse_encoding )
+ T1_FIELD_CALLBACK( "Subrs", parse_subrs )
+ T1_FIELD_CALLBACK( "CharStrings", parse_charstrings )
+
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+ T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions )
+ T1_FIELD_CALLBACK( "BlendDesignMap", parse_blend_design_map )
+ T1_FIELD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types )
+ T1_FIELD_CALLBACK( "WeightVector", parse_weight_vector )
+ T1_FIELD_CALLBACK( "shareddict", parse_shared_dict )
+#endif
+
+ { 0, t1_field_cid_info, t1_field_none, 0, 0, 0, 0, 0 }
+ };
+
+
+ static FT_Error
+ parse_dict( T1_Face face,
+ T1_Loader* loader,
+ FT_Byte* base,
+ FT_Long size )
+ {
+ T1_ParserRec* parser = &loader->parser;
+
+
+ parser->root.cursor = base;
+ parser->root.limit = base + size;
+ parser->root.error = 0;
+
+ {
+ FT_Byte* cur = base;
+ FT_Byte* limit = cur + size;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ /* look for `FontDirectory', which causes problems on some fonts */
+ if ( *cur == 'F' && cur + 25 < limit &&
+ strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
+ {
+ FT_Byte* cur2;
+
+
+ /* skip the `FontDirectory' keyword */
+ cur += 13;
+ cur2 = cur;
+
+ /* lookup the `known' keyword */
+ while ( cur < limit && *cur != 'k' &&
+ strncmp( (char*)cur, "known", 5 ) )
+ cur++;
+
+ if ( cur < limit )
+ {
+ T1_Token token;
+
+
+ /* skip the `known' keyword and the token following it */
+ cur += 5;
+ loader->parser.root.cursor = cur;
+ T1_ToToken( &loader->parser, &token );
+
+ /* if the last token was an array, skip it! */
+ if ( token.type == t1_token_array )
+ cur2 = parser->root.cursor;
+ }
+ cur = cur2;
+ }
+ /* look for immediates */
+ else if ( *cur == '/' && cur + 2 < limit )
+ {
+ FT_Byte* cur2;
+ FT_Int len;
+
+
+ cur++;
+ cur2 = cur;
+ while ( cur2 < limit && is_alpha( *cur2 ) )
+ cur2++;
+
+ len = (FT_Int)( cur2 - cur );
+ if ( len > 0 && len < 22 )
+ {
+ {
+ /* now, compare the immediate name to the keyword table */
+ T1_Field* keyword = (T1_Field*)t1_keywords;
+
+
+ for (;;)
+ {
+ FT_Byte* name;
+
+
+ name = (FT_Byte*)keyword->ident;
+ if ( !name )
+ break;
+
+ if ( cur[0] == name[0] &&
+ len == (FT_Int)strlen( (const char*)name ) )
+ {
+ FT_Int n;
+
+
+ for ( n = 1; n < len; n++ )
+ if ( cur[n] != name[n] )
+ break;
+
+ if ( n >= len )
+ {
+ /* we found it -- run the parsing callback! */
+ parser->root.cursor = cur2;
+ T1_Skip_Spaces( parser );
+ parser->root.error = t1_load_keyword( face,
+ loader,
+ keyword );
+ if ( parser->root.error )
+ return parser->root.error;
+
+ cur = parser->root.cursor;
+ break;
+ }
+ }
+ keyword++;
+ }
+ }
+ }
+ }
+ }
+ }
+ return parser->root.error;
+ }
+
+
+ static void
+ t1_init_loader( T1_Loader* loader,
+ T1_Face face )
+ {
+ FT_UNUSED( face );
+
+ MEM_Set( loader, 0, sizeof ( *loader ) );
+ loader->num_glyphs = 0;
+ loader->num_chars = 0;
+
+ /* initialize the tables -- simply set their `init' field to 0 */
+ loader->encoding_table.init = 0;
+ loader->charstrings.init = 0;
+ loader->glyph_names.init = 0;
+ loader->subrs.init = 0;
+ loader->swap_table.init = 0;
+ loader->fontdata = 0;
+ }
+
+
+ static void
+ t1_done_loader( T1_Loader* loader )
+ {
+ T1_ParserRec* parser = &loader->parser;
+
+
+ /* finalize tables */
+ T1_Release_Table( &loader->encoding_table );
+ T1_Release_Table( &loader->charstrings );
+ T1_Release_Table( &loader->glyph_names );
+ T1_Release_Table( &loader->swap_table );
+ T1_Release_Table( &loader->subrs );
+
+ /* finalize parser */
+ T1_Finalize_Parser( parser );
+ }
+
+
+ FT_LOCAL_DEF FT_Error
+ T1_Open_Face( T1_Face face )
+ {
+ T1_Loader loader;
+ T1_ParserRec* parser;
+ T1_Font* type1 = &face->type1;
+ FT_Error error;
+
+ PSAux_Interface* psaux = (PSAux_Interface*)face->psaux;
+
+
+ t1_init_loader( &loader, face );
+
+ /* default lenIV */
+ type1->private_dict.lenIV = 4;
+
+ parser = &loader.parser;
+ error = T1_New_Parser( parser,
+ face->root.stream,
+ face->root.memory,
+ psaux );
+ if ( error )
+ goto Exit;
+
+ error = parse_dict( face, &loader, parser->base_dict, parser->base_len );
+ if ( error )
+ goto Exit;
+
+ error = T1_Get_Private_Dict( parser, psaux );
+ if ( error )
+ goto Exit;
+
+ error = parse_dict( face, &loader, parser->private_dict,
+ parser->private_len );
+ if ( error )
+ goto Exit;
+
+ /* now, propagate the subrs, charstrings, and glyphnames tables */
+ /* to the Type1 data */
+ type1->num_glyphs = loader.num_glyphs;
+
+ if ( loader.subrs.init )
+ {
+ loader.subrs.init = 0;
+ type1->num_subrs = loader.num_subrs;
+ type1->subrs_block = loader.subrs.block;
+ type1->subrs = loader.subrs.elements;
+ type1->subrs_len = loader.subrs.lengths;
+ }
+
+ if ( !loader.charstrings.init )
+ {
+ FT_ERROR(( "T1_Open_Face: no charstrings array in face!\n" ));
+ error = T1_Err_Invalid_File_Format;
+ }
+
+ loader.charstrings.init = 0;
+ type1->charstrings_block = loader.charstrings.block;
+ type1->charstrings = loader.charstrings.elements;
+ type1->charstrings_len = loader.charstrings.lengths;
+
+ /* we copy the glyph names `block' and `elements' fields; */
+ /* the `lengths' field must be released later */
+ type1->glyph_names_block = loader.glyph_names.block;
+ type1->glyph_names = (FT_String**)loader.glyph_names.elements;
+ loader.glyph_names.block = 0;
+ loader.glyph_names.elements = 0;
+
+ /* we must now build type1.encoding when we have a custom */
+ /* array.. */
+ if ( type1->encoding_type == t1_encoding_array )
+ {
+ FT_Int charcode, index, min_char, max_char;
+ FT_Byte* char_name;
+ FT_Byte* glyph_name;
+
+
+ /* OK, we do the following: for each element in the encoding */
+ /* table, look up the index of the glyph having the same name */
+ /* the index is then stored in type1.encoding.char_index, and */
+ /* a the name to type1.encoding.char_name */
+
+ min_char = +32000;
+ max_char = -32000;
+
+ charcode = 0;
+ for ( ; charcode < loader.encoding_table.max_elems; charcode++ )
+ {
+ type1->encoding.char_index[charcode] = 0;
+ type1->encoding.char_name [charcode] = (char *)".notdef";
+
+ char_name = loader.encoding_table.elements[charcode];
+ if ( char_name )
+ for ( index = 0; index < type1->num_glyphs; index++ )
+ {
+ glyph_name = (FT_Byte*)type1->glyph_names[index];
+ if ( strcmp( (const char*)char_name,
+ (const char*)glyph_name ) == 0 )
+ {
+ type1->encoding.char_index[charcode] = (FT_UShort)index;
+ type1->encoding.char_name [charcode] = (char*)glyph_name;
+
+ /* Change min/max encoded char only if glyph name is */
+ /* not /.notdef */
+ if ( strcmp( (const char*)".notdef",
+ (const char*)glyph_name ) != 0 )
+ {
+ if (charcode < min_char) min_char = charcode;
+ if (charcode > max_char) max_char = charcode;
+ }
+ break;
+ }
+ }
+ }
+ type1->encoding.code_first = min_char;
+ type1->encoding.code_last = max_char;
+ type1->encoding.num_chars = loader.num_chars;
+ }
+
+ Exit:
+ t1_done_loader( &loader );
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* t1objs.c */
+/* */
+/* Type 1 objects manager (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+
+#include <string.h> /* strcmp() */
+
+#include "t1gload.h"
+#include "t1load.h"
+
+#include "t1errors.h"
+
+#ifndef T1_CONFIG_OPTION_NO_AFM
+#include "t1afm.h"
+#endif
+
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_t1objs
+
+
+ /*************************************************************************/
+ /* */
+ /* FACE FUNCTIONS */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* T1_Done_Face */
+ /* */
+ /* <Description> */
+ /* The face object destructor. */
+ /* */
+ /* <Input> */
+ /* face :: A typeless pointer to the face object to destroy. */
+ /* */
+ FT_LOCAL_DEF void
+ T1_Done_Face( T1_Face face )
+ {
+ FT_Memory memory;
+ T1_Font* type1 = &face->type1;
+
+
+ if ( face )
+ {
+ memory = face->root.memory;
+
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+ /* release multiple masters information */
+ T1_Done_Blend( face );
+ face->blend = 0;
+#endif
+
+ /* release font info strings */
+ {
+ T1_FontInfo* info = &type1->font_info;
+
+
+ FREE( info->version );
+ FREE( info->notice );
+ FREE( info->full_name );
+ FREE( info->family_name );
+ FREE( info->weight );
+ }
+
+ /* release top dictionary */
+ FREE( type1->charstrings_len );
+ FREE( type1->charstrings );
+ FREE( type1->glyph_names );
+
+ FREE( type1->subrs );
+ FREE( type1->subrs_len );
+
+ FREE( type1->subrs_block );
+ FREE( type1->charstrings_block );
+ FREE( type1->glyph_names_block );
+
+ FREE( type1->encoding.char_index );
+ FREE( type1->encoding.char_name );
+ FREE( type1->font_name );
+
+#ifndef T1_CONFIG_OPTION_NO_AFM
+ /* release afm data if present */
+ if ( face->afm_data )
+ T1_Done_AFM( memory, (T1_AFM*)face->afm_data );
+#endif
+
+ /* release unicode map, if any */
+ FREE( face->unicode_map.maps );
+ face->unicode_map.num_maps = 0;
+
+ face->root.family_name = 0;
+ face->root.style_name = 0;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* T1_Init_Face */
+ /* */
+ /* <Description> */
+ /* The face object constructor. */
+ /* */
+ /* <Input> */
+ /* stream :: input stream where to load font data. */
+ /* */
+ /* face_index :: The index of the font face in the resource. */
+ /* */
+ /* num_params :: Number of additional generic parameters. Ignored. */
+ /* */
+ /* params :: Additional generic parameters. Ignored. */
+ /* */
+ /* <InOut> */
+ /* face :: The face record to build. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ T1_Init_Face( FT_Stream stream,
+ T1_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ FT_Error error;
+ PSNames_Interface* psnames;
+ PSAux_Interface* psaux;
+
+ FT_UNUSED( num_params );
+ FT_UNUSED( params );
+ FT_UNUSED( face_index );
+ FT_UNUSED( stream );
+
+
+ face->root.num_faces = 1;
+
+ psnames = (PSNames_Interface*)face->psnames;
+ if ( !psnames )
+ {
+ psnames = (PSNames_Interface*)
+ FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), "psnames" );
+
+ face->psnames = psnames;
+ }
+
+ psaux = (PSAux_Interface*)face->psaux;
+ if ( !psaux )
+ {
+ psaux = (PSAux_Interface*)
+ FT_Get_Module_Interface( FT_FACE_LIBRARY( face ), "psaux" );
+
+ face->psaux = psaux;
+ }
+
+ /* open the tokenizer, this will also check the font format */
+ error = T1_Open_Face( face );
+ if ( error )
+ goto Exit;
+
+ /* if we just wanted to check the format, leave successfully now */
+ if ( face_index < 0 )
+ goto Exit;
+
+ /* check the face index */
+ if ( face_index != 0 )
+ {
+ FT_ERROR(( "T1_Init_Face: invalid face index\n" ));
+ error = T1_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ /* Now, load the font program into the face object */
+
+ /* Init the face object fields */
+ /* Now set up root face fields */
+ {
+ FT_Face root = (FT_Face)&face->root;
+
+
+ root->num_glyphs = face->type1.num_glyphs;
+ root->num_charmaps = 1;
+
+ root->face_index = face_index;
+ root->face_flags = FT_FACE_FLAG_SCALABLE;
+
+ root->face_flags |= FT_FACE_FLAG_HORIZONTAL;
+
+ root->face_flags |= FT_FACE_FLAG_GLYPH_NAMES;
+
+ if ( face->type1.font_info.is_fixed_pitch )
+ root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+ if ( face->blend )
+ root->face_flags |= FT_FACE_FLAG_MULTIPLE_MASTERS;
+
+ /* XXX: TODO -- add kerning with .afm support */
+
+ /* get style name -- be careful, some broken fonts only */
+ /* have a `/FontName' dictionary entry! */
+ root->family_name = face->type1.font_info.family_name;
+ if ( root->family_name )
+ {
+ char* full = face->type1.font_info.full_name;
+ char* family = root->family_name;
+
+
+ while ( *family && *full == *family )
+ {
+ family++;
+ full++;
+ }
+
+ root->style_name = ( *full == ' ' ? full + 1
+ : (char *)"Regular" );
+ }
+ else
+ {
+ /* do we have a `/FontName'? */
+ if ( face->type1.font_name )
+ {
+ root->family_name = face->type1.font_name;
+ root->style_name = (char *)"Regular";
+ }
+ }
+
+ /* compute style flags */
+ root->style_flags = 0;
+ if ( face->type1.font_info.italic_angle )
+ root->style_flags |= FT_STYLE_FLAG_ITALIC;
+ if ( face->type1.font_info.weight )
+ {
+ if ( !strcmp( face->type1.font_info.weight, "Bold" ) ||
+ !strcmp( face->type1.font_info.weight, "Black" ) )
+ root->style_flags |= FT_STYLE_FLAG_BOLD;
+ }
+
+ /* no embedded bitmap support */
+ root->num_fixed_sizes = 0;
+ root->available_sizes = 0;
+
+ root->bbox = face->type1.font_bbox;
+
+ /* Set units_per_EM if we didn't set it in parse_font_matrix. */
+ if ( !root->units_per_EM )
+ root->units_per_EM = 1000;
+
+ root->ascender = (FT_Short)( face->type1.font_bbox.yMax >> 16 );
+ root->descender = (FT_Short)( face->type1.font_bbox.yMin >> 16 );
+ root->height = (FT_Short)(
+ ( ( root->ascender - root->descender ) * 12 ) / 10 );
+
+ /* now compute the maximum advance width */
+ root->max_advance_width =
+ (FT_Short)( face->type1.font_bbox.xMax >> 16 );
+ {
+ FT_Int max_advance;
+
+
+ error = T1_Compute_Max_Advance( face, &max_advance );
+
+ /* in case of error, keep the standard width */
+ if ( !error )
+ root->max_advance_width = (FT_Short)max_advance;
+ else
+ error = 0; /* clear error */
+ }
+
+ root->max_advance_height = root->height;
+
+ root->underline_position = face->type1.font_info.underline_position;
+ root->underline_thickness = face->type1.font_info.underline_thickness;
+
+ root->internal->max_points = 0;
+ root->internal->max_contours = 0;
+ }
+
+ /* charmap support -- synthetize unicode charmap if possible */
+ {
+ FT_Face root = &face->root;
+ FT_CharMap charmap = face->charmaprecs;
+
+
+ /* synthesize a Unicode charmap if there is support in the `PSNames' */
+ /* module */
+ if ( psnames )
+ {
+ if ( psnames->unicode_value )
+ {
+ error = psnames->build_unicodes(
+ root->memory,
+ face->type1.num_glyphs,
+ (const char**)face->type1.glyph_names,
+ &face->unicode_map );
+ if ( !error )
+ {
+ root->charmap = charmap;
+ charmap->face = (FT_Face)face;
+ charmap->encoding = ft_encoding_unicode;
+ charmap->platform_id = 3;
+ charmap->encoding_id = 1;
+ charmap++;
+ }
+
+ /* simply clear the error in case of failure (which really) */
+ /* means that out of memory or no unicode glyph names */
+ error = T1_Err_Ok;
+ }
+ }
+
+ /* now, support either the standard, expert, or custom encoding */
+ charmap->face = (FT_Face)face;
+ charmap->platform_id = 7; /* a new platform id for Adobe fonts? */
+
+ switch ( face->type1.encoding_type )
+ {
+ case t1_encoding_standard:
+ charmap->encoding = ft_encoding_adobe_standard;
+ charmap->encoding_id = 0;
+ break;
+
+ case t1_encoding_expert:
+ charmap->encoding = ft_encoding_adobe_expert;
+ charmap->encoding_id = 1;
+ break;
+
+ default:
+ charmap->encoding = ft_encoding_adobe_custom;
+ charmap->encoding_id = 2;
+ break;
+ }
+
+ root->charmaps = face->charmaps;
+ root->num_charmaps = charmap - face->charmaprecs + 1;
+ face->charmaps[0] = &face->charmaprecs[0];
+ face->charmaps[1] = &face->charmaprecs[1];
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* T1_Init_Driver */
+ /* */
+ /* <Description> */
+ /* Initializes a given Type 1 driver object. */
+ /* */
+ /* <Input> */
+ /* driver :: A handle to the target driver object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ T1_Init_Driver( T1_Driver driver )
+ {
+ FT_UNUSED( driver );
+
+ return T1_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* T1_Done_Driver */
+ /* */
+ /* <Description> */
+ /* Finalizes a given Type 1 driver. */
+ /* */
+ /* <Input> */
+ /* driver :: A handle to the target Type 1 driver. */
+ /* */
+ FT_LOCAL_DEF void
+ T1_Done_Driver( T1_Driver driver )
+ {
+ FT_UNUSED( driver );
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* t1parse.c */
+/* */
+/* Type 1 parser (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* The Type 1 parser is in charge of the following: */
+ /* */
+ /* - provide an implementation of a growing sequence of objects called */
+ /* a `T1_Table' (used to build various tables needed by the loader). */
+ /* */
+ /* - opening .pfb and .pfa files to extract their top-level and private */
+ /* dictionaries. */
+ /* */
+ /* - read numbers, arrays & strings from any dictionary. */
+ /* */
+ /* See `t1load.c' to see how data is loaded from the font file. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+#include "t1parse.h"
+
+#include "t1errors.h"
+
+#include <string.h> /* for strncmp() */
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_t1parse
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** INPUT STREAM PARSER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#define IS_T1_WHITESPACE( c ) ( (c) == ' ' || (c) == '\t' )
+#define IS_T1_LINESPACE( c ) ( (c) == '\r' || (c) == '\n' )
+
+#define IS_T1_SPACE( c ) ( IS_T1_WHITESPACE( c ) || IS_T1_LINESPACE( c ) )
+
+
+ typedef struct PFB_Tag_
+ {
+ FT_UShort tag;
+ FT_Long size;
+
+ } PFB_Tag;
+
+
+#undef FT_STRUCTURE
+#define FT_STRUCTURE PFB_Tag
+
+
+ static
+ const FT_Frame_Field pfb_tag_fields[] =
+ {
+ FT_FRAME_START( 6 ),
+ FT_FRAME_USHORT ( tag ),
+ FT_FRAME_LONG_LE( size ),
+ FT_FRAME_END
+ };
+
+
+ static FT_Error
+ read_pfb_tag( FT_Stream stream,
+ FT_UShort* tag,
+ FT_Long* size )
+ {
+ FT_Error error;
+ PFB_Tag head;
+
+
+ *tag = 0;
+ *size = 0;
+ if ( !READ_Fields( pfb_tag_fields, &head ) )
+ {
+ if ( head.tag == 0x8001 || head.tag == 0x8002 )
+ {
+ *tag = head.tag;
+ *size = head.size;
+ }
+ }
+ return error;
+ }
+
+
+ FT_LOCAL_DEF FT_Error
+ T1_New_Parser( T1_ParserRec* parser,
+ FT_Stream stream,
+ FT_Memory memory,
+ PSAux_Interface* psaux )
+ {
+ FT_Error error;
+ FT_UShort tag;
+ FT_Long size;
+
+
+ psaux->t1_parser_funcs->init( &parser->root,0, 0, memory );
+
+ parser->stream = stream;
+ parser->base_len = 0;
+ parser->base_dict = 0;
+ parser->private_len = 0;
+ parser->private_dict = 0;
+ parser->in_pfb = 0;
+ parser->in_memory = 0;
+ parser->single_block = 0;
+
+ /******************************************************************/
+ /* */
+ /* Here a short summary of what is going on: */
+ /* */
+ /* When creating a new Type 1 parser, we try to locate and load */
+ /* the base dictionary if this is possible (i.e. for PFB */
+ /* files). Otherwise, we load the whole font into memory. */
+ /* */
+ /* When `loading' the base dictionary, we only setup pointers */
+ /* in the case of a memory-based stream. Otherwise, we */
+ /* allocate and load the base dictionary in it. */
+ /* */
+ /* parser->in_pfb is set if we are in a binary (".pfb") font. */
+ /* parser->in_memory is set if we have a memory stream. */
+ /* */
+
+ /* try to compute the size of the base dictionary; */
+ /* look for a Postscript binary file tag, i.e 0x8001 */
+ if ( FILE_Seek( 0L ) )
+ goto Exit;
+
+ error = read_pfb_tag( stream, &tag, &size );
+ if ( error )
+ goto Exit;
+
+ if ( tag != 0x8001 )
+ {
+ /* assume that this is a PFA file for now; an error will */
+ /* be produced later when more things are checked */
+ if ( FILE_Seek( 0L ) )
+ goto Exit;
+ size = stream->size;
+ }
+ else
+ parser->in_pfb = 1;
+
+ /* now, try to load `size' bytes of the `base' dictionary we */
+ /* found previously */
+
+ /* if it is a memory-based resource, set up pointers */
+ if ( !stream->read )
+ {
+ parser->base_dict = (FT_Byte*)stream->base + stream->pos;
+ parser->base_len = size;
+ parser->in_memory = 1;
+
+ /* check that the `size' field is valid */
+ if ( FILE_Skip( size ) )
+ goto Exit;
+ }
+ else
+ {
+ /* read segment in memory */
+ if ( ALLOC( parser->base_dict, size ) ||
+ FILE_Read( parser->base_dict, size ) )
+ goto Exit;
+ parser->base_len = size;
+ }
+
+ /* Now check font format; we must see `%!PS-AdobeFont-1' */
+ /* or `%!FontType' */
+ {
+ if ( size <= 16 ||
+ ( strncmp( (const char*)parser->base_dict,
+ "%!PS-AdobeFont-1", 16 ) &&
+ strncmp( (const char*)parser->base_dict,
+ "%!FontType", 10 ) ) )
+ {
+ FT_TRACE2(( "[not a Type1 font]\n" ));
+ error = T1_Err_Unknown_File_Format;
+ }
+ else
+ {
+ parser->root.base = parser->base_dict;
+ parser->root.cursor = parser->base_dict;
+ parser->root.limit = parser->root.cursor + parser->base_len;
+ }
+ }
+
+ Exit:
+ if ( error && !parser->in_memory )
+ FREE( parser->base_dict );
+
+ return error;
+ }
+
+
+ FT_LOCAL_DEF void
+ T1_Finalize_Parser( T1_ParserRec* parser )
+ {
+ FT_Memory memory = parser->root.memory;
+
+
+ /* always free the private dictionary */
+ FREE( parser->private_dict );
+
+ /* free the base dictionary only when we have a disk stream */
+ if ( !parser->in_memory )
+ FREE( parser->base_dict );
+
+ parser->root.funcs.done( &parser->root );
+ }
+
+
+ /* return the value of an hexadecimal digit */
+ static int
+ hexa_value( char c )
+ {
+ unsigned int d;
+
+
+ d = (unsigned int)( c - '0' );
+ if ( d <= 9 )
+ return (int)d;
+
+ d = (unsigned int)( c - 'a' );
+ if ( d <= 5 )
+ return (int)( d + 10 );
+
+ d = (unsigned int)( c - 'A' );
+ if ( d <= 5 )
+ return (int)( d + 10 );
+
+ return -1;
+ }
+
+
+ FT_LOCAL_DEF FT_Error
+ T1_Get_Private_Dict( T1_ParserRec* parser,
+ PSAux_Interface* psaux )
+ {
+ FT_Stream stream = parser->stream;
+ FT_Memory memory = parser->root.memory;
+ FT_Error error = 0;
+ FT_Long size;
+
+
+ if ( parser->in_pfb )
+ {
+ /* in the case of the PFB format, the private dictionary can be */
+ /* made of several segments. We thus first read the number of */
+ /* segments to compute the total size of the private dictionary */
+ /* then re-read them into memory. */
+ FT_Long start_pos = FILE_Pos();
+ FT_UShort tag;
+
+
+ parser->private_len = 0;
+ for (;;)
+ {
+ error = read_pfb_tag( stream, &tag, &size );
+ if ( error )
+ goto Fail;
+
+ if ( tag != 0x8002 )
+ break;
+
+ parser->private_len += size;
+
+ if ( FILE_Skip( size ) )
+ goto Fail;
+ }
+
+ /* Check that we have a private dictionary there */
+ /* and allocate private dictionary buffer */
+ if ( parser->private_len == 0 )
+ {
+ FT_ERROR(( "T1_Get_Private_Dict:" ));
+ FT_ERROR(( " invalid private dictionary section\n" ));
+ error = T1_Err_Invalid_File_Format;
+ goto Fail;
+ }
+
+ if ( FILE_Seek( start_pos ) ||
+ ALLOC( parser->private_dict, parser->private_len ) )
+ goto Fail;
+
+ parser->private_len = 0;
+ for (;;)
+ {
+ error = read_pfb_tag( stream, &tag, &size );
+ if ( error || tag != 0x8002 )
+ {
+ error = T1_Err_Ok;
+ break;
+ }
+
+ if ( FILE_Read( parser->private_dict + parser->private_len, size ) )
+ goto Fail;
+
+ parser->private_len += size;
+ }
+ }
+ else
+ {
+ /* we have already `loaded' the whole PFA font file into memory; */
+ /* if this is a memory resource, allocate a new block to hold */
+ /* the private dict. Otherwise, simply overwrite into the base */
+ /* dictionary block in the heap. */
+
+ /* first of all, look at the `eexec' keyword */
+ FT_Byte* cur = parser->base_dict;
+ FT_Byte* limit = cur + parser->base_len;
+ FT_Byte c;
+
+
+ for (;;)
+ {
+ c = cur[0];
+ if ( c == 'e' && cur + 9 < limit ) /* 9 = 5 letters for `eexec' + */
+ /* newline + 4 chars */
+ {
+ if ( cur[1] == 'e' && cur[2] == 'x' &&
+ cur[3] == 'e' && cur[4] == 'c' )
+ {
+ cur += 6; /* we skip the newling after the `eexec' */
+
+ /* XXX: Some fonts use DOS-linefeeds, i.e. \r\n; we need to */
+ /* skip the extra \n if we find it */
+ if ( cur[0] == '\n' )
+ cur++;
+
+ break;
+ }
+ }
+ cur++;
+ if ( cur >= limit )
+ {
+ FT_ERROR(( "T1_Get_Private_Dict:" ));
+ FT_ERROR(( " could not find `eexec' keyword\n" ));
+ error = T1_Err_Invalid_File_Format;
+ goto Exit;
+ }
+ }
+
+ /* now determine where to write the _encrypted_ binary private */
+ /* dictionary. We overwrite the base dictionary for disk-based */
+ /* resources and allocate a new block otherwise */
+
+ size = (FT_Long)( parser->base_len - ( cur - parser->base_dict ) );
+
+ if ( parser->in_memory )
+ {
+ /* note that we allocate one more byte to put a terminating `0' */
+ if ( ALLOC( parser->private_dict, size + 1 ) )
+ goto Fail;
+ parser->private_len = size;
+ }
+ else
+ {
+ parser->single_block = 1;
+ parser->private_dict = parser->base_dict;
+ parser->private_len = size;
+ parser->base_dict = 0;
+ parser->base_len = 0;
+ }
+
+ /* now determine whether the private dictionary is encoded in binary */
+ /* or hexadecimal ASCII format -- decode it accordingly */
+
+ /* we need to access the next 4 bytes (after the final \r following */
+ /* the `eexec' keyword); if they all are hexadecimal digits, then */
+ /* we have a case of ASCII storage */
+
+ if ( ( hexa_value( cur[0] ) | hexa_value( cur[1] ) |
+ hexa_value( cur[2] ) | hexa_value( cur[3] ) ) < 0 )
+
+ /* binary encoding -- `simply' copy the private dict */
+ MEM_Copy( parser->private_dict, cur, size );
+
+ else
+ {
+ /* ASCII hexadecimal encoding */
+
+ FT_Byte* write;
+ FT_Int count;
+
+
+ write = parser->private_dict;
+ count = 0;
+
+ for ( ;cur < limit; cur++ )
+ {
+ int hex1;
+
+
+ /* check for newline */
+ if ( cur[0] == '\r' || cur[0] == '\n' )
+ continue;
+
+ /* exit if we have a non-hexadecimal digit that isn't a newline */
+ hex1 = hexa_value( cur[0] );
+ if ( hex1 < 0 || cur + 1 >= limit )
+ break;
+
+ /* otherwise, store byte */
+ *write++ = (FT_Byte)( ( hex1 << 4 ) | hexa_value( cur[1] ) );
+ count++;
+ cur++;
+ }
+
+ /* put a safeguard */
+ parser->private_len = (FT_Int)( write - parser->private_dict );
+ *write++ = 0;
+ }
+ }
+
+ /* we now decrypt the encoded binary private dictionary */
+ psaux->t1_decrypt( parser->private_dict, parser->private_len, 55665U );
+ parser->root.base = parser->private_dict;
+ parser->root.cursor = parser->private_dict;
+ parser->root.limit = parser->root.cursor + parser->private_len;
+
+ Fail:
+ Exit:
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_BBOX_H
+
+
+#include <time.h> /* for clock() */
+
+/* SunOS 4.1.* does not define CLOCKS_PER_SEC, so include <sys/param.h> */
+/* to get the HZ macro which is the equivalent. */
+#if defined(__sun__) && !defined(SVR4) && !defined(__SVR4)
+#include <sys/param.h>
+#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;
+ }
+
--- /dev/null
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_TRIGONOMETRY_H
+
+#include <math.h>
+#include <stdio.h>
+
+#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;
+ }
--- /dev/null
+/***************************************************************************/
+/* */
+/* truetype.c */
+/* */
+/* FreeType TrueType driver component (body only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "ttdriver.c" /* driver interface */
+#include "ttpload.c" /* tables loader */
+#include "ttgload.c" /* glyph loader */
+#include "ttobjs.c" /* object manager */
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+#include "ttinterp.c"
+#endif
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ttcmap.c */
+/* */
+/* TrueType character mapping table (cmap) support (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include "ttload.h"
+#include "ttcmap.h"
+
+#include "sferrors.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ttcmap
+
+
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index0( TT_CMapTable* charmap,
+ FT_ULong char_code );
+
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index2( TT_CMapTable* charmap,
+ FT_ULong char_code );
+
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index4( TT_CMapTable* charmap,
+ FT_ULong char_code );
+
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index6( TT_CMapTable* charmap,
+ FT_ULong char_code );
+
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index8_12( TT_CMapTable* charmap,
+ FT_ULong char_code );
+
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index10( TT_CMapTable* charmap,
+ FT_ULong char_code );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_CharMap_Load */
+ /* */
+ /* <Description> */
+ /* Loads a given TrueType character map into memory. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the parent face object. */
+ /* stream :: A handle to the current stream object. */
+ /* */
+ /* <InOut> */
+ /* table :: A pointer to a cmap object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The function assumes that the stream is already in use (i.e., */
+ /* opened). In case of error, all partially allocated tables are */
+ /* released. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_CharMap_Load( TT_Face face,
+ TT_CMapTable* cmap,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_Memory memory;
+ FT_UShort num_SH, num_Seg, i;
+ FT_ULong j, n;
+
+ FT_UShort u, l;
+
+ TT_CMap0* cmap0;
+ TT_CMap2* cmap2;
+ TT_CMap4* cmap4;
+ TT_CMap6* cmap6;
+ TT_CMap8_12* cmap8_12;
+ TT_CMap10* cmap10;
+
+ TT_CMap2SubHeader* cmap2sub;
+ TT_CMap4Segment* segments;
+ TT_CMapGroup* groups;
+
+
+ if ( cmap->loaded )
+ return SFNT_Err_Ok;
+
+ memory = stream->memory;
+
+ if ( FILE_Seek( cmap->offset ) )
+ return error;
+
+ switch ( cmap->format )
+ {
+ case 0:
+ cmap0 = &cmap->c.cmap0;
+
+ if ( READ_UShort( cmap0->language ) ||
+ ALLOC( cmap0->glyphIdArray, 256L ) ||
+ FILE_Read( cmap0->glyphIdArray, 256L ) )
+ goto Fail;
+
+ cmap->get_index = code_to_index0;
+ break;
+
+ case 2:
+ num_SH = 0;
+ cmap2 = &cmap->c.cmap2;
+
+ /* allocate subheader keys */
+
+ if ( ALLOC_ARRAY( cmap2->subHeaderKeys, 256, FT_UShort ) ||
+ ACCESS_Frame( 2L + 512L ) )
+ goto Fail;
+
+ cmap2->language = GET_UShort();
+
+ for ( i = 0; i < 256; i++ )
+ {
+ u = (FT_UShort)( GET_UShort() / 8 );
+ cmap2->subHeaderKeys[i] = u;
+
+ if ( num_SH < u )
+ num_SH = u;
+ }
+
+ FORGET_Frame();
+
+ /* load subheaders */
+
+ cmap2->numGlyphId = l = (FT_UShort)(
+ ( ( cmap->length - 2L * ( 256 + 3 ) - num_SH * 8L ) & 0xFFFF ) / 2 );
+
+ if ( ALLOC_ARRAY( cmap2->subHeaders,
+ num_SH + 1,
+ TT_CMap2SubHeader ) ||
+ ACCESS_Frame( ( num_SH + 1 ) * 8L ) )
+ {
+ FREE( cmap2->subHeaderKeys );
+ goto Fail;
+ }
+
+ cmap2sub = cmap2->subHeaders;
+
+ for ( i = 0; i <= num_SH; i++ )
+ {
+ cmap2sub->firstCode = GET_UShort();
+ cmap2sub->entryCount = GET_UShort();
+ cmap2sub->idDelta = GET_Short();
+ /* we apply the location offset immediately */
+ cmap2sub->idRangeOffset = (FT_UShort)(
+ GET_UShort() - ( num_SH - i ) * 8 - 2 );
+
+ cmap2sub++;
+ }
+
+ FORGET_Frame();
+
+ /* load glyph IDs */
+
+ if ( ALLOC_ARRAY( cmap2->glyphIdArray, l, FT_UShort ) ||
+ ACCESS_Frame( l * 2L ) )
+ {
+ FREE( cmap2->subHeaders );
+ FREE( cmap2->subHeaderKeys );
+ goto Fail;
+ }
+
+ for ( i = 0; i < l; i++ )
+ cmap2->glyphIdArray[i] = GET_UShort();
+
+ FORGET_Frame();
+
+ cmap->get_index = code_to_index2;
+ break;
+
+ case 4:
+ cmap4 = &cmap->c.cmap4;
+
+ /* load header */
+
+ if ( ACCESS_Frame( 10L ) )
+ goto Fail;
+
+ cmap4->language = GET_UShort();
+ cmap4->segCountX2 = GET_UShort();
+ cmap4->searchRange = GET_UShort();
+ cmap4->entrySelector = GET_UShort();
+ cmap4->rangeShift = GET_UShort();
+
+ num_Seg = (FT_UShort)( cmap4->segCountX2 / 2 );
+
+ FORGET_Frame();
+
+ /* load segments */
+
+ if ( ALLOC_ARRAY( cmap4->segments,
+ num_Seg,
+ TT_CMap4Segment ) ||
+ ACCESS_Frame( ( num_Seg * 4 + 1 ) * 2L ) )
+ goto Fail;
+
+ segments = cmap4->segments;
+
+ for ( i = 0; i < num_Seg; i++ )
+ segments[i].endCount = GET_UShort();
+
+ (void)GET_UShort();
+
+ for ( i = 0; i < num_Seg; i++ )
+ segments[i].startCount = GET_UShort();
+
+ for ( i = 0; i < num_Seg; i++ )
+ segments[i].idDelta = GET_Short();
+
+ for ( i = 0; i < num_Seg; i++ )
+ segments[i].idRangeOffset = GET_UShort();
+
+ FORGET_Frame();
+
+ cmap4->numGlyphId = l = (FT_UShort)(
+ ( ( cmap->length - ( 16L + 8L * num_Seg ) ) & 0xFFFF ) / 2 );
+
+ /* load IDs */
+
+ if ( ALLOC_ARRAY( cmap4->glyphIdArray, l, FT_UShort ) ||
+ ACCESS_Frame( l * 2L ) )
+ {
+ FREE( cmap4->segments );
+ goto Fail;
+ }
+
+ for ( i = 0; i < l; i++ )
+ cmap4->glyphIdArray[i] = GET_UShort();
+
+ FORGET_Frame();
+
+ cmap4->last_segment = cmap4->segments;
+
+ cmap->get_index = code_to_index4;
+ break;
+
+ case 6:
+ cmap6 = &cmap->c.cmap6;
+
+ if ( ACCESS_Frame( 6L ) )
+ goto Fail;
+
+ cmap6->language = GET_UShort();
+ cmap6->firstCode = GET_UShort();
+ cmap6->entryCount = GET_UShort();
+
+ FORGET_Frame();
+
+ l = cmap6->entryCount;
+
+ if ( ALLOC_ARRAY( cmap6->glyphIdArray, l, FT_Short ) ||
+ ACCESS_Frame( l * 2L ) )
+ goto Fail;
+
+ for ( i = 0; i < l; i++ )
+ cmap6->glyphIdArray[i] = GET_UShort();
+
+ FORGET_Frame();
+ cmap->get_index = code_to_index6;
+ break;
+
+ case 8:
+ case 12:
+ cmap8_12 = &cmap->c.cmap8_12;
+
+ if ( ACCESS_Frame( 8L ) )
+ goto Fail;
+
+ cmap->length = GET_ULong();
+ cmap8_12->language = GET_ULong();
+
+ FORGET_Frame();
+
+ if ( cmap->format == 8 )
+ if ( FILE_Skip( 8192L ) )
+ goto Fail;
+
+ if ( READ_ULong( cmap8_12->nGroups ) )
+ goto Fail;
+
+ n = cmap8_12->nGroups;
+
+ if ( ALLOC_ARRAY( cmap8_12->groups, n, TT_CMapGroup ) ||
+ ACCESS_Frame( n * 3 * 4L ) )
+ goto Fail;
+
+ groups = cmap8_12->groups;
+
+ for ( j = 0; j < n; j++ )
+ {
+ groups[j].startCharCode = GET_ULong();
+ groups[j].endCharCode = GET_ULong();
+ groups[j].startGlyphID = GET_ULong();
+ }
+
+ FORGET_Frame();
+
+ cmap8_12->last_group = cmap8_12->groups;
+
+ cmap->get_index = code_to_index8_12;
+ break;
+
+ case 10:
+ cmap10 = &cmap->c.cmap10;
+
+ if ( ACCESS_Frame( 16L ) )
+ goto Fail;
+
+ cmap->length = GET_ULong();
+ cmap10->language = GET_ULong();
+ cmap10->startCharCode = GET_ULong();
+ cmap10->numChars = GET_ULong();
+
+ FORGET_Frame();
+
+ n = cmap10->numChars;
+
+ if ( ALLOC_ARRAY( cmap10->glyphs, n, FT_Short ) ||
+ ACCESS_Frame( n * 2L ) )
+ goto Fail;
+
+ for ( j = 0; j < n; j++ )
+ cmap10->glyphs[j] = GET_UShort();
+
+ FORGET_Frame();
+ cmap->get_index = code_to_index10;
+ break;
+
+ default: /* corrupt character mapping table */
+ return SFNT_Err_Invalid_CharMap_Format;
+
+ }
+
+ return SFNT_Err_Ok;
+
+ Fail:
+ TT_CharMap_Free( face, cmap );
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_CharMap_Free */
+ /* */
+ /* <Description> */
+ /* Destroys a character mapping table. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the parent face object. */
+ /* cmap :: A handle to a cmap object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_CharMap_Free( TT_Face face,
+ TT_CMapTable* cmap )
+ {
+ FT_Memory memory;
+
+
+ if ( !cmap )
+ return SFNT_Err_Ok;
+
+ memory = face->root.driver->root.memory;
+
+ switch ( cmap->format )
+ {
+ case 0:
+ FREE( cmap->c.cmap0.glyphIdArray );
+ break;
+
+ case 2:
+ FREE( cmap->c.cmap2.subHeaderKeys );
+ FREE( cmap->c.cmap2.subHeaders );
+ FREE( cmap->c.cmap2.glyphIdArray );
+ break;
+
+ case 4:
+ FREE( cmap->c.cmap4.segments );
+ FREE( cmap->c.cmap4.glyphIdArray );
+ cmap->c.cmap4.segCountX2 = 0;
+ break;
+
+ case 6:
+ FREE( cmap->c.cmap6.glyphIdArray );
+ cmap->c.cmap6.entryCount = 0;
+ break;
+
+ case 8:
+ case 12:
+ FREE( cmap->c.cmap8_12.groups );
+ cmap->c.cmap8_12.nGroups = 0;
+ break;
+
+ case 10:
+ FREE( cmap->c.cmap10.glyphs );
+ cmap->c.cmap10.numChars = 0;
+ break;
+
+ default:
+ /* invalid table format, do nothing */
+ ;
+ }
+
+ cmap->loaded = FALSE;
+ return SFNT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* code_to_index0 */
+ /* */
+ /* <Description> */
+ /* Converts the character code into a glyph index. Uses format 0. */
+ /* `charCode' must be in the range 0x00-0xFF (otherwise 0 is */
+ /* returned). */
+ /* */
+ /* <Input> */
+ /* charCode :: The wanted character code. */
+ /* cmap0 :: A pointer to a cmap table in format 0. */
+ /* */
+ /* <Return> */
+ /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
+ /* */
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index0( TT_CMapTable* cmap,
+ FT_ULong charCode )
+ {
+ TT_CMap0* cmap0 = &cmap->c.cmap0;
+
+
+ return ( charCode <= 0xFF ? cmap0->glyphIdArray[charCode] : 0 );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* code_to_index2 */
+ /* */
+ /* <Description> */
+ /* Converts the character code into a glyph index. Uses format 2. */
+ /* */
+ /* <Input> */
+ /* charCode :: The wanted character code. */
+ /* cmap2 :: A pointer to a cmap table in format 2. */
+ /* */
+ /* <Return> */
+ /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
+ /* */
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index2( TT_CMapTable* cmap,
+ FT_ULong charCode )
+ {
+ FT_UInt result, index1, offset;
+ FT_UInt char_lo;
+ FT_ULong char_hi;
+ TT_CMap2SubHeader* sh2;
+ TT_CMap2* cmap2;
+
+
+ cmap2 = &cmap->c.cmap2;
+ result = 0;
+ char_lo = (FT_UInt)( charCode & 0xFF );
+ char_hi = charCode >> 8;
+
+ if ( char_hi == 0 )
+ {
+ /* an 8-bit character code -- we use the subHeader 0 in this case */
+ /* to test whether the character code is in the charmap */
+ index1 = cmap2->subHeaderKeys[char_lo];
+ if ( index1 != 0 )
+ return 0;
+ }
+ else
+ {
+ /* a 16-bit character code */
+ index1 = cmap2->subHeaderKeys[char_hi & 0xFF];
+ if ( index1 == 0 )
+ return 0;
+ }
+
+ sh2 = cmap2->subHeaders + index1;
+ char_lo -= sh2->firstCode;
+
+ if ( char_lo < (FT_UInt)sh2->entryCount )
+ {
+ offset = sh2->idRangeOffset / 2 + char_lo;
+ if ( offset < (FT_UInt)cmap2->numGlyphId )
+ {
+ result = cmap2->glyphIdArray[offset];
+ if ( result )
+ result = ( result + sh2->idDelta ) & 0xFFFF;
+ }
+ }
+
+ return result;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* code_to_index4 */
+ /* */
+ /* <Description> */
+ /* Converts the character code into a glyph index. Uses format 4. */
+ /* */
+ /* <Input> */
+ /* charCode :: The wanted character code. */
+ /* cmap4 :: A pointer to a cmap table in format 4. */
+ /* */
+ /* <Return> */
+ /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
+ /* */
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index4( TT_CMapTable* cmap,
+ FT_ULong charCode )
+ {
+ FT_UInt result, index1, segCount;
+ TT_CMap4* cmap4;
+ TT_CMap4Segment *seg4, *limit;
+
+
+ cmap4 = &cmap->c.cmap4;
+ result = 0;
+ segCount = cmap4->segCountX2 / 2;
+ limit = cmap4->segments + segCount;
+
+ /* first, check against the last used segment */
+
+ seg4 = cmap4->last_segment;
+
+ /* the following is equivalent to performing two tests, as in */
+ /* */
+ /* if ( charCode >= seg4->startCount && charCode <= seg4->endCount ) */
+ /* */
+ /* This is a bit strange, but it is faster, and the idea behind the */
+ /* cache is to significantly speed up charcode to glyph index */
+ /* conversion. */
+
+ if ( (FT_ULong)( charCode - seg4->startCount ) <
+ (FT_ULong)( seg4->endCount - seg4->startCount ) )
+ goto Found1;
+
+ for ( seg4 = cmap4->segments; seg4 < limit; seg4++ )
+ {
+ /* the ranges are sorted in increasing order. If we are out of */
+ /* the range here, the char code isn't in the charmap, so exit. */
+
+ if ( charCode > (FT_UInt)seg4->endCount )
+ continue;
+
+ if ( charCode >= (FT_UInt)seg4->startCount )
+ goto Found;
+ }
+ return 0;
+
+ Found:
+ cmap4->last_segment = seg4;
+
+ Found1:
+ /* if the idRangeOffset is 0, we can compute the glyph index */
+ /* directly */
+
+ if ( seg4->idRangeOffset == 0 )
+ result = ( charCode + seg4->idDelta ) & 0xFFFF;
+ else
+ {
+ /* otherwise, we must use the glyphIdArray to do it */
+ index1 = (FT_UInt)( seg4->idRangeOffset / 2
+ + ( charCode - seg4->startCount )
+ + ( seg4 - cmap4->segments )
+ - segCount );
+
+ if ( index1 < (FT_UInt)cmap4->numGlyphId &&
+ cmap4->glyphIdArray[index1] != 0 )
+ result = ( cmap4->glyphIdArray[index1] + seg4->idDelta ) & 0xFFFF;
+ }
+
+ return result;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* code_to_index6 */
+ /* */
+ /* <Description> */
+ /* Converts the character code into a glyph index. Uses format 6. */
+ /* */
+ /* <Input> */
+ /* charCode :: The wanted character code. */
+ /* cmap6 :: A pointer to a cmap table in format 6. */
+ /* */
+ /* <Return> */
+ /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
+ /* */
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index6( TT_CMapTable* cmap,
+ FT_ULong charCode )
+ {
+ TT_CMap6* cmap6;
+ FT_UInt result = 0;
+
+
+ cmap6 = &cmap->c.cmap6;
+ charCode -= cmap6->firstCode;
+
+ if ( charCode < (FT_UInt)cmap6->entryCount )
+ result = cmap6->glyphIdArray[charCode];
+
+ return result;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* code_to_index8_12 */
+ /* */
+ /* <Description> */
+ /* Converts the (possibly 32bit) character code into a glyph index. */
+ /* Uses format 8 or 12. */
+ /* */
+ /* <Input> */
+ /* charCode :: The wanted character code. */
+ /* cmap8_12 :: A pointer to a cmap table in format 8 or 12. */
+ /* */
+ /* <Return> */
+ /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
+ /* */
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index8_12( TT_CMapTable* cmap,
+ FT_ULong charCode )
+ {
+ TT_CMap8_12* cmap8_12;
+ TT_CMapGroup *group, *limit;
+
+
+ cmap8_12 = &cmap->c.cmap8_12;
+ limit = cmap8_12->groups + cmap8_12->nGroups;
+
+ /* first, check against the last used group */
+
+ group = cmap8_12->last_group;
+
+ /* the following is equivalent to performing two tests, as in */
+ /* */
+ /* if ( charCode >= group->startCharCode && */
+ /* charCode <= group->endCharCode ) */
+ /* */
+ /* This is a bit strange, but it is faster, and the idea behind the */
+ /* cache is to significantly speed up charcode to glyph index */
+ /* conversion. */
+
+ if ( (FT_ULong)( charCode - group->startCharCode ) <
+ (FT_ULong)( group->endCharCode - group->startCharCode ) )
+ goto Found1;
+
+ for ( group = cmap8_12->groups; group < limit; group++ )
+ {
+ /* the ranges are sorted in increasing order. If we are out of */
+ /* the range here, the char code isn't in the charmap, so exit. */
+
+ if ( charCode > group->endCharCode )
+ continue;
+
+ if ( charCode >= group->startCharCode )
+ goto Found;
+ }
+ return 0;
+
+ Found:
+ cmap8_12->last_group = group;
+
+ Found1:
+ return group->startGlyphID + (FT_UInt)( charCode - group->startCharCode );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* code_to_index10 */
+ /* */
+ /* <Description> */
+ /* Converts the (possibly 32bit) character code into a glyph index. */
+ /* Uses format 10. */
+ /* */
+ /* <Input> */
+ /* charCode :: The wanted character code. */
+ /* cmap10 :: A pointer to a cmap table in format 10. */
+ /* */
+ /* <Return> */
+ /* Glyph index into the glyphs array. 0 if the glyph does not exist. */
+ /* */
+ FT_CALLBACK_DEF( FT_UInt )
+ code_to_index10( TT_CMapTable* cmap,
+ FT_ULong charCode )
+ {
+ TT_CMap10* cmap10;
+ FT_UInt result = 0;
+
+
+ cmap10 = &cmap->c.cmap10;
+ charCode -= cmap10->startCharCode;
+
+ /* the overflow trick for comparison works here also since the number */
+ /* of glyphs (even if numChars is specified as ULong in the specs) in */
+ /* an OpenType font is limited to 64k */
+
+ if ( charCode < cmap10->numChars )
+ result = cmap10->glyphs[charCode];
+
+ return result;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ttdriver.c */
+/* */
+/* TrueType font driver implementation (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_SFNT_H
+#include FT_TRUETYPE_IDS_H
+
+#include "ttdriver.h"
+#include "ttgload.h"
+
+#include "tterrors.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ttdriver
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** F A C E S ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#undef PAIR_TAG
+#define PAIR_TAG( left, right ) ( ( (FT_ULong)left << 16 ) | \
+ (FT_ULong)right )
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Get_Kerning */
+ /* */
+ /* <Description> */
+ /* A driver method used to return the kerning vector between two */
+ /* glyphs of the same face. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* left_glyph :: The index of the left glyph in the kern pair. */
+ /* */
+ /* right_glyph :: The index of the right glyph in the kern pair. */
+ /* */
+ /* <Output> */
+ /* kerning :: The kerning vector. This is in font units for */
+ /* scalable formats, and in pixels for fixed-sizes */
+ /* formats. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Only horizontal layouts (left-to-right & right-to-left) are */
+ /* supported by this function. Other layouts, or more sophisticated */
+ /* kernings, are out of scope of this method (the basic driver */
+ /* interface is meant to be simple). */
+ /* */
+ /* They can be implemented by format-specific interfaces. */
+ /* */
+ static FT_Error
+ Get_Kerning( TT_Face face,
+ FT_UInt left_glyph,
+ FT_UInt right_glyph,
+ FT_Vector* kerning )
+ {
+ TT_Kern_0_Pair* pair;
+
+
+ if ( !face )
+ return TT_Err_Invalid_Face_Handle;
+
+ kerning->x = 0;
+ kerning->y = 0;
+
+ if ( face->kern_pairs )
+ {
+ /* there are some kerning pairs in this font file! */
+ FT_ULong search_tag = PAIR_TAG( left_glyph, right_glyph );
+ FT_Long left, right;
+
+
+ left = 0;
+ right = face->num_kern_pairs - 1;
+
+ while ( left <= right )
+ {
+ FT_Int middle = left + ( ( right - left ) >> 1 );
+ FT_ULong cur_pair;
+
+
+ pair = face->kern_pairs + middle;
+ cur_pair = PAIR_TAG( pair->left, pair->right );
+
+ if ( cur_pair == search_tag )
+ goto Found;
+
+ if ( cur_pair < search_tag )
+ left = middle + 1;
+ else
+ right = middle - 1;
+ }
+ }
+
+ Exit:
+ return TT_Err_Ok;
+
+ Found:
+ kerning->x = pair->value;
+ goto Exit;
+ }
+
+
+#undef PAIR_TAG
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** S I Z E S ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Set_Char_Sizes */
+ /* */
+ /* <Description> */
+ /* A driver method used to reset a size's character sizes (horizontal */
+ /* and vertical) expressed in fractional points. */
+ /* */
+ /* <Input> */
+ /* char_width :: The character width expressed in 26.6 */
+ /* fractional points. */
+ /* */
+ /* char_height :: The character height expressed in 26.6 */
+ /* fractional points. */
+ /* */
+ /* horz_resolution :: The horizontal resolution of the output device. */
+ /* */
+ /* vert_resolution :: The vertical resolution of the output device. */
+ /* */
+ /* <InOut> */
+ /* size :: A handle to the target size object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ Set_Char_Sizes( TT_Size size,
+ FT_F26Dot6 char_width,
+ FT_F26Dot6 char_height,
+ FT_UInt horz_resolution,
+ FT_UInt vert_resolution )
+ {
+ FT_Size_Metrics* metrics = &size->root.metrics;
+ TT_Face face = (TT_Face)size->root.face;
+ FT_Long dim_x, dim_y;
+
+
+ /* This bit flag, when set, indicates that the pixel size must be */
+ /* truncated to an integer. Nearly all TrueType fonts have this */
+ /* bit set, as hinting won't work really well otherwise. */
+ /* */
+ /* However, for those rare fonts who do not set it, we override */
+ /* the default computations performed by the base layer. I */
+ /* really don't know whether this is useful, but hey, that's the */
+ /* spec :-) */
+ /* */
+ if ( ( face->header.Flags & 8 ) == 0 )
+ {
+ /* Compute pixel sizes in 26.6 units */
+ dim_x = ( char_width * horz_resolution ) / 72;
+ dim_y = ( char_height * vert_resolution ) / 72;
+
+ metrics->x_scale = FT_DivFix( dim_x, face->root.units_per_EM );
+ metrics->y_scale = FT_DivFix( dim_y, face->root.units_per_EM );
+
+ metrics->x_ppem = (FT_UShort)( dim_x >> 6 );
+ metrics->y_ppem = (FT_UShort)( dim_y >> 6 );
+ }
+
+ size->ttmetrics.valid = FALSE;
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+ size->strike_index = 0xFFFF;
+#endif
+
+ return TT_Reset_Size( size );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Set_Pixel_Sizes */
+ /* */
+ /* <Description> */
+ /* A driver method used to reset a size's character sizes (horizontal */
+ /* and vertical) expressed in integer pixels. */
+ /* */
+ /* <Input> */
+ /* pixel_width :: The character width expressed in integer pixels. */
+ /* */
+ /* pixel_height :: The character height expressed in integer pixels. */
+ /* */
+ /* <InOut> */
+ /* size :: A handle to the target size object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ Set_Pixel_Sizes( TT_Size size,
+ FT_UInt pixel_width,
+ FT_UInt pixel_height )
+ {
+ FT_UNUSED( pixel_width );
+ FT_UNUSED( pixel_height );
+
+ /* many things have been pre-computed by the base layer */
+
+ size->ttmetrics.valid = FALSE;
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+ size->strike_index = 0xFFFF;
+#endif
+
+ return TT_Reset_Size( size );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Load_Glyph */
+ /* */
+ /* <Description> */
+ /* A driver method used to load a glyph within a given glyph slot. */
+ /* */
+ /* <Input> */
+ /* slot :: A handle to the target slot object where the glyph */
+ /* will be loaded. */
+ /* */
+ /* size :: A handle to the source face size at which the glyph */
+ /* must be scaled, loaded, etc. */
+ /* */
+ /* glyph_index :: The index of the glyph in the font file. */
+ /* */
+ /* load_flags :: A flag indicating what to load for this glyph. The */
+ /* FTLOAD_??? constants can be used to control the */
+ /* glyph loading process (e.g., whether the outline */
+ /* should be scaled, whether to load bitmaps or not, */
+ /* whether to hint the outline, etc). */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ Load_Glyph( TT_GlyphSlot slot,
+ TT_Size size,
+ FT_UShort glyph_index,
+ FT_UInt load_flags )
+ {
+ FT_Error error;
+
+
+ if ( !slot )
+ return TT_Err_Invalid_Slot_Handle;
+
+ /* check whether we want a scaled outline or bitmap */
+ if ( !size )
+ load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+
+ if ( load_flags & FT_LOAD_NO_SCALE )
+ size = NULL;
+
+ /* reset the size object if necessary */
+ if ( size )
+ {
+ /* these two object must have the same parent */
+ if ( size->root.face != slot->face )
+ return TT_Err_Invalid_Face_Handle;
+
+ if ( !size->ttmetrics.valid )
+ {
+ if ( FT_SET_ERROR( TT_Reset_Size( size ) ) )
+ return error;
+ }
+ }
+
+ /* now load the glyph outline if necessary */
+ error = TT_Load_Glyph( size, slot, glyph_index, load_flags );
+
+ /* force drop-out mode to 2 - irrelevant now */
+ /* slot->outline.dropout_mode = 2; */
+
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** C H A R A C T E R M A P P I N G S ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Get_Char_Index */
+ /* */
+ /* <Description> */
+ /* Uses a charmap to return a given character code's glyph index. */
+ /* */
+ /* <Input> */
+ /* charmap :: A handle to the source charmap object. */
+ /* charcode :: The character code. */
+ /* */
+ /* <Return> */
+ /* Glyph index. 0 means `undefined character code'. */
+ /* */
+ static FT_UInt
+ Get_Char_Index( TT_CharMap charmap,
+ FT_Long charcode )
+ {
+ FT_Error error;
+ TT_Face face;
+ TT_CMapTable* cmap;
+
+
+ cmap = &charmap->cmap;
+ face = (TT_Face)charmap->root.face;
+
+ /* Load table if needed */
+ if ( !cmap->loaded )
+ {
+ SFNT_Interface* sfnt = (SFNT_Interface*)face->sfnt;
+
+
+ error = sfnt->load_charmap( face, cmap, face->root.stream );
+ if ( error )
+ return 0;
+
+ cmap->loaded = TRUE;
+ }
+
+ if ( cmap->get_index )
+ return cmap->get_index( cmap, charcode );
+ else
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** D R I V E R I N T E R F A C E ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ static FT_Module_Interface
+ tt_get_interface( TT_Driver driver,
+ const char* interface )
+ {
+ FT_Module sfntd = FT_Get_Module( driver->root.root.library,
+ "sfnt" );
+ SFNT_Interface* sfnt;
+
+
+ /* only return the default interface from the SFNT module */
+ if ( sfntd )
+ {
+ sfnt = (SFNT_Interface*)( sfntd->clazz->module_interface );
+ if ( sfnt )
+ return sfnt->get_interface( FT_MODULE( driver ), interface );
+ }
+
+ return 0;
+ }
+
+
+ /* The FT_DriverInterface structure is defined in ftdriver.h. */
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Driver_Class tt_driver_class =
+ {
+ {
+ ft_module_font_driver |
+ ft_module_driver_scalable |
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+ ft_module_driver_has_hinter,
+#else
+ 0,
+#endif
+
+ sizeof ( TT_DriverRec ),
+
+ "truetype", /* driver name */
+ 0x10000L, /* driver version == 1.0 */
+ 0x20000L, /* driver requires FreeType 2.0 or above */
+
+ (void*)0, /* driver specific interface */
+
+ (FT_Module_Constructor)TT_Init_Driver,
+ (FT_Module_Destructor) TT_Done_Driver,
+ (FT_Module_Requester) tt_get_interface,
+ },
+
+ sizeof ( TT_FaceRec ),
+ sizeof ( TT_SizeRec ),
+ sizeof ( FT_GlyphSlotRec ),
+
+
+ (FTDriver_initFace) TT_Init_Face,
+ (FTDriver_doneFace) TT_Done_Face,
+ (FTDriver_initSize) TT_Init_Size,
+ (FTDriver_doneSize) TT_Done_Size,
+ (FTDriver_initGlyphSlot)0,
+ (FTDriver_doneGlyphSlot)0,
+
+ (FTDriver_setCharSizes) Set_Char_Sizes,
+ (FTDriver_setPixelSizes)Set_Pixel_Sizes,
+ (FTDriver_loadGlyph) Load_Glyph,
+ (FTDriver_getCharIndex) Get_Char_Index,
+
+ (FTDriver_getKerning) Get_Kerning,
+ (FTDriver_attachFile) 0,
+ (FTDriver_getAdvances) 0
+ };
+
+
+#ifdef FT_CONFIG_OPTION_DYNAMIC_DRIVERS
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* getDriverClass */
+ /* */
+ /* <Description> */
+ /* This function is used when compiling the TrueType driver as a */
+ /* shared library (`.DLL' or `.so'). It will be used by the */
+ /* high-level library of FreeType to retrieve the address of the */
+ /* driver's generic interface. */
+ /* */
+ /* It shouldn't be implemented in a static build, as each driver must */
+ /* have the same function as an exported entry point. */
+ /* */
+ /* <Return> */
+ /* The address of the TrueType's driver generic interface. The */
+ /* format-specific interface can then be retrieved through the method */
+ /* interface->get_format_interface. */
+ /* */
+ FT_EXPORT_DEF( const FT_Driver_Class* )
+ getDriverClass( void )
+ {
+ return &tt_driver_class;
+ }
+
+
+#endif /* CONFIG_OPTION_DYNAMIC_DRIVERS */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ttgload.c */
+/* */
+/* TrueType Glyph Loader (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_SFNT_H
+#include FT_TRUETYPE_TAGS_H
+#include FT_OUTLINE_H
+
+#include "ttgload.h"
+
+#include "tterrors.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ttgload
+
+
+ /*************************************************************************/
+ /* */
+ /* Composite font flags. */
+ /* */
+#define ARGS_ARE_WORDS 0x001
+#define ARGS_ARE_XY_VALUES 0x002
+#define ROUND_XY_TO_GRID 0x004
+#define WE_HAVE_A_SCALE 0x008
+/* reserved 0x010 */
+#define MORE_COMPONENTS 0x020
+#define WE_HAVE_AN_XY_SCALE 0x040
+#define WE_HAVE_A_2X2 0x080
+#define WE_HAVE_INSTR 0x100
+#define USE_MY_METRICS 0x200
+
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Get_Metrics */
+ /* */
+ /* <Description> */
+ /* Returns the horizontal or vertical metrics in font units for a */
+ /* given glyph. The metrics are the left side bearing (resp. top */
+ /* side bearing) and advance width (resp. advance height). */
+ /* */
+ /* <Input> */
+ /* header :: A pointer to either the horizontal or vertical metrics */
+ /* structure. */
+ /* */
+ /* index :: The glyph index. */
+ /* */
+ /* <Output> */
+ /* bearing :: The bearing, either left side or top side. */
+ /* */
+ /* advance :: The advance width resp. advance height. */
+ /* */
+ /* <Note> */
+ /* This function will much probably move to another component in the */
+ /* near future, but I haven't decided which yet. */
+ /* */
+ FT_LOCAL_DEF void
+ TT_Get_Metrics( TT_HoriHeader* header,
+ FT_UInt index,
+ FT_Short* bearing,
+ FT_UShort* advance )
+ {
+ TT_LongMetrics* longs_m;
+ FT_UShort k = header->number_Of_HMetrics;
+
+
+ if ( index < (FT_UInt)k )
+ {
+ longs_m = (TT_LongMetrics*)header->long_metrics + index;
+ *bearing = longs_m->bearing;
+ *advance = longs_m->advance;
+ }
+ else
+ {
+ *bearing = ((TT_ShortMetrics*)header->short_metrics)[index - k];
+ *advance = ((TT_LongMetrics*)header->long_metrics)[k - 1].advance;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Returns the horizontal metrics in font units for a given glyph. If */
+ /* `check' is true, take care of monospaced fonts by returning the */
+ /* advance width maximum. */
+ /* */
+ static void
+ Get_HMetrics( TT_Face face,
+ FT_UInt index,
+ FT_Bool check,
+ FT_Short* lsb,
+ FT_UShort* aw )
+ {
+ TT_Get_Metrics( &face->horizontal, index, lsb, aw );
+
+ if ( check && face->postscript.isFixedPitch )
+ *aw = face->horizontal.advance_Width_Max;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Returns the advance width table for a given pixel size if it is */
+ /* found in the font's `hdmx' table (if any). */
+ /* */
+ static FT_Byte*
+ Get_Advance_Widths( TT_Face face,
+ FT_UShort ppem )
+ {
+ FT_UShort n;
+
+ for ( n = 0; n < face->hdmx.num_records; n++ )
+ if ( face->hdmx.records[n].ppem == ppem )
+ return face->hdmx.records[n].widths;
+
+ return NULL;
+ }
+
+
+#define cur_to_org( n, zone ) \
+ MEM_Copy( (zone)->org, (zone)->cur, n * sizeof ( FT_Vector ) )
+
+#define org_to_cur( n, zone ) \
+ MEM_Copy( (zone)->cur, (zone)->org, n * sizeof ( FT_Vector ) )
+
+
+ /*************************************************************************/
+ /* */
+ /* Translates an array of coordinates. */
+ /* */
+ static void
+ translate_array( FT_UInt n,
+ FT_Vector* coords,
+ FT_Pos delta_x,
+ FT_Pos delta_y )
+ {
+ FT_UInt k;
+
+
+ if ( delta_x )
+ for ( k = 0; k < n; k++ )
+ coords[k].x += delta_x;
+
+ if ( delta_y )
+ for ( k = 0; k < n; k++ )
+ coords[k].y += delta_y;
+ }
+
+
+ static void
+ tt_prepare_zone( TT_GlyphZone* zone,
+ FT_GlyphLoad* load,
+ FT_UInt start_point,
+ FT_UInt start_contour )
+ {
+ zone->n_points = (FT_UShort)( load->outline.n_points - start_point );
+ zone->n_contours = (FT_Short) ( load->outline.n_contours - start_contour );
+ zone->org = load->extra_points + start_point;
+ zone->cur = load->outline.points + start_point;
+ zone->tags = (FT_Byte*)load->outline.tags + start_point;
+ zone->contours = (FT_UShort*)load->outline.contours + start_contour;
+ }
+
+
+#undef IS_HINTED
+#define IS_HINTED( flags ) ( ( flags & FT_LOAD_NO_HINTING ) == 0 )
+
+
+ /*************************************************************************/
+ /* */
+ /* The following functions are used by default with TrueType fonts. */
+ /* However, they can be replaced by alternatives if we need to support */
+ /* TrueType-compressed formats (like MicroType) in the future. */
+ /* */
+ /*************************************************************************/
+
+ FT_CALLBACK_DEF( FT_Error )
+ TT_Access_Glyph_Frame( TT_Loader* loader,
+ FT_UInt glyph_index,
+ FT_ULong offset,
+ FT_UInt byte_count )
+ {
+ FT_Error error;
+ FT_Stream stream = loader->stream;
+
+ /* for non-debug mode */
+ FT_UNUSED( glyph_index );
+
+
+ FT_TRACE5(( "Glyph %ld\n", glyph_index ));
+
+ /* the following line sets the `error' variable through macros! */
+ if ( FILE_Seek( offset ) || ACCESS_Frame( byte_count ) )
+ return error;
+
+ return TT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ TT_Forget_Glyph_Frame( TT_Loader* loader )
+ {
+ FT_Stream stream = loader->stream;
+
+
+ FORGET_Frame();
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ TT_Load_Glyph_Header( TT_Loader* loader )
+ {
+ FT_Stream stream = loader->stream;
+
+
+ loader->n_contours = GET_Short();
+
+ loader->bbox.xMin = GET_Short();
+ loader->bbox.yMin = GET_Short();
+ loader->bbox.xMax = GET_Short();
+ loader->bbox.yMax = GET_Short();
+
+ FT_TRACE5(( " # of contours: %d\n", loader->n_contours ));
+ FT_TRACE5(( " xMin: %4d xMax: %4d\n", loader->bbox.xMin,
+ loader->bbox.xMax ));
+ FT_TRACE5(( " yMin: %4d yMax: %4d\n", loader->bbox.yMin,
+ loader->bbox.yMax ));
+
+ return TT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ TT_Load_Simple_Glyph( TT_Loader* load )
+ {
+ FT_Error error;
+ FT_Stream stream = load->stream;
+ FT_GlyphLoader* gloader = load->gloader;
+ FT_Int n_contours = load->n_contours;
+ FT_Outline* outline;
+ TT_Face face = (TT_Face)load->face;
+ TT_GlyphSlot slot = (TT_GlyphSlot)load->glyph;
+ FT_UShort n_ins;
+ FT_Int n, n_points;
+
+
+ /* reading the contours endpoints & number of points */
+ {
+ short* cur = gloader->current.outline.contours;
+ short* limit = cur + n_contours;
+
+
+ for ( ; cur < limit; cur++ )
+ cur[0] = GET_UShort();
+
+ n_points = 0;
+ if ( n_contours > 0 )
+ n_points = cur[-1] + 1;
+
+ error = FT_GlyphLoader_Check_Points( gloader, n_points + 2, 0 );
+ if ( error )
+ goto Fail;
+
+ outline = &gloader->current.outline;
+ }
+
+ /* reading the bytecode instructions */
+ slot->control_len = 0;
+ slot->control_data = 0;
+
+ n_ins = GET_UShort();
+
+ FT_TRACE5(( " Instructions size: %d\n", n_ins ));
+
+ if ( n_ins > face->max_profile.maxSizeOfInstructions )
+ {
+ FT_TRACE0(( "ERROR: Too many instructions!\n" ));
+ error = TT_Err_Too_Many_Hints;
+ goto Fail;
+ }
+
+ if ( stream->cursor + n_ins > stream->limit )
+ {
+ FT_TRACE0(( "ERROR: Instruction count mismatch!\n" ));
+ error = TT_Err_Too_Many_Hints;
+ goto Fail;
+ }
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ if ( ( load->load_flags &
+ ( FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING ) ) == 0 &&
+ load->instructions )
+ {
+ slot->control_len = n_ins;
+ slot->control_data = load->instructions;
+
+ MEM_Copy( load->instructions, stream->cursor, n_ins );
+ }
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+ stream->cursor += n_ins;
+
+ /* reading the point tags */
+
+ {
+ FT_Byte* flag = (FT_Byte*)outline->tags;
+ FT_Byte* limit = flag + n_points;
+ FT_Byte c, count;
+
+
+ for ( ; flag < limit; flag++ )
+ {
+ *flag = c = GET_Byte();
+ if ( c & 8 )
+ {
+ for ( count = GET_Byte(); count > 0; count-- )
+ *++flag = c;
+ }
+ }
+ }
+
+ /* reading the X coordinates */
+
+ {
+ FT_Vector* vec = outline->points;
+ FT_Vector* limit = vec + n_points;
+ FT_Byte* flag = (FT_Byte*)outline->tags;
+ FT_Pos x = 0;
+
+
+ for ( ; vec < limit; vec++, flag++ )
+ {
+ FT_Pos y = 0;
+
+
+ if ( *flag & 2 )
+ {
+ y = GET_Byte();
+ if ( ( *flag & 16 ) == 0 )
+ y = -y;
+ }
+ else if ( ( *flag & 16 ) == 0 )
+ y = GET_Short();
+
+ x += y;
+ vec->x = x;
+ }
+ }
+
+ /* reading the Y coordinates */
+
+ {
+ FT_Vector* vec = gloader->current.outline.points;
+ FT_Vector* limit = vec + n_points;
+ FT_Byte* flag = (FT_Byte*)outline->tags;
+ FT_Pos x = 0;
+
+
+ for ( ; vec < limit; vec++, flag++ )
+ {
+ FT_Pos y = 0;
+
+
+ if ( *flag & 4 )
+ {
+ y = GET_Byte();
+ if ( ( *flag & 32 ) == 0 )
+ y = -y;
+ }
+ else if ( ( *flag & 32 ) == 0 )
+ y = GET_Short();
+
+ x += y;
+ vec->y = x;
+ }
+ }
+
+ /* clear the touch tags */
+ for ( n = 0; n < n_points; n++ )
+ outline->tags[n] &= FT_Curve_Tag_On;
+
+ outline->n_points = (FT_UShort)n_points;
+ outline->n_contours = (FT_Short) n_contours;
+
+ Fail:
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ TT_Load_Composite_Glyph( TT_Loader* loader )
+ {
+ FT_Error error;
+ FT_Stream stream = loader->stream;
+ FT_GlyphLoader* gloader = loader->gloader;
+ FT_SubGlyph* subglyph;
+ FT_UInt num_subglyphs;
+
+
+ num_subglyphs = 0;
+
+ do
+ {
+ FT_Fixed xx, xy, yy, yx;
+
+
+ /* check that we can load a new subglyph */
+ error = FT_GlyphLoader_Check_Subglyphs( gloader, num_subglyphs + 1 );
+ if ( error )
+ goto Fail;
+
+ subglyph = gloader->current.subglyphs + num_subglyphs;
+
+ subglyph->arg1 = subglyph->arg2 = 0;
+
+ subglyph->flags = GET_UShort();
+ subglyph->index = GET_UShort();
+
+ /* read arguments */
+ if ( subglyph->flags & ARGS_ARE_WORDS )
+ {
+ subglyph->arg1 = GET_Short();
+ subglyph->arg2 = GET_Short();
+ }
+ else
+ {
+ subglyph->arg1 = GET_Char();
+ subglyph->arg2 = GET_Char();
+ }
+
+ /* read transform */
+ xx = yy = 0x10000L;
+ xy = yx = 0;
+
+ if ( subglyph->flags & WE_HAVE_A_SCALE )
+ {
+ xx = (FT_Fixed)GET_Short() << 2;
+ yy = xx;
+ }
+ else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE )
+ {
+ xx = (FT_Fixed)GET_Short() << 2;
+ yy = (FT_Fixed)GET_Short() << 2;
+ }
+ else if ( subglyph->flags & WE_HAVE_A_2X2 )
+ {
+ xx = (FT_Fixed)GET_Short() << 2;
+ xy = (FT_Fixed)GET_Short() << 2;
+ yx = (FT_Fixed)GET_Short() << 2;
+ yy = (FT_Fixed)GET_Short() << 2;
+ }
+
+ subglyph->transform.xx = xx;
+ subglyph->transform.xy = xy;
+ subglyph->transform.yx = yx;
+ subglyph->transform.yy = yy;
+
+ num_subglyphs++;
+
+ } while ( subglyph->flags & MORE_COMPONENTS );
+
+ gloader->current.num_subglyphs = num_subglyphs;
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+ {
+ /* we must undo the ACCESS_Frame in order to point to the */
+ /* composite instructions, if we find some. */
+ /* we will process them later... */
+ /* */
+ loader->ins_pos = (FT_ULong)( FILE_Pos() +
+ stream->cursor - stream->limit );
+ }
+#endif
+
+ Fail:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF void
+ TT_Init_Glyph_Loading( TT_Face face )
+ {
+ face->access_glyph_frame = TT_Access_Glyph_Frame;
+ face->read_glyph_header = TT_Load_Glyph_Header;
+ face->read_simple_glyph = TT_Load_Simple_Glyph;
+ face->read_composite_glyph = TT_Load_Composite_Glyph;
+ face->forget_glyph_frame = TT_Forget_Glyph_Frame;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Process_Simple_Glyph */
+ /* */
+ /* <Description> */
+ /* Once a simple glyph has been loaded, it needs to be processed. */
+ /* Usually, this means scaling and hinting through bytecode */
+ /* interpretation. */
+ /* */
+ static FT_Error
+ TT_Process_Simple_Glyph( TT_Loader* load,
+ FT_Bool debug )
+ {
+ FT_GlyphLoader* gloader = load->gloader;
+ FT_Outline* outline = &gloader->current.outline;
+ FT_UInt n_points = outline->n_points;
+ FT_UInt n_ins;
+ TT_GlyphZone* zone = &load->zone;
+ FT_Error error = TT_Err_Ok;
+
+ FT_UNUSED( debug ); /* used by truetype interpreter only */
+
+
+ n_ins = load->glyph->control_len;
+
+ /* add shadow points */
+
+ /* Now add the two shadow points at n and n + 1. */
+ /* We need the left side bearing and advance width. */
+
+ {
+ FT_Vector* pp1;
+ FT_Vector* pp2;
+
+
+ /* pp1 = xMin - lsb */
+ pp1 = outline->points + n_points;
+ pp1->x = load->bbox.xMin - load->left_bearing;
+ pp1->y = 0;
+
+ /* pp2 = pp1 + aw */
+ pp2 = pp1 + 1;
+ pp2->x = pp1->x + load->advance;
+ pp2->y = 0;
+
+ outline->tags[n_points ] = 0;
+ outline->tags[n_points + 1] = 0;
+ }
+
+ /* Note that we return two more points that are not */
+ /* part of the glyph outline. */
+
+ n_points += 2;
+
+ /* set up zone for hinting */
+ tt_prepare_zone( zone, &gloader->current, 0, 0 );
+
+ /* eventually scale the glyph */
+ if ( !( load->load_flags & FT_LOAD_NO_SCALE ) )
+ {
+ FT_Vector* vec = zone->cur;
+ FT_Vector* limit = vec + n_points;
+ FT_Fixed x_scale = load->size->metrics.x_scale;
+ FT_Fixed y_scale = load->size->metrics.y_scale;
+
+
+ /* first scale the glyph points */
+ for ( ; vec < limit; vec++ )
+ {
+ vec->x = FT_MulFix( vec->x, x_scale );
+ vec->y = FT_MulFix( vec->y, y_scale );
+ }
+ }
+
+ cur_to_org( n_points, zone );
+
+ /* eventually hint the glyph */
+ if ( IS_HINTED( load->load_flags ) )
+ {
+ FT_Pos x = zone->org[n_points-2].x;
+
+
+ x = ( ( x + 32 ) & -64 ) - x;
+ translate_array( n_points, zone->org, x, 0 );
+
+ org_to_cur( n_points, zone );
+
+ zone->cur[n_points - 1].x = ( zone->cur[n_points - 1].x + 32 ) & -64;
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ /* now consider hinting */
+ if ( n_ins > 0 )
+ {
+ error = TT_Set_CodeRange( load->exec, tt_coderange_glyph,
+ load->exec->glyphIns, n_ins );
+ if ( error )
+ goto Exit;
+
+ load->exec->is_composite = FALSE;
+ load->exec->pedantic_hinting = (FT_Bool)( load->load_flags &
+ FT_LOAD_PEDANTIC );
+ load->exec->pts = *zone;
+ load->exec->pts.n_points += 2;
+
+ error = TT_Run_Context( load->exec, debug );
+ if ( error && load->exec->pedantic_hinting )
+ goto Exit;
+
+ error = TT_Err_Ok; /* ignore bytecode errors in non-pedantic mode */
+ }
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+ }
+
+ /* save glyph phantom points */
+ if ( !load->preserve_pps )
+ {
+ load->pp1 = zone->cur[n_points - 2];
+ load->pp2 = zone->cur[n_points - 1];
+ }
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+ Exit:
+#endif
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* load_truetype_glyph */
+ /* */
+ /* <Description> */
+ /* Loads a given truetype glyph. Handles composites and uses a */
+ /* TT_Loader object. */
+ /* */
+ static FT_Error
+ load_truetype_glyph( TT_Loader* loader,
+ FT_UInt glyph_index )
+ {
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+ FT_Stream stream = loader->stream;
+#endif
+
+ FT_Error error;
+ TT_Face face = (TT_Face)loader->face;
+ FT_ULong offset;
+ FT_Int contours_count;
+ FT_UInt index, num_points, count;
+ FT_Fixed x_scale, y_scale;
+ FT_GlyphLoader* gloader = loader->gloader;
+ FT_Bool opened_frame = 0;
+
+
+ /* check glyph index */
+ index = glyph_index;
+ if ( index >= (FT_UInt)face->root.num_glyphs )
+ {
+ error = TT_Err_Invalid_Glyph_Index;
+ goto Exit;
+ }
+
+ loader->glyph_index = glyph_index;
+ num_points = 0;
+
+ x_scale = 0x10000L;
+ y_scale = 0x10000L;
+ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
+ {
+ x_scale = loader->size->metrics.x_scale;
+ y_scale = loader->size->metrics.y_scale;
+ }
+
+ /* get horizontal metrics */
+ {
+ FT_Short left_bearing;
+ FT_UShort advance_width;
+
+
+ Get_HMetrics( face, index,
+ (FT_Bool)!(loader->load_flags &
+ FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH),
+ &left_bearing,
+ &advance_width );
+
+ loader->left_bearing = left_bearing;
+ loader->advance = advance_width;
+
+ if ( !loader->linear_def )
+ {
+ loader->linear_def = 1;
+ loader->linear = advance_width;
+ }
+ }
+
+ offset = face->glyph_locations[index];
+ count = 0;
+
+ if ( index < (FT_UInt)face->num_locations - 1 )
+ count = face->glyph_locations[index + 1] - offset;
+
+ if ( count == 0 )
+ {
+ /* as described by Frederic Loyer, these are spaces, and */
+ /* not the unknown glyph. */
+ loader->bbox.xMin = 0;
+ loader->bbox.xMax = 0;
+ loader->bbox.yMin = 0;
+ loader->bbox.yMax = 0;
+
+ loader->pp1.x = 0;
+ loader->pp2.x = loader->advance;
+
+ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
+ loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale );
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ if ( loader->exec )
+ loader->exec->glyphSize = 0;
+
+#endif
+
+ error = TT_Err_Ok;
+ goto Exit;
+ }
+
+ offset = loader->glyf_offset + offset;
+
+ /* access glyph frame */
+ error = face->access_glyph_frame( loader, glyph_index, offset, count );
+ if ( error )
+ goto Exit;
+
+ opened_frame = 1;
+
+ /* read first glyph header */
+ error = face->read_glyph_header( loader );
+ if ( error )
+ goto Fail;
+
+ contours_count = loader->n_contours;
+
+ count -= 10;
+
+ loader->pp1.x = loader->bbox.xMin - loader->left_bearing;
+ loader->pp1.y = 0;
+ loader->pp2.x = loader->pp1.x + loader->advance;
+ loader->pp2.y = 0;
+
+ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
+ {
+ loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale );
+ loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale );
+ }
+
+ /***********************************************************************/
+ /***********************************************************************/
+ /***********************************************************************/
+
+ /* if it is a simple glyph, load it */
+
+ if ( contours_count >= 0 )
+ {
+ /* check that we can add the contours to the glyph */
+ error = FT_GlyphLoader_Check_Points( gloader, 0, contours_count );
+ if ( error )
+ goto Fail;
+
+ error = face->read_simple_glyph( loader );
+ if ( error )
+ goto Fail;
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ {
+ TT_Size size = (TT_Size)loader->size;
+
+
+ error = TT_Process_Simple_Glyph( loader,
+ (FT_Bool)( size && size->debug ) );
+ }
+
+#else
+
+ error = TT_Process_Simple_Glyph( loader, 0 );
+
+#endif
+
+ if ( error )
+ goto Fail;
+
+ FT_GlyphLoader_Add( gloader );
+
+ /* Note: We could have put the simple loader source there */
+ /* but the code is fat enough already :-) */
+ }
+
+ /***********************************************************************/
+ /***********************************************************************/
+ /***********************************************************************/
+
+ /* otherwise, load a composite! */
+ else
+ {
+ TT_GlyphSlot glyph = (TT_GlyphSlot)loader->glyph;
+ FT_UInt start_point, start_contour;
+ FT_ULong ins_pos; /* position of composite instructions, if any */
+
+
+ /* for each subglyph, read composite header */
+ start_point = gloader->base.outline.n_points;
+ start_contour = gloader->base.outline.n_contours;
+
+ error = face->read_composite_glyph( loader );
+ if ( error )
+ goto Fail;
+
+ ins_pos = loader->ins_pos;
+ face->forget_glyph_frame( loader );
+ opened_frame = 0;
+
+ /* if the flag FT_LOAD_NO_RECURSE is set, we return the subglyph */
+ /* `as is' in the glyph slot (the client application will be */
+ /* responsible for interpreting this data)... */
+ /* */
+ if ( loader->load_flags & FT_LOAD_NO_RECURSE )
+ {
+ /* set up remaining glyph fields */
+ FT_GlyphLoader_Add( gloader );
+
+ glyph->num_subglyphs = gloader->base.num_subglyphs;
+ glyph->format = ft_glyph_format_composite;
+ glyph->subglyphs = gloader->base.subglyphs;
+
+ goto Exit;
+ }
+
+ /*********************************************************************/
+ /*********************************************************************/
+ /*********************************************************************/
+
+ /* Now, read each subglyph independently. */
+ {
+ FT_Int n, num_base_points, num_new_points;
+ FT_SubGlyph* subglyph = 0;
+
+ FT_UInt num_subglyphs = gloader->current.num_subglyphs;
+ FT_UInt num_base_subgs = gloader->base.num_subglyphs;
+
+
+ FT_GlyphLoader_Add( gloader );
+
+ for ( n = 0; n < (FT_Int)num_subglyphs; n++ )
+ {
+ FT_Vector pp1, pp2;
+ FT_Pos x, y;
+
+
+ /* Each time we call load_truetype_glyph in this loop, the */
+ /* value of `gloader.base.subglyphs' can change due to table */
+ /* reallocations. We thus need to recompute the subglyph */
+ /* pointer on each iteration. */
+ subglyph = gloader->base.subglyphs + num_base_subgs + n;
+
+ pp1 = loader->pp1;
+ pp2 = loader->pp2;
+
+ num_base_points = gloader->base.outline.n_points;
+
+ error = load_truetype_glyph( loader, subglyph->index );
+ if ( error )
+ goto Fail;
+
+ /* restore subglyph pointer */
+ subglyph = gloader->base.subglyphs + num_base_subgs + n;
+
+ if ( subglyph->flags & USE_MY_METRICS )
+ {
+ pp1 = loader->pp1;
+ pp2 = loader->pp2;
+ }
+ else
+ {
+ loader->pp1 = pp1;
+ loader->pp2 = pp2;
+ }
+
+ num_points = gloader->base.outline.n_points;
+
+ num_new_points = num_points - num_base_points;
+
+ /* now perform the transform required for this subglyph */
+
+ if ( subglyph->flags & ( WE_HAVE_A_SCALE |
+ WE_HAVE_AN_XY_SCALE |
+ WE_HAVE_A_2X2 ) )
+ {
+ FT_Vector* cur = gloader->base.outline.points +
+ num_base_points;
+ FT_Vector* org = gloader->base.extra_points +
+ num_base_points;
+ FT_Vector* limit = cur + num_new_points;
+
+
+ for ( ; cur < limit; cur++, org++ )
+ {
+ FT_Vector_Transform( cur, &subglyph->transform );
+ FT_Vector_Transform( org, &subglyph->transform );
+ }
+ }
+
+ /* apply offset */
+
+ if ( !( subglyph->flags & ARGS_ARE_XY_VALUES ) )
+ {
+ FT_UInt k = subglyph->arg1;
+ FT_UInt l = subglyph->arg2;
+ FT_Vector* p1;
+ FT_Vector* p2;
+
+
+ if ( start_point + k >= (FT_UInt)num_base_points ||
+ l >= (FT_UInt)num_new_points )
+ {
+ error = TT_Err_Invalid_Composite;
+ goto Fail;
+ }
+
+ l += num_base_points;
+
+ p1 = gloader->base.outline.points + start_point + k;
+ p2 = gloader->base.outline.points + start_point + l;
+
+ x = p1->x - p2->x;
+ y = p1->y - p2->y;
+ }
+ else
+ {
+ x = subglyph->arg1;
+ y = subglyph->arg2;
+
+ if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) )
+ {
+ x = FT_MulFix( x, x_scale );
+ y = FT_MulFix( y, y_scale );
+
+ if ( subglyph->flags & ROUND_XY_TO_GRID )
+ {
+ x = ( x + 32 ) & -64;
+ y = ( y + 32 ) & -64;
+ }
+ }
+ }
+
+ if ( x | y )
+ {
+ translate_array( num_new_points,
+ gloader->base.outline.points + num_base_points,
+ x, y );
+
+ translate_array( num_new_points,
+ gloader->base.extra_points + num_base_points,
+ x, y );
+ }
+ }
+
+ /*******************************************************************/
+ /*******************************************************************/
+ /*******************************************************************/
+
+ /* we have finished loading all sub-glyphs; now, look for */
+ /* instructions for this composite! */
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ if ( num_subglyphs > 0 &&
+ loader->exec &&
+ ins_pos > 0 &&
+ subglyph->flags & WE_HAVE_INSTR )
+ {
+ FT_UShort n_ins;
+ TT_ExecContext exec = loader->exec;
+ TT_GlyphZone* pts;
+ FT_Vector* pp1;
+
+
+ /* read size of instructions */
+ if ( FILE_Seek( ins_pos ) ||
+ READ_UShort( n_ins ) )
+ goto Fail;
+ FT_TRACE5(( " Instructions size = %d\n", n_ins ));
+
+ /* in some fonts? */
+ if ( n_ins == 0xFFFF )
+ n_ins = 0;
+
+ /* check it */
+ if ( n_ins > face->max_profile.maxSizeOfInstructions )
+ {
+ FT_TRACE0(( "Too many instructions (%d) in composite glyph %ld\n",
+ n_ins, subglyph->index ));
+ return TT_Err_Too_Many_Hints;
+ }
+
+ /* read the instructions */
+ if ( FILE_Read( exec->glyphIns, n_ins ) )
+ goto Fail;
+
+ glyph->control_data = exec->glyphIns;
+ glyph->control_len = n_ins;
+
+ error = TT_Set_CodeRange( exec,
+ tt_coderange_glyph,
+ exec->glyphIns,
+ n_ins );
+ if ( error )
+ goto Fail;
+
+ /* prepare the execution context */
+ tt_prepare_zone( &exec->pts, &gloader->base,
+ start_point, start_contour );
+ pts = &exec->pts;
+
+ pts->n_points = (short)(num_points + 2);
+ pts->n_contours = gloader->base.outline.n_contours;
+
+ /* add phantom points */
+ pp1 = pts->cur + num_points;
+ pp1[0] = loader->pp1;
+ pp1[1] = loader->pp2;
+
+ pts->tags[num_points ] = 0;
+ pts->tags[num_points + 1] = 0;
+
+ /* if hinting, round the phantom points */
+ if ( IS_HINTED( loader->load_flags ) )
+ {
+ pp1[0].x = ( ( loader->pp1.x + 32 ) & -64 );
+ pp1[1].x = ( ( loader->pp2.x + 32 ) & -64 );
+ }
+
+ {
+ FT_UInt k;
+
+
+ for ( k = 0; k < num_points; k++ )
+ pts->tags[k] &= FT_Curve_Tag_On;
+ }
+
+ cur_to_org( num_points + 2, pts );
+
+ /* now consider hinting */
+ if ( IS_HINTED( loader->load_flags ) && n_ins > 0 )
+ {
+ exec->is_composite = TRUE;
+ exec->pedantic_hinting =
+ (FT_Bool)( loader->load_flags & FT_LOAD_PEDANTIC );
+
+ error = TT_Run_Context( exec, ((TT_Size)loader->size)->debug );
+ if ( error && exec->pedantic_hinting )
+ goto Fail;
+ }
+
+ /* save glyph origin and advance points */
+ loader->pp1 = pp1[0];
+ loader->pp2 = pp1[1];
+ }
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+ }
+ /* end of composite loading */
+ }
+
+ /***********************************************************************/
+ /***********************************************************************/
+ /***********************************************************************/
+
+ Fail:
+ if ( opened_frame )
+ face->forget_glyph_frame( loader );
+
+ Exit:
+ return error;
+ }
+
+
+ static void
+ compute_glyph_metrics( TT_Loader* loader,
+ FT_UInt glyph_index )
+ {
+ FT_BBox bbox;
+ TT_Face face = (TT_Face)loader->face;
+ FT_Fixed y_scale;
+ TT_GlyphSlot glyph = loader->glyph;
+ TT_Size size = (TT_Size)loader->size;
+
+
+ y_scale = 0x10000L;
+ if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
+ y_scale = size->root.metrics.y_scale;
+
+ if ( glyph->format != ft_glyph_format_composite )
+ {
+ glyph->outline.flags &= ~ft_outline_single_pass;
+
+ /* copy outline to our glyph slot */
+ FT_GlyphLoader_Copy_Points( glyph->internal->loader, loader->gloader );
+ glyph->outline = glyph->internal->loader->base.outline;
+
+ /* translate array so that (0,0) is the glyph's origin */
+ FT_Outline_Translate( &glyph->outline, -loader->pp1.x, 0 );
+
+ FT_Outline_Get_CBox( &glyph->outline, &bbox );
+
+ if ( IS_HINTED( loader->load_flags ) )
+ {
+ /* grid-fit the bounding box */
+ bbox.xMin &= -64;
+ bbox.yMin &= -64;
+ bbox.xMax = ( bbox.xMax + 63 ) & -64;
+ bbox.yMax = ( bbox.yMax + 63 ) & -64;
+ }
+ }
+ else
+ bbox = loader->bbox;
+
+ /* get the device-independent horizontal advance. It is scaled later */
+ /* by the base layer. */
+ {
+ FT_Pos advance = loader->linear;
+
+
+ /* the flag FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH was introduced to */
+ /* correctly support DynaLab fonts, which have an incorrect */
+ /* `advance_Width_Max' field! It is used, to my knowledge, */
+ /* exclusively in the X-TrueType font server. */
+ /* */
+ if ( face->postscript.isFixedPitch &&
+ ( loader->load_flags & FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ) == 0 )
+ advance = face->horizontal.advance_Width_Max;
+
+ /* we need to return the advance in font units in linearHoriAdvance, */
+ /* it will be scaled later by the base layer. */
+ glyph->linearHoriAdvance = advance;
+ }
+
+ glyph->metrics.horiBearingX = bbox.xMin;
+ glyph->metrics.horiBearingY = bbox.yMax;
+ glyph->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
+
+ /* Now take care of vertical metrics. In the case where there is */
+ /* no vertical information within the font (relatively common), make */
+ /* up some metrics by `hand'... */
+
+ {
+ FT_Short top_bearing; /* vertical top side bearing (EM units) */
+ FT_UShort advance_height; /* vertical advance height (EM units) */
+
+ FT_Pos left; /* scaled vertical left side bearing */
+ FT_Pos top; /* scaled vertical top side bearing */
+ FT_Pos advance; /* scaled vertical advance height */
+
+
+ /* Get the unscaled `tsb' and `ah' */
+ if ( face->vertical_info &&
+ face->vertical.number_Of_VMetrics > 0 )
+ {
+ /* Don't assume that both the vertical header and vertical */
+ /* metrics are present in the same font :-) */
+
+ TT_Get_Metrics( (TT_HoriHeader*)&face->vertical,
+ glyph_index,
+ &top_bearing,
+ &advance_height );
+ }
+ else
+ {
+ /* Make up the distances from the horizontal header. */
+
+ /* NOTE: The OS/2 values are the only `portable' ones, */
+ /* which is why we use them, if there is an OS/2 */
+ /* table in the font. Otherwise, we use the */
+ /* values defined in the horizontal header. */
+ /* */
+ /* NOTE2: The sTypoDescender is negative, which is why */
+ /* we compute the baseline-to-baseline distance */
+ /* here with: */
+ /* ascender - descender + linegap */
+ /* */
+ if ( face->os2.version != 0xFFFF )
+ {
+ top_bearing = (FT_Short)( face->os2.sTypoLineGap / 2 );
+ advance_height = (FT_UShort)( face->os2.sTypoAscender -
+ face->os2.sTypoDescender +
+ face->os2.sTypoLineGap );
+ }
+ else
+ {
+ top_bearing = (FT_Short)( face->horizontal.Line_Gap / 2 );
+ advance_height = (FT_UShort)( face->horizontal.Ascender +
+ face->horizontal.Descender +
+ face->horizontal.Line_Gap );
+ }
+ }
+
+ /* We must adjust the top_bearing value from the bounding box given */
+ /* in the glyph header to te bounding box calculated with */
+ /* FT_Get_Outline_CBox(). */
+
+ /* scale the metrics */
+ if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) )
+ {
+ top = FT_MulFix( top_bearing + loader->bbox.yMax, y_scale )
+ - bbox.yMax;
+ advance = FT_MulFix( advance_height, y_scale );
+ }
+ else
+ {
+ top = top_bearing + loader->bbox.yMax - bbox.yMax;
+ advance = advance_height;
+ }
+
+ /* set the advance height in design units. It is scaled later by */
+ /* the base layer. */
+ glyph->linearVertAdvance = advance_height;
+
+ /* XXX: for now, we have no better algorithm for the lsb, but it */
+ /* should work fine. */
+ /* */
+ left = ( bbox.xMin - bbox.xMax ) / 2;
+
+ /* grid-fit them if necessary */
+ if ( IS_HINTED( loader->load_flags ) )
+ {
+ left &= -64;
+ top = ( top + 63 ) & -64;
+ advance = ( advance + 32 ) & -64;
+ }
+
+ glyph->metrics.vertBearingX = left;
+ glyph->metrics.vertBearingY = top;
+ glyph->metrics.vertAdvance = advance;
+ }
+
+ /* adjust advance width to the value contained in the hdmx table */
+ if ( !face->postscript.isFixedPitch && size &&
+ IS_HINTED( loader->load_flags ) )
+ {
+ FT_Byte* widths = Get_Advance_Widths( face,
+ size->root.metrics.x_ppem );
+
+
+ if ( widths )
+ glyph->metrics.horiAdvance = widths[glyph_index] << 6;
+ }
+
+ /* set glyph dimensions */
+ glyph->metrics.width = bbox.xMax - bbox.xMin;
+ glyph->metrics.height = bbox.yMax - bbox.yMin;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_Glyph */
+ /* */
+ /* <Description> */
+ /* A function used to load a single glyph within a given glyph slot, */
+ /* for a given size. */
+ /* */
+ /* <Input> */
+ /* glyph :: A handle to a target slot object where the glyph */
+ /* will be loaded. */
+ /* */
+ /* size :: A handle to the source face size at which the glyph */
+ /* must be scaled/loaded. */
+ /* */
+ /* glyph_index :: The index of the glyph in the font file. */
+ /* */
+ /* load_flags :: A flag indicating what to load for this glyph. The */
+ /* FT_LOAD_XXX constants can be used to control the */
+ /* glyph loading process (e.g., whether the outline */
+ /* should be scaled, whether to load bitmaps or not, */
+ /* whether to hint the outline, etc). */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Load_Glyph( TT_Size size,
+ TT_GlyphSlot glyph,
+ FT_UShort glyph_index,
+ FT_UInt load_flags )
+ {
+ SFNT_Interface* sfnt;
+ TT_Face face;
+ FT_Stream stream;
+ FT_Error error;
+ TT_Loader loader;
+
+
+ face = (TT_Face)glyph->face;
+ sfnt = (SFNT_Interface*)face->sfnt;
+ stream = face->root.stream;
+ error = 0;
+
+ if ( !size || ( load_flags & FT_LOAD_NO_SCALE ) ||
+ ( load_flags & FT_LOAD_NO_RECURSE ) )
+ {
+ size = NULL;
+ load_flags |= FT_LOAD_NO_SCALE |
+ FT_LOAD_NO_HINTING |
+ FT_LOAD_NO_BITMAP;
+ }
+
+ glyph->num_subglyphs = 0;
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ /* try to load embedded bitmap if any */
+ /* */
+ /* XXX: The convention should be emphasized in */
+ /* the documents because it can be confusing. */
+ if ( size &&
+ size->strike_index != 0xFFFF &&
+ sfnt->load_sbits &&
+ ( load_flags & FT_LOAD_NO_BITMAP ) == 0 )
+
+ {
+ TT_SBit_Metrics metrics;
+
+
+ error = sfnt->load_sbit_image( face,
+ size->strike_index,
+ glyph_index,
+ load_flags,
+ stream,
+ &glyph->bitmap,
+ &metrics );
+ if ( !error )
+ {
+ glyph->outline.n_points = 0;
+ glyph->outline.n_contours = 0;
+
+ glyph->metrics.width = (FT_Pos)metrics.width << 6;
+ glyph->metrics.height = (FT_Pos)metrics.height << 6;
+
+ glyph->metrics.horiBearingX = (FT_Pos)metrics.horiBearingX << 6;
+ glyph->metrics.horiBearingY = (FT_Pos)metrics.horiBearingY << 6;
+ glyph->metrics.horiAdvance = (FT_Pos)metrics.horiAdvance << 6;
+
+ glyph->metrics.vertBearingX = (FT_Pos)metrics.vertBearingX << 6;
+ glyph->metrics.vertBearingY = (FT_Pos)metrics.vertBearingY << 6;
+ glyph->metrics.vertAdvance = (FT_Pos)metrics.vertAdvance << 6;
+
+ glyph->format = ft_glyph_format_bitmap;
+ if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
+ {
+ glyph->bitmap_left = metrics.vertBearingX;
+ glyph->bitmap_top = metrics.vertBearingY;
+ }
+ else
+ {
+ glyph->bitmap_left = metrics.horiBearingX;
+ glyph->bitmap_top = metrics.horiBearingY;
+ }
+ return error;
+ }
+ }
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+ /* seek to the beginning of the glyph table. For Type 42 fonts */
+ /* the table might be accessed from a Postscript stream or something */
+ /* else... */
+
+ error = face->goto_table( face, TTAG_glyf, stream, 0 );
+ if ( error )
+ {
+ FT_ERROR(( "TT_Load_Glyph: could not access glyph table\n" ));
+ goto Exit;
+ }
+
+ MEM_Set( &loader, 0, sizeof ( loader ) );
+
+ /* update the glyph zone bounds */
+ {
+ FT_GlyphLoader* gloader = FT_FACE_DRIVER(face)->glyph_loader;
+
+
+ loader.gloader = gloader;
+
+ FT_GlyphLoader_Rewind( gloader );
+
+ tt_prepare_zone( &loader.zone, &gloader->base, 0, 0 );
+ tt_prepare_zone( &loader.base, &gloader->base, 0, 0 );
+ }
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ if ( size )
+ {
+ /* query new execution context */
+ loader.exec = size->debug ? size->context : TT_New_Context( face );
+ if ( !loader.exec )
+ return TT_Err_Could_Not_Find_Context;
+
+ TT_Load_Context( loader.exec, face, size );
+ loader.instructions = loader.exec->glyphIns;
+
+ /* load default graphics state - if needed */
+ if ( size->GS.instruct_control & 2 )
+ loader.exec->GS = tt_default_graphics_state;
+ }
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+ /* clear all outline flags, except the `owner' one */
+ glyph->outline.flags = 0;
+
+ if ( size && size->root.metrics.y_ppem < 24 )
+ glyph->outline.flags |= ft_outline_high_precision;
+
+ /* let's initialize the rest of our loader now */
+
+ loader.load_flags = load_flags;
+
+ loader.face = (FT_Face)face;
+ loader.size = (FT_Size)size;
+ loader.glyph = (FT_GlyphSlot)glyph;
+ loader.stream = stream;
+
+ loader.glyf_offset = FILE_Pos();
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ /* if the cvt program has disabled hinting, the argument */
+ /* is ignored. */
+ if ( size && ( size->GS.instruct_control & 1 ) )
+ loader.load_flags |= FT_LOAD_NO_HINTING;
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+ /* Main loading loop */
+ glyph->format = ft_glyph_format_outline;
+ glyph->num_subglyphs = 0;
+ error = load_truetype_glyph( &loader, glyph_index );
+ if ( !error )
+ compute_glyph_metrics( &loader, glyph_index );
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ if ( !size || !size->debug )
+ TT_Done_Context( loader.exec );
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+ Exit:
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ttinterp.c */
+/* */
+/* TrueType bytecode interpreter (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_TRIGONOMETRY_H
+#include FT_SYSTEM_H
+
+#include "ttinterp.h"
+
+#include "tterrors.h"
+
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+
+#define TT_MULFIX FT_MulFix
+#define TT_MULDIV FT_MulDiv
+#define TT_INT64 FT_Int64
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ttinterp
+
+#undef NO_APPLE_PATENT
+#define APPLE_THRESHOLD 0x4000000L
+
+ /*************************************************************************/
+ /* */
+ /* In order to detect infinite loops in the code, we set up a counter */
+ /* within the run loop. A single stroke of interpretation is now */
+ /* limitet to a maximal number of opcodes defined below. */
+ /* */
+#define MAX_RUNNABLE_OPCODES 1000000L
+
+
+ /*************************************************************************/
+ /* */
+ /* There are two kinds of implementations: */
+ /* */
+ /* a. static implementation */
+ /* */
+ /* The current execution context is a static variable, which fields */
+ /* are accessed directly by the interpreter during execution. The */
+ /* context is named `cur'. */
+ /* */
+ /* This version is non-reentrant, of course. */
+ /* */
+ /* b. indirect implementation */
+ /* */
+ /* The current execution context is passed to _each_ function as its */
+ /* first argument, and each field is thus accessed indirectly. */
+ /* */
+ /* This version is fully re-entrant. */
+ /* */
+ /* The idea is that an indirect implementation may be slower to execute */
+ /* on low-end processors that are used in some systems (like 386s or */
+ /* even 486s). */
+ /* */
+ /* As a consequence, the indirect implementation is now the default, as */
+ /* its performance costs can be considered negligible in our context. */
+ /* Note, however, that we kept the same source with macros because: */
+ /* */
+ /* - The code is kept very close in design to the Pascal code used for */
+ /* development. */
+ /* */
+ /* - It's much more readable that way! */
+ /* */
+ /* - It's still open to experimentation and tuning. */
+ /* */
+ /*************************************************************************/
+
+
+#ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */
+
+#define CUR (*exc) /* see ttobjs.h */
+
+#else /* static implementation */
+
+#define CUR cur
+
+ static
+ TT_ExecContextRec cur; /* static exec. context variable */
+
+ /* apparently, we have a _lot_ of direct indexing when accessing */
+ /* the static `cur', which makes the code bigger (due to all the */
+ /* four bytes addresses). */
+
+#endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */
+
+
+ /*************************************************************************/
+ /* */
+ /* The instruction argument stack. */
+ /* */
+#define INS_ARG EXEC_OP_ FT_Long* args /* see ttobjs.h for EXEC_OP_ */
+
+
+ /*************************************************************************/
+ /* */
+ /* This macro is used whenever `exec' is unused in a function, to avoid */
+ /* stupid warnings from pedantic compilers. */
+ /* */
+#define FT_UNUSED_EXEC FT_UNUSED( CUR )
+
+
+ /*************************************************************************/
+ /* */
+ /* This macro is used whenever `args' is unused in a function, to avoid */
+ /* stupid warnings from pedantic compilers. */
+ /* */
+#define FT_UNUSED_ARG FT_UNUSED_EXEC; FT_UNUSED( args )
+
+
+ /*************************************************************************/
+ /* */
+ /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to */
+ /* increase readabilty of the code. */
+ /* */
+ /*************************************************************************/
+
+
+#define SKIP_Code() \
+ SkipCode( EXEC_ARG )
+
+#define GET_ShortIns() \
+ GetShortIns( EXEC_ARG )
+
+#define NORMalize( x, y, v ) \
+ Normalize( EXEC_ARG_ x, y, v )
+
+#define SET_SuperRound( scale, flags ) \
+ SetSuperRound( EXEC_ARG_ scale, flags )
+
+#define ROUND_None( d, c ) \
+ Round_None( EXEC_ARG_ d, c )
+
+#define INS_Goto_CodeRange( range, ip ) \
+ Ins_Goto_CodeRange( EXEC_ARG_ range, ip )
+
+#define CUR_Func_project( x, y ) \
+ CUR.func_project( EXEC_ARG_ x, y )
+
+#define CUR_Func_move( z, p, d ) \
+ CUR.func_move( EXEC_ARG_ z, p, d )
+
+#define CUR_Func_dualproj( x, y ) \
+ CUR.func_dualproj( EXEC_ARG_ x, y )
+
+#define CUR_Func_freeProj( x, y ) \
+ CUR.func_freeProj( EXEC_ARG_ x, y )
+
+#define CUR_Func_round( d, c ) \
+ CUR.func_round( EXEC_ARG_ d, c )
+
+#define CUR_Func_read_cvt( index ) \
+ CUR.func_read_cvt( EXEC_ARG_ index )
+
+#define CUR_Func_write_cvt( index, val ) \
+ CUR.func_write_cvt( EXEC_ARG_ index, val )
+
+#define CUR_Func_move_cvt( index, val ) \
+ CUR.func_move_cvt( EXEC_ARG_ index, val )
+
+#define CURRENT_Ratio() \
+ Current_Ratio( EXEC_ARG )
+
+#define CURRENT_Ppem() \
+ Current_Ppem( EXEC_ARG )
+
+#define CUR_Ppem() \
+ Cur_PPEM( EXEC_ARG )
+
+#define INS_SxVTL( a, b, c, d ) \
+ Ins_SxVTL( EXEC_ARG_ a, b, c, d )
+
+#define COMPUTE_Funcs() \
+ Compute_Funcs( EXEC_ARG )
+
+#define COMPUTE_Round( a ) \
+ Compute_Round( EXEC_ARG_ a )
+
+#define COMPUTE_Point_Displacement( a, b, c, d ) \
+ Compute_Point_Displacement( EXEC_ARG_ a, b, c, d )
+
+#define MOVE_Zp2_Point( a, b, c, t ) \
+ Move_Zp2_Point( EXEC_ARG_ a, b, c, t )
+
+
+ /*************************************************************************/
+ /* */
+ /* Instruction dispatch function, as used by the interpreter. */
+ /* */
+ typedef void (*TInstruction_Function)( INS_ARG );
+
+
+ /*************************************************************************/
+ /* */
+ /* A simple bounds-checking macro. */
+ /* */
+#define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )
+
+
+#undef SUCCESS
+#define SUCCESS 0
+
+#undef FAILURE
+#define FAILURE 1
+
+
+ /*************************************************************************/
+ /* */
+ /* CODERANGE FUNCTIONS */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Goto_CodeRange */
+ /* */
+ /* <Description> */
+ /* Switches to a new code range (updates the code related elements in */
+ /* `exec', and `IP'). */
+ /* */
+ /* <Input> */
+ /* range :: The new execution code range. */
+ /* */
+ /* IP :: The new IP in the new code range. */
+ /* */
+ /* <InOut> */
+ /* exec :: The target execution context. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Goto_CodeRange( TT_ExecContext exec,
+ FT_Int range,
+ FT_Long IP )
+ {
+ TT_CodeRange* coderange;
+
+
+ FT_Assert( range >= 1 && range <= 3 );
+
+ coderange = &exec->codeRangeTable[range - 1];
+
+ FT_Assert( coderange->base != NULL );
+
+ /* NOTE: Because the last instruction of a program may be a CALL */
+ /* which will return to the first byte *after* the code */
+ /* range, we test for IP <= Size instead of IP < Size. */
+ /* */
+ FT_Assert( (FT_ULong)IP <= coderange->size );
+
+ exec->code = coderange->base;
+ exec->codeSize = coderange->size;
+ exec->IP = IP;
+ exec->curRange = range;
+
+ return TT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Set_CodeRange */
+ /* */
+ /* <Description> */
+ /* Sets a code range. */
+ /* */
+ /* <Input> */
+ /* range :: The code range index. */
+ /* */
+ /* base :: The new code base. */
+ /* */
+ /* length :: The range size in bytes. */
+ /* */
+ /* <InOut> */
+ /* exec :: The target execution context. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Set_CodeRange( TT_ExecContext exec,
+ FT_Int range,
+ void* base,
+ FT_Long length )
+ {
+ FT_Assert( range >= 1 && range <= 3 );
+
+ exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
+ exec->codeRangeTable[range - 1].size = length;
+
+ return TT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Clear_CodeRange */
+ /* */
+ /* <Description> */
+ /* Clears a code range. */
+ /* */
+ /* <Input> */
+ /* range :: The code range index. */
+ /* */
+ /* <InOut> */
+ /* exec :: The target execution context. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Does not set the Error variable. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Clear_CodeRange( TT_ExecContext exec,
+ FT_Int range )
+ {
+ FT_Assert( range >= 1 && range <= 3 );
+
+ exec->codeRangeTable[range - 1].base = NULL;
+ exec->codeRangeTable[range - 1].size = 0;
+
+ return TT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* EXECUTION CONTEXT ROUTINES */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Destroy_Context */
+ /* */
+ /* <Description> */
+ /* Destroys a given context. */
+ /* */
+ /* <Input> */
+ /* exec :: A handle to the target execution context. */
+ /* */
+ /* memory :: A handle to the parent memory object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Only the glyph loader and debugger should call this function. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Destroy_Context( TT_ExecContext exec,
+ FT_Memory memory )
+ {
+ /* free composite load stack */
+ FREE( exec->loadStack );
+ exec->loadSize = 0;
+
+ /* points zone */
+ exec->maxPoints = 0;
+ exec->maxContours = 0;
+
+ /* free stack */
+ FREE( exec->stack );
+ exec->stackSize = 0;
+
+ /* free call stack */
+ FREE( exec->callStack );
+ exec->callSize = 0;
+ exec->callTop = 0;
+
+ /* free glyph code range */
+ FREE( exec->glyphIns );
+ exec->glyphSize = 0;
+
+ exec->size = NULL;
+ exec->face = NULL;
+
+ FREE( exec );
+ return TT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Init_Context */
+ /* */
+ /* <Description> */
+ /* Initializes a context object. */
+ /* */
+ /* <Input> */
+ /* memory :: A handle to the parent memory object. */
+ /* */
+ /* face :: A handle to the source TrueType face object. */
+ /* */
+ /* <InOut> */
+ /* exec :: A handle to the target execution context. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ Init_Context( TT_ExecContext exec,
+ TT_Face face,
+ FT_Memory memory )
+ {
+ FT_Error error;
+
+
+ FT_TRACE1(( "Init_Context: new object at 0x%08p, parent = 0x%08p\n",
+ exec, face ));
+
+ exec->memory = memory;
+ exec->callSize = 32;
+
+ if ( ALLOC_ARRAY( exec->callStack, exec->callSize, TT_CallRec ) )
+ goto Fail_Memory;
+
+ /* all values in the context are set to 0 already, but this is */
+ /* here as a remainder */
+ exec->maxPoints = 0;
+ exec->maxContours = 0;
+
+ exec->stackSize = 0;
+ exec->loadSize = 0;
+ exec->glyphSize = 0;
+
+ exec->stack = NULL;
+ exec->loadStack = NULL;
+ exec->glyphIns = NULL;
+
+ exec->face = face;
+ exec->size = NULL;
+
+ return TT_Err_Ok;
+
+ Fail_Memory:
+ FT_ERROR(( "Init_Context: not enough memory for 0x%08lx\n",
+ (FT_Long)exec ));
+ TT_Destroy_Context( exec, memory );
+
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Update_Max */
+ /* */
+ /* <Description> */
+ /* Checks the size of a buffer and reallocates it if necessary. */
+ /* */
+ /* <Input> */
+ /* memory :: A handle to the parent memory object. */
+ /* */
+ /* multiplier :: The size in bytes of each element in the buffer. */
+ /* */
+ /* new_max :: The new capacity (size) of the buffer. */
+ /* */
+ /* <InOut> */
+ /* size :: The address of the buffer's current size expressed */
+ /* in elements. */
+ /* */
+ /* buff :: The address of the buffer base pointer. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ Update_Max( FT_Memory memory,
+ FT_ULong* size,
+ FT_Long multiplier,
+ void** buff,
+ FT_ULong new_max )
+ {
+ FT_Error error;
+
+
+ if ( *size < new_max )
+ {
+ FREE( *buff );
+ if ( ALLOC( *buff, new_max * multiplier ) )
+ return error;
+ *size = new_max;
+ }
+
+ return TT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_Context */
+ /* */
+ /* <Description> */
+ /* Prepare an execution context for glyph hinting. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the source face object. */
+ /* */
+ /* size :: A handle to the source size object. */
+ /* */
+ /* <InOut> */
+ /* exec :: A handle to the target execution context. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Only the glyph loader and debugger should call this function. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Load_Context( TT_ExecContext exec,
+ TT_Face face,
+ TT_Size size )
+ {
+ FT_Int i;
+ FT_ULong tmp;
+ TT_MaxProfile* maxp;
+ FT_Error error;
+
+
+ exec->face = face;
+ maxp = &face->max_profile;
+ exec->size = size;
+
+ if ( size )
+ {
+ exec->numFDefs = size->num_function_defs;
+ exec->maxFDefs = size->max_function_defs;
+ exec->numIDefs = size->num_instruction_defs;
+ exec->maxIDefs = size->max_instruction_defs;
+ exec->FDefs = size->function_defs;
+ exec->IDefs = size->instruction_defs;
+ exec->tt_metrics = size->ttmetrics;
+ exec->metrics = size->root.metrics;
+
+ exec->maxFunc = size->max_func;
+ exec->maxIns = size->max_ins;
+
+ for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
+ exec->codeRangeTable[i] = size->codeRangeTable[i];
+
+ /* set graphics state */
+ exec->GS = size->GS;
+
+ exec->cvtSize = size->cvt_size;
+ exec->cvt = size->cvt;
+
+ exec->storeSize = size->storage_size;
+ exec->storage = size->storage;
+
+ exec->twilight = size->twilight;
+ }
+
+ error = Update_Max( exec->memory,
+ &exec->loadSize,
+ sizeof ( TT_SubGlyphRec ),
+ (void**)&exec->loadStack,
+ exec->face->max_components + 1 );
+ if ( error )
+ return error;
+
+ /* XXX: We reserve a little more elements on the stack to deal safely */
+ /* with broken fonts like arialbs, courbs, timesbs, etc. */
+ tmp = exec->stackSize;
+ error = Update_Max( exec->memory,
+ &tmp,
+ sizeof ( FT_F26Dot6 ),
+ (void**)&exec->stack,
+ maxp->maxStackElements + 32 );
+ exec->stackSize = (FT_UInt)tmp;
+ if ( error )
+ return error;
+
+ tmp = exec->glyphSize;
+ error = Update_Max( exec->memory,
+ &tmp,
+ sizeof ( FT_Byte ),
+ (void**)&exec->glyphIns,
+ maxp->maxSizeOfInstructions );
+ exec->glyphSize = (FT_UShort)tmp;
+ if ( error )
+ return error;
+
+ exec->pts.n_points = 0;
+ exec->pts.n_contours = 0;
+
+ exec->instruction_trap = FALSE;
+
+ return TT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Save_Context */
+ /* */
+ /* <Description> */
+ /* Saves the code ranges in a `size' object. */
+ /* */
+ /* <Input> */
+ /* exec :: A handle to the source execution context. */
+ /* */
+ /* <InOut> */
+ /* size :: A handle to the target size object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Only the glyph loader and debugger should call this function. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Save_Context( TT_ExecContext exec,
+ TT_Size size )
+ {
+ FT_Int i;
+
+
+ /* XXXX: Will probably disappear soon with all the code range */
+ /* management, which is now rather obsolete. */
+ /* */
+ size->num_function_defs = exec->numFDefs;
+ size->num_instruction_defs = exec->numIDefs;
+
+ size->max_func = exec->maxFunc;
+ size->max_ins = exec->maxIns;
+
+ for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
+ size->codeRangeTable[i] = exec->codeRangeTable[i];
+
+ return TT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Run_Context */
+ /* */
+ /* <Description> */
+ /* Executes one or more instructions in the execution context. */
+ /* */
+ /* <Input> */
+ /* debug :: A Boolean flag. If set, the function sets some internal */
+ /* variables and returns immediately, otherwise TT_RunIns() */
+ /* is called. */
+ /* */
+ /* This is commented out currently. */
+ /* */
+ /* <Input> */
+ /* exec :: A handle to the target execution context. */
+ /* */
+ /* <Return> */
+ /* TrueTyoe error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Only the glyph loader and debugger should call this function. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Run_Context( TT_ExecContext exec,
+ FT_Bool debug )
+ {
+ FT_Error error;
+
+
+ if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ) )
+ != TT_Err_Ok )
+ return error;
+
+ exec->zp0 = exec->pts;
+ exec->zp1 = exec->pts;
+ exec->zp2 = exec->pts;
+
+ exec->GS.gep0 = 1;
+ exec->GS.gep1 = 1;
+ exec->GS.gep2 = 1;
+
+ exec->GS.projVector.x = 0x4000;
+ exec->GS.projVector.y = 0x0000;
+
+ exec->GS.freeVector = exec->GS.projVector;
+ exec->GS.dualVector = exec->GS.projVector;
+
+ exec->GS.round_state = 1;
+ exec->GS.loop = 1;
+
+ /* some glyphs leave something on the stack. so we clean it */
+ /* before a new execution. */
+ exec->top = 0;
+ exec->callTop = 0;
+
+#if 1
+ FT_UNUSED( debug );
+
+ return exec->face->interpreter( exec );
+#else
+ if ( !debug )
+ return TT_RunIns( exec );
+ else
+ return TT_Err_Ok;
+#endif
+ }
+
+
+ const TT_GraphicsState tt_default_graphics_state =
+ {
+ 0, 0, 0,
+ { 0x4000, 0 },
+ { 0x4000, 0 },
+ { 0x4000, 0 },
+ 1, 64, 1,
+ TRUE, 68, 0, 0, 9, 3,
+ 0, FALSE, 2, 1, 1, 1
+ };
+
+
+ /* documentation is in ttinterp.h */
+
+ FT_EXPORT_DEF( TT_ExecContext )
+ TT_New_Context( TT_Face face )
+ {
+ TT_Driver driver;
+ TT_ExecContext exec;
+ FT_Memory memory;
+
+
+ if ( !face )
+ return 0;
+
+ driver = (TT_Driver)face->root.driver;
+
+ memory = driver->root.root.memory;
+ exec = driver->context;
+
+ if ( !driver->context )
+ {
+ FT_Error error;
+
+
+ /* allocate object */
+ if ( ALLOC( exec, sizeof ( *exec ) ) )
+ goto Exit;
+
+ /* initialize it */
+ error = Init_Context( exec, face, memory );
+ if ( error )
+ goto Fail;
+
+ /* store it into the driver */
+ driver->context = exec;
+ }
+
+ Exit:
+ return driver->context;
+
+ Fail:
+ FREE( exec );
+
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Done_Context */
+ /* */
+ /* <Description> */
+ /* Discards an execution context. */
+ /* */
+ /* <Input> */
+ /* exec :: A handle to the target execution context. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* Only the glyph loader and debugger should call this function. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Done_Context( TT_ExecContext exec )
+ {
+ /* Nothing at all for now */
+ FT_UNUSED( exec );
+
+ return TT_Err_Ok;
+ }
+
+
+ /* 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 */
+
+
+ /*************************************************************************/
+ /* */
+ /* Before an opcode is executed, the interpreter verifies that there are */
+ /* enough arguments on the stack, with the help of the Pop_Push_Count */
+ /* table. */
+ /* */
+ /* For each opcode, the first column gives the number of arguments that */
+ /* are popped from the stack; the second one gives the number of those */
+ /* that are pushed in result. */
+ /* */
+ /* Note that for opcodes with a varying number of parameters, either 0 */
+ /* or 1 arg is verified before execution, depending on the nature of the */
+ /* instruction: */
+ /* */
+ /* - if the number of arguments is given by the bytecode stream or the */
+ /* loop variable, 0 is chosen. */
+ /* */
+ /* - if the first argument is a count n that is followed by arguments */
+ /* a1 .. an, then 1 is chosen. */
+ /* */
+ /*************************************************************************/
+
+
+#undef PACK
+#define PACK( x, y ) ( ( x << 4 ) | y )
+
+
+ static
+ const FT_Byte Pop_Push_Count[256] =
+ {
+ /* opcodes are gathered in groups of 16 */
+ /* please keep the spaces as they are */
+
+ /* SVTCA y */ PACK( 0, 0 ),
+ /* SVTCA x */ PACK( 0, 0 ),
+ /* SPvTCA y */ PACK( 0, 0 ),
+ /* SPvTCA x */ PACK( 0, 0 ),
+ /* SFvTCA y */ PACK( 0, 0 ),
+ /* SFvTCA x */ PACK( 0, 0 ),
+ /* SPvTL // */ PACK( 2, 0 ),
+ /* SPvTL + */ PACK( 2, 0 ),
+ /* SFvTL // */ PACK( 2, 0 ),
+ /* SFvTL + */ PACK( 2, 0 ),
+ /* SPvFS */ PACK( 2, 0 ),
+ /* SFvFS */ PACK( 2, 0 ),
+ /* GPV */ PACK( 0, 2 ),
+ /* GFV */ PACK( 0, 2 ),
+ /* SFvTPv */ PACK( 0, 0 ),
+ /* ISECT */ PACK( 5, 0 ),
+
+ /* SRP0 */ PACK( 1, 0 ),
+ /* SRP1 */ PACK( 1, 0 ),
+ /* SRP2 */ PACK( 1, 0 ),
+ /* SZP0 */ PACK( 1, 0 ),
+ /* SZP1 */ PACK( 1, 0 ),
+ /* SZP2 */ PACK( 1, 0 ),
+ /* SZPS */ PACK( 1, 0 ),
+ /* SLOOP */ PACK( 1, 0 ),
+ /* RTG */ PACK( 0, 0 ),
+ /* RTHG */ PACK( 0, 0 ),
+ /* SMD */ PACK( 1, 0 ),
+ /* ELSE */ PACK( 0, 0 ),
+ /* JMPR */ PACK( 1, 0 ),
+ /* SCvTCi */ PACK( 1, 0 ),
+ /* SSwCi */ PACK( 1, 0 ),
+ /* SSW */ PACK( 1, 0 ),
+
+ /* DUP */ PACK( 1, 2 ),
+ /* POP */ PACK( 1, 0 ),
+ /* CLEAR */ PACK( 0, 0 ),
+ /* SWAP */ PACK( 2, 2 ),
+ /* DEPTH */ PACK( 0, 1 ),
+ /* CINDEX */ PACK( 1, 1 ),
+ /* MINDEX */ PACK( 1, 0 ),
+ /* AlignPTS */ PACK( 2, 0 ),
+ /* INS_$28 */ PACK( 0, 0 ),
+ /* UTP */ PACK( 1, 0 ),
+ /* LOOPCALL */ PACK( 2, 0 ),
+ /* CALL */ PACK( 1, 0 ),
+ /* FDEF */ PACK( 1, 0 ),
+ /* ENDF */ PACK( 0, 0 ),
+ /* MDAP[0] */ PACK( 1, 0 ),
+ /* MDAP[1] */ PACK( 1, 0 ),
+
+ /* IUP[0] */ PACK( 0, 0 ),
+ /* IUP[1] */ PACK( 0, 0 ),
+ /* SHP[0] */ PACK( 0, 0 ),
+ /* SHP[1] */ PACK( 0, 0 ),
+ /* SHC[0] */ PACK( 1, 0 ),
+ /* SHC[1] */ PACK( 1, 0 ),
+ /* SHZ[0] */ PACK( 1, 0 ),
+ /* SHZ[1] */ PACK( 1, 0 ),
+ /* SHPIX */ PACK( 1, 0 ),
+ /* IP */ PACK( 0, 0 ),
+ /* MSIRP[0] */ PACK( 2, 0 ),
+ /* MSIRP[1] */ PACK( 2, 0 ),
+ /* AlignRP */ PACK( 0, 0 ),
+ /* RTDG */ PACK( 0, 0 ),
+ /* MIAP[0] */ PACK( 2, 0 ),
+ /* MIAP[1] */ PACK( 2, 0 ),
+
+ /* NPushB */ PACK( 0, 0 ),
+ /* NPushW */ PACK( 0, 0 ),
+ /* WS */ PACK( 2, 0 ),
+ /* RS */ PACK( 1, 1 ),
+ /* WCvtP */ PACK( 2, 0 ),
+ /* RCvt */ PACK( 1, 1 ),
+ /* GC[0] */ PACK( 1, 1 ),
+ /* GC[1] */ PACK( 1, 1 ),
+ /* SCFS */ PACK( 2, 0 ),
+ /* MD[0] */ PACK( 2, 1 ),
+ /* MD[1] */ PACK( 2, 1 ),
+ /* MPPEM */ PACK( 0, 1 ),
+ /* MPS */ PACK( 0, 1 ),
+ /* FlipON */ PACK( 0, 0 ),
+ /* FlipOFF */ PACK( 0, 0 ),
+ /* DEBUG */ PACK( 1, 0 ),
+
+ /* LT */ PACK( 2, 1 ),
+ /* LTEQ */ PACK( 2, 1 ),
+ /* GT */ PACK( 2, 1 ),
+ /* GTEQ */ PACK( 2, 1 ),
+ /* EQ */ PACK( 2, 1 ),
+ /* NEQ */ PACK( 2, 1 ),
+ /* ODD */ PACK( 1, 1 ),
+ /* EVEN */ PACK( 1, 1 ),
+ /* IF */ PACK( 1, 0 ),
+ /* EIF */ PACK( 0, 0 ),
+ /* AND */ PACK( 2, 1 ),
+ /* OR */ PACK( 2, 1 ),
+ /* NOT */ PACK( 1, 1 ),
+ /* DeltaP1 */ PACK( 1, 0 ),
+ /* SDB */ PACK( 1, 0 ),
+ /* SDS */ PACK( 1, 0 ),
+
+ /* ADD */ PACK( 2, 1 ),
+ /* SUB */ PACK( 2, 1 ),
+ /* DIV */ PACK( 2, 1 ),
+ /* MUL */ PACK( 2, 1 ),
+ /* ABS */ PACK( 1, 1 ),
+ /* NEG */ PACK( 1, 1 ),
+ /* FLOOR */ PACK( 1, 1 ),
+ /* CEILING */ PACK( 1, 1 ),
+ /* ROUND[0] */ PACK( 1, 1 ),
+ /* ROUND[1] */ PACK( 1, 1 ),
+ /* ROUND[2] */ PACK( 1, 1 ),
+ /* ROUND[3] */ PACK( 1, 1 ),
+ /* NROUND[0] */ PACK( 1, 1 ),
+ /* NROUND[1] */ PACK( 1, 1 ),
+ /* NROUND[2] */ PACK( 1, 1 ),
+ /* NROUND[3] */ PACK( 1, 1 ),
+
+ /* WCvtF */ PACK( 2, 0 ),
+ /* DeltaP2 */ PACK( 1, 0 ),
+ /* DeltaP3 */ PACK( 1, 0 ),
+ /* DeltaCn[0] */ PACK( 1, 0 ),
+ /* DeltaCn[1] */ PACK( 1, 0 ),
+ /* DeltaCn[2] */ PACK( 1, 0 ),
+ /* SROUND */ PACK( 1, 0 ),
+ /* S45Round */ PACK( 1, 0 ),
+ /* JROT */ PACK( 2, 0 ),
+ /* JROF */ PACK( 2, 0 ),
+ /* ROFF */ PACK( 0, 0 ),
+ /* INS_$7B */ PACK( 0, 0 ),
+ /* RUTG */ PACK( 0, 0 ),
+ /* RDTG */ PACK( 0, 0 ),
+ /* SANGW */ PACK( 1, 0 ),
+ /* AA */ PACK( 1, 0 ),
+
+ /* FlipPT */ PACK( 0, 0 ),
+ /* FlipRgON */ PACK( 2, 0 ),
+ /* FlipRgOFF */ PACK( 2, 0 ),
+ /* INS_$83 */ PACK( 0, 0 ),
+ /* INS_$84 */ PACK( 0, 0 ),
+ /* ScanCTRL */ PACK( 1, 0 ),
+ /* SDVPTL[0] */ PACK( 2, 0 ),
+ /* SDVPTL[1] */ PACK( 2, 0 ),
+ /* GetINFO */ PACK( 1, 1 ),
+ /* IDEF */ PACK( 1, 0 ),
+ /* ROLL */ PACK( 3, 3 ),
+ /* MAX */ PACK( 2, 1 ),
+ /* MIN */ PACK( 2, 1 ),
+ /* ScanTYPE */ PACK( 1, 0 ),
+ /* InstCTRL */ PACK( 2, 0 ),
+ /* INS_$8F */ PACK( 0, 0 ),
+
+ /* INS_$90 */ PACK( 0, 0 ),
+ /* INS_$91 */ PACK( 0, 0 ),
+ /* INS_$92 */ PACK( 0, 0 ),
+ /* INS_$93 */ PACK( 0, 0 ),
+ /* INS_$94 */ PACK( 0, 0 ),
+ /* INS_$95 */ PACK( 0, 0 ),
+ /* INS_$96 */ PACK( 0, 0 ),
+ /* INS_$97 */ PACK( 0, 0 ),
+ /* INS_$98 */ PACK( 0, 0 ),
+ /* INS_$99 */ PACK( 0, 0 ),
+ /* INS_$9A */ PACK( 0, 0 ),
+ /* INS_$9B */ PACK( 0, 0 ),
+ /* INS_$9C */ PACK( 0, 0 ),
+ /* INS_$9D */ PACK( 0, 0 ),
+ /* INS_$9E */ PACK( 0, 0 ),
+ /* INS_$9F */ PACK( 0, 0 ),
+
+ /* INS_$A0 */ PACK( 0, 0 ),
+ /* INS_$A1 */ PACK( 0, 0 ),
+ /* INS_$A2 */ PACK( 0, 0 ),
+ /* INS_$A3 */ PACK( 0, 0 ),
+ /* INS_$A4 */ PACK( 0, 0 ),
+ /* INS_$A5 */ PACK( 0, 0 ),
+ /* INS_$A6 */ PACK( 0, 0 ),
+ /* INS_$A7 */ PACK( 0, 0 ),
+ /* INS_$A8 */ PACK( 0, 0 ),
+ /* INS_$A9 */ PACK( 0, 0 ),
+ /* INS_$AA */ PACK( 0, 0 ),
+ /* INS_$AB */ PACK( 0, 0 ),
+ /* INS_$AC */ PACK( 0, 0 ),
+ /* INS_$AD */ PACK( 0, 0 ),
+ /* INS_$AE */ PACK( 0, 0 ),
+ /* INS_$AF */ PACK( 0, 0 ),
+
+ /* PushB[0] */ PACK( 0, 1 ),
+ /* PushB[1] */ PACK( 0, 2 ),
+ /* PushB[2] */ PACK( 0, 3 ),
+ /* PushB[3] */ PACK( 0, 4 ),
+ /* PushB[4] */ PACK( 0, 5 ),
+ /* PushB[5] */ PACK( 0, 6 ),
+ /* PushB[6] */ PACK( 0, 7 ),
+ /* PushB[7] */ PACK( 0, 8 ),
+ /* PushW[0] */ PACK( 0, 1 ),
+ /* PushW[1] */ PACK( 0, 2 ),
+ /* PushW[2] */ PACK( 0, 3 ),
+ /* PushW[3] */ PACK( 0, 4 ),
+ /* PushW[4] */ PACK( 0, 5 ),
+ /* PushW[5] */ PACK( 0, 6 ),
+ /* PushW[6] */ PACK( 0, 7 ),
+ /* PushW[7] */ PACK( 0, 8 ),
+
+ /* MDRP[00] */ PACK( 1, 0 ),
+ /* MDRP[01] */ PACK( 1, 0 ),
+ /* MDRP[02] */ PACK( 1, 0 ),
+ /* MDRP[03] */ PACK( 1, 0 ),
+ /* MDRP[04] */ PACK( 1, 0 ),
+ /* MDRP[05] */ PACK( 1, 0 ),
+ /* MDRP[06] */ PACK( 1, 0 ),
+ /* MDRP[07] */ PACK( 1, 0 ),
+ /* MDRP[08] */ PACK( 1, 0 ),
+ /* MDRP[09] */ PACK( 1, 0 ),
+ /* MDRP[10] */ PACK( 1, 0 ),
+ /* MDRP[11] */ PACK( 1, 0 ),
+ /* MDRP[12] */ PACK( 1, 0 ),
+ /* MDRP[13] */ PACK( 1, 0 ),
+ /* MDRP[14] */ PACK( 1, 0 ),
+ /* MDRP[15] */ PACK( 1, 0 ),
+
+ /* MDRP[16] */ PACK( 1, 0 ),
+ /* MDRP[17] */ PACK( 1, 0 ),
+ /* MDRP[18] */ PACK( 1, 0 ),
+ /* MDRP[19] */ PACK( 1, 0 ),
+ /* MDRP[20] */ PACK( 1, 0 ),
+ /* MDRP[21] */ PACK( 1, 0 ),
+ /* MDRP[22] */ PACK( 1, 0 ),
+ /* MDRP[23] */ PACK( 1, 0 ),
+ /* MDRP[24] */ PACK( 1, 0 ),
+ /* MDRP[25] */ PACK( 1, 0 ),
+ /* MDRP[26] */ PACK( 1, 0 ),
+ /* MDRP[27] */ PACK( 1, 0 ),
+ /* MDRP[28] */ PACK( 1, 0 ),
+ /* MDRP[29] */ PACK( 1, 0 ),
+ /* MDRP[30] */ PACK( 1, 0 ),
+ /* MDRP[31] */ PACK( 1, 0 ),
+
+ /* MIRP[00] */ PACK( 2, 0 ),
+ /* MIRP[01] */ PACK( 2, 0 ),
+ /* MIRP[02] */ PACK( 2, 0 ),
+ /* MIRP[03] */ PACK( 2, 0 ),
+ /* MIRP[04] */ PACK( 2, 0 ),
+ /* MIRP[05] */ PACK( 2, 0 ),
+ /* MIRP[06] */ PACK( 2, 0 ),
+ /* MIRP[07] */ PACK( 2, 0 ),
+ /* MIRP[08] */ PACK( 2, 0 ),
+ /* MIRP[09] */ PACK( 2, 0 ),
+ /* MIRP[10] */ PACK( 2, 0 ),
+ /* MIRP[11] */ PACK( 2, 0 ),
+ /* MIRP[12] */ PACK( 2, 0 ),
+ /* MIRP[13] */ PACK( 2, 0 ),
+ /* MIRP[14] */ PACK( 2, 0 ),
+ /* MIRP[15] */ PACK( 2, 0 ),
+
+ /* MIRP[16] */ PACK( 2, 0 ),
+ /* MIRP[17] */ PACK( 2, 0 ),
+ /* MIRP[18] */ PACK( 2, 0 ),
+ /* MIRP[19] */ PACK( 2, 0 ),
+ /* MIRP[20] */ PACK( 2, 0 ),
+ /* MIRP[21] */ PACK( 2, 0 ),
+ /* MIRP[22] */ PACK( 2, 0 ),
+ /* MIRP[23] */ PACK( 2, 0 ),
+ /* MIRP[24] */ PACK( 2, 0 ),
+ /* MIRP[25] */ PACK( 2, 0 ),
+ /* MIRP[26] */ PACK( 2, 0 ),
+ /* MIRP[27] */ PACK( 2, 0 ),
+ /* MIRP[28] */ PACK( 2, 0 ),
+ /* MIRP[29] */ PACK( 2, 0 ),
+ /* MIRP[30] */ PACK( 2, 0 ),
+ /* MIRP[31] */ PACK( 2, 0 )
+ };
+
+
+ static
+ const FT_Char opcode_length[256] =
+ {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ -1,-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+ };
+
+ static
+ const FT_Vector Null_Vector = {0,0};
+
+
+#undef PACK
+
+
+#undef NULL_Vector
+#define NULL_Vector (FT_Vector*)&Null_Vector
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Current_Ratio */
+ /* */
+ /* <Description> */
+ /* Returns the current aspect ratio scaling factor depending on the */
+ /* projection vector's state and device resolutions. */
+ /* */
+ /* <Return> */
+ /* The aspect ratio in 16.16 format, always <= 1.0 . */
+ /* */
+ static FT_Long
+ Current_Ratio( EXEC_OP )
+ {
+ if ( CUR.tt_metrics.ratio )
+ return CUR.tt_metrics.ratio;
+
+ if ( CUR.GS.projVector.y == 0 )
+ CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
+
+ else if ( CUR.GS.projVector.x == 0 )
+ CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
+
+ else
+ {
+ 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 );
+ }
+
+ return CUR.tt_metrics.ratio;
+ }
+
+
+ static FT_Long
+ Current_Ppem( EXEC_OP )
+ {
+ return TT_MULFIX( CUR.tt_metrics.ppem, CURRENT_Ratio() );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Functions related to the control value table (CVT). */
+ /* */
+ /*************************************************************************/
+
+
+ FT_CALLBACK_DEF( FT_F26Dot6 )
+ Read_CVT( EXEC_OP_ FT_ULong index )
+ {
+ return CUR.cvt[index];
+ }
+
+
+ FT_CALLBACK_DEF( FT_F26Dot6 )
+ Read_CVT_Stretched( EXEC_OP_ FT_ULong index )
+ {
+ return TT_MULFIX( CUR.cvt[index], CURRENT_Ratio() );
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ Write_CVT( EXEC_OP_ FT_ULong index,
+ FT_F26Dot6 value )
+ {
+ CUR.cvt[index] = value;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ Write_CVT_Stretched( EXEC_OP_ FT_ULong index,
+ FT_F26Dot6 value )
+ {
+ CUR.cvt[index] = FT_DivFix( value, CURRENT_Ratio() );
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ Move_CVT( EXEC_OP_ FT_ULong index,
+ FT_F26Dot6 value )
+ {
+ CUR.cvt[index] += value;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ Move_CVT_Stretched( EXEC_OP_ FT_ULong index,
+ FT_F26Dot6 value )
+ {
+ CUR.cvt[index] += FT_DivFix( value, CURRENT_Ratio() );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* GetShortIns */
+ /* */
+ /* <Description> */
+ /* Returns a short integer taken from the instruction stream at */
+ /* address IP. */
+ /* */
+ /* <Return> */
+ /* Short read at code[IP]. */
+ /* */
+ /* <Note> */
+ /* This one could become a macro. */
+ /* */
+ static FT_Short
+ GetShortIns( EXEC_OP )
+ {
+ /* Reading a byte stream so there is no endianess (DaveP) */
+ CUR.IP += 2;
+ return (FT_Short)( ( CUR.code[CUR.IP - 2] << 8 ) +
+ CUR.code[CUR.IP - 1] );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Ins_Goto_CodeRange */
+ /* */
+ /* <Description> */
+ /* Goes to a certain code range in the instruction stream. */
+ /* */
+ /* <Input> */
+ /* aRange :: The index of the code range. */
+ /* */
+ /* aIP :: The new IP address in the code range. */
+ /* */
+ /* <Return> */
+ /* SUCCESS or FAILURE. */
+ /* */
+ static FT_Bool
+ Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange,
+ FT_ULong aIP )
+ {
+ TT_CodeRange* range;
+
+
+ if ( aRange < 1 || aRange > 3 )
+ {
+ CUR.error = TT_Err_Bad_Argument;
+ return FAILURE;
+ }
+
+ range = &CUR.codeRangeTable[aRange - 1];
+
+ if ( range->base == NULL ) /* invalid coderange */
+ {
+ CUR.error = TT_Err_Invalid_CodeRange;
+ return FAILURE;
+ }
+
+ /* NOTE: Because the last instruction of a program may be a CALL */
+ /* which will return to the first byte *after* the code */
+ /* range, we test for AIP <= Size, instead of AIP < Size. */
+
+ if ( aIP > range->size )
+ {
+ CUR.error = TT_Err_Code_Overflow;
+ return FAILURE;
+ }
+
+ CUR.code = range->base;
+ CUR.codeSize = range->size;
+ CUR.IP = aIP;
+ CUR.curRange = aRange;
+
+ return SUCCESS;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Direct_Move */
+ /* */
+ /* <Description> */
+ /* Moves a point by a given distance along the freedom vector. The */
+ /* point will be `touched'. */
+ /* */
+ /* <Input> */
+ /* point :: The index of the point to move. */
+ /* */
+ /* distance :: The distance to apply. */
+ /* */
+ /* <InOut> */
+ /* zone :: The affected glyph zone. */
+ /* */
+ static void
+ Direct_Move( EXEC_OP_ TT_GlyphZone* zone,
+ FT_UShort point,
+ FT_F26Dot6 distance )
+ {
+ FT_F26Dot6 v;
+
+
+ v = CUR.GS.freeVector.x;
+
+ if ( v != 0 )
+ {
+
+#ifdef NO_APPLE_PATENT
+
+ if ( ABS( CUR.F_dot_P ) > APPLE_THRESHOLD )
+ zone->cur[point].x += distance;
+
+#else
+
+ zone->cur[point].x += TT_MULDIV( distance,
+ v * 0x10000L,
+ CUR.F_dot_P );
+
+#endif
+
+ zone->tags[point] |= FT_Curve_Tag_Touch_X;
+ }
+
+ v = CUR.GS.freeVector.y;
+
+ if ( v != 0 )
+ {
+
+#ifdef NO_APPLE_PATENT
+
+ if ( ABS( CUR.F_dot_P ) > APPLE_THRESHOLD )
+ zone->cur[point].y += distance;
+
+#else
+
+ zone->cur[point].y += TT_MULDIV( distance,
+ v * 0x10000L,
+ CUR.F_dot_P );
+
+#endif
+
+ zone->tags[point] |= FT_Curve_Tag_Touch_Y;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Special versions of Direct_Move() */
+ /* */
+ /* The following versions are used whenever both vectors are both */
+ /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
+ /* */
+ /*************************************************************************/
+
+
+ static void
+ Direct_Move_X( EXEC_OP_ TT_GlyphZone* zone,
+ FT_UShort point,
+ FT_F26Dot6 distance )
+ {
+ FT_UNUSED_EXEC;
+
+ zone->cur[point].x += distance;
+ zone->tags[point] |= FT_Curve_Tag_Touch_X;
+ }
+
+
+ static void
+ Direct_Move_Y( EXEC_OP_ TT_GlyphZone* zone,
+ FT_UShort point,
+ FT_F26Dot6 distance )
+ {
+ FT_UNUSED_EXEC;
+
+ zone->cur[point].y += distance;
+ zone->tags[point] |= FT_Curve_Tag_Touch_Y;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Round_None */
+ /* */
+ /* <Description> */
+ /* Does not round, but adds engine compensation. */
+ /* */
+ /* <Input> */
+ /* distance :: The distance (not) to round. */
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
+ /* <Return> */
+ /* The compensated distance. */
+ /* */
+ /* <Note> */
+ /* The TrueType specification says very few about the relationship */
+ /* between rounding and engine compensation. However, it seems from */
+ /* the description of super round that we should add the compensation */
+ /* before rounding. */
+ /* */
+ static FT_F26Dot6
+ Round_None( EXEC_OP_ FT_F26Dot6 distance,
+ FT_F26Dot6 compensation )
+ {
+ FT_F26Dot6 val;
+
+ FT_UNUSED_EXEC;
+
+
+ if ( distance >= 0 )
+ {
+ val = distance + compensation;
+ if ( val < 0 )
+ val = 0;
+ }
+ else {
+ val = distance - compensation;
+ if ( val > 0 )
+ val = 0;
+ }
+ return val;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Round_To_Grid */
+ /* */
+ /* <Description> */
+ /* Rounds value to grid after adding engine compensation. */
+ /* */
+ /* <Input> */
+ /* distance :: The distance to round. */
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
+ /* <Return> */
+ /* Rounded distance. */
+ /* */
+ static FT_F26Dot6
+ Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
+ FT_F26Dot6 compensation )
+ {
+ FT_F26Dot6 val;
+
+ FT_UNUSED_EXEC;
+
+
+ if ( distance >= 0 )
+ {
+ val = distance + compensation + 32;
+ if ( val > 0 )
+ val &= ~63;
+ else
+ val = 0;
+ }
+ else
+ {
+ val = -( ( compensation - distance + 32 ) & -64 );
+ if ( val > 0 )
+ val = 0;
+ }
+
+ return val;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Round_To_Half_Grid */
+ /* */
+ /* <Description> */
+ /* Rounds value to half grid after adding engine compensation. */
+ /* */
+ /* <Input> */
+ /* distance :: The distance to round. */
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
+ /* <Return> */
+ /* Rounded distance. */
+ /* */
+ static FT_F26Dot6
+ Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance,
+ FT_F26Dot6 compensation )
+ {
+ FT_F26Dot6 val;
+
+ FT_UNUSED_EXEC;
+
+
+ if ( distance >= 0 )
+ {
+ val = ( ( distance + compensation ) & -64 ) + 32;
+ if ( val < 0 )
+ val = 0;
+ }
+ else
+ {
+ val = -( ( (compensation - distance) & -64 ) + 32 );
+ if ( val > 0 )
+ val = 0;
+ }
+
+ return val;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Round_Down_To_Grid */
+ /* */
+ /* <Description> */
+ /* Rounds value down to grid after adding engine compensation. */
+ /* */
+ /* <Input> */
+ /* distance :: The distance to round. */
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
+ /* <Return> */
+ /* Rounded distance. */
+ /* */
+ static FT_F26Dot6
+ Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
+ FT_F26Dot6 compensation )
+ {
+ FT_F26Dot6 val;
+
+ FT_UNUSED_EXEC;
+
+
+ if ( distance >= 0 )
+ {
+ val = distance + compensation;
+ if ( val > 0 )
+ val &= ~63;
+ else
+ val = 0;
+ }
+ else
+ {
+ val = -( ( compensation - distance ) & -64 );
+ if ( val > 0 )
+ val = 0;
+ }
+
+ return val;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Round_Up_To_Grid */
+ /* */
+ /* <Description> */
+ /* Rounds value up to grid after adding engine compensation. */
+ /* */
+ /* <Input> */
+ /* distance :: The distance to round. */
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
+ /* <Return> */
+ /* Rounded distance. */
+ /* */
+ static FT_F26Dot6
+ Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
+ FT_F26Dot6 compensation )
+ {
+ FT_F26Dot6 val;
+
+
+ FT_UNUSED_EXEC;
+
+ if ( distance >= 0 )
+ {
+ val = distance + compensation + 63;
+ if ( val > 0 )
+ val &= ~63;
+ else
+ val = 0;
+ }
+ else
+ {
+ val = -( ( compensation - distance + 63 ) & -64 );
+ if ( val > 0 )
+ val = 0;
+ }
+
+ return val;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Round_To_Double_Grid */
+ /* */
+ /* <Description> */
+ /* Rounds value to double grid after adding engine compensation. */
+ /* */
+ /* <Input> */
+ /* distance :: The distance to round. */
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
+ /* <Return> */
+ /* Rounded distance. */
+ /* */
+ static FT_F26Dot6
+ Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance,
+ FT_F26Dot6 compensation )
+ {
+ FT_F26Dot6 val;
+
+ FT_UNUSED_EXEC;
+
+
+ if ( distance >= 0 )
+ {
+ val = distance + compensation + 16;
+ if ( val > 0 )
+ val &= ~31;
+ else
+ val = 0;
+ }
+ else
+ {
+ val = -( ( compensation - distance + 16 ) & -32 );
+ if ( val > 0 )
+ val = 0;
+ }
+
+ return val;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Round_Super */
+ /* */
+ /* <Description> */
+ /* Super-rounds value to grid after adding engine compensation. */
+ /* */
+ /* <Input> */
+ /* distance :: The distance to round. */
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
+ /* <Return> */
+ /* Rounded distance. */
+ /* */
+ /* <Note> */
+ /* The TrueType specification says very few about the relationship */
+ /* between rounding and engine compensation. However, it seems from */
+ /* the description of super round that we should add the compensation */
+ /* before rounding. */
+ /* */
+ static FT_F26Dot6
+ Round_Super( EXEC_OP_ FT_F26Dot6 distance,
+ FT_F26Dot6 compensation )
+ {
+ FT_F26Dot6 val;
+
+
+ if ( distance >= 0 )
+ {
+ val = ( distance - CUR.phase + CUR.threshold + compensation ) &
+ -CUR.period;
+ if ( val < 0 )
+ val = 0;
+ val += CUR.phase;
+ }
+ else
+ {
+ val = -( ( CUR.threshold - CUR.phase - distance + compensation ) &
+ -CUR.period );
+ if ( val > 0 )
+ val = 0;
+ val -= CUR.phase;
+ }
+
+ return val;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Round_Super_45 */
+ /* */
+ /* <Description> */
+ /* Super-rounds value to grid after adding engine compensation. */
+ /* */
+ /* <Input> */
+ /* distance :: The distance to round. */
+ /* */
+ /* compensation :: The engine compensation. */
+ /* */
+ /* <Return> */
+ /* Rounded distance. */
+ /* */
+ /* <Note> */
+ /* There is a separate function for Round_Super_45() as we may need */
+ /* greater precision. */
+ /* */
+ static FT_F26Dot6
+ Round_Super_45( EXEC_OP_ FT_F26Dot6 distance,
+ FT_F26Dot6 compensation )
+ {
+ FT_F26Dot6 val;
+
+
+ if ( distance >= 0 )
+ {
+ val = ( ( distance - CUR.phase + CUR.threshold + compensation ) /
+ CUR.period ) * CUR.period;
+ if ( val < 0 )
+ val = 0;
+ val += CUR.phase;
+ }
+ else
+ {
+ val = -( ( ( CUR.threshold - CUR.phase - distance + compensation ) /
+ CUR.period ) * CUR.period );
+ if ( val > 0 )
+ val = 0;
+ val -= CUR.phase;
+ }
+
+ return val;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Compute_Round */
+ /* */
+ /* <Description> */
+ /* Sets the rounding mode. */
+ /* */
+ /* <Input> */
+ /* round_mode :: The rounding mode to be used. */
+ /* */
+ static void
+ Compute_Round( EXEC_OP_ FT_Byte round_mode )
+ {
+ switch ( round_mode )
+ {
+ case TT_Round_Off:
+ CUR.func_round = (TT_Round_Func)Round_None;
+ break;
+
+ case TT_Round_To_Grid:
+ CUR.func_round = (TT_Round_Func)Round_To_Grid;
+ break;
+
+ case TT_Round_Up_To_Grid:
+ CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
+ break;
+
+ case TT_Round_Down_To_Grid:
+ CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
+ break;
+
+ case TT_Round_To_Half_Grid:
+ CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
+ break;
+
+ case TT_Round_To_Double_Grid:
+ CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
+ break;
+
+ case TT_Round_Super:
+ CUR.func_round = (TT_Round_Func)Round_Super;
+ break;
+
+ case TT_Round_Super_45:
+ CUR.func_round = (TT_Round_Func)Round_Super_45;
+ break;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* SetSuperRound */
+ /* */
+ /* <Description> */
+ /* Sets Super Round parameters. */
+ /* */
+ /* <Input> */
+ /* GridPeriod :: Grid period */
+ /* selector :: SROUND opcode */
+ /* */
+ static void
+ SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod,
+ FT_Long selector )
+ {
+ switch ( (FT_Int)( selector & 0xC0 ) )
+ {
+ case 0:
+ CUR.period = GridPeriod / 2;
+ break;
+
+ case 0x40:
+ CUR.period = GridPeriod;
+ break;
+
+ case 0x80:
+ CUR.period = GridPeriod * 2;
+ break;
+
+ /* This opcode is reserved, but... */
+
+ case 0xC0:
+ CUR.period = GridPeriod;
+ break;
+ }
+
+ switch ( (FT_Int)( selector & 0x30 ) )
+ {
+ case 0:
+ CUR.phase = 0;
+ break;
+
+ case 0x10:
+ CUR.phase = CUR.period / 4;
+ break;
+
+ case 0x20:
+ CUR.phase = CUR.period / 2;
+ break;
+
+ case 0x30:
+ CUR.phase = GridPeriod * 3 / 4;
+ break;
+ }
+
+ if ( (selector & 0x0F) == 0 )
+ CUR.threshold = CUR.period - 1;
+ else
+ CUR.threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * CUR.period / 8;
+
+ CUR.period /= 256;
+ CUR.phase /= 256;
+ CUR.threshold /= 256;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Project */
+ /* */
+ /* <Description> */
+ /* Computes the projection of vector given by (v2-v1) along the */
+ /* current projection vector. */
+ /* */
+ /* <Input> */
+ /* v1 :: First input vector. */
+ /* v2 :: Second input vector. */
+ /* */
+ /* <Return> */
+ /* The distance in F26dot6 format. */
+ /* */
+ static FT_F26Dot6
+ 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 );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Dual_Project */
+ /* */
+ /* <Description> */
+ /* Computes the projection of the vector given by (v2-v1) along the */
+ /* current dual vector. */
+ /* */
+ /* <Input> */
+ /* v1 :: First input vector. */
+ /* v2 :: Second input vector. */
+ /* */
+ /* <Return> */
+ /* The distance in F26dot6 format. */
+ /* */
+ static FT_F26Dot6
+ 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 );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Free_Project */
+ /* */
+ /* <Description> */
+ /* Computes the projection of the vector given by (v2-v1) along the */
+ /* current freedom vector. */
+ /* */
+ /* <Input> */
+ /* v1 :: First input vector. */
+ /* v2 :: Second input vector. */
+ /* */
+ /* <Return> */
+ /* The distance in F26dot6 format. */
+ /* */
+ static FT_F26Dot6
+ 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 );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Project_x */
+ /* */
+ /* <Description> */
+ /* Computes the projection of the vector given by (v2-v1) along the */
+ /* horizontal axis. */
+ /* */
+ /* <Input> */
+ /* v1 :: First input vector. */
+ /* v2 :: Second input vector. */
+ /* */
+ /* <Return> */
+ /* The distance in F26dot6 format. */
+ /* */
+ static FT_F26Dot6
+ Project_x( EXEC_OP_ FT_Vector* v1,
+ FT_Vector* v2 )
+ {
+ FT_UNUSED_EXEC;
+
+ return ( v1->x - v2->x );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Project_y */
+ /* */
+ /* <Description> */
+ /* Computes the projection of the vector given by (v2-v1) along the */
+ /* vertical axis. */
+ /* */
+ /* <Input> */
+ /* v1 :: First input vector. */
+ /* v2 :: Second input vector. */
+ /* */
+ /* <Return> */
+ /* The distance in F26dot6 format. */
+ /* */
+ static FT_F26Dot6
+ Project_y( EXEC_OP_ FT_Vector* v1,
+ FT_Vector* v2 )
+ {
+ FT_UNUSED_EXEC;
+
+ return ( v1->y - v2->y );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Compute_Funcs */
+ /* */
+ /* <Description> */
+ /* Computes the projection and movement function pointers according */
+ /* to the current graphics state. */
+ /* */
+ static void
+ Compute_Funcs( EXEC_OP )
+ {
+ if ( CUR.GS.freeVector.x == 0x4000 )
+ {
+ CUR.func_freeProj = (TT_Project_Func)Project_x;
+ CUR.F_dot_P = CUR.GS.projVector.x * 0x10000L;
+ }
+ else
+ {
+ if ( CUR.GS.freeVector.y == 0x4000 )
+ {
+ CUR.func_freeProj = (TT_Project_Func)Project_y;
+ CUR.F_dot_P = CUR.GS.projVector.y * 0x10000L;
+ }
+ else
+ {
+ CUR.func_freeProj = (TT_Project_Func)Free_Project;
+ CUR.F_dot_P = (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 +
+ (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4;
+ }
+ }
+
+ if ( CUR.GS.projVector.x == 0x4000 )
+ CUR.func_project = (TT_Project_Func)Project_x;
+ else
+ {
+ if ( CUR.GS.projVector.y == 0x4000 )
+ CUR.func_project = (TT_Project_Func)Project_y;
+ else
+ CUR.func_project = (TT_Project_Func)Project;
+ }
+
+ if ( CUR.GS.dualVector.x == 0x4000 )
+ CUR.func_dualproj = (TT_Project_Func)Project_x;
+ else
+ {
+ if ( CUR.GS.dualVector.y == 0x4000 )
+ CUR.func_dualproj = (TT_Project_Func)Project_y;
+ else
+ CUR.func_dualproj = (TT_Project_Func)Dual_Project;
+ }
+
+ CUR.func_move = (TT_Move_Func)Direct_Move;
+
+ if ( CUR.F_dot_P == 0x40000000L )
+ {
+ if ( CUR.GS.freeVector.x == 0x4000 )
+ CUR.func_move = (TT_Move_Func)Direct_Move_X;
+ else
+ {
+ if ( CUR.GS.freeVector.y == 0x4000 )
+ CUR.func_move = (TT_Move_Func)Direct_Move_Y;
+ }
+ }
+
+ /* at small sizes, F_dot_P can become too small, resulting */
+ /* in overflows and `spikes' in a number of glyphs like `w'. */
+
+ if ( ABS( CUR.F_dot_P ) < 0x4000000L )
+ CUR.F_dot_P = 0x40000000L;
+
+ /* Disable cached aspect ratio */
+ CUR.tt_metrics.ratio = 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Normalize */
+ /* */
+ /* <Description> */
+ /* Norms a vector. */
+ /* */
+ /* <Input> */
+ /* Vx :: The horizontal input vector coordinate. */
+ /* Vy :: The vertical input vector coordinate. */
+ /* */
+ /* <Output> */
+ /* R :: The normed unit vector. */
+ /* */
+ /* <Return> */
+ /* Returns FAILURE if a vector parameter is zero. */
+ /* */
+ /* <Note> */
+ /* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */
+ /* R is undefined. */
+ /* */
+
+#ifdef FT_CONFIG_OPTION_OLD_CALCS
+
+ static FT_Bool
+ Normalize( EXEC_OP_ FT_F26Dot6 Vx,
+ FT_F26Dot6 Vy,
+ FT_UnitVector* R )
+ {
+ FT_F26Dot6 W;
+ FT_Bool S1, S2;
+
+ FT_UNUSED_EXEC;
+
+
+ if ( ABS( Vx ) < 0x10000L && ABS( Vy ) < 0x10000L )
+ {
+ Vx *= 0x100;
+ Vy *= 0x100;
+
+ W = Norm( Vx, Vy );
+
+ if ( W == 0 )
+ {
+ /* XXX: UNDOCUMENTED! It seems that it is possible to try */
+ /* to normalize the vector (0,0). Return immediately. */
+ return SUCCESS;
+ }
+
+ R->x = (FT_F2Dot14)FT_MulDiv( Vx, 0x4000L, W );
+ R->y = (FT_F2Dot14)FT_MulDiv( Vy, 0x4000L, W );
+
+ return SUCCESS;
+ }
+
+ W = Norm( Vx, Vy );
+
+ Vx = FT_MulDiv( Vx, 0x4000L, W );
+ Vy = FT_MulDiv( Vy, 0x4000L, W );
+
+ W = Vx * Vx + Vy * Vy;
+
+ /* Now, we want that Sqrt( W ) = 0x4000 */
+ /* Or 0x1000000 <= W < 0x1004000 */
+
+ if ( Vx < 0 )
+ {
+ Vx = -Vx;
+ S1 = TRUE;
+ }
+ else
+ S1 = FALSE;
+
+ if ( Vy < 0 )
+ {
+ Vy = -Vy;
+ S2 = TRUE;
+ }
+ else
+ S2 = FALSE;
+
+ while ( W < 0x1000000L )
+ {
+ /* We need to increase W by a minimal amount */
+ if ( Vx < Vy )
+ Vx++;
+ else
+ Vy++;
+
+ W = Vx * Vx + Vy * Vy;
+ }
+
+ while ( W >= 0x1004000L )
+ {
+ /* We need to decrease W by a minimal amount */
+ if ( Vx < Vy )
+ Vx--;
+ else
+ Vy--;
+
+ W = Vx * Vx + Vy * Vy;
+ }
+
+ /* Note that in various cases, we can only */
+ /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */
+
+ if ( S1 )
+ Vx = -Vx;
+
+ if ( S2 )
+ Vy = -Vy;
+
+ R->x = (FT_F2Dot14)Vx; /* Type conversion */
+ R->y = (FT_F2Dot14)Vy; /* Type conversion */
+
+ 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 */
+
+
+ /*************************************************************************/
+ /* */
+ /* Here we start with the implementation of the various opcodes. */
+ /* */
+ /*************************************************************************/
+
+
+ static FT_Bool
+ Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1,
+ FT_UShort aIdx2,
+ FT_Int aOpc,
+ FT_UnitVector* Vec )
+ {
+ FT_Long A, B, C;
+ FT_Vector* p1;
+ FT_Vector* p2;
+
+
+ if ( BOUNDS( aIdx1, CUR.zp2.n_points ) ||
+ BOUNDS( aIdx2, CUR.zp1.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return FAILURE;
+ }
+
+ p1 = CUR.zp1.cur + aIdx2;
+ p2 = CUR.zp2.cur + aIdx1;
+
+ A = p1->x - p2->x;
+ B = p1->y - p2->y;
+
+ if ( ( aOpc & 1 ) != 0 )
+ {
+ C = B; /* counter clockwise rotation */
+ B = A;
+ A = -C;
+ }
+
+ NORMalize( A, B, Vec );
+
+ return SUCCESS;
+ }
+
+
+ /* When not using the big switch statements, the interpreter uses a */
+ /* call table defined later below in this source. Each opcode must */
+ /* thus have a corresponding function, even trivial ones. */
+ /* */
+ /* They are all defined there. */
+
+#define DO_SVTCA \
+ { \
+ FT_Short A, B; \
+ \
+ \
+ A = (FT_Short)( CUR.opcode & 1 ) << 14; \
+ B = A ^ (FT_Short)0x4000; \
+ \
+ CUR.GS.freeVector.x = A; \
+ CUR.GS.projVector.x = A; \
+ CUR.GS.dualVector.x = A; \
+ \
+ CUR.GS.freeVector.y = B; \
+ CUR.GS.projVector.y = B; \
+ CUR.GS.dualVector.y = B; \
+ \
+ COMPUTE_Funcs(); \
+ }
+
+
+#define DO_SPVTCA \
+ { \
+ FT_Short A, B; \
+ \
+ \
+ A = (FT_Short)( CUR.opcode & 1 ) << 14; \
+ B = A ^ (FT_Short)0x4000; \
+ \
+ CUR.GS.projVector.x = A; \
+ CUR.GS.dualVector.x = A; \
+ \
+ CUR.GS.projVector.y = B; \
+ CUR.GS.dualVector.y = B; \
+ \
+ COMPUTE_Funcs(); \
+ }
+
+
+#define DO_SFVTCA \
+ { \
+ FT_Short A, B; \
+ \
+ \
+ A = (FT_Short)( CUR.opcode & 1 ) << 14; \
+ B = A ^ (FT_Short)0x4000; \
+ \
+ CUR.GS.freeVector.x = A; \
+ CUR.GS.freeVector.y = B; \
+ \
+ COMPUTE_Funcs(); \
+ }
+
+
+#define DO_SPVTL \
+ if ( INS_SxVTL( (FT_UShort)args[1], \
+ (FT_UShort)args[0], \
+ CUR.opcode, \
+ &CUR.GS.projVector ) == SUCCESS ) \
+ { \
+ CUR.GS.dualVector = CUR.GS.projVector; \
+ COMPUTE_Funcs(); \
+ }
+
+
+#define DO_SFVTL \
+ if ( INS_SxVTL( (FT_UShort)args[1], \
+ (FT_UShort)args[0], \
+ CUR.opcode, \
+ &CUR.GS.freeVector ) == SUCCESS ) \
+ COMPUTE_Funcs();
+
+
+#define DO_SFVTPV \
+ CUR.GS.freeVector = CUR.GS.projVector; \
+ COMPUTE_Funcs();
+
+
+#define DO_SPVFS \
+ { \
+ FT_Short S; \
+ FT_Long X, Y; \
+ \
+ \
+ /* Only use low 16bits, then sign extend */ \
+ S = (FT_Short)args[1]; \
+ Y = (FT_Long)S; \
+ S = (FT_Short)args[0]; \
+ X = (FT_Long)S; \
+ \
+ NORMalize( X, Y, &CUR.GS.projVector ); \
+ \
+ CUR.GS.dualVector = CUR.GS.projVector; \
+ COMPUTE_Funcs(); \
+ }
+
+
+#define DO_SFVFS \
+ { \
+ FT_Short S; \
+ FT_Long X, Y; \
+ \
+ \
+ /* Only use low 16bits, then sign extend */ \
+ S = (FT_Short)args[1]; \
+ Y = (FT_Long)S; \
+ S = (FT_Short)args[0]; \
+ X = S; \
+ \
+ NORMalize( X, Y, &CUR.GS.freeVector ); \
+ COMPUTE_Funcs(); \
+ }
+
+
+#define DO_GPV \
+ args[0] = CUR.GS.projVector.x; \
+ args[1] = CUR.GS.projVector.y;
+
+
+#define DO_GFV \
+ args[0] = CUR.GS.freeVector.x; \
+ args[1] = CUR.GS.freeVector.y;
+
+
+#define DO_SRP0 \
+ CUR.GS.rp0 = (FT_UShort)args[0];
+
+
+#define DO_SRP1 \
+ CUR.GS.rp1 = (FT_UShort)args[0];
+
+
+#define DO_SRP2 \
+ CUR.GS.rp2 = (FT_UShort)args[0];
+
+
+#define DO_RTHG \
+ CUR.GS.round_state = TT_Round_To_Half_Grid; \
+ CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
+
+
+#define DO_RTG \
+ CUR.GS.round_state = TT_Round_To_Grid; \
+ CUR.func_round = (TT_Round_Func)Round_To_Grid;
+
+
+#define DO_RTDG \
+ CUR.GS.round_state = TT_Round_To_Double_Grid; \
+ CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
+
+
+#define DO_RUTG \
+ CUR.GS.round_state = TT_Round_Up_To_Grid; \
+ CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
+
+
+#define DO_RDTG \
+ CUR.GS.round_state = TT_Round_Down_To_Grid; \
+ CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
+
+
+#define DO_ROFF \
+ CUR.GS.round_state = TT_Round_Off; \
+ CUR.func_round = (TT_Round_Func)Round_None;
+
+
+#define DO_SROUND \
+ SET_SuperRound( 0x4000, args[0] ); \
+ CUR.GS.round_state = TT_Round_Super; \
+ CUR.func_round = (TT_Round_Func)Round_Super;
+
+
+#define DO_S45ROUND \
+ SET_SuperRound( 0x2D41, args[0] ); \
+ CUR.GS.round_state = TT_Round_Super_45; \
+ CUR.func_round = (TT_Round_Func)Round_Super_45;
+
+
+#define DO_SLOOP \
+ if ( args[0] < 0 ) \
+ CUR.error = TT_Err_Bad_Argument; \
+ else \
+ CUR.GS.loop = args[0];
+
+
+#define DO_SMD \
+ CUR.GS.minimum_distance = args[0];
+
+
+#define DO_SCVTCI \
+ CUR.GS.control_value_cutin = (FT_F26Dot6)args[0];
+
+
+#define DO_SSWCI \
+ CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];
+
+
+ /* XXX: UNDOCUMENTED! or bug in the Windows engine? */
+ /* */
+ /* It seems that the value that is read here is */
+ /* expressed in 16.16 format rather than in font */
+ /* units. */
+ /* */
+#define DO_SSW \
+ CUR.GS.single_width_value = (FT_F26Dot6)( args[0] >> 10 );
+
+
+#define DO_FLIPON \
+ CUR.GS.auto_flip = TRUE;
+
+
+#define DO_FLIPOFF \
+ CUR.GS.auto_flip = FALSE;
+
+
+#define DO_SDB \
+ CUR.GS.delta_base = (FT_Short)args[0];
+
+
+#define DO_SDS \
+ CUR.GS.delta_shift = (FT_Short)args[0];
+
+
+#define DO_MD /* nothing */
+
+
+#define DO_MPPEM \
+ args[0] = CURRENT_Ppem();
+
+
+ /* Note: The pointSize should be irrelevant in a given font program; */
+ /* we thus decide to return only the ppem. */
+#if 0
+
+#define DO_MPS \
+ args[0] = CUR.metrics.pointSize;
+
+#else
+
+#define DO_MPS \
+ args[0] = CURRENT_Ppem();
+
+#endif /* 0 */
+
+
+#define DO_DUP \
+ args[1] = args[0];
+
+
+#define DO_CLEAR \
+ CUR.new_top = 0;
+
+
+#define DO_SWAP \
+ { \
+ FT_Long L; \
+ \
+ \
+ L = args[0]; \
+ args[0] = args[1]; \
+ args[1] = L; \
+ }
+
+
+#define DO_DEPTH \
+ args[0] = CUR.top;
+
+
+#define DO_CINDEX \
+ { \
+ FT_Long L; \
+ \
+ \
+ L = args[0]; \
+ \
+ if ( L <= 0 || L > CUR.args ) \
+ CUR.error = TT_Err_Invalid_Reference; \
+ else \
+ args[0] = CUR.stack[CUR.args - L]; \
+ }
+
+
+#define DO_JROT \
+ if ( args[1] != 0 ) \
+ { \
+ CUR.IP += args[0]; \
+ CUR.step_ins = FALSE; \
+ }
+
+
+#define DO_JMPR \
+ CUR.IP += args[0]; \
+ CUR.step_ins = FALSE;
+
+
+#define DO_JROF \
+ if ( args[1] == 0 ) \
+ { \
+ CUR.IP += args[0]; \
+ CUR.step_ins = FALSE; \
+ }
+
+
+#define DO_LT \
+ args[0] = ( args[0] < args[1] );
+
+
+#define DO_LTEQ \
+ args[0] = ( args[0] <= args[1] );
+
+
+#define DO_GT \
+ args[0] = ( args[0] > args[1] );
+
+
+#define DO_GTEQ \
+ args[0] = ( args[0] >= args[1] );
+
+
+#define DO_EQ \
+ args[0] = ( args[0] == args[1] );
+
+
+#define DO_NEQ \
+ args[0] = ( args[0] != args[1] );
+
+
+#define DO_ODD \
+ args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );
+
+
+#define DO_EVEN \
+ args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );
+
+
+#define DO_AND \
+ args[0] = ( args[0] && args[1] );
+
+
+#define DO_OR \
+ args[0] = ( args[0] || args[1] );
+
+
+#define DO_NOT \
+ args[0] = !args[0];
+
+
+#define DO_ADD \
+ args[0] += args[1];
+
+
+#define DO_SUB \
+ args[0] -= args[1];
+
+
+#define DO_DIV \
+ if ( args[1] == 0 ) \
+ CUR.error = TT_Err_Divide_By_Zero; \
+ else \
+ args[0] = TT_MULDIV( args[0], 64L, args[1] );
+
+
+#define DO_MUL \
+ args[0] = TT_MULDIV( args[0], args[1], 64L );
+
+
+#define DO_ABS \
+ args[0] = ABS( args[0] );
+
+
+#define DO_NEG \
+ args[0] = -args[0];
+
+
+#define DO_FLOOR \
+ args[0] &= -64;
+
+
+#define DO_CEILING \
+ args[0] = ( args[0] + 63 ) & -64;
+
+
+#define DO_RS \
+ { \
+ FT_ULong I = (FT_ULong)args[0]; \
+ \
+ \
+ if ( BOUNDS( I, CUR.storeSize ) ) \
+ { \
+ if ( CUR.pedantic_hinting ) \
+ { \
+ ARRAY_BOUND_ERROR; \
+ } \
+ else \
+ args[0] = 0; \
+ } \
+ else \
+ args[0] = CUR.storage[I]; \
+ }
+
+
+#define DO_WS \
+ { \
+ FT_ULong I = (FT_ULong)args[0]; \
+ \
+ \
+ if ( BOUNDS( I, CUR.storeSize ) ) \
+ { \
+ if ( CUR.pedantic_hinting ) \
+ { \
+ ARRAY_BOUND_ERROR; \
+ } \
+ } \
+ else \
+ CUR.storage[I] = args[1]; \
+ }
+
+
+#define DO_RCVT \
+ { \
+ FT_ULong I = (FT_ULong)args[0]; \
+ \
+ \
+ if ( BOUNDS( I, CUR.cvtSize ) ) \
+ { \
+ if ( CUR.pedantic_hinting ) \
+ { \
+ ARRAY_BOUND_ERROR; \
+ } \
+ else \
+ args[0] = 0; \
+ } \
+ else \
+ args[0] = CUR_Func_read_cvt( I ); \
+ }
+
+
+#define DO_WCVTP \
+ { \
+ FT_ULong I = (FT_ULong)args[0]; \
+ \
+ \
+ if ( BOUNDS( I, CUR.cvtSize ) ) \
+ { \
+ if ( CUR.pedantic_hinting ) \
+ { \
+ ARRAY_BOUND_ERROR; \
+ } \
+ } \
+ else \
+ CUR_Func_write_cvt( I, args[1] ); \
+ }
+
+
+#define DO_WCVTF \
+ { \
+ FT_ULong I = (FT_ULong)args[0]; \
+ \
+ \
+ if ( BOUNDS( I, CUR.cvtSize ) ) \
+ { \
+ if ( CUR.pedantic_hinting ) \
+ { \
+ ARRAY_BOUND_ERROR; \
+ } \
+ } \
+ else \
+ CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \
+ }
+
+
+#define DO_DEBUG \
+ CUR.error = TT_Err_Debug_OpCode;
+
+
+#define DO_ROUND \
+ args[0] = CUR_Func_round( \
+ args[0], \
+ CUR.tt_metrics.compensations[CUR.opcode - 0x68] );
+
+
+#define DO_NROUND \
+ args[0] = ROUND_None( args[0], \
+ CUR.tt_metrics.compensations[CUR.opcode - 0x6C] );
+
+
+#define DO_MAX \
+ if ( args[1] > args[0] ) \
+ args[0] = args[1];
+
+
+#define DO_MIN \
+ if ( args[1] < args[0] ) \
+ args[0] = args[1];
+
+
+#ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
+
+
+#undef ARRAY_BOUND_ERROR
+#define ARRAY_BOUND_ERROR \
+ { \
+ CUR.error = TT_Err_Invalid_Reference; \
+ return; \
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */
+ /* Opcode range: 0x00-0x01 */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_SVTCA( INS_ARG )
+ {
+ DO_SVTCA
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SPVTCA[a]: Set PVector to Coordinate Axis */
+ /* Opcode range: 0x02-0x03 */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_SPVTCA( INS_ARG )
+ {
+ DO_SPVTCA
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SFVTCA[a]: Set FVector to Coordinate Axis */
+ /* Opcode range: 0x04-0x05 */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_SFVTCA( INS_ARG )
+ {
+ DO_SFVTCA
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SPVTL[a]: Set PVector To Line */
+ /* Opcode range: 0x06-0x07 */
+ /* Stack: uint32 uint32 --> */
+ /* */
+ static void
+ Ins_SPVTL( INS_ARG )
+ {
+ DO_SPVTL
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SFVTL[a]: Set FVector To Line */
+ /* Opcode range: 0x08-0x09 */
+ /* Stack: uint32 uint32 --> */
+ /* */
+ static void
+ Ins_SFVTL( INS_ARG )
+ {
+ DO_SFVTL
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SFVTPV[]: Set FVector To PVector */
+ /* Opcode range: 0x0E */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_SFVTPV( INS_ARG )
+ {
+ DO_SFVTPV
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SPVFS[]: Set PVector From Stack */
+ /* Opcode range: 0x0A */
+ /* Stack: f2.14 f2.14 --> */
+ /* */
+ static void
+ Ins_SPVFS( INS_ARG )
+ {
+ DO_SPVFS
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SFVFS[]: Set FVector From Stack */
+ /* Opcode range: 0x0B */
+ /* Stack: f2.14 f2.14 --> */
+ /* */
+ static void
+ Ins_SFVFS( INS_ARG )
+ {
+ DO_SFVFS
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* GPV[]: Get Projection Vector */
+ /* Opcode range: 0x0C */
+ /* Stack: ef2.14 --> ef2.14 */
+ /* */
+ static void
+ Ins_GPV( INS_ARG )
+ {
+ DO_GPV
+ }
+
+
+ /*************************************************************************/
+ /* GFV[]: Get Freedom Vector */
+ /* Opcode range: 0x0D */
+ /* Stack: ef2.14 --> ef2.14 */
+ /* */
+ static void
+ Ins_GFV( INS_ARG )
+ {
+ DO_GFV
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SRP0[]: Set Reference Point 0 */
+ /* Opcode range: 0x10 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SRP0( INS_ARG )
+ {
+ DO_SRP0
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SRP1[]: Set Reference Point 1 */
+ /* Opcode range: 0x11 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SRP1( INS_ARG )
+ {
+ DO_SRP1
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SRP2[]: Set Reference Point 2 */
+ /* Opcode range: 0x12 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SRP2( INS_ARG )
+ {
+ DO_SRP2
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* RTHG[]: Round To Half Grid */
+ /* Opcode range: 0x19 */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_RTHG( INS_ARG )
+ {
+ DO_RTHG
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* RTG[]: Round To Grid */
+ /* Opcode range: 0x18 */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_RTG( INS_ARG )
+ {
+ DO_RTG
+ }
+
+
+ /*************************************************************************/
+ /* RTDG[]: Round To Double Grid */
+ /* Opcode range: 0x3D */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_RTDG( INS_ARG )
+ {
+ DO_RTDG
+ }
+
+
+ /*************************************************************************/
+ /* RUTG[]: Round Up To Grid */
+ /* Opcode range: 0x7C */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_RUTG( INS_ARG )
+ {
+ DO_RUTG
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* RDTG[]: Round Down To Grid */
+ /* Opcode range: 0x7D */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_RDTG( INS_ARG )
+ {
+ DO_RDTG
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ROFF[]: Round OFF */
+ /* Opcode range: 0x7A */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_ROFF( INS_ARG )
+ {
+ DO_ROFF
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SROUND[]: Super ROUND */
+ /* Opcode range: 0x76 */
+ /* Stack: Eint8 --> */
+ /* */
+ static void
+ Ins_SROUND( INS_ARG )
+ {
+ DO_SROUND
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* S45ROUND[]: Super ROUND 45 degrees */
+ /* Opcode range: 0x77 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_S45ROUND( INS_ARG )
+ {
+ DO_S45ROUND
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SLOOP[]: Set LOOP variable */
+ /* Opcode range: 0x17 */
+ /* Stack: int32? --> */
+ /* */
+ static void
+ Ins_SLOOP( INS_ARG )
+ {
+ DO_SLOOP
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SMD[]: Set Minimum Distance */
+ /* Opcode range: 0x1A */
+ /* Stack: f26.6 --> */
+ /* */
+ static void
+ Ins_SMD( INS_ARG )
+ {
+ DO_SMD
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SCVTCI[]: Set Control Value Table Cut In */
+ /* Opcode range: 0x1D */
+ /* Stack: f26.6 --> */
+ /* */
+ static void
+ Ins_SCVTCI( INS_ARG )
+ {
+ DO_SCVTCI
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SSWCI[]: Set Single Width Cut In */
+ /* Opcode range: 0x1E */
+ /* Stack: f26.6 --> */
+ /* */
+ static void
+ Ins_SSWCI( INS_ARG )
+ {
+ DO_SSWCI
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SSW[]: Set Single Width */
+ /* Opcode range: 0x1F */
+ /* Stack: int32? --> */
+ /* */
+ static void
+ Ins_SSW( INS_ARG )
+ {
+ DO_SSW
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* FLIPON[]: Set auto-FLIP to ON */
+ /* Opcode range: 0x4D */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_FLIPON( INS_ARG )
+ {
+ DO_FLIPON
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* FLIPOFF[]: Set auto-FLIP to OFF */
+ /* Opcode range: 0x4E */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_FLIPOFF( INS_ARG )
+ {
+ DO_FLIPOFF
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SANGW[]: Set ANGle Weight */
+ /* Opcode range: 0x7E */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SANGW( INS_ARG )
+ {
+ /* instruction not supported anymore */
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SDB[]: Set Delta Base */
+ /* Opcode range: 0x5E */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SDB( INS_ARG )
+ {
+ DO_SDB
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SDS[]: Set Delta Shift */
+ /* Opcode range: 0x5F */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SDS( INS_ARG )
+ {
+ DO_SDS
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MPPEM[]: Measure Pixel Per EM */
+ /* Opcode range: 0x4B */
+ /* Stack: --> Euint16 */
+ /* */
+ static void
+ Ins_MPPEM( INS_ARG )
+ {
+ DO_MPPEM
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MPS[]: Measure Point Size */
+ /* Opcode range: 0x4C */
+ /* Stack: --> Euint16 */
+ /* */
+ static void
+ Ins_MPS( INS_ARG )
+ {
+ DO_MPS
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* DUP[]: DUPlicate the top stack's element */
+ /* Opcode range: 0x20 */
+ /* Stack: StkElt --> StkElt StkElt */
+ /* */
+ static void
+ Ins_DUP( INS_ARG )
+ {
+ DO_DUP
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* POP[]: POP the stack's top element */
+ /* Opcode range: 0x21 */
+ /* Stack: StkElt --> */
+ /* */
+ static void
+ Ins_POP( INS_ARG )
+ {
+ /* nothing to do */
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* CLEAR[]: CLEAR the entire stack */
+ /* Opcode range: 0x22 */
+ /* Stack: StkElt... --> */
+ /* */
+ static void
+ Ins_CLEAR( INS_ARG )
+ {
+ DO_CLEAR
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SWAP[]: SWAP the stack's top two elements */
+ /* Opcode range: 0x23 */
+ /* Stack: 2 * StkElt --> 2 * StkElt */
+ /* */
+ static void
+ Ins_SWAP( INS_ARG )
+ {
+ DO_SWAP
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* DEPTH[]: return the stack DEPTH */
+ /* Opcode range: 0x24 */
+ /* Stack: --> uint32 */
+ /* */
+ static void
+ Ins_DEPTH( INS_ARG )
+ {
+ DO_DEPTH
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* CINDEX[]: Copy INDEXed element */
+ /* Opcode range: 0x25 */
+ /* Stack: int32 --> StkElt */
+ /* */
+ static void
+ Ins_CINDEX( INS_ARG )
+ {
+ DO_CINDEX
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* EIF[]: End IF */
+ /* Opcode range: 0x59 */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_EIF( INS_ARG )
+ {
+ /* nothing to do */
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* JROT[]: Jump Relative On True */
+ /* Opcode range: 0x78 */
+ /* Stack: StkElt int32 --> */
+ /* */
+ static void
+ Ins_JROT( INS_ARG )
+ {
+ DO_JROT
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* JMPR[]: JuMP Relative */
+ /* Opcode range: 0x1C */
+ /* Stack: int32 --> */
+ /* */
+ static void
+ Ins_JMPR( INS_ARG )
+ {
+ DO_JMPR
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* JROF[]: Jump Relative On False */
+ /* Opcode range: 0x79 */
+ /* Stack: StkElt int32 --> */
+ /* */
+ static void
+ Ins_JROF( INS_ARG )
+ {
+ DO_JROF
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* LT[]: Less Than */
+ /* Opcode range: 0x50 */
+ /* Stack: int32? int32? --> bool */
+ /* */
+ static void
+ Ins_LT( INS_ARG )
+ {
+ DO_LT
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* LTEQ[]: Less Than or EQual */
+ /* Opcode range: 0x51 */
+ /* Stack: int32? int32? --> bool */
+ /* */
+ static void
+ Ins_LTEQ( INS_ARG )
+ {
+ DO_LTEQ
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* GT[]: Greater Than */
+ /* Opcode range: 0x52 */
+ /* Stack: int32? int32? --> bool */
+ /* */
+ static void
+ Ins_GT( INS_ARG )
+ {
+ DO_GT
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* GTEQ[]: Greater Than or EQual */
+ /* Opcode range: 0x53 */
+ /* Stack: int32? int32? --> bool */
+ /* */
+ static void
+ Ins_GTEQ( INS_ARG )
+ {
+ DO_GTEQ
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* EQ[]: EQual */
+ /* Opcode range: 0x54 */
+ /* Stack: StkElt StkElt --> bool */
+ /* */
+ static void
+ Ins_EQ( INS_ARG )
+ {
+ DO_EQ
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* NEQ[]: Not EQual */
+ /* Opcode range: 0x55 */
+ /* Stack: StkElt StkElt --> bool */
+ /* */
+ static void
+ Ins_NEQ( INS_ARG )
+ {
+ DO_NEQ
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ODD[]: Is ODD */
+ /* Opcode range: 0x56 */
+ /* Stack: f26.6 --> bool */
+ /* */
+ static void
+ Ins_ODD( INS_ARG )
+ {
+ DO_ODD
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* EVEN[]: Is EVEN */
+ /* Opcode range: 0x57 */
+ /* Stack: f26.6 --> bool */
+ /* */
+ static void
+ Ins_EVEN( INS_ARG )
+ {
+ DO_EVEN
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* AND[]: logical AND */
+ /* Opcode range: 0x5A */
+ /* Stack: uint32 uint32 --> uint32 */
+ /* */
+ static void
+ Ins_AND( INS_ARG )
+ {
+ DO_AND
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* OR[]: logical OR */
+ /* Opcode range: 0x5B */
+ /* Stack: uint32 uint32 --> uint32 */
+ /* */
+ static void
+ Ins_OR( INS_ARG )
+ {
+ DO_OR
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* NOT[]: logical NOT */
+ /* Opcode range: 0x5C */
+ /* Stack: StkElt --> uint32 */
+ /* */
+ static void
+ Ins_NOT( INS_ARG )
+ {
+ DO_NOT
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ADD[]: ADD */
+ /* Opcode range: 0x60 */
+ /* Stack: f26.6 f26.6 --> f26.6 */
+ /* */
+ static void
+ Ins_ADD( INS_ARG )
+ {
+ DO_ADD
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SUB[]: SUBtract */
+ /* Opcode range: 0x61 */
+ /* Stack: f26.6 f26.6 --> f26.6 */
+ /* */
+ static void
+ Ins_SUB( INS_ARG )
+ {
+ DO_SUB
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* DIV[]: DIVide */
+ /* Opcode range: 0x62 */
+ /* Stack: f26.6 f26.6 --> f26.6 */
+ /* */
+ static void
+ Ins_DIV( INS_ARG )
+ {
+ DO_DIV
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MUL[]: MULtiply */
+ /* Opcode range: 0x63 */
+ /* Stack: f26.6 f26.6 --> f26.6 */
+ /* */
+ static void
+ Ins_MUL( INS_ARG )
+ {
+ DO_MUL
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ABS[]: ABSolute value */
+ /* Opcode range: 0x64 */
+ /* Stack: f26.6 --> f26.6 */
+ /* */
+ static void
+ Ins_ABS( INS_ARG )
+ {
+ DO_ABS
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* NEG[]: NEGate */
+ /* Opcode range: 0x65 */
+ /* Stack: f26.6 --> f26.6 */
+ /* */
+ static void
+ Ins_NEG( INS_ARG )
+ {
+ DO_NEG
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* FLOOR[]: FLOOR */
+ /* Opcode range: 0x66 */
+ /* Stack: f26.6 --> f26.6 */
+ /* */
+ static void
+ Ins_FLOOR( INS_ARG )
+ {
+ DO_FLOOR
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* CEILING[]: CEILING */
+ /* Opcode range: 0x67 */
+ /* Stack: f26.6 --> f26.6 */
+ /* */
+ static void
+ Ins_CEILING( INS_ARG )
+ {
+ DO_CEILING
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* RS[]: Read Store */
+ /* Opcode range: 0x43 */
+ /* Stack: uint32 --> uint32 */
+ /* */
+ static void
+ Ins_RS( INS_ARG )
+ {
+ DO_RS
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* WS[]: Write Store */
+ /* Opcode range: 0x42 */
+ /* Stack: uint32 uint32 --> */
+ /* */
+ static void
+ Ins_WS( INS_ARG )
+ {
+ DO_WS
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* WCVTP[]: Write CVT in Pixel units */
+ /* Opcode range: 0x44 */
+ /* Stack: f26.6 uint32 --> */
+ /* */
+ static void
+ Ins_WCVTP( INS_ARG )
+ {
+ DO_WCVTP
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* WCVTF[]: Write CVT in Funits */
+ /* Opcode range: 0x70 */
+ /* Stack: uint32 uint32 --> */
+ /* */
+ static void
+ Ins_WCVTF( INS_ARG )
+ {
+ DO_WCVTF
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* RCVT[]: Read CVT */
+ /* Opcode range: 0x45 */
+ /* Stack: uint32 --> f26.6 */
+ /* */
+ static void
+ Ins_RCVT( INS_ARG )
+ {
+ DO_RCVT
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* AA[]: Adjust Angle */
+ /* Opcode range: 0x7F */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_AA( INS_ARG )
+ {
+ /* intentionally no longer supported */
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* DEBUG[]: DEBUG. Unsupported. */
+ /* Opcode range: 0x4F */
+ /* Stack: uint32 --> */
+ /* */
+ /* Note: The original instruction pops a value from the stack. */
+ /* */
+ static void
+ Ins_DEBUG( INS_ARG )
+ {
+ DO_DEBUG
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ROUND[ab]: ROUND value */
+ /* Opcode range: 0x68-0x6B */
+ /* Stack: f26.6 --> f26.6 */
+ /* */
+ static void
+ Ins_ROUND( INS_ARG )
+ {
+ DO_ROUND
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* NROUND[ab]: No ROUNDing of value */
+ /* Opcode range: 0x6C-0x6F */
+ /* Stack: f26.6 --> f26.6 */
+ /* */
+ static void
+ Ins_NROUND( INS_ARG )
+ {
+ DO_NROUND
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MAX[]: MAXimum */
+ /* Opcode range: 0x68 */
+ /* Stack: int32? int32? --> int32 */
+ /* */
+ static void
+ Ins_MAX( INS_ARG )
+ {
+ DO_MAX
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MIN[]: MINimum */
+ /* Opcode range: 0x69 */
+ /* Stack: int32? int32? --> int32 */
+ /* */
+ static void
+ Ins_MIN( INS_ARG )
+ {
+ DO_MIN
+ }
+
+
+#endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
+
+
+ /*************************************************************************/
+ /* */
+ /* The following functions are called as is within the switch statement. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* MINDEX[]: Move INDEXed element */
+ /* Opcode range: 0x26 */
+ /* Stack: int32? --> StkElt */
+ /* */
+ static void
+ Ins_MINDEX( INS_ARG )
+ {
+ FT_Long L, K;
+
+
+ L = args[0];
+
+ if ( L <= 0 || L > CUR.args )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ K = CUR.stack[CUR.args - L];
+
+ MEM_Move( &CUR.stack[CUR.args - L ],
+ &CUR.stack[CUR.args - L + 1],
+ ( L - 1 ) * sizeof ( FT_Long ) );
+
+ CUR.stack[CUR.args - 1] = K;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ROLL[]: ROLL top three elements */
+ /* Opcode range: 0x8A */
+ /* Stack: 3 * StkElt --> 3 * StkElt */
+ /* */
+ static void
+ Ins_ROLL( INS_ARG )
+ {
+ FT_Long A, B, C;
+
+ FT_UNUSED_EXEC;
+
+
+ A = args[2];
+ B = args[1];
+ C = args[0];
+
+ args[2] = C;
+ args[1] = A;
+ args[0] = B;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MANAGING THE FLOW OF CONTROL */
+ /* */
+ /* Instructions appear in the specification's order. */
+ /* */
+ /*************************************************************************/
+
+
+ static FT_Bool
+ SkipCode( EXEC_OP )
+ {
+ CUR.IP += CUR.length;
+
+ if ( CUR.IP < CUR.codeSize )
+ {
+ CUR.opcode = CUR.code[CUR.IP];
+
+ CUR.length = opcode_length[CUR.opcode];
+ if ( CUR.length < 0 )
+ {
+ if ( CUR.IP + 1 > CUR.codeSize )
+ goto Fail_Overflow;
+ CUR.length = CUR.code[CUR.IP + 1] + 2;
+ }
+
+ if ( CUR.IP + CUR.length <= CUR.codeSize )
+ return SUCCESS;
+ }
+
+ Fail_Overflow:
+ CUR.error = TT_Err_Code_Overflow;
+ return FAILURE;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* IF[]: IF test */
+ /* Opcode range: 0x58 */
+ /* Stack: StkElt --> */
+ /* */
+ static void
+ Ins_IF( INS_ARG )
+ {
+ FT_Int nIfs;
+ FT_Bool Out;
+
+
+ if ( args[0] != 0 )
+ return;
+
+ nIfs = 1;
+ Out = 0;
+
+ do
+ {
+ if ( SKIP_Code() == FAILURE )
+ return;
+
+ switch ( CUR.opcode )
+ {
+ case 0x58: /* IF */
+ nIfs++;
+ break;
+
+ case 0x1B: /* ELSE */
+ Out = FT_BOOL( nIfs == 1 );
+ break;
+
+ case 0x59: /* EIF */
+ nIfs--;
+ Out = FT_BOOL( nIfs == 0 );
+ break;
+ }
+ } while ( Out == 0 );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ELSE[]: ELSE */
+ /* Opcode range: 0x1B */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_ELSE( INS_ARG )
+ {
+ FT_Int nIfs;
+
+ FT_UNUSED_ARG;
+
+
+ nIfs = 1;
+
+ do
+ {
+ if ( SKIP_Code() == FAILURE )
+ return;
+
+ switch ( CUR.opcode )
+ {
+ case 0x58: /* IF */
+ nIfs++;
+ break;
+
+ case 0x59: /* EIF */
+ nIfs--;
+ break;
+ }
+ } while ( nIfs != 0 );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */
+ /* */
+ /* Instructions appear in the specification's order. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* FDEF[]: Function DEFinition */
+ /* Opcode range: 0x2C */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_FDEF( INS_ARG )
+ {
+ FT_ULong n;
+ TT_DefRecord* rec;
+ TT_DefRecord* limit;
+
+
+ /* some font programs are broken enough to redefine functions! */
+ /* We will then parse the current table. */
+
+ rec = CUR.FDefs;
+ limit = rec + CUR.numFDefs;
+ n = args[0];
+
+ for ( ; rec < limit; rec++ )
+ {
+ if ( rec->opc == n )
+ break;
+ }
+
+ if ( rec == limit )
+ {
+ /* check that there is enough room for new functions */
+ if ( CUR.numFDefs >= CUR.maxFDefs )
+ {
+ CUR.error = TT_Err_Too_Many_Function_Defs;
+ return;
+ }
+ CUR.numFDefs++;
+ }
+
+ rec->range = CUR.curRange;
+ rec->opc = n;
+ rec->start = CUR.IP + 1;
+ rec->active = TRUE;
+
+ if ( n > CUR.maxFunc )
+ CUR.maxFunc = n;
+
+ /* Now skip the whole function definition. */
+ /* We don't allow nested IDEFS & FDEFs. */
+
+ while ( SKIP_Code() == SUCCESS )
+ {
+ switch ( CUR.opcode )
+ {
+ case 0x89: /* IDEF */
+ case 0x2C: /* FDEF */
+ CUR.error = TT_Err_Nested_DEFS;
+ return;
+
+ case 0x2D: /* ENDF */
+ return;
+ }
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ENDF[]: END Function definition */
+ /* Opcode range: 0x2D */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_ENDF( INS_ARG )
+ {
+ TT_CallRec* pRec;
+
+ FT_UNUSED_ARG;
+
+
+ if ( CUR.callTop <= 0 ) /* We encountered an ENDF without a call */
+ {
+ CUR.error = TT_Err_ENDF_In_Exec_Stream;
+ return;
+ }
+
+ CUR.callTop--;
+
+ pRec = &CUR.callStack[CUR.callTop];
+
+ pRec->Cur_Count--;
+
+ CUR.step_ins = FALSE;
+
+ if ( pRec->Cur_Count > 0 )
+ {
+ CUR.callTop++;
+ CUR.IP = pRec->Cur_Restart;
+ }
+ else
+ /* Loop through the current function */
+ INS_Goto_CodeRange( pRec->Caller_Range,
+ pRec->Caller_IP );
+
+ /* Exit the current call frame. */
+
+ /* NOTE: If the last intruction of a program is a */
+ /* CALL or LOOPCALL, the return address is */
+ /* always out of the code range. This is a */
+ /* valid address, and it is why we do not test */
+ /* the result of Ins_Goto_CodeRange() here! */
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* CALL[]: CALL function */
+ /* Opcode range: 0x2B */
+ /* Stack: uint32? --> */
+ /* */
+ static void
+ Ins_CALL( INS_ARG )
+ {
+ FT_ULong F;
+ TT_CallRec* pCrec;
+ TT_DefRecord* def;
+
+
+ /* first of all, check the index */
+
+ F = args[0];
+ if ( BOUNDS( F, CUR.maxFunc + 1 ) )
+ goto Fail;
+
+ /* Except for some old Apple fonts, all functions in a TrueType */
+ /* font are defined in increasing order, starting from 0. This */
+ /* means that we normally have */
+ /* */
+ /* CUR.maxFunc+1 == CUR.numFDefs */
+ /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
+ /* */
+ /* If this isn't true, we need to look up the function table. */
+
+ def = CUR.FDefs + F;
+ if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
+ {
+ /* look up the FDefs table */
+ TT_DefRecord* limit;
+
+
+ def = CUR.FDefs;
+ limit = def + CUR.numFDefs;
+
+ while ( def < limit && def->opc != F )
+ def++;
+
+ if ( def == limit )
+ goto Fail;
+ }
+
+ /* check that the function is active */
+ if ( !def->active )
+ goto Fail;
+
+ /* check the call stack */
+ if ( CUR.callTop >= CUR.callSize )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ return;
+ }
+
+ pCrec = CUR.callStack + CUR.callTop;
+
+ pCrec->Caller_Range = CUR.curRange;
+ pCrec->Caller_IP = CUR.IP + 1;
+ pCrec->Cur_Count = 1;
+ pCrec->Cur_Restart = def->start;
+
+ CUR.callTop++;
+
+ INS_Goto_CodeRange( def->range,
+ def->start );
+
+ CUR.step_ins = FALSE;
+ return;
+
+ Fail:
+ CUR.error = TT_Err_Invalid_Reference;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* LOOPCALL[]: LOOP and CALL function */
+ /* Opcode range: 0x2A */
+ /* Stack: uint32? Eint16? --> */
+ /* */
+ static void
+ Ins_LOOPCALL( INS_ARG )
+ {
+ FT_ULong F;
+ TT_CallRec* pCrec;
+ TT_DefRecord* def;
+
+
+ /* first of all, check the index */
+ F = args[1];
+ if ( BOUNDS( F, CUR.maxFunc + 1 ) )
+ goto Fail;
+
+ /* Except for some old Apple fonts, all functions in a TrueType */
+ /* font are defined in increasing order, starting from 0. This */
+ /* means that we normally have */
+ /* */
+ /* CUR.maxFunc+1 == CUR.numFDefs */
+ /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
+ /* */
+ /* If this isn't true, we need to look up the function table. */
+
+ def = CUR.FDefs + F;
+ if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
+ {
+ /* look up the FDefs table */
+ TT_DefRecord* limit;
+
+
+ def = CUR.FDefs;
+ limit = def + CUR.numFDefs;
+
+ while ( def < limit && def->opc != F )
+ def++;
+
+ if ( def == limit )
+ goto Fail;
+ }
+
+ /* check that the function is active */
+ if ( !def->active )
+ goto Fail;
+
+ /* check stack */
+ if ( CUR.callTop >= CUR.callSize )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ return;
+ }
+
+ if ( args[0] > 0 )
+ {
+ pCrec = CUR.callStack + CUR.callTop;
+
+ pCrec->Caller_Range = CUR.curRange;
+ pCrec->Caller_IP = CUR.IP + 1;
+ pCrec->Cur_Count = (FT_Int)args[0];
+ pCrec->Cur_Restart = def->start;
+
+ CUR.callTop++;
+
+ INS_Goto_CodeRange( def->range, def->start );
+
+ CUR.step_ins = FALSE;
+ }
+ return;
+
+ Fail:
+ CUR.error = TT_Err_Invalid_Reference;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* IDEF[]: Instruction DEFinition */
+ /* Opcode range: 0x89 */
+ /* Stack: Eint8 --> */
+ /* */
+ static void
+ Ins_IDEF( INS_ARG )
+ {
+ TT_DefRecord* def;
+ TT_DefRecord* limit;
+
+
+ /* First of all, look for the same function in our table */
+
+ def = CUR.IDefs;
+ limit = def + CUR.numIDefs;
+
+ for ( ; def < limit; def++ )
+ if ( def->opc == (FT_ULong)args[0] )
+ break;
+
+ if ( def == limit )
+ {
+ /* check that there is enough room for a new instruction */
+ if ( CUR.numIDefs >= CUR.maxIDefs )
+ {
+ CUR.error = TT_Err_Too_Many_Instruction_Defs;
+ return;
+ }
+ CUR.numIDefs++;
+ }
+
+ def->opc = args[0];
+ def->start = CUR.IP+1;
+ def->range = CUR.curRange;
+ def->active = TRUE;
+
+ if ( (FT_ULong)args[0] > CUR.maxIns )
+ CUR.maxIns = args[0];
+
+ /* Now skip the whole function definition. */
+ /* We don't allow nested IDEFs & FDEFs. */
+
+ while ( SKIP_Code() == SUCCESS )
+ {
+ switch ( CUR.opcode )
+ {
+ case 0x89: /* IDEF */
+ case 0x2C: /* FDEF */
+ CUR.error = TT_Err_Nested_DEFS;
+ return;
+ case 0x2D: /* ENDF */
+ return;
+ }
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* PUSHING DATA ONTO THE INTERPRETER STACK */
+ /* */
+ /* Instructions appear in the specification's order. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* NPUSHB[]: PUSH N Bytes */
+ /* Opcode range: 0x40 */
+ /* Stack: --> uint32... */
+ /* */
+ static void
+ Ins_NPUSHB( INS_ARG )
+ {
+ FT_UShort L, K;
+
+
+ L = (FT_UShort)CUR.code[CUR.IP + 1];
+
+ if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ return;
+ }
+
+ for ( K = 1; K <= L; K++ )
+ args[K - 1] = CUR.code[CUR.IP + K + 1];
+
+ CUR.new_top += L;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* NPUSHW[]: PUSH N Words */
+ /* Opcode range: 0x41 */
+ /* Stack: --> int32... */
+ /* */
+ static void
+ Ins_NPUSHW( INS_ARG )
+ {
+ FT_UShort L, K;
+
+
+ L = (FT_UShort)CUR.code[CUR.IP + 1];
+
+ if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ return;
+ }
+
+ CUR.IP += 2;
+
+ for ( K = 0; K < L; K++ )
+ args[K] = GET_ShortIns();
+
+ CUR.step_ins = FALSE;
+ CUR.new_top += L;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* PUSHB[abc]: PUSH Bytes */
+ /* Opcode range: 0xB0-0xB7 */
+ /* Stack: --> uint32... */
+ /* */
+ static void
+ Ins_PUSHB( INS_ARG )
+ {
+ FT_UShort L, K;
+
+
+ L = (FT_UShort)(CUR.opcode - 0xB0 + 1);
+
+ if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ return;
+ }
+
+ for ( K = 1; K <= L; K++ )
+ args[K - 1] = CUR.code[CUR.IP + K];
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* PUSHW[abc]: PUSH Words */
+ /* Opcode range: 0xB8-0xBF */
+ /* Stack: --> int32... */
+ /* */
+ static void
+ Ins_PUSHW( INS_ARG )
+ {
+ FT_UShort L, K;
+
+
+ L = (FT_UShort)(CUR.opcode - 0xB8 + 1);
+
+ if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ return;
+ }
+
+ CUR.IP++;
+
+ for ( K = 0; K < L; K++ )
+ args[K] = GET_ShortIns();
+
+ CUR.step_ins = FALSE;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MANAGING THE GRAPHICS STATE */
+ /* */
+ /* Instructions appear in the specs' order. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* GC[a]: Get Coordinate projected onto */
+ /* Opcode range: 0x46-0x47 */
+ /* Stack: uint32 --> f26.6 */
+ /* */
+ /* BULLSHIT: Measures from the original glyph must be taken along the */
+ /* dual projection vector! */
+ /* */
+ static void
+ Ins_GC( INS_ARG )
+ {
+ FT_ULong L;
+ FT_F26Dot6 R;
+
+
+ L = (FT_ULong)args[0];
+
+ if ( BOUNDS( L, CUR.zp2.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ else
+ R = 0;
+ }
+ else
+ {
+ if ( CUR.opcode & 1 )
+ R = CUR_Func_dualproj( CUR.zp2.org + L, NULL_Vector );
+ else
+ R = CUR_Func_project( CUR.zp2.cur + L, NULL_Vector );
+ }
+
+ args[0] = R;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SCFS[]: Set Coordinate From Stack */
+ /* Opcode range: 0x48 */
+ /* Stack: f26.6 uint32 --> */
+ /* */
+ /* Formula: */
+ /* */
+ /* OA := OA + ( value - OA.p )/( f.p ) * f */
+ /* */
+ static void
+ Ins_SCFS( INS_ARG )
+ {
+ FT_Long K;
+ FT_UShort L;
+
+
+ L = (FT_UShort)args[0];
+
+ if ( BOUNDS( L, CUR.zp2.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ K = CUR_Func_project( CUR.zp2.cur + L, NULL_Vector );
+
+ CUR_Func_move( &CUR.zp2, L, args[1] - K );
+
+ /* not part of the specs, but here for safety */
+
+ if ( CUR.GS.gep2 == 0 )
+ CUR.zp2.org[L] = CUR.zp2.cur[L];
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MD[a]: Measure Distance */
+ /* Opcode range: 0x49-0x4A */
+ /* Stack: uint32 uint32 --> f26.6 */
+ /* */
+ /* BULLSHIT: Measure taken in the original glyph must be along the dual */
+ /* projection vector. */
+ /* */
+ /* Second BULLSHIT: Flag attributes are inverted! */
+ /* 0 => measure distance in original outline */
+ /* 1 => measure distance in grid-fitted outline */
+ /* */
+ /* Third one: `zp0 - zp1', and not `zp2 - zp1! */
+ /* */
+ static void
+ Ins_MD( INS_ARG )
+ {
+ FT_UShort K, L;
+ FT_F26Dot6 D;
+
+
+ K = (FT_UShort)args[1];
+ L = (FT_UShort)args[0];
+
+ if( BOUNDS( L, CUR.zp0.n_points ) ||
+ BOUNDS( K, CUR.zp1.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ D = 0;
+ }
+ else
+ {
+ if ( CUR.opcode & 1 )
+ D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K );
+ else
+ D = CUR_Func_dualproj( CUR.zp0.org + L, CUR.zp1.org + K );
+ }
+
+ args[0] = D;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SDPVTL[a]: Set Dual PVector to Line */
+ /* Opcode range: 0x86-0x87 */
+ /* Stack: uint32 uint32 --> */
+ /* */
+ static void
+ Ins_SDPVTL( INS_ARG )
+ {
+ FT_Long A, B, C;
+ FT_UShort p1, p2; /* was FT_Int in pas type ERROR */
+
+
+ p1 = (FT_UShort)args[1];
+ p2 = (FT_UShort)args[0];
+
+ if ( BOUNDS( p2, CUR.zp1.n_points ) ||
+ BOUNDS( p1, CUR.zp2.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ {
+ FT_Vector* v1 = CUR.zp1.org + p2;
+ FT_Vector* v2 = CUR.zp2.org + p1;
+
+
+ A = v1->x - v2->x;
+ B = v1->y - v2->y;
+ }
+
+ if ( ( CUR.opcode & 1 ) != 0 )
+ {
+ C = B; /* counter clockwise rotation */
+ B = A;
+ A = -C;
+ }
+
+ NORMalize( A, B, &CUR.GS.dualVector );
+
+ {
+ FT_Vector* v1 = CUR.zp1.cur + p2;
+ FT_Vector* v2 = CUR.zp2.cur + p1;
+
+
+ A = v1->x - v2->x;
+ B = v1->y - v2->y;
+ }
+
+ if ( ( CUR.opcode & 1 ) != 0 )
+ {
+ C = B; /* counter clockwise rotation */
+ B = A;
+ A = -C;
+ }
+
+ NORMalize( A, B, &CUR.GS.projVector );
+
+ COMPUTE_Funcs();
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SZP0[]: Set Zone Pointer 0 */
+ /* Opcode range: 0x13 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SZP0( INS_ARG )
+ {
+ switch ( (FT_Int)args[0] )
+ {
+ case 0:
+ CUR.zp0 = CUR.twilight;
+ break;
+
+ case 1:
+ CUR.zp0 = CUR.pts;
+ break;
+
+ default:
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ CUR.GS.gep0 = (FT_UShort)args[0];
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SZP1[]: Set Zone Pointer 1 */
+ /* Opcode range: 0x14 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SZP1( INS_ARG )
+ {
+ switch ( (FT_Int)args[0] )
+ {
+ case 0:
+ CUR.zp1 = CUR.twilight;
+ break;
+
+ case 1:
+ CUR.zp1 = CUR.pts;
+ break;
+
+ default:
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ CUR.GS.gep1 = (FT_UShort)args[0];
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SZP2[]: Set Zone Pointer 2 */
+ /* Opcode range: 0x15 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SZP2( INS_ARG )
+ {
+ switch ( (FT_Int)args[0] )
+ {
+ case 0:
+ CUR.zp2 = CUR.twilight;
+ break;
+
+ case 1:
+ CUR.zp2 = CUR.pts;
+ break;
+
+ default:
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ CUR.GS.gep2 = (FT_UShort)args[0];
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SZPS[]: Set Zone PointerS */
+ /* Opcode range: 0x16 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SZPS( INS_ARG )
+ {
+ switch ( (FT_Int)args[0] )
+ {
+ case 0:
+ CUR.zp0 = CUR.twilight;
+ break;
+
+ case 1:
+ CUR.zp0 = CUR.pts;
+ break;
+
+ default:
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ CUR.zp1 = CUR.zp0;
+ CUR.zp2 = CUR.zp0;
+
+ CUR.GS.gep0 = (FT_UShort)args[0];
+ CUR.GS.gep1 = (FT_UShort)args[0];
+ CUR.GS.gep2 = (FT_UShort)args[0];
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* INSTCTRL[]: INSTruction ConTRoL */
+ /* Opcode range: 0x8e */
+ /* Stack: int32 int32 --> */
+ /* */
+ static void
+ Ins_INSTCTRL( INS_ARG )
+ {
+ FT_Long K, L;
+
+
+ K = args[1];
+ L = args[0];
+
+ if ( K < 1 || K > 2 )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ if ( L != 0 )
+ L = K;
+
+ CUR.GS.instruct_control = FT_BOOL(
+ ( (FT_Byte)CUR.GS.instruct_control & ~(FT_Byte)K ) | (FT_Byte)L );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SCANCTRL[]: SCAN ConTRoL */
+ /* Opcode range: 0x85 */
+ /* Stack: uint32? --> */
+ /* */
+ static void
+ Ins_SCANCTRL( INS_ARG )
+ {
+ FT_Int A;
+
+
+ /* Get Threshold */
+ A = (FT_Int)( args[0] & 0xFF );
+
+ if ( A == 0xFF )
+ {
+ CUR.GS.scan_control = TRUE;
+ return;
+ }
+ else if ( A == 0 )
+ {
+ CUR.GS.scan_control = FALSE;
+ return;
+ }
+
+ A *= 64;
+
+#if 0
+ if ( (args[0] & 0x100) != 0 && CUR.metrics.pointSize <= A )
+ CUR.GS.scan_control = TRUE;
+#endif
+
+ if ( (args[0] & 0x200) != 0 && CUR.tt_metrics.rotated )
+ CUR.GS.scan_control = TRUE;
+
+ if ( (args[0] & 0x400) != 0 && CUR.tt_metrics.stretched )
+ CUR.GS.scan_control = TRUE;
+
+#if 0
+ if ( (args[0] & 0x800) != 0 && CUR.metrics.pointSize > A )
+ CUR.GS.scan_control = FALSE;
+#endif
+
+ if ( (args[0] & 0x1000) != 0 && CUR.tt_metrics.rotated )
+ CUR.GS.scan_control = FALSE;
+
+ if ( (args[0] & 0x2000) != 0 && CUR.tt_metrics.stretched )
+ CUR.GS.scan_control = FALSE;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SCANTYPE[]: SCAN TYPE */
+ /* Opcode range: 0x8D */
+ /* Stack: uint32? --> */
+ /* */
+ static void
+ Ins_SCANTYPE( INS_ARG )
+ {
+ /* for compatibility with future enhancements, */
+ /* we must ignore new modes */
+
+ if ( args[0] >= 0 && args[0] <= 5 )
+ {
+ if ( args[0] == 3 )
+ args[0] = 2;
+
+ CUR.GS.scan_type = (FT_Int)args[0];
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MANAGING OUTLINES */
+ /* */
+ /* Instructions appear in the specification's order. */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* FLIPPT[]: FLIP PoinT */
+ /* Opcode range: 0x80 */
+ /* Stack: uint32... --> */
+ /* */
+ static void
+ Ins_FLIPPT( INS_ARG )
+ {
+ FT_UShort point;
+
+ FT_UNUSED_ARG;
+
+
+ if ( CUR.top < CUR.GS.loop )
+ {
+ CUR.error = TT_Err_Too_Few_Arguments;
+ return;
+ }
+
+ while ( CUR.GS.loop > 0 )
+ {
+ CUR.args--;
+
+ point = (FT_UShort)CUR.stack[CUR.args];
+
+ if ( BOUNDS( point, CUR.pts.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ }
+ else
+ CUR.pts.tags[point] ^= FT_Curve_Tag_On;
+
+ CUR.GS.loop--;
+ }
+
+ CUR.GS.loop = 1;
+ CUR.new_top = CUR.args;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* FLIPRGON[]: FLIP RanGe ON */
+ /* Opcode range: 0x81 */
+ /* Stack: uint32 uint32 --> */
+ /* */
+ static void
+ Ins_FLIPRGON( INS_ARG )
+ {
+ FT_UShort I, K, L;
+
+
+ K = (FT_UShort)args[1];
+ L = (FT_UShort)args[0];
+
+ if ( BOUNDS( K, CUR.pts.n_points ) ||
+ BOUNDS( L, CUR.pts.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ for ( I = L; I <= K; I++ )
+ CUR.pts.tags[I] |= FT_Curve_Tag_On;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* FLIPRGOFF: FLIP RanGe OFF */
+ /* Opcode range: 0x82 */
+ /* Stack: uint32 uint32 --> */
+ /* */
+ static void
+ Ins_FLIPRGOFF( INS_ARG )
+ {
+ FT_UShort I, K, L;
+
+
+ K = (FT_UShort)args[1];
+ L = (FT_UShort)args[0];
+
+ if ( BOUNDS( K, CUR.pts.n_points ) ||
+ BOUNDS( L, CUR.pts.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ for ( I = L; I <= K; I++ )
+ CUR.pts.tags[I] &= ~FT_Curve_Tag_On;
+ }
+
+
+ static FT_Bool
+ Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6* x,
+ FT_F26Dot6* y,
+ TT_GlyphZone* zone,
+ FT_UShort* refp )
+ {
+ TT_GlyphZone zp;
+ FT_UShort p;
+ FT_F26Dot6 d;
+
+
+ if ( CUR.opcode & 1 )
+ {
+ zp = CUR.zp0;
+ p = CUR.GS.rp1;
+ }
+ else
+ {
+ zp = CUR.zp1;
+ p = CUR.GS.rp2;
+ }
+
+ if ( BOUNDS( p, zp.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return FAILURE;
+ }
+
+ *zone = zp;
+ *refp = p;
+
+ d = CUR_Func_project( zp.cur + p, zp.org + p );
+
+#ifdef NO_APPLE_PATENT
+
+ *x = TT_MULDIV( d, CUR.GS.freeVector.x, 0x4000 );
+ *y = TT_MULDIV( d, CUR.GS.freeVector.y, 0x4000 );
+
+#else
+
+ *x = TT_MULDIV( d,
+ (FT_Long)CUR.GS.freeVector.x * 0x10000L,
+ CUR.F_dot_P );
+ *y = TT_MULDIV( d,
+ (FT_Long)CUR.GS.freeVector.y * 0x10000L,
+ CUR.F_dot_P );
+
+#endif /* NO_APPLE_PATENT */
+
+ return SUCCESS;
+ }
+
+
+ static void
+ Move_Zp2_Point( EXEC_OP_ FT_UShort point,
+ FT_F26Dot6 dx,
+ FT_F26Dot6 dy,
+ FT_Bool touch )
+ {
+ if ( CUR.GS.freeVector.x != 0 )
+ {
+ CUR.zp2.cur[point].x += dx;
+ if ( touch )
+ CUR.zp2.tags[point] |= FT_Curve_Tag_Touch_X;
+ }
+
+ if ( CUR.GS.freeVector.y != 0 )
+ {
+ CUR.zp2.cur[point].y += dy;
+ if ( touch )
+ CUR.zp2.tags[point] |= FT_Curve_Tag_Touch_Y;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SHP[a]: SHift Point by the last point */
+ /* Opcode range: 0x32-0x33 */
+ /* Stack: uint32... --> */
+ /* */
+ static void
+ Ins_SHP( INS_ARG )
+ {
+ TT_GlyphZone zp;
+ FT_UShort refp;
+
+ FT_F26Dot6 dx,
+ dy;
+ FT_UShort point;
+
+ FT_UNUSED_ARG;
+
+
+ if ( CUR.top < CUR.GS.loop )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
+ return;
+
+ while ( CUR.GS.loop > 0 )
+ {
+ CUR.args--;
+ point = (FT_UShort)CUR.stack[CUR.args];
+
+ if ( BOUNDS( point, CUR.zp2.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ }
+ else
+ /* XXX: UNDOCUMENTED! SHP touches the points */
+ MOVE_Zp2_Point( point, dx, dy, TRUE );
+
+ CUR.GS.loop--;
+ }
+
+ CUR.GS.loop = 1;
+ CUR.new_top = CUR.args;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SHC[a]: SHift Contour */
+ /* Opcode range: 0x34-35 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SHC( INS_ARG )
+ {
+ TT_GlyphZone zp;
+ FT_UShort refp;
+ FT_F26Dot6 dx,
+ dy;
+
+ FT_Short contour;
+ FT_UShort first_point, last_point, i;
+
+
+ contour = (FT_UShort)args[0];
+
+ if ( BOUNDS( contour, CUR.pts.n_contours ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
+ return;
+
+ if ( contour == 0 )
+ first_point = 0;
+ else
+ first_point = (FT_UShort)(CUR.pts.contours[contour - 1] + 1);
+
+ last_point = CUR.pts.contours[contour];
+
+ /* XXX: this is probably wrong... at least it prevents memory */
+ /* corruption when zp2 is the twilight zone */
+ if ( last_point > CUR.zp2.n_points )
+ {
+ if ( CUR.zp2.n_points > 0 )
+ last_point = (FT_UShort)(CUR.zp2.n_points - 1);
+ else
+ last_point = 0;
+ }
+
+ /* XXX: UNDOCUMENTED! SHC doesn't touch the points */
+ for ( i = first_point; i <= last_point; i++ )
+ {
+ if ( zp.cur != CUR.zp2.cur || refp != i )
+ MOVE_Zp2_Point( i, dx, dy, FALSE );
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SHZ[a]: SHift Zone */
+ /* Opcode range: 0x36-37 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_SHZ( INS_ARG )
+ {
+ TT_GlyphZone zp;
+ FT_UShort refp;
+ FT_F26Dot6 dx,
+ dy;
+
+ FT_UShort last_point, i;
+
+
+ if ( BOUNDS( args[0], 2 ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
+ return;
+
+ if ( CUR.zp2.n_points > 0 )
+ last_point = (FT_UShort)(CUR.zp2.n_points - 1);
+ else
+ last_point = 0;
+
+ /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
+ for ( i = 0; i <= last_point; i++ )
+ {
+ if ( zp.cur != CUR.zp2.cur || refp != i )
+ MOVE_Zp2_Point( i, dx, dy, FALSE );
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SHPIX[]: SHift points by a PIXel amount */
+ /* Opcode range: 0x38 */
+ /* Stack: f26.6 uint32... --> */
+ /* */
+ static void
+ Ins_SHPIX( INS_ARG )
+ {
+ FT_F26Dot6 dx, dy;
+ FT_UShort point;
+
+
+ if ( CUR.top < CUR.GS.loop + 1 )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ 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 );
+
+ while ( CUR.GS.loop > 0 )
+ {
+ CUR.args--;
+
+ point = (FT_UShort)CUR.stack[CUR.args];
+
+ if ( BOUNDS( point, CUR.zp2.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ }
+ else
+ MOVE_Zp2_Point( point, dx, dy, TRUE );
+
+ CUR.GS.loop--;
+ }
+
+ CUR.GS.loop = 1;
+ CUR.new_top = CUR.args;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MSIRP[a]: Move Stack Indirect Relative Position */
+ /* Opcode range: 0x3A-0x3B */
+ /* Stack: f26.6 uint32 --> */
+ /* */
+ static void
+ Ins_MSIRP( INS_ARG )
+ {
+ FT_UShort point;
+ FT_F26Dot6 distance;
+
+
+ point = (FT_UShort)args[0];
+
+ if ( BOUNDS( point, CUR.zp1.n_points ) ||
+ BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ /* XXX: UNDOCUMENTED! behaviour */
+ if ( CUR.GS.gep0 == 0 ) /* if in twilight zone */
+ {
+ CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0];
+ CUR.zp1.cur[point] = CUR.zp1.org[point];
+ }
+
+ distance = CUR_Func_project( CUR.zp1.cur + point,
+ CUR.zp0.cur + CUR.GS.rp0 );
+
+ CUR_Func_move( &CUR.zp1, point, args[1] - distance );
+
+ CUR.GS.rp1 = CUR.GS.rp0;
+ CUR.GS.rp2 = point;
+
+ if ( (CUR.opcode & 1) != 0 )
+ CUR.GS.rp0 = point;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MDAP[a]: Move Direct Absolute Point */
+ /* Opcode range: 0x2E-0x2F */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_MDAP( INS_ARG )
+ {
+ FT_UShort point;
+ FT_F26Dot6 cur_dist,
+ distance;
+
+
+ point = (FT_UShort)args[0];
+
+ if ( BOUNDS( point, CUR.zp0.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ /* XXX: Is there some undocumented feature while in the */
+ /* twilight zone? ? */
+ if ( ( CUR.opcode & 1 ) != 0 )
+ {
+ cur_dist = CUR_Func_project( CUR.zp0.cur + point, NULL_Vector );
+ distance = CUR_Func_round( cur_dist,
+ CUR.tt_metrics.compensations[0] ) - cur_dist;
+ }
+ else
+ distance = 0;
+
+ CUR_Func_move( &CUR.zp0, point, distance );
+
+ CUR.GS.rp0 = point;
+ CUR.GS.rp1 = point;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MIAP[a]: Move Indirect Absolute Point */
+ /* Opcode range: 0x3E-0x3F */
+ /* Stack: uint32 uint32 --> */
+ /* */
+ static void
+ Ins_MIAP( INS_ARG )
+ {
+ FT_ULong cvtEntry;
+ FT_UShort point;
+ FT_F26Dot6 distance,
+ org_dist;
+
+
+ cvtEntry = (FT_ULong)args[1];
+ point = (FT_UShort)args[0];
+
+ if ( BOUNDS( point, CUR.zp0.n_points ) ||
+ BOUNDS( cvtEntry, CUR.cvtSize ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ /* UNDOCUMENTED! */
+ /* */
+ /* The behaviour of an MIAP instruction is quite */
+ /* different when used in the twilight zone. */
+ /* */
+ /* First, no control value cutin test is performed */
+ /* as it would fail anyway. Second, the original */
+ /* point, i.e. (org_x,org_y) of zp0.point, is set */
+ /* to the absolute, unrounded distance found in */
+ /* the CVT. */
+ /* */
+ /* This is used in the CVT programs of the Microsoft */
+ /* fonts Arial, Times, etc., in order to re-adjust */
+ /* some key font heights. It allows the use of the */
+ /* IP instruction in the twilight zone, which */
+ /* otherwise would be `illegal' according to the */
+ /* specification. */
+ /* */
+ /* We implement it with a special sequence for the */
+ /* twilight zone. This is a bad hack, but it seems */
+ /* to work. */
+
+ distance = CUR_Func_read_cvt( cvtEntry );
+
+ 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];
+ }
+
+ org_dist = CUR_Func_project( CUR.zp0.cur + point, NULL_Vector );
+
+ if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cutin flag */
+ {
+ if ( ABS( distance - org_dist ) > CUR.GS.control_value_cutin )
+ distance = org_dist;
+
+ distance = CUR_Func_round( distance, CUR.tt_metrics.compensations[0] );
+ }
+
+ CUR_Func_move( &CUR.zp0, point, distance - org_dist );
+
+ CUR.GS.rp0 = point;
+ CUR.GS.rp1 = point;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MDRP[abcde]: Move Direct Relative Point */
+ /* Opcode range: 0xC0-0xDF */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_MDRP( INS_ARG )
+ {
+ FT_UShort point;
+ FT_F26Dot6 org_dist, distance;
+
+
+ point = (FT_UShort)args[0];
+
+ if ( BOUNDS( point, CUR.zp1.n_points ) ||
+ BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ /* XXX: Is there some undocumented feature while in the */
+ /* twilight zone? */
+
+ org_dist = CUR_Func_dualproj( CUR.zp1.org + point,
+ CUR.zp0.org + CUR.GS.rp0 );
+
+ /* single width cutin test */
+
+ if ( ABS( org_dist ) < CUR.GS.single_width_cutin )
+ {
+ if ( org_dist >= 0 )
+ org_dist = CUR.GS.single_width_value;
+ else
+ org_dist = -CUR.GS.single_width_value;
+ }
+
+ /* round flag */
+
+ if ( ( CUR.opcode & 4 ) != 0 )
+ distance = CUR_Func_round(
+ org_dist,
+ CUR.tt_metrics.compensations[CUR.opcode & 3] );
+ else
+ distance = ROUND_None(
+ org_dist,
+ CUR.tt_metrics.compensations[CUR.opcode & 3] );
+
+ /* minimum distance flag */
+
+ if ( ( CUR.opcode & 8 ) != 0 )
+ {
+ if ( org_dist >= 0 )
+ {
+ if ( distance < CUR.GS.minimum_distance )
+ distance = CUR.GS.minimum_distance;
+ }
+ else
+ {
+ if ( distance > -CUR.GS.minimum_distance )
+ distance = -CUR.GS.minimum_distance;
+ }
+ }
+
+ /* now move the point */
+
+ org_dist = CUR_Func_project( CUR.zp1.cur + point,
+ CUR.zp0.cur + CUR.GS.rp0 );
+
+ CUR_Func_move( &CUR.zp1, point, distance - org_dist );
+
+ CUR.GS.rp1 = CUR.GS.rp0;
+ CUR.GS.rp2 = point;
+
+ if ( ( CUR.opcode & 16 ) != 0 )
+ CUR.GS.rp0 = point;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MIRP[abcde]: Move Indirect Relative Point */
+ /* Opcode range: 0xE0-0xFF */
+ /* Stack: int32? uint32 --> */
+ /* */
+ static void
+ Ins_MIRP( INS_ARG )
+ {
+ FT_UShort point;
+ FT_ULong cvtEntry;
+
+ FT_F26Dot6 cvt_dist,
+ distance,
+ cur_dist,
+ org_dist;
+
+
+ point = (FT_UShort)args[0];
+ cvtEntry = (FT_ULong)( args[1] + 1 );
+
+ /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
+
+ if ( BOUNDS( point, CUR.zp1.n_points ) ||
+ BOUNDS( cvtEntry, CUR.cvtSize + 1 ) ||
+ BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ if ( !cvtEntry )
+ cvt_dist = 0;
+ else
+ cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );
+
+ /* single width test */
+
+ if ( ABS( cvt_dist ) < CUR.GS.single_width_cutin )
+ {
+ if ( cvt_dist >= 0 )
+ cvt_dist = CUR.GS.single_width_value;
+ else
+ cvt_dist = -CUR.GS.single_width_value;
+ }
+
+ /* XXX: UNDOCUMENTED! -- twilight zone */
+
+ 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 );
+
+ CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y +
+ TT_MULDIV( cvt_dist,
+ CUR.GS.freeVector.y,
+ 0x4000 );
+
+ CUR.zp1.cur[point] = CUR.zp1.org[point];
+ }
+
+ org_dist = CUR_Func_dualproj( CUR.zp1.org + point,
+ CUR.zp0.org + CUR.GS.rp0 );
+
+ cur_dist = CUR_Func_project( CUR.zp1.cur + point,
+ CUR.zp0.cur + CUR.GS.rp0 );
+
+ /* auto-flip test */
+
+ if ( CUR.GS.auto_flip )
+ {
+ if ( ( org_dist ^ cvt_dist ) < 0 )
+ cvt_dist = -cvt_dist;
+ }
+
+ /* control value cutin and round */
+
+ if ( ( CUR.opcode & 4 ) != 0 )
+ {
+ /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */
+ /* refer to the same zone. */
+
+ if ( CUR.GS.gep0 == CUR.GS.gep1 )
+ if ( ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin )
+ cvt_dist = org_dist;
+
+ distance = CUR_Func_round(
+ cvt_dist,
+ CUR.tt_metrics.compensations[CUR.opcode & 3] );
+ }
+ else
+ distance = ROUND_None(
+ cvt_dist,
+ CUR.tt_metrics.compensations[CUR.opcode & 3] );
+
+ /* minimum distance test */
+
+ if ( ( CUR.opcode & 8 ) != 0 )
+ {
+ if ( org_dist >= 0 )
+ {
+ if ( distance < CUR.GS.minimum_distance )
+ distance = CUR.GS.minimum_distance;
+ }
+ else
+ {
+ if ( distance > -CUR.GS.minimum_distance )
+ distance = -CUR.GS.minimum_distance;
+ }
+ }
+
+ CUR_Func_move( &CUR.zp1, point, distance - cur_dist );
+
+ CUR.GS.rp1 = CUR.GS.rp0;
+
+ if ( ( CUR.opcode & 16 ) != 0 )
+ CUR.GS.rp0 = point;
+
+ /* XXX: UNDOCUMENTED! */
+
+ CUR.GS.rp2 = point;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ALIGNRP[]: ALIGN Relative Point */
+ /* Opcode range: 0x3C */
+ /* Stack: uint32 uint32... --> */
+ /* */
+ static void
+ Ins_ALIGNRP( INS_ARG )
+ {
+ FT_UShort point;
+ FT_F26Dot6 distance;
+
+ FT_UNUSED_ARG;
+
+
+ if ( CUR.top < CUR.GS.loop ||
+ BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ while ( CUR.GS.loop > 0 )
+ {
+ CUR.args--;
+
+ point = (FT_UShort)CUR.stack[CUR.args];
+
+ if ( BOUNDS( point, CUR.zp1.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ }
+ else
+ {
+ distance = CUR_Func_project( CUR.zp1.cur + point,
+ CUR.zp0.cur + CUR.GS.rp0 );
+
+ CUR_Func_move( &CUR.zp1, point, -distance );
+ }
+
+ CUR.GS.loop--;
+ }
+
+ CUR.GS.loop = 1;
+ CUR.new_top = CUR.args;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ISECT[]: moves point to InterSECTion */
+ /* Opcode range: 0x0F */
+ /* Stack: 5 * uint32 --> */
+ /* */
+ static void
+ Ins_ISECT( INS_ARG )
+ {
+ FT_UShort point,
+ a0, a1,
+ b0, b1;
+
+ FT_F26Dot6 discriminant;
+
+ FT_F26Dot6 dx, dy,
+ dax, day,
+ dbx, dby;
+
+ FT_F26Dot6 val;
+
+ FT_Vector R;
+
+
+ point = (FT_UShort)args[0];
+
+ a0 = (FT_UShort)args[1];
+ a1 = (FT_UShort)args[2];
+ b0 = (FT_UShort)args[3];
+ b1 = (FT_UShort)args[4];
+
+ if ( BOUNDS( b0, CUR.zp0.n_points ) ||
+ BOUNDS( b1, CUR.zp0.n_points ) ||
+ BOUNDS( a0, CUR.zp1.n_points ) ||
+ BOUNDS( a1, CUR.zp1.n_points ) ||
+ BOUNDS( point, CUR.zp2.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x;
+ dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y;
+
+ dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x;
+ day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y;
+
+ dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x;
+ dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y;
+
+ CUR.zp2.tags[point] |= FT_Curve_Tag_Touch_Both;
+
+ discriminant = TT_MULDIV( dax, -dby, 0x40 ) +
+ TT_MULDIV( day, dbx, 0x40 );
+
+ if ( ABS( discriminant ) >= 0x40 )
+ {
+ val = TT_MULDIV( dx, -dby, 0x40 ) + TT_MULDIV( dy, dbx, 0x40 );
+
+ R.x = TT_MULDIV( val, dax, discriminant );
+ R.y = TT_MULDIV( val, day, discriminant );
+
+ CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x;
+ CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y;
+ }
+ else
+ {
+ /* else, take the middle of the middles of A and B */
+
+ CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x +
+ CUR.zp1.cur[a1].x +
+ CUR.zp0.cur[b0].x +
+ CUR.zp0.cur[b1].x ) / 4;
+ CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y +
+ CUR.zp1.cur[a1].y +
+ CUR.zp0.cur[b0].y +
+ CUR.zp0.cur[b1].y ) / 4;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* ALIGNPTS[]: ALIGN PoinTS */
+ /* Opcode range: 0x27 */
+ /* Stack: uint32 uint32 --> */
+ /* */
+ static void
+ Ins_ALIGNPTS( INS_ARG )
+ {
+ FT_UShort p1, p2;
+ FT_F26Dot6 distance;
+
+
+ p1 = (FT_UShort)args[0];
+ p2 = (FT_UShort)args[1];
+
+ if ( BOUNDS( args[0], CUR.zp1.n_points ) ||
+ BOUNDS( args[1], CUR.zp0.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ distance = CUR_Func_project( CUR.zp0.cur + p2,
+ CUR.zp1.cur + p1 ) / 2;
+
+ CUR_Func_move( &CUR.zp1, p1, distance );
+ CUR_Func_move( &CUR.zp0, p2, -distance );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* IP[]: Interpolate Point */
+ /* Opcode range: 0x39 */
+ /* Stack: uint32... --> */
+ /* */
+ static void
+ Ins_IP( INS_ARG )
+ {
+ FT_F26Dot6 org_a, org_b, org_x,
+ cur_a, cur_b, cur_x,
+ distance;
+ FT_UShort point;
+
+ FT_UNUSED_ARG;
+
+
+ if ( CUR.top < CUR.GS.loop )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ /* XXX: There are some glyphs in some braindead but popular */
+ /* fonts out there (e.g. [aeu]grave in monotype.ttf) */
+ /* calling IP[] with bad values of rp[12]. */
+ /* Do something sane when this odd thing happens. */
+
+ if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ||
+ BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) )
+ {
+ org_a = cur_a = 0;
+ org_b = cur_b = 0;
+ }
+ else
+ {
+ org_a = CUR_Func_dualproj( CUR.zp0.org + CUR.GS.rp1, NULL_Vector );
+ org_b = CUR_Func_dualproj( CUR.zp1.org + CUR.GS.rp2, NULL_Vector );
+
+ cur_a = CUR_Func_project( CUR.zp0.cur + CUR.GS.rp1, NULL_Vector );
+ cur_b = CUR_Func_project( CUR.zp1.cur + CUR.GS.rp2, NULL_Vector );
+ }
+
+ while ( CUR.GS.loop > 0 )
+ {
+ CUR.args--;
+
+ point = (FT_UShort)CUR.stack[CUR.args];
+ if ( BOUNDS( point, CUR.zp2.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ }
+ else
+ {
+ org_x = CUR_Func_dualproj( CUR.zp2.org + point, NULL_Vector );
+ cur_x = CUR_Func_project ( CUR.zp2.cur + point, NULL_Vector );
+
+ if ( ( org_a <= org_b && org_x <= org_a ) ||
+ ( org_a > org_b && org_x >= org_a ) )
+
+ distance = ( cur_a - org_a ) + ( org_x - cur_x );
+
+ else if ( ( org_a <= org_b && org_x >= org_b ) ||
+ ( org_a > org_b && org_x < org_b ) )
+
+ distance = ( cur_b - org_b ) + ( org_x - cur_x );
+
+ else
+ /* note: it seems that rounding this value isn't a good */
+ /* idea (cf. width of capital `S' in Times) */
+
+ distance = TT_MULDIV( cur_b - cur_a,
+ org_x - org_a,
+ org_b - org_a ) + ( cur_a - cur_x );
+
+ CUR_Func_move( &CUR.zp2, point, distance );
+ }
+
+ CUR.GS.loop--;
+ }
+
+ CUR.GS.loop = 1;
+ CUR.new_top = CUR.args;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* UTP[a]: UnTouch Point */
+ /* Opcode range: 0x29 */
+ /* Stack: uint32 --> */
+ /* */
+ static void
+ Ins_UTP( INS_ARG )
+ {
+ FT_UShort point;
+ FT_Byte mask;
+
+
+ point = (FT_UShort)args[0];
+
+ if ( BOUNDS( point, CUR.zp0.n_points ) )
+ {
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+
+ mask = 0xFF;
+
+ if ( CUR.GS.freeVector.x != 0 )
+ mask &= ~FT_Curve_Tag_Touch_X;
+
+ if ( CUR.GS.freeVector.y != 0 )
+ mask &= ~FT_Curve_Tag_Touch_Y;
+
+ CUR.zp0.tags[point] &= mask;
+ }
+
+
+ /* Local variables for Ins_IUP: */
+ struct LOC_Ins_IUP
+ {
+ FT_Vector* orgs; /* original and current coordinate */
+ FT_Vector* curs; /* arrays */
+ };
+
+
+ static void
+ Shift( FT_UInt p1,
+ FT_UInt p2,
+ FT_UInt p,
+ struct LOC_Ins_IUP* LINK )
+ {
+ FT_UInt i;
+ FT_F26Dot6 x;
+
+
+ x = LINK->curs[p].x - LINK->orgs[p].x;
+
+ for ( i = p1; i < p; i++ )
+ LINK->curs[i].x += x;
+
+ for ( i = p + 1; i <= p2; i++ )
+ LINK->curs[i].x += x;
+ }
+
+
+ static void
+ Interp( FT_UInt p1,
+ FT_UInt p2,
+ FT_UInt ref1,
+ FT_UInt ref2,
+ struct LOC_Ins_IUP* LINK )
+ {
+ FT_UInt i;
+ FT_F26Dot6 x, x1, x2, d1, d2;
+
+
+ if ( p1 > p2 )
+ return;
+
+ x1 = LINK->orgs[ref1].x;
+ d1 = LINK->curs[ref1].x - LINK->orgs[ref1].x;
+ x2 = LINK->orgs[ref2].x;
+ d2 = LINK->curs[ref2].x - LINK->orgs[ref2].x;
+
+ if ( x1 == x2 )
+ {
+ for ( i = p1; i <= p2; i++ )
+ {
+ x = LINK->orgs[i].x;
+
+ if ( x <= x1 )
+ x += d1;
+ else
+ x += d2;
+
+ LINK->curs[i].x = x;
+ }
+ return;
+ }
+
+ if ( x1 < x2 )
+ {
+ for ( i = p1; i <= p2; i++ )
+ {
+ x = LINK->orgs[i].x;
+
+ if ( x <= x1 )
+ x += d1;
+ else
+ {
+ if ( x >= x2 )
+ x += d2;
+ else
+ x = LINK->curs[ref1].x +
+ TT_MULDIV( x - x1,
+ LINK->curs[ref2].x - LINK->curs[ref1].x,
+ x2 - x1 );
+ }
+ LINK->curs[i].x = x;
+ }
+ return;
+ }
+
+ /* x2 < x1 */
+
+ for ( i = p1; i <= p2; i++ )
+ {
+ x = LINK->orgs[i].x;
+ if ( x <= x2 )
+ x += d2;
+ else
+ {
+ if ( x >= x1 )
+ x += d1;
+ else
+ x = LINK->curs[ref1].x +
+ TT_MULDIV( x - x1,
+ LINK->curs[ref2].x - LINK->curs[ref1].x,
+ x2 - x1 );
+ }
+ LINK->curs[i].x = x;
+ }
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* IUP[a]: Interpolate Untouched Points */
+ /* Opcode range: 0x30-0x31 */
+ /* Stack: --> */
+ /* */
+ static void
+ Ins_IUP( INS_ARG )
+ {
+ struct LOC_Ins_IUP V;
+ FT_Byte mask;
+
+ FT_UInt first_point; /* first point of contour */
+ FT_UInt end_point; /* end point (last+1) of contour */
+
+ FT_UInt first_touched; /* first touched point in contour */
+ FT_UInt cur_touched; /* current touched point in contour */
+
+ FT_UInt point; /* current point */
+ FT_Short contour; /* current contour */
+
+ FT_UNUSED_ARG;
+
+
+ if ( CUR.opcode & 1 )
+ {
+ mask = FT_Curve_Tag_Touch_X;
+ V.orgs = CUR.pts.org;
+ V.curs = CUR.pts.cur;
+ }
+ else
+ {
+ mask = FT_Curve_Tag_Touch_Y;
+ V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 );
+ V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 );
+ }
+
+ contour = 0;
+ point = 0;
+
+ do
+ {
+ end_point = CUR.pts.contours[contour];
+ first_point = point;
+
+ while ( point <= end_point && (CUR.pts.tags[point] & mask) == 0 )
+ point++;
+
+ if ( point <= end_point )
+ {
+ first_touched = point;
+ cur_touched = point;
+
+ point++;
+
+ while ( point <= end_point )
+ {
+ if ( ( CUR.pts.tags[point] & mask ) != 0 )
+ {
+ if ( point > 0 )
+ Interp( cur_touched + 1,
+ point - 1,
+ cur_touched,
+ point,
+ &V );
+ cur_touched = point;
+ }
+
+ point++;
+ }
+
+ if ( cur_touched == first_touched )
+ Shift( first_point, end_point, cur_touched, &V );
+ else
+ {
+ Interp( (FT_UShort)( cur_touched + 1 ),
+ end_point,
+ cur_touched,
+ first_touched,
+ &V );
+
+ if ( first_touched > 0 )
+ Interp( first_point,
+ first_touched - 1,
+ cur_touched,
+ first_touched,
+ &V );
+ }
+ }
+ contour++;
+ } while ( contour < CUR.pts.n_contours );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* DELTAPn[]: DELTA exceptions P1, P2, P3 */
+ /* Opcode range: 0x5D,0x71,0x72 */
+ /* Stack: uint32 (2 * uint32)... --> */
+ /* */
+ static void
+ Ins_DELTAP( INS_ARG )
+ {
+ FT_ULong k, nump;
+ FT_UShort A;
+ FT_ULong C;
+ FT_Long B;
+
+
+ nump = (FT_ULong)args[0]; /* some points theoretically may occur more
+ than once, thus UShort isn't enough */
+
+ for ( k = 1; k <= nump; k++ )
+ {
+ if ( CUR.args < 2 )
+ {
+ CUR.error = TT_Err_Too_Few_Arguments;
+ return;
+ }
+
+ CUR.args -= 2;
+
+ A = (FT_UShort)CUR.stack[CUR.args + 1];
+ B = CUR.stack[CUR.args];
+
+ /* XXX: Because some popular fonts contain some invalid DeltaP */
+ /* instructions, we simply ignore them when the stacked */
+ /* point reference is off limit, rather than returning an */
+ /* error. As a delta instruction doesn't change a glyph */
+ /* in great ways, this shouldn't be a problem. */
+
+ if ( !BOUNDS( A, CUR.zp0.n_points ) )
+ {
+ C = ( (FT_ULong)B & 0xF0 ) >> 4;
+
+ switch ( CUR.opcode )
+ {
+ case 0x5D:
+ break;
+
+ case 0x71:
+ C += 16;
+ break;
+
+ case 0x72:
+ C += 32;
+ break;
+ }
+
+ C += CUR.GS.delta_base;
+
+ if ( CURRENT_Ppem() == (FT_Long)C )
+ {
+ B = ( (FT_ULong)B & 0xF ) - 8;
+ if ( B >= 0 )
+ B++;
+ B = B * 64 / ( 1L << CUR.GS.delta_shift );
+
+ CUR_Func_move( &CUR.zp0, A, B );
+ }
+ }
+ else
+ if ( CUR.pedantic_hinting )
+ CUR.error = TT_Err_Invalid_Reference;
+ }
+
+ CUR.new_top = CUR.args;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* DELTACn[]: DELTA exceptions C1, C2, C3 */
+ /* Opcode range: 0x73,0x74,0x75 */
+ /* Stack: uint32 (2 * uint32)... --> */
+ /* */
+ static void
+ Ins_DELTAC( INS_ARG )
+ {
+ FT_ULong nump, k;
+ FT_ULong A, C;
+ FT_Long B;
+
+
+ nump = (FT_ULong)args[0];
+
+ for ( k = 1; k <= nump; k++ )
+ {
+ if ( CUR.args < 2 )
+ {
+ CUR.error = TT_Err_Too_Few_Arguments;
+ return;
+ }
+
+ CUR.args -= 2;
+
+ A = (FT_ULong)CUR.stack[CUR.args + 1];
+ B = CUR.stack[CUR.args];
+
+ if ( BOUNDS( A, CUR.cvtSize ) )
+ {
+ if ( CUR.pedantic_hinting )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ return;
+ }
+ }
+ else
+ {
+ C = ( (FT_ULong)B & 0xF0 ) >> 4;
+
+ switch ( CUR.opcode )
+ {
+ case 0x73:
+ break;
+
+ case 0x74:
+ C += 16;
+ break;
+
+ case 0x75:
+ C += 32;
+ break;
+ }
+
+ C += CUR.GS.delta_base;
+
+ if ( CURRENT_Ppem() == (FT_Long)C )
+ {
+ B = ( (FT_ULong)B & 0xF ) - 8;
+ if ( B >= 0 )
+ B++;
+ B = B * 64 / ( 1L << CUR.GS.delta_shift );
+
+ CUR_Func_move_cvt( A, B );
+ }
+ }
+ }
+
+ CUR.new_top = CUR.args;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* MISC. INSTRUCTIONS */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* GETINFO[]: GET INFOrmation */
+ /* Opcode range: 0x88 */
+ /* Stack: uint32 --> uint32 */
+ /* */
+ /* XXX: According to Apple specs, bits 1 & 2 of the argument ought to be */
+ /* consulted before rotated/stretched info is returned. */
+ static void
+ Ins_GETINFO( INS_ARG )
+ {
+ FT_Long K;
+
+
+ K = 0;
+
+ /* We return then Windows 3.1 version number */
+ /* for the font scaler */
+ if ( ( args[0] & 1 ) != 0 )
+ K = 3;
+
+ /* Has the glyph been rotated ? */
+ if ( CUR.tt_metrics.rotated )
+ K |= 0x80;
+
+ /* Has the glyph been stretched ? */
+ if ( CUR.tt_metrics.stretched )
+ K |= 0x100;
+
+ args[0] = K;
+ }
+
+
+ static void
+ Ins_UNKNOWN( INS_ARG )
+ {
+ TT_DefRecord* def = CUR.IDefs;
+ TT_DefRecord* limit = def + CUR.numIDefs;
+
+ FT_UNUSED_ARG;
+
+
+ for ( ; def < limit; def++ )
+ {
+ if ( (FT_Byte)def->opc == CUR.opcode && def->active )
+ {
+ TT_CallRec* call;
+
+
+ if ( CUR.callTop >= CUR.callSize )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ return;
+ }
+
+ call = CUR.callStack + CUR.callTop++;
+
+ call->Caller_Range = CUR.curRange;
+ call->Caller_IP = CUR.IP+1;
+ call->Cur_Count = 1;
+ call->Cur_Restart = def->start;
+
+ INS_Goto_CodeRange( def->range, def->start );
+
+ CUR.step_ins = FALSE;
+ return;
+ }
+ }
+
+ CUR.error = TT_Err_Invalid_Opcode;
+ }
+
+
+#ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
+
+
+ static
+ TInstruction_Function Instruct_Dispatch[256] =
+ {
+ /* Opcodes are gathered in groups of 16. */
+ /* Please keep the spaces as they are. */
+
+ /* SVTCA y */ Ins_SVTCA,
+ /* SVTCA x */ Ins_SVTCA,
+ /* SPvTCA y */ Ins_SPVTCA,
+ /* SPvTCA x */ Ins_SPVTCA,
+ /* SFvTCA y */ Ins_SFVTCA,
+ /* SFvTCA x */ Ins_SFVTCA,
+ /* SPvTL // */ Ins_SPVTL,
+ /* SPvTL + */ Ins_SPVTL,
+ /* SFvTL // */ Ins_SFVTL,
+ /* SFvTL + */ Ins_SFVTL,
+ /* SPvFS */ Ins_SPVFS,
+ /* SFvFS */ Ins_SFVFS,
+ /* GPV */ Ins_GPV,
+ /* GFV */ Ins_GFV,
+ /* SFvTPv */ Ins_SFVTPV,
+ /* ISECT */ Ins_ISECT,
+
+ /* SRP0 */ Ins_SRP0,
+ /* SRP1 */ Ins_SRP1,
+ /* SRP2 */ Ins_SRP2,
+ /* SZP0 */ Ins_SZP0,
+ /* SZP1 */ Ins_SZP1,
+ /* SZP2 */ Ins_SZP2,
+ /* SZPS */ Ins_SZPS,
+ /* SLOOP */ Ins_SLOOP,
+ /* RTG */ Ins_RTG,
+ /* RTHG */ Ins_RTHG,
+ /* SMD */ Ins_SMD,
+ /* ELSE */ Ins_ELSE,
+ /* JMPR */ Ins_JMPR,
+ /* SCvTCi */ Ins_SCVTCI,
+ /* SSwCi */ Ins_SSWCI,
+ /* SSW */ Ins_SSW,
+
+ /* DUP */ Ins_DUP,
+ /* POP */ Ins_POP,
+ /* CLEAR */ Ins_CLEAR,
+ /* SWAP */ Ins_SWAP,
+ /* DEPTH */ Ins_DEPTH,
+ /* CINDEX */ Ins_CINDEX,
+ /* MINDEX */ Ins_MINDEX,
+ /* AlignPTS */ Ins_ALIGNPTS,
+ /* INS_0x28 */ Ins_UNKNOWN,
+ /* UTP */ Ins_UTP,
+ /* LOOPCALL */ Ins_LOOPCALL,
+ /* CALL */ Ins_CALL,
+ /* FDEF */ Ins_FDEF,
+ /* ENDF */ Ins_ENDF,
+ /* MDAP[0] */ Ins_MDAP,
+ /* MDAP[1] */ Ins_MDAP,
+
+ /* IUP[0] */ Ins_IUP,
+ /* IUP[1] */ Ins_IUP,
+ /* SHP[0] */ Ins_SHP,
+ /* SHP[1] */ Ins_SHP,
+ /* SHC[0] */ Ins_SHC,
+ /* SHC[1] */ Ins_SHC,
+ /* SHZ[0] */ Ins_SHZ,
+ /* SHZ[1] */ Ins_SHZ,
+ /* SHPIX */ Ins_SHPIX,
+ /* IP */ Ins_IP,
+ /* MSIRP[0] */ Ins_MSIRP,
+ /* MSIRP[1] */ Ins_MSIRP,
+ /* AlignRP */ Ins_ALIGNRP,
+ /* RTDG */ Ins_RTDG,
+ /* MIAP[0] */ Ins_MIAP,
+ /* MIAP[1] */ Ins_MIAP,
+
+ /* NPushB */ Ins_NPUSHB,
+ /* NPushW */ Ins_NPUSHW,
+ /* WS */ Ins_WS,
+ /* RS */ Ins_RS,
+ /* WCvtP */ Ins_WCVTP,
+ /* RCvt */ Ins_RCVT,
+ /* GC[0] */ Ins_GC,
+ /* GC[1] */ Ins_GC,
+ /* SCFS */ Ins_SCFS,
+ /* MD[0] */ Ins_MD,
+ /* MD[1] */ Ins_MD,
+ /* MPPEM */ Ins_MPPEM,
+ /* MPS */ Ins_MPS,
+ /* FlipON */ Ins_FLIPON,
+ /* FlipOFF */ Ins_FLIPOFF,
+ /* DEBUG */ Ins_DEBUG,
+
+ /* LT */ Ins_LT,
+ /* LTEQ */ Ins_LTEQ,
+ /* GT */ Ins_GT,
+ /* GTEQ */ Ins_GTEQ,
+ /* EQ */ Ins_EQ,
+ /* NEQ */ Ins_NEQ,
+ /* ODD */ Ins_ODD,
+ /* EVEN */ Ins_EVEN,
+ /* IF */ Ins_IF,
+ /* EIF */ Ins_EIF,
+ /* AND */ Ins_AND,
+ /* OR */ Ins_OR,
+ /* NOT */ Ins_NOT,
+ /* DeltaP1 */ Ins_DELTAP,
+ /* SDB */ Ins_SDB,
+ /* SDS */ Ins_SDS,
+
+ /* ADD */ Ins_ADD,
+ /* SUB */ Ins_SUB,
+ /* DIV */ Ins_DIV,
+ /* MUL */ Ins_MUL,
+ /* ABS */ Ins_ABS,
+ /* NEG */ Ins_NEG,
+ /* FLOOR */ Ins_FLOOR,
+ /* CEILING */ Ins_CEILING,
+ /* ROUND[0] */ Ins_ROUND,
+ /* ROUND[1] */ Ins_ROUND,
+ /* ROUND[2] */ Ins_ROUND,
+ /* ROUND[3] */ Ins_ROUND,
+ /* NROUND[0] */ Ins_NROUND,
+ /* NROUND[1] */ Ins_NROUND,
+ /* NROUND[2] */ Ins_NROUND,
+ /* NROUND[3] */ Ins_NROUND,
+
+ /* WCvtF */ Ins_WCVTF,
+ /* DeltaP2 */ Ins_DELTAP,
+ /* DeltaP3 */ Ins_DELTAP,
+ /* DeltaCn[0] */ Ins_DELTAC,
+ /* DeltaCn[1] */ Ins_DELTAC,
+ /* DeltaCn[2] */ Ins_DELTAC,
+ /* SROUND */ Ins_SROUND,
+ /* S45Round */ Ins_S45ROUND,
+ /* JROT */ Ins_JROT,
+ /* JROF */ Ins_JROF,
+ /* ROFF */ Ins_ROFF,
+ /* INS_0x7B */ Ins_UNKNOWN,
+ /* RUTG */ Ins_RUTG,
+ /* RDTG */ Ins_RDTG,
+ /* SANGW */ Ins_SANGW,
+ /* AA */ Ins_AA,
+
+ /* FlipPT */ Ins_FLIPPT,
+ /* FlipRgON */ Ins_FLIPRGON,
+ /* FlipRgOFF */ Ins_FLIPRGOFF,
+ /* INS_0x83 */ Ins_UNKNOWN,
+ /* INS_0x84 */ Ins_UNKNOWN,
+ /* ScanCTRL */ Ins_SCANCTRL,
+ /* SDPVTL[0] */ Ins_SDPVTL,
+ /* SDPVTL[1] */ Ins_SDPVTL,
+ /* GetINFO */ Ins_GETINFO,
+ /* IDEF */ Ins_IDEF,
+ /* ROLL */ Ins_ROLL,
+ /* MAX */ Ins_MAX,
+ /* MIN */ Ins_MIN,
+ /* ScanTYPE */ Ins_SCANTYPE,
+ /* InstCTRL */ Ins_INSTCTRL,
+ /* INS_0x8F */ Ins_UNKNOWN,
+
+ /* INS_0x90 */ Ins_UNKNOWN,
+ /* INS_0x91 */ Ins_UNKNOWN,
+ /* INS_0x92 */ Ins_UNKNOWN,
+ /* INS_0x93 */ Ins_UNKNOWN,
+ /* INS_0x94 */ Ins_UNKNOWN,
+ /* INS_0x95 */ Ins_UNKNOWN,
+ /* INS_0x96 */ Ins_UNKNOWN,
+ /* INS_0x97 */ Ins_UNKNOWN,
+ /* INS_0x98 */ Ins_UNKNOWN,
+ /* INS_0x99 */ Ins_UNKNOWN,
+ /* INS_0x9A */ Ins_UNKNOWN,
+ /* INS_0x9B */ Ins_UNKNOWN,
+ /* INS_0x9C */ Ins_UNKNOWN,
+ /* INS_0x9D */ Ins_UNKNOWN,
+ /* INS_0x9E */ Ins_UNKNOWN,
+ /* INS_0x9F */ Ins_UNKNOWN,
+
+ /* INS_0xA0 */ Ins_UNKNOWN,
+ /* INS_0xA1 */ Ins_UNKNOWN,
+ /* INS_0xA2 */ Ins_UNKNOWN,
+ /* INS_0xA3 */ Ins_UNKNOWN,
+ /* INS_0xA4 */ Ins_UNKNOWN,
+ /* INS_0xA5 */ Ins_UNKNOWN,
+ /* INS_0xA6 */ Ins_UNKNOWN,
+ /* INS_0xA7 */ Ins_UNKNOWN,
+ /* INS_0xA8 */ Ins_UNKNOWN,
+ /* INS_0xA9 */ Ins_UNKNOWN,
+ /* INS_0xAA */ Ins_UNKNOWN,
+ /* INS_0xAB */ Ins_UNKNOWN,
+ /* INS_0xAC */ Ins_UNKNOWN,
+ /* INS_0xAD */ Ins_UNKNOWN,
+ /* INS_0xAE */ Ins_UNKNOWN,
+ /* INS_0xAF */ Ins_UNKNOWN,
+
+ /* PushB[0] */ Ins_PUSHB,
+ /* PushB[1] */ Ins_PUSHB,
+ /* PushB[2] */ Ins_PUSHB,
+ /* PushB[3] */ Ins_PUSHB,
+ /* PushB[4] */ Ins_PUSHB,
+ /* PushB[5] */ Ins_PUSHB,
+ /* PushB[6] */ Ins_PUSHB,
+ /* PushB[7] */ Ins_PUSHB,
+ /* PushW[0] */ Ins_PUSHW,
+ /* PushW[1] */ Ins_PUSHW,
+ /* PushW[2] */ Ins_PUSHW,
+ /* PushW[3] */ Ins_PUSHW,
+ /* PushW[4] */ Ins_PUSHW,
+ /* PushW[5] */ Ins_PUSHW,
+ /* PushW[6] */ Ins_PUSHW,
+ /* PushW[7] */ Ins_PUSHW,
+
+ /* MDRP[00] */ Ins_MDRP,
+ /* MDRP[01] */ Ins_MDRP,
+ /* MDRP[02] */ Ins_MDRP,
+ /* MDRP[03] */ Ins_MDRP,
+ /* MDRP[04] */ Ins_MDRP,
+ /* MDRP[05] */ Ins_MDRP,
+ /* MDRP[06] */ Ins_MDRP,
+ /* MDRP[07] */ Ins_MDRP,
+ /* MDRP[08] */ Ins_MDRP,
+ /* MDRP[09] */ Ins_MDRP,
+ /* MDRP[10] */ Ins_MDRP,
+ /* MDRP[11] */ Ins_MDRP,
+ /* MDRP[12] */ Ins_MDRP,
+ /* MDRP[13] */ Ins_MDRP,
+ /* MDRP[14] */ Ins_MDRP,
+ /* MDRP[15] */ Ins_MDRP,
+
+ /* MDRP[16] */ Ins_MDRP,
+ /* MDRP[17] */ Ins_MDRP,
+ /* MDRP[18] */ Ins_MDRP,
+ /* MDRP[19] */ Ins_MDRP,
+ /* MDRP[20] */ Ins_MDRP,
+ /* MDRP[21] */ Ins_MDRP,
+ /* MDRP[22] */ Ins_MDRP,
+ /* MDRP[23] */ Ins_MDRP,
+ /* MDRP[24] */ Ins_MDRP,
+ /* MDRP[25] */ Ins_MDRP,
+ /* MDRP[26] */ Ins_MDRP,
+ /* MDRP[27] */ Ins_MDRP,
+ /* MDRP[28] */ Ins_MDRP,
+ /* MDRP[29] */ Ins_MDRP,
+ /* MDRP[30] */ Ins_MDRP,
+ /* MDRP[31] */ Ins_MDRP,
+
+ /* MIRP[00] */ Ins_MIRP,
+ /* MIRP[01] */ Ins_MIRP,
+ /* MIRP[02] */ Ins_MIRP,
+ /* MIRP[03] */ Ins_MIRP,
+ /* MIRP[04] */ Ins_MIRP,
+ /* MIRP[05] */ Ins_MIRP,
+ /* MIRP[06] */ Ins_MIRP,
+ /* MIRP[07] */ Ins_MIRP,
+ /* MIRP[08] */ Ins_MIRP,
+ /* MIRP[09] */ Ins_MIRP,
+ /* MIRP[10] */ Ins_MIRP,
+ /* MIRP[11] */ Ins_MIRP,
+ /* MIRP[12] */ Ins_MIRP,
+ /* MIRP[13] */ Ins_MIRP,
+ /* MIRP[14] */ Ins_MIRP,
+ /* MIRP[15] */ Ins_MIRP,
+
+ /* MIRP[16] */ Ins_MIRP,
+ /* MIRP[17] */ Ins_MIRP,
+ /* MIRP[18] */ Ins_MIRP,
+ /* MIRP[19] */ Ins_MIRP,
+ /* MIRP[20] */ Ins_MIRP,
+ /* MIRP[21] */ Ins_MIRP,
+ /* MIRP[22] */ Ins_MIRP,
+ /* MIRP[23] */ Ins_MIRP,
+ /* MIRP[24] */ Ins_MIRP,
+ /* MIRP[25] */ Ins_MIRP,
+ /* MIRP[26] */ Ins_MIRP,
+ /* MIRP[27] */ Ins_MIRP,
+ /* MIRP[28] */ Ins_MIRP,
+ /* MIRP[29] */ Ins_MIRP,
+ /* MIRP[30] */ Ins_MIRP,
+ /* MIRP[31] */ Ins_MIRP
+ };
+
+
+#endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
+
+
+ /*************************************************************************/
+ /* */
+ /* RUN */
+ /* */
+ /* This function executes a run of opcodes. It will exit in the */
+ /* following cases: */
+ /* */
+ /* - Errors (in which case it returns FALSE). */
+ /* */
+ /* - Reaching the end of the main code range (returns TRUE). */
+ /* Reaching the end of a code range within a function call is an */
+ /* error. */
+ /* */
+ /* - After executing one single opcode, if the flag `Instruction_Trap' */
+ /* is set to TRUE (returns TRUE). */
+ /* */
+ /* On exit whith TRUE, test IP < CodeSize to know wether it comes from */
+ /* an instruction trap or a normal termination. */
+ /* */
+ /* */
+ /* Note: The documented DEBUG opcode pops a value from the stack. This */
+ /* behaviour is unsupported; here a DEBUG opcode is always an */
+ /* error. */
+ /* */
+ /* */
+ /* THIS IS THE INTERPRETER'S MAIN LOOP. */
+ /* */
+ /* Instructions appear in the specification's order. */
+ /* */
+ /*************************************************************************/
+
+
+ /* documentation is in ttinterp.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ TT_RunIns( TT_ExecContext exc )
+ {
+ FT_Long ins_counter = 0; /* executed instructions counter */
+
+
+#ifdef TT_CONFIG_OPTION_STATIC_RASTER
+ cur = *exc;
+#endif
+
+ /* set CVT functions */
+ CUR.tt_metrics.ratio = 0;
+ if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem )
+ {
+ /* non-square pixels, use the stretched routines */
+ CUR.func_read_cvt = Read_CVT_Stretched;
+ CUR.func_write_cvt = Write_CVT_Stretched;
+ CUR.func_move_cvt = Move_CVT_Stretched;
+ }
+ else
+ {
+ /* square pixels, use normal routines */
+ CUR.func_read_cvt = Read_CVT;
+ CUR.func_write_cvt = Write_CVT;
+ CUR.func_move_cvt = Move_CVT;
+ }
+
+ COMPUTE_Funcs();
+ COMPUTE_Round( (FT_Byte)exc->GS.round_state );
+
+ do
+ {
+ CUR.opcode = CUR.code[CUR.IP];
+
+ if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 )
+ {
+ if ( CUR.IP + 1 > CUR.codeSize )
+ goto LErrorCodeOverflow_;
+
+ CUR.length = CUR.code[CUR.IP + 1] + 2;
+ }
+
+ if ( CUR.IP + CUR.length > CUR.codeSize )
+ goto LErrorCodeOverflow_;
+
+ /* First, let's check for empty stack and overflow */
+ CUR.args = CUR.top - ( Pop_Push_Count[CUR.opcode] >> 4 );
+
+ /* `args' is the top of the stack once arguments have been popped. */
+ /* One can also interpret it as the index of the last argument. */
+ if ( CUR.args < 0 )
+ {
+ CUR.error = TT_Err_Too_Few_Arguments;
+ goto LErrorLabel_;
+ }
+
+ CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 );
+
+ /* `new_top' is the new top of the stack, after the instruction's */
+ /* execution. `top' will be set to `new_top' after the `switch' */
+ /* statement. */
+ if ( CUR.new_top > CUR.stackSize )
+ {
+ CUR.error = TT_Err_Stack_Overflow;
+ goto LErrorLabel_;
+ }
+
+ CUR.step_ins = TRUE;
+ CUR.error = TT_Err_Ok;
+
+#ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
+
+ {
+ FT_Long* args = CUR.stack + CUR.args;
+ FT_Byte opcode = CUR.opcode;
+
+
+#undef ARRAY_BOUND_ERROR
+#define ARRAY_BOUND_ERROR goto Set_Invalid_Ref
+
+
+ switch ( opcode )
+ {
+ case 0x00: /* SVTCA y */
+ case 0x01: /* SVTCA x */
+ case 0x02: /* SPvTCA y */
+ case 0x03: /* SPvTCA x */
+ case 0x04: /* SFvTCA y */
+ case 0x05: /* SFvTCA x */
+ {
+ FT_Short AA, BB;
+
+
+ AA = (FT_Short)( ( opcode & 1 ) << 14 );
+ BB = (FT_Short)( AA ^ 0x4000 );
+
+ if ( opcode < 4 )
+ {
+ CUR.GS.projVector.x = AA;
+ CUR.GS.projVector.y = BB;
+
+ CUR.GS.dualVector.x = AA;
+ CUR.GS.dualVector.y = BB;
+ }
+
+ if ( ( opcode & 2 ) == 0 )
+ {
+ CUR.GS.freeVector.x = AA;
+ CUR.GS.freeVector.y = BB;
+ }
+
+ COMPUTE_Funcs();
+ }
+ break;
+
+ case 0x06: /* SPvTL // */
+ case 0x07: /* SPvTL + */
+ DO_SPVTL
+ break;
+
+ case 0x08: /* SFvTL // */
+ case 0x09: /* SFvTL + */
+ DO_SFVTL
+ break;
+
+ case 0x0A: /* SPvFS */
+ DO_SPVFS
+ break;
+
+ case 0x0B: /* SFvFS */
+ DO_SFVFS
+ break;
+
+ case 0x0C: /* GPV */
+ DO_GPV
+ break;
+
+ case 0x0D: /* GFV */
+ DO_GFV
+ break;
+
+ case 0x0E: /* SFvTPv */
+ DO_SFVTPV
+ break;
+
+ case 0x0F: /* ISECT */
+ Ins_ISECT( EXEC_ARG_ args );
+ break;
+
+ case 0x10: /* SRP0 */
+ DO_SRP0
+ break;
+
+ case 0x11: /* SRP1 */
+ DO_SRP1
+ break;
+
+ case 0x12: /* SRP2 */
+ DO_SRP2
+ break;
+
+ case 0x13: /* SZP0 */
+ Ins_SZP0( EXEC_ARG_ args );
+ break;
+
+ case 0x14: /* SZP1 */
+ Ins_SZP1( EXEC_ARG_ args );
+ break;
+
+ case 0x15: /* SZP2 */
+ Ins_SZP2( EXEC_ARG_ args );
+ break;
+
+ case 0x16: /* SZPS */
+ Ins_SZPS( EXEC_ARG_ args );
+ break;
+
+ case 0x17: /* SLOOP */
+ DO_SLOOP
+ break;
+
+ case 0x18: /* RTG */
+ DO_RTG
+ break;
+
+ case 0x19: /* RTHG */
+ DO_RTHG
+ break;
+
+ case 0x1A: /* SMD */
+ DO_SMD
+ break;
+
+ case 0x1B: /* ELSE */
+ Ins_ELSE( EXEC_ARG_ args );
+ break;
+
+ case 0x1C: /* JMPR */
+ DO_JMPR
+ break;
+
+ case 0x1D: /* SCVTCI */
+ DO_SCVTCI
+ break;
+
+ case 0x1E: /* SSWCI */
+ DO_SSWCI
+ break;
+
+ case 0x1F: /* SSW */
+ DO_SSW
+ break;
+
+ case 0x20: /* DUP */
+ DO_DUP
+ break;
+
+ case 0x21: /* POP */
+ /* nothing :-) */
+ break;
+
+ case 0x22: /* CLEAR */
+ DO_CLEAR
+ break;
+
+ case 0x23: /* SWAP */
+ DO_SWAP
+ break;
+
+ case 0x24: /* DEPTH */
+ DO_DEPTH
+ break;
+
+ case 0x25: /* CINDEX */
+ DO_CINDEX
+ break;
+
+ case 0x26: /* MINDEX */
+ Ins_MINDEX( EXEC_ARG_ args );
+ break;
+
+ case 0x27: /* ALIGNPTS */
+ Ins_ALIGNPTS( EXEC_ARG_ args );
+ break;
+
+ case 0x28: /* ???? */
+ Ins_UNKNOWN( EXEC_ARG_ args );
+ break;
+
+ case 0x29: /* UTP */
+ Ins_UTP( EXEC_ARG_ args );
+ break;
+
+ case 0x2A: /* LOOPCALL */
+ Ins_LOOPCALL( EXEC_ARG_ args );
+ break;
+
+ case 0x2B: /* CALL */
+ Ins_CALL( EXEC_ARG_ args );
+ break;
+
+ case 0x2C: /* FDEF */
+ Ins_FDEF( EXEC_ARG_ args );
+ break;
+
+ case 0x2D: /* ENDF */
+ Ins_ENDF( EXEC_ARG_ args );
+ break;
+
+ case 0x2E: /* MDAP */
+ case 0x2F: /* MDAP */
+ Ins_MDAP( EXEC_ARG_ args );
+ break;
+
+
+ case 0x30: /* IUP */
+ case 0x31: /* IUP */
+ Ins_IUP( EXEC_ARG_ args );
+ break;
+
+ case 0x32: /* SHP */
+ case 0x33: /* SHP */
+ Ins_SHP( EXEC_ARG_ args );
+ break;
+
+ case 0x34: /* SHC */
+ case 0x35: /* SHC */
+ Ins_SHC( EXEC_ARG_ args );
+ break;
+
+ case 0x36: /* SHZ */
+ case 0x37: /* SHZ */
+ Ins_SHZ( EXEC_ARG_ args );
+ break;
+
+ case 0x38: /* SHPIX */
+ Ins_SHPIX( EXEC_ARG_ args );
+ break;
+
+ case 0x39: /* IP */
+ Ins_IP( EXEC_ARG_ args );
+ break;
+
+ case 0x3A: /* MSIRP */
+ case 0x3B: /* MSIRP */
+ Ins_MSIRP( EXEC_ARG_ args );
+ break;
+
+ case 0x3C: /* AlignRP */
+ Ins_ALIGNRP( EXEC_ARG_ args );
+ break;
+
+ case 0x3D: /* RTDG */
+ DO_RTDG
+ break;
+
+ case 0x3E: /* MIAP */
+ case 0x3F: /* MIAP */
+ Ins_MIAP( EXEC_ARG_ args );
+ break;
+
+ case 0x40: /* NPUSHB */
+ Ins_NPUSHB( EXEC_ARG_ args );
+ break;
+
+ case 0x41: /* NPUSHW */
+ Ins_NPUSHW( EXEC_ARG_ args );
+ break;
+
+ case 0x42: /* WS */
+ DO_WS
+ break;
+
+ Set_Invalid_Ref:
+ CUR.error = TT_Err_Invalid_Reference;
+ break;
+
+ case 0x43: /* RS */
+ DO_RS
+ break;
+
+ case 0x44: /* WCVTP */
+ DO_WCVTP
+ break;
+
+ case 0x45: /* RCVT */
+ DO_RCVT
+ break;
+
+ case 0x46: /* GC */
+ case 0x47: /* GC */
+ Ins_GC( EXEC_ARG_ args );
+ break;
+
+ case 0x48: /* SCFS */
+ Ins_SCFS( EXEC_ARG_ args );
+ break;
+
+ case 0x49: /* MD */
+ case 0x4A: /* MD */
+ Ins_MD( EXEC_ARG_ args );
+ break;
+
+ case 0x4B: /* MPPEM */
+ DO_MPPEM
+ break;
+
+ case 0x4C: /* MPS */
+ DO_MPS
+ break;
+
+ case 0x4D: /* FLIPON */
+ DO_FLIPON
+ break;
+
+ case 0x4E: /* FLIPOFF */
+ DO_FLIPOFF
+ break;
+
+ case 0x4F: /* DEBUG */
+ DO_DEBUG
+ break;
+
+ case 0x50: /* LT */
+ DO_LT
+ break;
+
+ case 0x51: /* LTEQ */
+ DO_LTEQ
+ break;
+
+ case 0x52: /* GT */
+ DO_GT
+ break;
+
+ case 0x53: /* GTEQ */
+ DO_GTEQ
+ break;
+
+ case 0x54: /* EQ */
+ DO_EQ
+ break;
+
+ case 0x55: /* NEQ */
+ DO_NEQ
+ break;
+
+ case 0x56: /* ODD */
+ DO_ODD
+ break;
+
+ case 0x57: /* EVEN */
+ DO_EVEN
+ break;
+
+ case 0x58: /* IF */
+ Ins_IF( EXEC_ARG_ args );
+ break;
+
+ case 0x59: /* EIF */
+ /* do nothing */
+ break;
+
+ case 0x5A: /* AND */
+ DO_AND
+ break;
+
+ case 0x5B: /* OR */
+ DO_OR
+ break;
+
+ case 0x5C: /* NOT */
+ DO_NOT
+ break;
+
+ case 0x5D: /* DELTAP1 */
+ Ins_DELTAP( EXEC_ARG_ args );
+ break;
+
+ case 0x5E: /* SDB */
+ DO_SDB
+ break;
+
+ case 0x5F: /* SDS */
+ DO_SDS
+ break;
+
+ case 0x60: /* ADD */
+ DO_ADD
+ break;
+
+ case 0x61: /* SUB */
+ DO_SUB
+ break;
+
+ case 0x62: /* DIV */
+ DO_DIV
+ break;
+
+ case 0x63: /* MUL */
+ DO_MUL
+ break;
+
+ case 0x64: /* ABS */
+ DO_ABS
+ break;
+
+ case 0x65: /* NEG */
+ DO_NEG
+ break;
+
+ case 0x66: /* FLOOR */
+ DO_FLOOR
+ break;
+
+ case 0x67: /* CEILING */
+ DO_CEILING
+ break;
+
+ case 0x68: /* ROUND */
+ case 0x69: /* ROUND */
+ case 0x6A: /* ROUND */
+ case 0x6B: /* ROUND */
+ DO_ROUND
+ break;
+
+ case 0x6C: /* NROUND */
+ case 0x6D: /* NROUND */
+ case 0x6E: /* NRRUND */
+ case 0x6F: /* NROUND */
+ DO_NROUND
+ break;
+
+ case 0x70: /* WCVTF */
+ DO_WCVTF
+ break;
+
+ case 0x71: /* DELTAP2 */
+ case 0x72: /* DELTAP3 */
+ Ins_DELTAP( EXEC_ARG_ args );
+ break;
+
+ case 0x73: /* DELTAC0 */
+ case 0x74: /* DELTAC1 */
+ case 0x75: /* DELTAC2 */
+ Ins_DELTAC( EXEC_ARG_ args );
+ break;
+
+ case 0x76: /* SROUND */
+ DO_SROUND
+ break;
+
+ case 0x77: /* S45Round */
+ DO_S45ROUND
+ break;
+
+ case 0x78: /* JROT */
+ DO_JROT
+ break;
+
+ case 0x79: /* JROF */
+ DO_JROF
+ break;
+
+ case 0x7A: /* ROFF */
+ DO_ROFF
+ break;
+
+ case 0x7B: /* ???? */
+ Ins_UNKNOWN( EXEC_ARG_ args );
+ break;
+
+ case 0x7C: /* RUTG */
+ DO_RUTG
+ break;
+
+ case 0x7D: /* RDTG */
+ DO_RDTG
+ break;
+
+ case 0x7E: /* SANGW */
+ case 0x7F: /* AA */
+ /* nothing - obsolete */
+ break;
+
+ case 0x80: /* FLIPPT */
+ Ins_FLIPPT( EXEC_ARG_ args );
+ break;
+
+ case 0x81: /* FLIPRGON */
+ Ins_FLIPRGON( EXEC_ARG_ args );
+ break;
+
+ case 0x82: /* FLIPRGOFF */
+ Ins_FLIPRGOFF( EXEC_ARG_ args );
+ break;
+
+ case 0x83: /* UNKNOWN */
+ case 0x84: /* UNKNOWN */
+ Ins_UNKNOWN( EXEC_ARG_ args );
+ break;
+
+ case 0x85: /* SCANCTRL */
+ Ins_SCANCTRL( EXEC_ARG_ args );
+ break;
+
+ case 0x86: /* SDPVTL */
+ case 0x87: /* SDPVTL */
+ Ins_SDPVTL( EXEC_ARG_ args );
+ break;
+
+ case 0x88: /* GETINFO */
+ Ins_GETINFO( EXEC_ARG_ args );
+ break;
+
+ case 0x89: /* IDEF */
+ Ins_IDEF( EXEC_ARG_ args );
+ break;
+
+ case 0x8A: /* ROLL */
+ Ins_ROLL( EXEC_ARG_ args );
+ break;
+
+ case 0x8B: /* MAX */
+ DO_MAX
+ break;
+
+ case 0x8C: /* MIN */
+ DO_MIN
+ break;
+
+ case 0x8D: /* SCANTYPE */
+ Ins_SCANTYPE( EXEC_ARG_ args );
+ break;
+
+ case 0x8E: /* INSTCTRL */
+ Ins_INSTCTRL( EXEC_ARG_ args );
+ break;
+
+ case 0x8F:
+ Ins_UNKNOWN( EXEC_ARG_ args );
+ break;
+
+ default:
+ if ( opcode >= 0xE0 )
+ Ins_MIRP( EXEC_ARG_ args );
+ else if ( opcode >= 0xC0 )
+ Ins_MDRP( EXEC_ARG_ args );
+ else if ( opcode >= 0xB8 )
+ Ins_PUSHW( EXEC_ARG_ args );
+ else if ( opcode >= 0xB0 )
+ Ins_PUSHB( EXEC_ARG_ args );
+ else
+ Ins_UNKNOWN( EXEC_ARG_ args );
+ }
+
+ }
+
+#else
+
+ Instruct_Dispatch[CUR.opcode]( EXEC_ARG_ &CUR.stack[CUR.args] );
+
+#endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
+
+ if ( CUR.error != TT_Err_Ok )
+ {
+ switch ( CUR.error )
+ {
+ case TT_Err_Invalid_Opcode: /* looking for redefined instructions */
+ {
+ TT_DefRecord* def = CUR.IDefs;
+ TT_DefRecord* limit = def + CUR.numIDefs;
+
+
+ for ( ; def < limit; def++ )
+ {
+ if ( def->active && CUR.opcode == (FT_Byte)def->opc )
+ {
+ TT_CallRec* callrec;
+
+
+ if ( CUR.callTop >= CUR.callSize )
+ {
+ CUR.error = TT_Err_Invalid_Reference;
+ goto LErrorLabel_;
+ }
+
+ callrec = &CUR.callStack[CUR.callTop];
+
+ callrec->Caller_Range = CUR.curRange;
+ callrec->Caller_IP = CUR.IP + 1;
+ callrec->Cur_Count = 1;
+ callrec->Cur_Restart = def->start;
+
+ if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE )
+ goto LErrorLabel_;
+
+ goto LSuiteLabel_;
+ }
+ }
+ }
+
+ CUR.error = TT_Err_Invalid_Opcode;
+ goto LErrorLabel_;
+
+#if 0
+ break; /* Unreachable code warning suppression. */
+ /* Leave to remind in case a later change the editor */
+ /* to consider break; */
+#endif
+
+ default:
+ goto LErrorLabel_;
+
+#if 0
+ break;
+#endif
+ }
+ }
+
+ CUR.top = CUR.new_top;
+
+ if ( CUR.step_ins )
+ CUR.IP += CUR.length;
+
+ /* increment instruction counter and check if we didn't */
+ /* run this program for too long (e.g. infinite loops). */
+ if ( ++ins_counter > MAX_RUNNABLE_OPCODES )
+ return TT_Err_Execution_Too_Long;
+
+ LSuiteLabel_:
+ if ( CUR.IP >= CUR.codeSize )
+ {
+ if ( CUR.callTop > 0 )
+ {
+ CUR.error = TT_Err_Code_Overflow;
+ goto LErrorLabel_;
+ }
+ else
+ goto LNo_Error_;
+ }
+ } while ( !CUR.instruction_trap );
+
+ LNo_Error_:
+
+#ifdef TT_CONFIG_OPTION_STATIC_RASTER
+ *exc = cur;
+#endif
+
+ return TT_Err_Ok;
+
+ LErrorCodeOverflow_:
+ CUR.error = TT_Err_Code_Overflow;
+
+ LErrorLabel_:
+
+#ifdef TT_CONFIG_OPTION_STATIC_RASTER
+ *exc = cur;
+#endif
+
+ return CUR.error;
+ }
+
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ttload.c */
+/* */
+/* Load the basic TrueType tables, i.e., tables that can be either in */
+/* TTF or OTF fonts (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TAGS_H
+#include "ttload.h"
+#include "ttcmap.h"
+
+#include "sferrors.h"
+
+#include <stdlib.h> /* for qsort */
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ttload
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_LookUp_Table */
+ /* */
+ /* <Description> */
+ /* Looks for a TrueType table by name. */
+ /* */
+ /* <Input> */
+ /* face :: A face object handle. */
+ /* tag :: The searched tag. */
+ /* */
+ /* <Return> */
+ /* A pointer to the table directory entry. 0 if not found. */
+ /* */
+ FT_LOCAL_DEF TT_Table*
+ TT_LookUp_Table( TT_Face face,
+ FT_ULong tag )
+ {
+ TT_Table* entry;
+ TT_Table* limit;
+
+
+ FT_TRACE3(( "TT_LookUp_Table: %08p, `%c%c%c%c' -- ",
+ face,
+ (FT_Char)( tag >> 24 ),
+ (FT_Char)( tag >> 16 ),
+ (FT_Char)( tag >> 8 ),
+ (FT_Char)( tag ) ));
+
+ entry = face->dir_tables;
+ limit = entry + face->num_tables;
+
+ for ( ; entry < limit; entry++ )
+ {
+ if ( entry->Tag == tag )
+ {
+ FT_TRACE3(( "found table.\n" ));
+ return entry;
+ }
+ }
+
+ FT_TRACE3(( "could not find table!\n" ));
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Goto_Table */
+ /* */
+ /* <Description> */
+ /* Looks for a TrueType table by name, then seek a stream to it. */
+ /* */
+ /* <Input> */
+ /* face :: A face object handle. */
+ /* tag :: The searched tag. */
+ /* stream :: The stream to seek when the table is found. */
+ /* */
+ /* <Output> */
+ /* length :: The length of the table if found, undefined otherwise. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Goto_Table( TT_Face face,
+ FT_ULong tag,
+ FT_Stream stream,
+ FT_ULong* length )
+ {
+ TT_Table* table;
+ FT_Error error;
+
+
+ table = TT_LookUp_Table( face, tag );
+ if ( table )
+ {
+ if ( length )
+ *length = table->Length;
+
+ if ( FILE_Seek( table->Offset ) )
+ goto Exit;
+ }
+ else
+ error = SFNT_Err_Table_Missing;
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_SFNT_Header */
+ /* */
+ /* <Description> */
+ /* Loads the header of a SFNT font file. Supports collections. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* stream :: The input stream. */
+ /* face_index :: If the font is a collection, the number of the font */
+ /* in the collection, ignored otherwise. */
+ /* */
+ /* <Output> */
+ /* sfnt :: The SFNT header. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The stream cursor must be at the font file's origin. */
+ /* */
+ /* This function recognizes fonts embedded in a `TrueType collection' */
+ /* */
+ /* The header will be checked whether it is valid by looking at the */
+ /* values of `search_range', `entry_selector', and `range_shift'. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Load_SFNT_Header( TT_Face face,
+ FT_Stream stream,
+ FT_Long face_index,
+ SFNT_Header* sfnt )
+ {
+ FT_Error error;
+ FT_ULong format_tag;
+ FT_Memory memory = stream->memory;
+
+ const FT_Frame_Field sfnt_header_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE SFNT_Header
+
+ FT_FRAME_START( 8 ),
+ FT_FRAME_USHORT( num_tables ),
+ FT_FRAME_USHORT( search_range ),
+ FT_FRAME_USHORT( entry_selector ),
+ FT_FRAME_USHORT( range_shift ),
+ FT_FRAME_END
+ };
+
+ const FT_Frame_Field ttc_header_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TTC_Header
+
+ FT_FRAME_START( 8 ),
+ FT_FRAME_LONG( version ),
+ FT_FRAME_LONG( count ),
+ FT_FRAME_END };
+
+
+ FT_TRACE2(( "TT_Load_SFNT_Header: %08p, %ld\n",
+ face, face_index ));
+
+ face->ttc_header.tag = 0;
+ face->ttc_header.version = 0;
+ face->ttc_header.count = 0;
+
+ face->num_tables = 0;
+
+ /* first of all, read the first 4 bytes. If it is `ttcf', then the */
+ /* file is a TrueType collection, otherwise it can be any other */
+ /* kind of font. */
+ if ( READ_ULong( format_tag ) )
+ goto Exit;
+
+ if ( format_tag == TTAG_ttcf )
+ {
+ FT_Int n;
+
+
+ FT_TRACE3(( "TT_Load_SFNT_Header: file is a collection\n" ));
+
+ /* it's a TrueType collection, i.e. a file containing several */
+ /* font files. Read the font directory now */
+ if ( READ_Fields( ttc_header_fields, &face->ttc_header ) )
+ goto Exit;
+
+ /* now read the offsets of each font in the file */
+ if ( ALLOC_ARRAY( face->ttc_header.offsets,
+ face->ttc_header.count,
+ FT_ULong ) ||
+ ACCESS_Frame( face->ttc_header.count * 4L ) )
+ goto Exit;
+
+ for ( n = 0; n < face->ttc_header.count; n++ )
+ face->ttc_header.offsets[n] = GET_ULong();
+
+ FORGET_Frame();
+
+ /* check face index */
+ if ( face_index >= face->ttc_header.count )
+ {
+ error = SFNT_Err_Bad_Argument;
+ goto Exit;
+ }
+
+ /* seek to the appropriate TrueType file, then read tag */
+ if ( FILE_Seek( face->ttc_header.offsets[face_index] ) ||
+ READ_Long( format_tag ) )
+ goto Exit;
+ }
+
+ /* the format tag was read, now check the rest of the header */
+ sfnt->format_tag = format_tag;
+ if ( READ_Fields( sfnt_header_fields, sfnt ) )
+ goto Exit;
+
+ /* now, check the values of `num_tables', `seach_range', etc. */
+ {
+ FT_UInt num_tables = sfnt->num_tables;
+ FT_ULong entry_selector = 1L << sfnt->entry_selector;
+
+
+ /* IMPORTANT: Many fonts have an incorrect `search_range' value, so */
+ /* we only check the `entry_selector' correctness here. */
+ /* */
+ if ( num_tables == 0 ||
+ entry_selector > num_tables ||
+ entry_selector * 2 <= num_tables )
+ {
+ FT_TRACE2(( "TT_Load_SFNT_Header: file is not SFNT!\n" ));
+ error = SFNT_Err_Unknown_File_Format;
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_Directory */
+ /* */
+ /* <Description> */
+ /* Loads the table directory into a face object. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* <Input> */
+ /* stream :: The input stream. */
+ /* sfnt :: The SFNT directory header. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The stream cursor must be at the font file's origin. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Load_Directory( TT_Face face,
+ FT_Stream stream,
+ SFNT_Header* sfnt )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+
+ TT_Table *entry, *limit;
+
+
+ FT_TRACE2(( "TT_Load_Directory: %08p\n", face ));
+
+ FT_TRACE2(( "-- Tables count: %12u\n", sfnt->num_tables ));
+ FT_TRACE2(( "-- Format version: %08lx\n", sfnt->format_tag ));
+
+ face->num_tables = sfnt->num_tables;
+
+ if ( ALLOC_ARRAY( face->dir_tables,
+ face->num_tables,
+ TT_Table ) )
+ goto Exit;
+
+ if ( ACCESS_Frame( face->num_tables * 16L ) )
+ goto Exit;
+
+ entry = face->dir_tables;
+ limit = entry + face->num_tables;
+
+ for ( ; entry < limit; entry++ )
+ { /* loop through the tables and get all entries */
+ entry->Tag = GET_Tag4();
+ entry->CheckSum = GET_ULong();
+ entry->Offset = GET_Long();
+ entry->Length = GET_Long();
+
+ FT_TRACE2(( " %c%c%c%c - %08lx - %08lx\n",
+ (FT_Char)( entry->Tag >> 24 ),
+ (FT_Char)( entry->Tag >> 16 ),
+ (FT_Char)( entry->Tag >> 8 ),
+ (FT_Char)( entry->Tag ),
+ entry->Offset,
+ entry->Length ));
+ }
+
+ FORGET_Frame();
+
+ FT_TRACE2(( "Directory loaded\n\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_Any */
+ /* */
+ /* <Description> */
+ /* Loads any font table into client memory. */
+ /* */
+ /* <Input> */
+ /* face :: The face object to look for. */
+ /* */
+ /* tag :: The tag of table to load. Use the value 0 if you want */
+ /* to access the whole font file, else set this parameter */
+ /* to a valid TrueType table tag that you can forge with */
+ /* the MAKE_TT_TAG macro. */
+ /* */
+ /* offset :: The starting offset in the table (or the file if */
+ /* tag == 0). */
+ /* */
+ /* length :: The address of the decision variable: */
+ /* */
+ /* If length == NULL: */
+ /* Loads the whole table. Returns an error if */
+ /* `offset' == 0! */
+ /* */
+ /* If *length == 0: */
+ /* Exits immediately; returning the length of the given */
+ /* table or of the font file, depending on the value of */
+ /* `tag'. */
+ /* */
+ /* If *length != 0: */
+ /* Loads the next `length' bytes of table or font, */
+ /* starting at offset `offset' (in table or font too). */
+ /* */
+ /* <Output> */
+ /* buffer :: The address of target buffer. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Load_Any( TT_Face face,
+ FT_ULong tag,
+ FT_Long offset,
+ FT_Byte* buffer,
+ FT_ULong* length )
+ {
+ FT_Error error;
+ FT_Stream stream;
+ TT_Table* table;
+ FT_ULong size;
+
+
+ if ( tag != 0 )
+ {
+ /* look for tag in font directory */
+ table = TT_LookUp_Table( face, tag );
+ if ( !table )
+ {
+ error = SFNT_Err_Table_Missing;
+ goto Exit;
+ }
+
+ offset += table->Offset;
+ size = table->Length;
+ }
+ else
+ /* tag == 0 -- the user wants to access the font file directly */
+ size = face->root.stream->size;
+
+ if ( length && *length == 0 )
+ {
+ *length = size;
+
+ return SFNT_Err_Ok;
+ }
+
+ if ( length )
+ size = *length;
+
+ stream = face->root.stream;
+ /* the `if' is syntactic sugar for picky compilers */
+ if ( FILE_Read_At( offset, buffer, size ) )
+ goto Exit;
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_Generic_Header */
+ /* */
+ /* <Description> */
+ /* Loads the TrueType table `head' or `bhed'. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* stream :: The input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ TT_Load_Generic_Header( TT_Face face,
+ FT_Stream stream,
+ FT_ULong tag )
+ {
+ FT_Error error;
+ TT_Header* header;
+
+ static const FT_Frame_Field header_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_Header
+
+ FT_FRAME_START( 54 ),
+ FT_FRAME_ULONG ( Table_Version ),
+ FT_FRAME_ULONG ( Font_Revision ),
+ FT_FRAME_LONG ( CheckSum_Adjust ),
+ FT_FRAME_LONG ( Magic_Number ),
+ FT_FRAME_USHORT( Flags ),
+ FT_FRAME_USHORT( Units_Per_EM ),
+ FT_FRAME_LONG ( Created[0] ),
+ FT_FRAME_LONG ( Created[1] ),
+ FT_FRAME_LONG ( Modified[0] ),
+ FT_FRAME_LONG ( Modified[1] ),
+ FT_FRAME_SHORT ( xMin ),
+ FT_FRAME_SHORT ( yMin ),
+ FT_FRAME_SHORT ( xMax ),
+ FT_FRAME_SHORT ( yMax ),
+ FT_FRAME_USHORT( Mac_Style ),
+ FT_FRAME_USHORT( Lowest_Rec_PPEM ),
+ FT_FRAME_SHORT ( Font_Direction ),
+ FT_FRAME_SHORT ( Index_To_Loc_Format ),
+ FT_FRAME_SHORT ( Glyph_Data_Format ),
+ FT_FRAME_END
+ };
+
+
+ FT_TRACE2(( "TT_Load_Generic_Header: "
+ "%08p, looking up font table `%c%c%c%c'.\n",
+ face,
+ (FT_Char)( tag >> 24 ),
+ (FT_Char)( tag >> 16 ),
+ (FT_Char)( tag >> 8 ),
+ (FT_Char)( tag ) ));
+
+ error = face->goto_table( face, tag, stream, 0 );
+ if ( error )
+ {
+ FT_TRACE2(( "TT_Load_Generic_Table: Font table is missing!\n" ));
+ goto Exit;
+ }
+
+ header = &face->header;
+
+ if ( READ_Fields( header_fields, header ) )
+ goto Exit;
+
+ FT_TRACE2(( " Units per EM: %8u\n", header->Units_Per_EM ));
+ FT_TRACE2(( " IndexToLoc: %8d\n", header->Index_To_Loc_Format ));
+ FT_TRACE2(( "TT_Load_Generic_Table: Font table loaded.\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF FT_Error
+ TT_Load_Header( TT_Face face,
+ FT_Stream stream )
+ {
+ return TT_Load_Generic_Header( face, stream, TTAG_head );
+ }
+
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ FT_LOCAL_DEF FT_Error
+ TT_Load_Bitmap_Header( TT_Face face,
+ FT_Stream stream )
+ {
+ return TT_Load_Generic_Header( face, stream, TTAG_bhed );
+ }
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_MaxProfile */
+ /* */
+ /* <Description> */
+ /* Loads the maximum profile into a face object. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* stream :: The input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Load_MaxProfile( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ TT_MaxProfile* maxProfile = &face->max_profile;
+
+ const FT_Frame_Field maxp_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_MaxProfile
+
+ FT_FRAME_START( 6 ),
+ FT_FRAME_LONG ( version ),
+ FT_FRAME_USHORT( numGlyphs ),
+ FT_FRAME_END
+ };
+
+ const FT_Frame_Field maxp_fields_extra[] =
+ {
+ FT_FRAME_START( 26 ),
+ FT_FRAME_USHORT( maxPoints ),
+ FT_FRAME_USHORT( maxContours ),
+ FT_FRAME_USHORT( maxCompositePoints ),
+ FT_FRAME_USHORT( maxCompositeContours ),
+ FT_FRAME_USHORT( maxZones ),
+ FT_FRAME_USHORT( maxTwilightPoints ),
+ FT_FRAME_USHORT( maxStorage ),
+ FT_FRAME_USHORT( maxFunctionDefs ),
+ FT_FRAME_USHORT( maxInstructionDefs ),
+ FT_FRAME_USHORT( maxStackElements ),
+ FT_FRAME_USHORT( maxSizeOfInstructions ),
+ FT_FRAME_USHORT( maxComponentElements ),
+ FT_FRAME_USHORT( maxComponentDepth ),
+ FT_FRAME_END
+ };
+
+
+ FT_TRACE2(( "Load_TT_MaxProfile: %08p\n", face ));
+
+ error = face->goto_table( face, TTAG_maxp, stream, 0 );
+ if ( error )
+ goto Exit;
+
+ if ( READ_Fields( maxp_fields, maxProfile ) )
+ goto Exit;
+
+ maxProfile->maxPoints = 0;
+ maxProfile->maxContours = 0;
+ maxProfile->maxCompositePoints = 0;
+ maxProfile->maxCompositeContours = 0;
+ maxProfile->maxZones = 0;
+ maxProfile->maxTwilightPoints = 0;
+ maxProfile->maxStorage = 0;
+ maxProfile->maxFunctionDefs = 0;
+ maxProfile->maxInstructionDefs = 0;
+ maxProfile->maxStackElements = 0;
+ maxProfile->maxSizeOfInstructions = 0;
+ maxProfile->maxComponentElements = 0;
+ maxProfile->maxComponentDepth = 0;
+
+ if ( maxProfile->version >= 0x10000L )
+ {
+ if ( READ_Fields( maxp_fields_extra, maxProfile ) )
+ goto Exit;
+
+ /* XXX: an adjustment that is necessary to load certain */
+ /* broken fonts like `Keystrokes MT' :-( */
+ /* */
+ /* We allocate 64 function entries by default when */
+ /* the maxFunctionDefs field is null. */
+
+ if ( maxProfile->maxFunctionDefs == 0 )
+ maxProfile->maxFunctionDefs = 64;
+
+ face->root.num_glyphs = maxProfile->numGlyphs;
+
+ face->root.internal->max_points =
+ (FT_UShort)MAX( maxProfile->maxCompositePoints,
+ maxProfile->maxPoints );
+
+ face->root.internal->max_contours =
+ (FT_Short)MAX( maxProfile->maxCompositeContours,
+ maxProfile->maxContours );
+
+ face->max_components = (FT_ULong)maxProfile->maxComponentElements +
+ maxProfile->maxComponentDepth;
+
+ /* XXX: some fonts have maxComponents set to 0; we will */
+ /* then use 16 of them by default. */
+ if ( face->max_components == 0 )
+ face->max_components = 16;
+
+ /* We also increase maxPoints and maxContours in order to support */
+ /* some broken fonts. */
+ face->root.internal->max_points += 8;
+ face->root.internal->max_contours += 4;
+ }
+
+ FT_TRACE2(( "MAXP loaded.\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_Metrics */
+ /* */
+ /* <Description> */
+ /* Loads the horizontal or vertical metrics table into a face object. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* stream :: The input stream. */
+ /* vertical :: A boolean flag. If set, load vertical metrics. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ TT_Load_Metrics( TT_Face face,
+ FT_Stream stream,
+ FT_Bool vertical )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+
+ FT_ULong table_len;
+ FT_Long num_shorts, num_longs, num_shorts_checked;
+
+ TT_LongMetrics** longs;
+ TT_ShortMetrics** shorts;
+
+
+ FT_TRACE2(( "TT_Load_%s_Metrics: %08p\n", vertical ? "Vertical"
+ : "Horizontal",
+ face ));
+
+ if ( vertical )
+ {
+ /* The table is optional, quit silently if it wasn't found */
+ /* XXX: Some fonts have a valid vertical header with a non-null */
+ /* `number_of_VMetrics' fields, but no corresponding `vmtx' */
+ /* table to get the metrics from (e.g. mingliu). */
+ /* */
+ /* For safety, we set the field to 0! */
+ /* */
+ error = face->goto_table( face, TTAG_vmtx, stream, &table_len );
+ if ( error )
+ {
+ /* Set number_Of_VMetrics to 0! */
+ FT_TRACE2(( " no vertical header in file.\n" ));
+ face->vertical.number_Of_VMetrics = 0;
+ error = SFNT_Err_Ok;
+ goto Exit;
+ }
+
+ num_longs = face->vertical.number_Of_VMetrics;
+ longs = (TT_LongMetrics**)&face->vertical.long_metrics;
+ shorts = (TT_ShortMetrics**)&face->vertical.short_metrics;
+ }
+ else
+ {
+ error = face->goto_table( face, TTAG_hmtx, stream, &table_len );
+ if ( error )
+ {
+ FT_ERROR(( " no horizontal metrics in file!\n" ));
+ error = SFNT_Err_Hmtx_Table_Missing;
+ goto Exit;
+ }
+
+ num_longs = face->horizontal.number_Of_HMetrics;
+ longs = (TT_LongMetrics**)&face->horizontal.long_metrics;
+ shorts = (TT_ShortMetrics**)&face->horizontal.short_metrics;
+ }
+
+ /* never trust derived values */
+
+ num_shorts = face->max_profile.numGlyphs - num_longs;
+ num_shorts_checked = ( table_len - num_longs * 4L ) / 2;
+
+ if ( num_shorts < 0 )
+ {
+ FT_ERROR(( "TT_Load_%s_Metrics: more metrics than glyphs!\n",
+ vertical ? "Vertical"
+ : "Horizontal" ));
+
+ error = vertical ? SFNT_Err_Invalid_Vert_Metrics
+ : SFNT_Err_Invalid_Horiz_Metrics;
+ goto Exit;
+ }
+
+ if ( ALLOC_ARRAY( *longs, num_longs, TT_LongMetrics ) ||
+ ALLOC_ARRAY( *shorts, num_shorts, TT_ShortMetrics ) )
+ goto Exit;
+
+ if ( ACCESS_Frame( table_len ) )
+ goto Exit;
+
+ {
+ TT_LongMetrics* cur = *longs;
+ TT_LongMetrics* limit = cur + num_longs;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ cur->advance = GET_UShort();
+ cur->bearing = GET_Short();
+ }
+ }
+
+ /* do we have an inconsistent number of metric values? */
+ {
+ TT_ShortMetrics* cur = *shorts;
+ TT_ShortMetrics* limit = cur + MIN( num_shorts, num_shorts_checked );
+
+
+ for ( ; cur < limit; cur++ )
+ *cur = GET_Short();
+
+ /* we fill up the missing left side bearings with the */
+ /* last valid value. Since this will occur for buggy CJK */
+ /* fonts usually only, nothing serious will happen */
+ if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 )
+ {
+ FT_Short val = (*shorts)[num_shorts_checked - 1];
+
+
+ limit = *shorts + num_shorts;
+ for ( ; cur < limit; cur++ )
+ *cur = val;
+ }
+ }
+
+ FORGET_Frame();
+
+ FT_TRACE2(( "loaded\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_Metrics_Header */
+ /* */
+ /* <Description> */
+ /* Loads the horizontal or vertical header in a face object. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* stream :: The input stream. */
+ /* vertical :: A boolean flag. If set, load vertical metrics. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Load_Metrics_Header( TT_Face face,
+ FT_Stream stream,
+ FT_Bool vertical )
+ {
+ FT_Error error;
+ TT_HoriHeader* header;
+
+ const FT_Frame_Field metrics_header_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_HoriHeader
+
+ FT_FRAME_START( 36 ),
+ FT_FRAME_ULONG ( Version ),
+ FT_FRAME_SHORT ( Ascender ),
+ FT_FRAME_SHORT ( Descender ),
+ FT_FRAME_SHORT ( Line_Gap ),
+ FT_FRAME_USHORT( advance_Width_Max ),
+ FT_FRAME_SHORT ( min_Left_Side_Bearing ),
+ FT_FRAME_SHORT ( min_Right_Side_Bearing ),
+ FT_FRAME_SHORT ( xMax_Extent ),
+ FT_FRAME_SHORT ( caret_Slope_Rise ),
+ FT_FRAME_SHORT ( caret_Slope_Run ),
+ FT_FRAME_SHORT ( caret_Offset ),
+ FT_FRAME_SHORT ( Reserved[0] ),
+ FT_FRAME_SHORT ( Reserved[1] ),
+ FT_FRAME_SHORT ( Reserved[2] ),
+ FT_FRAME_SHORT ( Reserved[3] ),
+ FT_FRAME_SHORT ( metric_Data_Format ),
+ FT_FRAME_USHORT( number_Of_HMetrics ),
+ FT_FRAME_END
+ };
+
+
+ FT_TRACE2(( vertical ? "Vertical header " : "Horizontal header " ));
+
+ if ( vertical )
+ {
+ face->vertical_info = 0;
+
+ /* The vertical header table is optional, so return quietly if */
+ /* we don't find it. */
+ error = face->goto_table( face, TTAG_vhea, stream, 0 );
+ if ( error )
+ {
+ error = SFNT_Err_Ok;
+ goto Exit;
+ }
+
+ face->vertical_info = 1;
+ header = (TT_HoriHeader*)&face->vertical;
+ }
+ else
+ {
+ /* The horizontal header is mandatory; return an error if we */
+ /* don't find it. */
+ error = face->goto_table( face, TTAG_hhea, stream, 0 );
+ if ( error )
+ {
+ error = SFNT_Err_Horiz_Header_Missing;
+ goto Exit;
+ }
+
+ header = &face->horizontal;
+ }
+
+ if ( READ_Fields( metrics_header_fields, header ) )
+ goto Exit;
+
+ header->long_metrics = NULL;
+ header->short_metrics = NULL;
+
+ FT_TRACE2(( "loaded\n" ));
+
+ /* Now try to load the corresponding metrics */
+
+ error = TT_Load_Metrics( face, stream, vertical );
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_Names */
+ /* */
+ /* <Description> */
+ /* Loads the name records. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* stream :: The input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Load_Names( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+
+ FT_ULong table_pos, table_len;
+ FT_ULong storageSize;
+
+ TT_NameTable* names;
+
+ const FT_Frame_Field name_table_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_NameTable
+
+ FT_FRAME_START( 6 ),
+ FT_FRAME_USHORT( format ),
+ FT_FRAME_USHORT( numNameRecords ),
+ FT_FRAME_USHORT( storageOffset ),
+ FT_FRAME_END
+ };
+
+ const FT_Frame_Field name_record_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_NameRec
+
+ /* no FT_FRAME_START */
+ FT_FRAME_USHORT( platformID ),
+ FT_FRAME_USHORT( encodingID ),
+ FT_FRAME_USHORT( languageID ),
+ FT_FRAME_USHORT( nameID ),
+ FT_FRAME_USHORT( stringLength ),
+ FT_FRAME_USHORT( stringOffset ),
+ FT_FRAME_END
+ };
+
+
+ FT_TRACE2(( "Names " ));
+
+ error = face->goto_table( face, TTAG_name, stream, &table_len );
+ if ( error )
+ {
+ /* The name table is required so indicate failure. */
+ FT_TRACE2(( "is missing!\n" ));
+ error = SFNT_Err_Name_Table_Missing;
+ goto Exit;
+ }
+
+ table_pos = FILE_Pos();
+
+ names = &face->name_table;
+
+ if ( READ_Fields( name_table_fields, names ) )
+ goto Exit;
+
+ /* Allocate the array of name records. */
+ if ( ALLOC_ARRAY( names->names,
+ names->numNameRecords,
+ TT_NameRec ) ||
+ ACCESS_Frame( names->numNameRecords * 12L ) )
+ goto Exit;
+
+ /* Load the name records and determine how much storage is needed */
+ /* to hold the strings themselves. */
+ {
+ TT_NameRec* cur = names->names;
+ TT_NameRec* limit = cur + names->numNameRecords;
+
+
+ storageSize = 0;
+
+ for ( ; cur < limit; cur ++ )
+ {
+ FT_ULong upper;
+
+
+ if ( READ_Fields( name_record_fields, cur ) )
+ break;
+
+ upper = (FT_ULong)( cur->stringOffset + cur->stringLength );
+ if ( upper > storageSize )
+ storageSize = upper;
+ }
+ }
+
+ FORGET_Frame();
+
+ if ( storageSize > 0 )
+ {
+ /* allocate the name storage area in memory, then read it */
+ if ( ALLOC( names->storage, storageSize ) ||
+ FILE_Read_At( table_pos + names->storageOffset,
+ names->storage, storageSize ) )
+ goto Exit;
+
+ /* Go through and assign the string pointers to the name records. */
+ {
+ TT_NameRec* cur = names->names;
+ TT_NameRec* limit = cur + names->numNameRecords;
+
+
+ for ( ; cur < limit; cur++ )
+ cur->string = names->storage + cur->stringOffset;
+ }
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+
+ /* Print Name Record Table in case of debugging */
+ {
+ TT_NameRec* cur = names->names;
+ TT_NameRec* limit = cur + names->numNameRecords;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ FT_UInt j;
+
+
+ FT_TRACE3(( "%d %d %x %d\n ",
+ cur->platformID,
+ cur->encodingID,
+ cur->languageID,
+ cur->nameID ));
+
+ /* I know that M$ encoded strings are Unicode, */
+ /* but this works reasonable well for debugging purposes. */
+ if ( cur->string )
+ for ( j = 0; j < (FT_UInt)cur->stringLength; j++ )
+ {
+ FT_Char c = *( cur->string + j );
+
+
+ if ( (FT_Byte)c < 128 )
+ FT_TRACE3(( "%c", c ));
+ }
+ }
+ }
+ FT_TRACE3(( "\n" ));
+
+#endif /* FT_DEBUG_LEVEL_TRACE */
+
+ }
+ FT_TRACE2(( "loaded\n" ));
+
+ /* everything went well, update face->num_names */
+ face->num_names = names->numNameRecords;
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Free_Names */
+ /* */
+ /* <Description> */
+ /* Frees the name records. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ FT_LOCAL_DEF void
+ TT_Free_Names( TT_Face face )
+ {
+ FT_Memory memory = face->root.driver->root.memory;
+ TT_NameTable* names = &face->name_table;
+
+
+ /* free strings table */
+ FREE( names->names );
+
+ /* free strings storage */
+ FREE( names->storage );
+
+ names->numNameRecords = 0;
+ names->format = 0;
+ names->storageOffset = 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_CMap */
+ /* */
+ /* <Description> */
+ /* Loads the cmap directory in a face object. The cmaps itselves are */
+ /* loaded on demand in the `ttcmap.c' module. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* stream :: A handle to the input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Load_CMap( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+ FT_Long table_start;
+ TT_CMapDir cmap_dir;
+
+ const FT_Frame_Field cmap_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_CMapDir
+
+ FT_FRAME_START( 4 ),
+ FT_FRAME_USHORT( tableVersionNumber ),
+ FT_FRAME_USHORT( numCMaps ),
+ FT_FRAME_END
+ };
+
+ const FT_Frame_Field cmap_rec_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_CMapTable
+
+ FT_FRAME_START( 4 ),
+ FT_FRAME_USHORT( format ),
+ FT_FRAME_USHORT( length ),
+ FT_FRAME_END
+ };
+
+
+ FT_TRACE2(( "CMaps " ));
+
+ error = face->goto_table( face, TTAG_cmap, stream, 0 );
+ if ( error )
+ {
+ error = SFNT_Err_CMap_Table_Missing;
+ goto Exit;
+ }
+
+ table_start = FILE_Pos();
+
+ if ( READ_Fields( cmap_fields, &cmap_dir ) )
+ goto Exit;
+
+ /* reserve space in face table for cmap tables */
+ if ( ALLOC_ARRAY( face->charmaps,
+ cmap_dir.numCMaps,
+ TT_CharMapRec ) )
+ goto Exit;
+
+ face->num_charmaps = cmap_dir.numCMaps;
+ {
+ TT_CharMap charmap = face->charmaps;
+ TT_CharMap limit = charmap + face->num_charmaps;
+
+
+ /* read the header of each charmap first */
+ if ( ACCESS_Frame( face->num_charmaps * 8L ) )
+ goto Exit;
+
+ for ( ; charmap < limit; charmap++ )
+ {
+ TT_CMapTable* cmap;
+
+
+ charmap->root.face = (FT_Face)face;
+ cmap = &charmap->cmap;
+
+ cmap->loaded = FALSE;
+ cmap->platformID = GET_UShort();
+ cmap->platformEncodingID = GET_UShort();
+ cmap->offset = (FT_ULong)GET_Long();
+ }
+
+ FORGET_Frame();
+
+ /* now read the rest of each table */
+ for ( charmap = face->charmaps; charmap < limit; charmap++ )
+ {
+ TT_CMapTable* cmap = &charmap->cmap;
+
+
+ if ( FILE_Seek( table_start + (FT_Long)cmap->offset ) ||
+ READ_Fields( cmap_rec_fields, cmap ) )
+ goto Exit;
+
+ cmap->offset = FILE_Pos();
+ }
+ }
+
+ FT_TRACE2(( "loaded\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_OS2 */
+ /* */
+ /* <Description> */
+ /* Loads the OS2 table. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* stream :: A handle to the input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Load_OS2( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ TT_OS2* os2;
+
+ const FT_Frame_Field os2_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_OS2
+
+ FT_FRAME_START( 78 ),
+ FT_FRAME_USHORT( version ),
+ FT_FRAME_SHORT ( xAvgCharWidth ),
+ FT_FRAME_USHORT( usWeightClass ),
+ FT_FRAME_USHORT( usWidthClass ),
+ FT_FRAME_SHORT ( fsType ),
+ FT_FRAME_SHORT ( ySubscriptXSize ),
+ FT_FRAME_SHORT ( ySubscriptYSize ),
+ FT_FRAME_SHORT ( ySubscriptXOffset ),
+ FT_FRAME_SHORT ( ySubscriptYOffset ),
+ FT_FRAME_SHORT ( ySuperscriptXSize ),
+ FT_FRAME_SHORT ( ySuperscriptYSize ),
+ FT_FRAME_SHORT ( ySuperscriptXOffset ),
+ FT_FRAME_SHORT ( ySuperscriptYOffset ),
+ FT_FRAME_SHORT ( yStrikeoutSize ),
+ FT_FRAME_SHORT ( yStrikeoutPosition ),
+ FT_FRAME_SHORT ( sFamilyClass ),
+ FT_FRAME_BYTE ( panose[0] ),
+ FT_FRAME_BYTE ( panose[1] ),
+ FT_FRAME_BYTE ( panose[2] ),
+ FT_FRAME_BYTE ( panose[3] ),
+ FT_FRAME_BYTE ( panose[4] ),
+ FT_FRAME_BYTE ( panose[5] ),
+ FT_FRAME_BYTE ( panose[6] ),
+ FT_FRAME_BYTE ( panose[7] ),
+ FT_FRAME_BYTE ( panose[8] ),
+ FT_FRAME_BYTE ( panose[9] ),
+ FT_FRAME_ULONG ( ulUnicodeRange1 ),
+ FT_FRAME_ULONG ( ulUnicodeRange2 ),
+ FT_FRAME_ULONG ( ulUnicodeRange3 ),
+ FT_FRAME_ULONG ( ulUnicodeRange4 ),
+ FT_FRAME_BYTE ( achVendID[0] ),
+ FT_FRAME_BYTE ( achVendID[1] ),
+ FT_FRAME_BYTE ( achVendID[2] ),
+ FT_FRAME_BYTE ( achVendID[3] ),
+
+ FT_FRAME_USHORT( fsSelection ),
+ FT_FRAME_USHORT( usFirstCharIndex ),
+ FT_FRAME_USHORT( usLastCharIndex ),
+ FT_FRAME_SHORT ( sTypoAscender ),
+ FT_FRAME_SHORT ( sTypoDescender ),
+ FT_FRAME_SHORT ( sTypoLineGap ),
+ FT_FRAME_USHORT( usWinAscent ),
+ FT_FRAME_USHORT( usWinDescent ),
+ FT_FRAME_END
+ };
+
+ const FT_Frame_Field os2_fields_extra[] =
+ {
+ FT_FRAME_START( 8 ),
+ FT_FRAME_ULONG( ulCodePageRange1 ),
+ FT_FRAME_ULONG( ulCodePageRange2 ),
+ FT_FRAME_END
+ };
+
+ const FT_Frame_Field os2_fields_extra2[] =
+ {
+ FT_FRAME_START( 10 ),
+ FT_FRAME_SHORT ( sxHeight ),
+ FT_FRAME_SHORT ( sCapHeight ),
+ FT_FRAME_USHORT( usDefaultChar ),
+ FT_FRAME_USHORT( usBreakChar ),
+ FT_FRAME_USHORT( usMaxContext ),
+ FT_FRAME_END
+ };
+
+
+ FT_TRACE2(( "OS/2 Table " ));
+
+ /* We now support old Mac fonts where the OS/2 table doesn't */
+ /* exist. Simply put, we set the `version' field to 0xFFFF */
+ /* and test this value each time we need to access the table. */
+ error = face->goto_table( face, TTAG_OS2, stream, 0 );
+ if ( error )
+ {
+ FT_TRACE2(( "is missing!\n" ));
+ face->os2.version = 0xFFFF;
+ error = SFNT_Err_Ok;
+ goto Exit;
+ }
+
+ os2 = &face->os2;
+
+ if ( READ_Fields( os2_fields, os2 ) )
+ goto Exit;
+
+ os2->ulCodePageRange1 = 0;
+ os2->ulCodePageRange2 = 0;
+ os2->sxHeight = 0;
+ os2->sCapHeight = 0;
+ os2->usDefaultChar = 0;
+ os2->usBreakChar = 0;
+ os2->usMaxContext = 0;
+
+ if ( os2->version >= 0x0001 )
+ {
+ /* only version 1 tables */
+ if ( READ_Fields( os2_fields_extra, os2 ) )
+ goto Exit;
+
+ if ( os2->version >= 0x0002 )
+ {
+ /* only version 2 tables */
+ if ( READ_Fields( os2_fields_extra2, os2 ) )
+ goto Exit;
+ }
+ }
+
+ FT_TRACE2(( "loaded\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_Postscript */
+ /* */
+ /* <Description> */
+ /* Loads the Postscript table. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* stream :: A handle to the input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Load_PostScript( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ TT_Postscript* post = &face->postscript;
+
+ static const FT_Frame_Field post_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_Postscript
+
+ FT_FRAME_START( 32 ),
+ FT_FRAME_ULONG( FormatType ),
+ FT_FRAME_ULONG( italicAngle ),
+ FT_FRAME_SHORT( underlinePosition ),
+ FT_FRAME_SHORT( underlineThickness ),
+ FT_FRAME_ULONG( isFixedPitch ),
+ FT_FRAME_ULONG( minMemType42 ),
+ FT_FRAME_ULONG( maxMemType42 ),
+ FT_FRAME_ULONG( minMemType1 ),
+ FT_FRAME_ULONG( maxMemType1 ),
+ FT_FRAME_END
+ };
+
+
+ FT_TRACE2(( "PostScript " ));
+
+ error = face->goto_table( face, TTAG_post, stream, 0 );
+ if ( error )
+ return SFNT_Err_Post_Table_Missing;
+
+ if ( READ_Fields( post_fields, post ) )
+ return error;
+
+ /* we don't load the glyph names, we do that in another */
+ /* module (ttpost). */
+ FT_TRACE2(( "loaded\n" ));
+
+ return SFNT_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_PCLT */
+ /* */
+ /* <Description> */
+ /* Loads the PCL 5 Table. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* stream :: A handle to the input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Load_PCLT( TT_Face face,
+ FT_Stream stream )
+ {
+ static const FT_Frame_Field pclt_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_PCLT
+
+ FT_FRAME_START( 54 ),
+ FT_FRAME_ULONG ( Version ),
+ FT_FRAME_ULONG ( FontNumber ),
+ FT_FRAME_USHORT( Pitch ),
+ FT_FRAME_USHORT( xHeight ),
+ FT_FRAME_USHORT( Style ),
+ FT_FRAME_USHORT( TypeFamily ),
+ FT_FRAME_USHORT( CapHeight ),
+ FT_FRAME_BYTES ( TypeFace, 16 ),
+ FT_FRAME_BYTES ( CharacterComplement, 8 ),
+ FT_FRAME_BYTES ( FileName, 6 ),
+ FT_FRAME_CHAR ( StrokeWeight ),
+ FT_FRAME_CHAR ( WidthType ),
+ FT_FRAME_BYTE ( SerifStyle ),
+ FT_FRAME_BYTE ( Reserved ),
+ FT_FRAME_END
+ };
+
+ FT_Error error;
+ TT_PCLT* pclt = &face->pclt;
+
+
+ FT_TRACE2(( "PCLT " ));
+
+ /* optional table */
+ error = face->goto_table( face, TTAG_PCLT, stream, 0 );
+ if ( error )
+ {
+ FT_TRACE2(( "missing (optional)\n" ));
+ pclt->Version = 0;
+ return SFNT_Err_Ok;
+ }
+
+ if ( READ_Fields( pclt_fields, pclt ) )
+ goto Exit;
+
+ FT_TRACE2(( "loaded\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_Gasp */
+ /* */
+ /* <Description> */
+ /* Loads the `gasp' table into a face object. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* stream :: The input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Load_Gasp( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+
+ FT_UInt j,num_ranges;
+ TT_GaspRange* gaspranges;
+
+
+ FT_TRACE2(( "TT_Load_Gasp: %08p\n", face ));
+
+ /* the gasp table is optional */
+ error = face->goto_table( face, TTAG_gasp, stream, 0 );
+ if ( error )
+ return SFNT_Err_Ok;
+
+ if ( ACCESS_Frame( 4L ) )
+ goto Exit;
+
+ face->gasp.version = GET_UShort();
+ face->gasp.numRanges = GET_UShort();
+
+ FORGET_Frame();
+
+ num_ranges = face->gasp.numRanges;
+ FT_TRACE3(( "number of ranges = %d\n", num_ranges ));
+
+ if ( ALLOC_ARRAY( gaspranges, num_ranges, TT_GaspRange ) ||
+ ACCESS_Frame( num_ranges * 4L ) )
+ goto Exit;
+
+ face->gasp.gaspRanges = gaspranges;
+
+ for ( j = 0; j < num_ranges; j++ )
+ {
+ gaspranges[j].maxPPEM = GET_UShort();
+ gaspranges[j].gaspFlag = GET_UShort();
+
+ FT_TRACE3(( " [max:%d flag:%d]",
+ gaspranges[j].maxPPEM,
+ gaspranges[j].gaspFlag ));
+ }
+ FT_TRACE3(( "\n" ));
+
+ FORGET_Frame();
+ FT_TRACE2(( "GASP loaded\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( int )
+ tt_kern_pair_compare( const void* a,
+ const void* b );
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_Kern */
+ /* */
+ /* <Description> */
+ /* Loads the first kerning table with format 0 in the font. Only */
+ /* accepts the first horizontal kerning table. Developers should use */
+ /* the `ftxkern' extension to access other kerning tables in the font */
+ /* file, if they really want to. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* stream :: The input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Load_Kern( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+
+ FT_UInt n, num_tables;
+
+
+ /* the kern table is optional; exit silently if it is missing */
+ error = face->goto_table( face, TTAG_kern, stream, 0 );
+ if ( error )
+ return SFNT_Err_Ok;
+
+ if ( ACCESS_Frame( 4L ) )
+ goto Exit;
+
+ (void)GET_UShort(); /* version */
+ num_tables = GET_UShort();
+
+ FORGET_Frame();
+
+ for ( n = 0; n < num_tables; n++ )
+ {
+ FT_UInt coverage;
+ FT_UInt length;
+
+
+ if ( ACCESS_Frame( 6L ) )
+ goto Exit;
+
+ (void)GET_UShort(); /* version */
+ length = GET_UShort() - 6; /* substract header length */
+ coverage = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( coverage == 0x0001 )
+ {
+ FT_UInt num_pairs;
+ TT_Kern_0_Pair* pair;
+ TT_Kern_0_Pair* limit;
+
+
+ /* found a horizontal format 0 kerning table! */
+ if ( ACCESS_Frame( 8L ) )
+ goto Exit;
+
+ num_pairs = GET_UShort();
+
+ /* skip the rest */
+
+ FORGET_Frame();
+
+ /* allocate array of kerning pairs */
+ if ( ALLOC_ARRAY( face->kern_pairs, num_pairs, TT_Kern_0_Pair ) ||
+ ACCESS_Frame( 6L * num_pairs ) )
+ goto Exit;
+
+ pair = face->kern_pairs;
+ limit = pair + num_pairs;
+ for ( ; pair < limit; pair++ )
+ {
+ pair->left = GET_UShort();
+ pair->right = GET_UShort();
+ pair->value = GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ face->num_kern_pairs = num_pairs;
+ face->kern_table_index = n;
+
+ /* ensure that the kerning pair table is sorted (yes, some */
+ /* fonts have unsorted tables!) */
+ {
+ FT_UInt i;
+ TT_Kern_0_Pair* pair0;
+
+
+ pair0 = face->kern_pairs;
+
+ for ( i = 1; i < num_pairs; i++, pair0++ )
+ {
+ if ( tt_kern_pair_compare( pair0, pair0 + 1 ) != -1 )
+ {
+ qsort( (void*)face->kern_pairs, (int)num_pairs,
+ sizeof ( TT_Kern_0_Pair ), tt_kern_pair_compare );
+ break;
+ }
+ }
+ }
+
+ goto Exit;
+ }
+
+ if ( FILE_Skip( length ) )
+ goto Exit;
+ }
+
+ /* no kern table found -- doesn't matter */
+ face->kern_table_index = -1;
+ face->num_kern_pairs = 0;
+ face->kern_pairs = NULL;
+
+ Exit:
+ return error;
+ }
+
+
+#undef TT_KERN_INDEX
+#define TT_KERN_INDEX( g1, g2 ) ( ( (FT_ULong)g1 << 16 ) | g2 )
+
+ FT_CALLBACK_DEF( int )
+ tt_kern_pair_compare( const void* a,
+ const void* b )
+ {
+ TT_Kern_0_Pair* pair1 = (TT_Kern_0_Pair*)a;
+ TT_Kern_0_Pair* pair2 = (TT_Kern_0_Pair*)b;
+
+ FT_ULong index1 = TT_KERN_INDEX( pair1->left, pair1->right );
+ FT_ULong index2 = TT_KERN_INDEX( pair2->left, pair2->right );
+
+
+ return ( index1 < index2 ? -1 :
+ ( index1 > index2 ? 1 : 0 ));
+ }
+
+#undef TT_KERN_INDEX
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_Hdmx */
+ /* */
+ /* <Description> */
+ /* Loads the horizontal device metrics table. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* stream :: A handle to the input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Load_Hdmx( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+
+ TT_Hdmx* hdmx = &face->hdmx;
+ FT_Long num_glyphs;
+ FT_Long record_size;
+
+
+ hdmx->version = 0;
+ hdmx->num_records = 0;
+ hdmx->records = 0;
+
+ /* this table is optional */
+ error = face->goto_table( face, TTAG_hdmx, stream, 0 );
+ if ( error )
+ return SFNT_Err_Ok;
+
+ if ( ACCESS_Frame( 8L ) )
+ goto Exit;
+
+ hdmx->version = GET_UShort();
+ hdmx->num_records = GET_Short();
+ record_size = GET_Long();
+
+ FORGET_Frame();
+
+ /* Only recognize format 0 */
+ if ( hdmx->version != 0 )
+ goto Exit;
+
+ if ( ALLOC_ARRAY( hdmx->records, hdmx->num_records, TT_HdmxRec ) )
+ goto Exit;
+
+ num_glyphs = face->root.num_glyphs;
+ record_size -= num_glyphs + 2;
+
+ {
+ TT_HdmxRec* cur = hdmx->records;
+ TT_HdmxRec* limit = cur + hdmx->num_records;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ /* read record */
+ if ( READ_Byte( cur->ppem ) ||
+ READ_Byte( cur->max_width ) )
+ goto Exit;
+
+ if ( ALLOC( cur->widths, num_glyphs ) ||
+ FILE_Read( cur->widths, num_glyphs ) )
+ goto Exit;
+
+ /* skip padding bytes */
+ if ( record_size > 0 && FILE_Skip( record_size ) )
+ goto Exit;
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Free_Hdmx */
+ /* */
+ /* <Description> */
+ /* Frees the horizontal device metrics table. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the target face object. */
+ /* */
+ FT_LOCAL_DEF void
+ TT_Free_Hdmx( TT_Face face )
+ {
+ if ( face )
+ {
+ FT_Int n;
+ FT_Memory memory = face->root.driver->root.memory;
+
+
+ for ( n = 0; n < face->hdmx.num_records; n++ )
+ FREE( face->hdmx.records[n].widths );
+
+ FREE( face->hdmx.records );
+ face->hdmx.num_records = 0;
+ }
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ttobjs.c */
+/* */
+/* Objects manager (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_IDS_H
+#include FT_TRUETYPE_TAGS_H
+#include FT_INTERNAL_SFNT_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+#include "ttgload.h"
+#include "ttpload.h"
+
+#include "tterrors.h"
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+#include "ttinterp.h"
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ttobjs
+
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ /*************************************************************************/
+ /* */
+ /* GLYPH ZONE FUNCTIONS */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Done_GlyphZone */
+ /* */
+ /* <Description> */
+ /* Deallocates a glyph zone. */
+ /* */
+ /* <Input> */
+ /* zone :: A pointer to the target glyph zone. */
+ /* */
+ FT_LOCAL_DEF void
+ TT_Done_GlyphZone( TT_GlyphZone* zone )
+ {
+ FT_Memory memory = zone->memory;
+
+
+ FREE( zone->contours );
+ FREE( zone->tags );
+ FREE( zone->cur );
+ FREE( zone->org );
+
+ zone->max_points = zone->n_points = 0;
+ zone->max_contours = zone->n_contours = 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_New_GlyphZone */
+ /* */
+ /* <Description> */
+ /* Allocates a new glyph zone. */
+ /* */
+ /* <Input> */
+ /* memory :: A handle to the current memory object. */
+ /* */
+ /* maxPoints :: The capacity of glyph zone in points. */
+ /* */
+ /* maxContours :: The capacity of glyph zone in contours. */
+ /* */
+ /* <Output> */
+ /* zone :: A pointer to the target glyph zone record. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_New_GlyphZone( FT_Memory memory,
+ FT_UShort maxPoints,
+ FT_Short maxContours,
+ TT_GlyphZone* zone )
+ {
+ FT_Error error;
+
+
+ if ( maxPoints > 0 )
+ maxPoints += 2;
+
+ MEM_Set( zone, 0, sizeof ( *zone ) );
+ zone->memory = memory;
+
+ if ( ALLOC_ARRAY( zone->org, maxPoints * 2, FT_F26Dot6 ) ||
+ ALLOC_ARRAY( zone->cur, maxPoints * 2, FT_F26Dot6 ) ||
+ ALLOC_ARRAY( zone->tags, maxPoints, FT_Byte ) ||
+ ALLOC_ARRAY( zone->contours, maxContours, FT_UShort ) )
+ {
+ TT_Done_GlyphZone( zone );
+ }
+
+ return error;
+ }
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Init_Face */
+ /* */
+ /* <Description> */
+ /* Initializes a given TrueType face object. */
+ /* */
+ /* <Input> */
+ /* stream :: The source font stream. */
+ /* */
+ /* face_index :: The index of the font face in the resource. */
+ /* */
+ /* num_params :: Number of additional generic parameters. Ignored. */
+ /* */
+ /* params :: Additional generic parameters. Ignored. */
+ /* */
+ /* <InOut> */
+ /* face :: The newly built face object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Init_Face( FT_Stream stream,
+ TT_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ FT_Error error;
+ FT_Library library;
+ SFNT_Interface* sfnt;
+
+
+ library = face->root.driver->root.library;
+ sfnt = (SFNT_Interface*)FT_Get_Module_Interface( library, "sfnt" );
+ if ( !sfnt )
+ goto Bad_Format;
+
+ /* create input stream from resource */
+ if ( FILE_Seek( 0 ) )
+ goto Exit;
+
+ /* check that we have a valid TrueType file */
+ error = sfnt->init_face( stream, face, face_index, num_params, params );
+ if ( error )
+ goto Exit;
+
+ /* We must also be able to accept Mac/GX fonts, as well as OT ones */
+ if ( face->format_tag != 0x00010000L && /* MS fonts */
+ face->format_tag != TTAG_true ) /* Mac fonts */
+ {
+ FT_TRACE2(( "[not a valid TTF font]\n" ));
+ goto Bad_Format;
+ }
+
+ /* If we are performing a simple font format check, exit immediately */
+ if ( face_index < 0 )
+ return TT_Err_Ok;
+
+ /* Load font directory */
+ error = sfnt->load_face( stream, face, face_index, num_params, params );
+ if ( error )
+ goto Exit;
+
+ if ( face->root.face_flags & FT_FACE_FLAG_SCALABLE )
+ error = TT_Load_Locations( face, stream ) ||
+ TT_Load_CVT ( face, stream ) ||
+ TT_Load_Programs ( face, stream );
+
+ /* initialize standard glyph loading routines */
+ TT_Init_Glyph_Loading( face );
+
+ Exit:
+ return error;
+
+ Bad_Format:
+ error = TT_Err_Unknown_File_Format;
+ goto Exit;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Done_Face */
+ /* */
+ /* <Description> */
+ /* Finalizes a given face object. */
+ /* */
+ /* <Input> */
+ /* face :: A pointer to the face object to destroy. */
+ /* */
+ FT_LOCAL_DEF void
+ TT_Done_Face( TT_Face face )
+ {
+ FT_Memory memory = face->root.memory;
+ FT_Stream stream = face->root.stream;
+
+ SFNT_Interface* sfnt = (SFNT_Interface*)face->sfnt;
+
+
+ /* for `extended TrueType formats' (i.e. compressed versions) */
+ if ( face->extra.finalizer )
+ face->extra.finalizer( face->extra.data );
+
+ if ( sfnt )
+ sfnt->done_face( face );
+
+ /* freeing the locations table */
+ FREE( face->glyph_locations );
+ face->num_locations = 0;
+
+ /* freeing the CVT */
+ FREE( face->cvt );
+ face->cvt_size = 0;
+
+ /* freeing the programs */
+ RELEASE_Frame( face->font_program );
+ RELEASE_Frame( face->cvt_program );
+ face->font_program_size = 0;
+ face->cvt_program_size = 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* SIZE FUNCTIONS */
+ /* */
+ /*************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Init_Size */
+ /* */
+ /* <Description> */
+ /* Initializes a new TrueType size object. */
+ /* */
+ /* <InOut> */
+ /* size :: A handle to the size object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Init_Size( TT_Size size )
+ {
+ FT_Error error = TT_Err_Ok;
+
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ TT_Face face = (TT_Face)size->root.face;
+ FT_Memory memory = face->root.memory;
+ FT_Int i;
+
+ TT_ExecContext exec;
+ FT_UShort n_twilight;
+ TT_MaxProfile* maxp = &face->max_profile;
+
+
+ size->ttmetrics.valid = FALSE;
+
+ size->max_function_defs = maxp->maxFunctionDefs;
+ size->max_instruction_defs = maxp->maxInstructionDefs;
+
+ size->num_function_defs = 0;
+ size->num_instruction_defs = 0;
+
+ size->max_func = 0;
+ size->max_ins = 0;
+
+ size->cvt_size = face->cvt_size;
+ size->storage_size = maxp->maxStorage;
+
+ /* Set default metrics */
+ {
+ FT_Size_Metrics* metrics = &size->root.metrics;
+ TT_Size_Metrics* metrics2 = &size->ttmetrics;
+
+
+ metrics->x_ppem = 0;
+ metrics->y_ppem = 0;
+
+ metrics2->rotated = FALSE;
+ metrics2->stretched = FALSE;
+
+ /* set default compensation (all 0) */
+ for ( i = 0; i < 4; i++ )
+ metrics2->compensations[i] = 0;
+ }
+
+ /* allocate function defs, instruction defs, cvt, and storage area */
+ if ( ALLOC_ARRAY( size->function_defs,
+ size->max_function_defs,
+ TT_DefRecord ) ||
+
+ ALLOC_ARRAY( size->instruction_defs,
+ size->max_instruction_defs,
+ TT_DefRecord ) ||
+
+ ALLOC_ARRAY( size->cvt,
+ size->cvt_size, FT_Long ) ||
+
+ ALLOC_ARRAY( size->storage,
+ size->storage_size, FT_Long ) )
+
+ goto Fail_Memory;
+
+ /* reserve twilight zone */
+ n_twilight = maxp->maxTwilightPoints;
+ error = TT_New_GlyphZone( memory, n_twilight, 0, &size->twilight );
+ if ( error )
+ goto Fail_Memory;
+
+ size->twilight.n_points = n_twilight;
+
+ /* set `face->interpreter' according to the debug hook present */
+ {
+ FT_Library library = face->root.driver->root.library;
+
+
+ face->interpreter = (TT_Interpreter)
+ library->debug_hooks[FT_DEBUG_HOOK_TRUETYPE];
+ if ( !face->interpreter )
+ face->interpreter = (TT_Interpreter)TT_RunIns;
+ }
+
+ /* Fine, now execute the font program! */
+ exec = size->context;
+ /* size objects used during debugging have their own context */
+ if ( !size->debug )
+ exec = TT_New_Context( face );
+
+ if ( !exec )
+ {
+ error = TT_Err_Could_Not_Find_Context;
+ goto Fail_Memory;
+ }
+
+ size->GS = tt_default_graphics_state;
+ TT_Load_Context( exec, face, size );
+
+ exec->callTop = 0;
+ exec->top = 0;
+
+ exec->period = 64;
+ exec->phase = 0;
+ exec->threshold = 0;
+
+ {
+ FT_Size_Metrics* metrics = &exec->metrics;
+ TT_Size_Metrics* tt_metrics = &exec->tt_metrics;
+
+
+ metrics->x_ppem = 0;
+ metrics->y_ppem = 0;
+ metrics->x_scale = 0;
+ metrics->y_scale = 0;
+
+ tt_metrics->ppem = 0;
+ tt_metrics->scale = 0;
+ tt_metrics->ratio = 0x10000L;
+ }
+
+ exec->instruction_trap = FALSE;
+
+ exec->cvtSize = size->cvt_size;
+ exec->cvt = size->cvt;
+
+ exec->F_dot_P = 0x10000L;
+
+ /* allow font program execution */
+ TT_Set_CodeRange( exec,
+ tt_coderange_font,
+ face->font_program,
+ face->font_program_size );
+
+ /* disable CVT and glyph programs coderange */
+ TT_Clear_CodeRange( exec, tt_coderange_cvt );
+ TT_Clear_CodeRange( exec, tt_coderange_glyph );
+
+ if ( face->font_program_size > 0 )
+ {
+ error = TT_Goto_CodeRange( exec, tt_coderange_font, 0 );
+ if ( !error )
+ error = face->interpreter( exec );
+
+ if ( error )
+ goto Fail_Exec;
+ }
+ else
+ error = TT_Err_Ok;
+
+ TT_Save_Context( exec, size );
+
+ if ( !size->debug )
+ TT_Done_Context( exec );
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+ size->ttmetrics.valid = FALSE;
+ return error;
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ Fail_Exec:
+ if ( !size->debug )
+ TT_Done_Context( exec );
+
+ Fail_Memory:
+
+ TT_Done_Size( size );
+ return error;
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Done_Size */
+ /* */
+ /* <Description> */
+ /* The TrueType size object finalizer. */
+ /* */
+ /* <Input> */
+ /* size :: A handle to the target size object. */
+ /* */
+ FT_LOCAL_DEF void
+ TT_Done_Size( TT_Size size )
+ {
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ FT_Memory memory = size->root.face->memory;
+
+
+ if ( size->debug )
+ {
+ /* the debug context must be deleted by the debugger itself */
+ size->context = NULL;
+ size->debug = FALSE;
+ }
+
+ FREE( size->cvt );
+ size->cvt_size = 0;
+
+ /* free storage area */
+ FREE( size->storage );
+ size->storage_size = 0;
+
+ /* twilight zone */
+ TT_Done_GlyphZone( &size->twilight );
+
+ FREE( size->function_defs );
+ FREE( size->instruction_defs );
+
+ size->num_function_defs = 0;
+ size->max_function_defs = 0;
+ size->num_instruction_defs = 0;
+ size->max_instruction_defs = 0;
+
+ size->max_func = 0;
+ size->max_ins = 0;
+
+#endif
+
+ size->ttmetrics.valid = FALSE;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Reset_Outline_Size */
+ /* */
+ /* <Description> */
+ /* Resets a TrueType outline size when resolutions and character */
+ /* dimensions have been changed. */
+ /* */
+ /* <Input> */
+ /* size :: A handle to the target size object. */
+ /* */
+ static FT_Error
+ Reset_Outline_Size( TT_Size size )
+ {
+ TT_Face face;
+ FT_Error error = TT_Err_Ok;
+
+ FT_Size_Metrics* metrics;
+
+
+ if ( size->ttmetrics.valid )
+ return TT_Err_Ok;
+
+ face = (TT_Face)size->root.face;
+
+ metrics = &size->root.metrics;
+
+ if ( metrics->x_ppem < 1 || metrics->y_ppem < 1 )
+ return TT_Err_Invalid_PPem;
+
+ /* compute new transformation */
+ if ( metrics->x_ppem >= metrics->y_ppem )
+ {
+ size->ttmetrics.scale = metrics->x_scale;
+ size->ttmetrics.ppem = metrics->x_ppem;
+ size->ttmetrics.x_ratio = 0x10000L;
+ size->ttmetrics.y_ratio = FT_MulDiv( metrics->y_ppem,
+ 0x10000L,
+ metrics->x_ppem );
+ }
+ else
+ {
+ size->ttmetrics.scale = metrics->y_scale;
+ size->ttmetrics.ppem = metrics->y_ppem;
+ size->ttmetrics.x_ratio = FT_MulDiv( metrics->x_ppem,
+ 0x10000L,
+ metrics->y_ppem );
+ size->ttmetrics.y_ratio = 0x10000L;
+ }
+
+ /* Compute root ascender, descender, test height, and max_advance */
+ metrics->ascender = ( FT_MulFix( face->root.ascender,
+ metrics->y_scale ) + 32 ) & -64;
+ metrics->descender = ( FT_MulFix( face->root.descender,
+ metrics->y_scale ) + 32 ) & -64;
+ metrics->height = ( FT_MulFix( face->root.height,
+ metrics->y_scale ) + 32 ) & -64;
+ metrics->max_advance = ( FT_MulFix( face->root.max_advance_width,
+ metrics->x_scale ) + 32 ) & -64;
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+ /* set to `invalid' by default */
+ size->strike_index = 0xFFFF;
+#endif
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ {
+ TT_ExecContext exec;
+ FT_UInt i, j;
+
+
+ /* Scale the cvt values to the new ppem. */
+ /* We use by default the y ppem to scale the CVT. */
+ for ( i = 0; i < size->cvt_size; i++ )
+ size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale );
+
+ /* All twilight points are originally zero */
+ for ( j = 0; j < (FT_UInt)size->twilight.n_points; j++ )
+ {
+ size->twilight.org[j].x = 0;
+ size->twilight.org[j].y = 0;
+ size->twilight.cur[j].x = 0;
+ size->twilight.cur[j].y = 0;
+ }
+
+ /* clear storage area */
+ for ( i = 0; i < (FT_UInt)size->storage_size; i++ )
+ size->storage[i] = 0;
+
+ size->GS = tt_default_graphics_state;
+
+ /* get execution context and run prep program */
+ if ( size->debug )
+ exec = size->context;
+ else
+ exec = TT_New_Context( face );
+ /* debugging instances have their own context */
+
+ if ( !exec )
+ return TT_Err_Could_Not_Find_Context;
+
+ TT_Load_Context( exec, face, size );
+
+ TT_Set_CodeRange( exec,
+ tt_coderange_cvt,
+ face->cvt_program,
+ face->cvt_program_size );
+
+ TT_Clear_CodeRange( exec, tt_coderange_glyph );
+
+ exec->instruction_trap = FALSE;
+
+ exec->top = 0;
+ exec->callTop = 0;
+
+ if ( face->cvt_program_size > 0 )
+ {
+ error = TT_Goto_CodeRange( exec, tt_coderange_cvt, 0 );
+ if ( error )
+ goto End;
+
+ if ( !size->debug )
+ error = face->interpreter( exec );
+ }
+ else
+ error = TT_Err_Ok;
+
+ size->GS = exec->GS;
+ /* save default graphics state */
+
+ End:
+ TT_Save_Context( exec, size );
+
+ if ( !size->debug )
+ TT_Done_Context( exec );
+ /* debugging instances keep their context */
+ }
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+ if ( !error )
+ size->ttmetrics.valid = TRUE;
+
+ return error;
+ }
+
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Reset_SBit_Size */
+ /* */
+ /* <Description> */
+ /* Resets a TrueType sbit size when resolutions and character */
+ /* dimensions have been changed. */
+ /* */
+ /* <Input> */
+ /* size :: A handle to the target size object. */
+ /* */
+ static FT_Error
+ Reset_SBit_Size( TT_Size size )
+ {
+ TT_Face face;
+ FT_Error error = TT_Err_Ok;
+
+ FT_ULong strike_index;
+ FT_Size_Metrics* metrics;
+ FT_Size_Metrics* sbit_metrics;
+ SFNT_Interface* sfnt;
+
+
+ metrics = &size->root.metrics;
+
+ if ( size->strike_index != 0xFFFF )
+ return TT_Err_Ok;
+
+ face = (TT_Face)size->root.face;
+ sfnt = (SFNT_Interface*)face->sfnt;
+
+ sbit_metrics = &size->strike_metrics;
+
+ error = sfnt->set_sbit_strike(face,
+ metrics->x_ppem, metrics->y_ppem,
+ &strike_index);
+
+ if ( !error )
+ {
+ TT_SBit_Strike* strike = face->sbit_strikes + strike_index;
+
+
+ sbit_metrics->x_ppem = metrics->x_ppem;
+ sbit_metrics->y_ppem = metrics->y_ppem;
+#if 0
+ /*
+ * sbit_metrics->?_scale
+ * are not used now.
+ */
+ sbit_metrics->x_scale = 1 << 16;
+ sbit_metrics->y_scale = 1 << 16;
+#endif
+
+ sbit_metrics->ascender = strike->hori.ascender << 6;
+ sbit_metrics->descender = strike->hori.descender << 6;
+
+ /* XXX: Is this correct? */
+ sbit_metrics->height = sbit_metrics->ascender -
+ sbit_metrics->descender;
+
+ /* XXX: Is this correct? */
+ sbit_metrics->max_advance = ( strike->hori.min_origin_SB +
+ strike->hori.max_width +
+ strike->hori.min_advance_SB ) << 6;
+
+ size->strike_index = strike_index;
+ }
+ else
+ {
+ size->strike_index = 0xFFFF;
+
+ sbit_metrics->x_ppem = 0;
+ sbit_metrics->y_ppem = 0;
+ sbit_metrics->ascender = 0;
+ sbit_metrics->descender = 0;
+ sbit_metrics->height = 0;
+ sbit_metrics->max_advance = 0;
+ }
+
+ return error;
+ }
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Reset_Size */
+ /* */
+ /* <Description> */
+ /* Resets a TrueType size when resolutions and character dimensions */
+ /* have been changed. */
+ /* */
+ /* <Input> */
+ /* size :: A handle to the target size object. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Reset_Size( TT_Size size )
+ {
+ FT_Face face;
+ FT_Error error = TT_Err_Ok;
+
+
+ face = size->root.face;
+
+ if ( face->face_flags & FT_FACE_FLAG_SCALABLE )
+ {
+ if ( !size->ttmetrics.valid )
+ error = Reset_Outline_Size( size );
+
+ if ( error )
+ return error;
+ }
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+ if ( face->face_flags & FT_FACE_FLAG_FIXED_SIZES )
+ {
+ if ( size->strike_index == 0xFFFF )
+ error = Reset_SBit_Size( size );
+
+ if ( !error && !( face->face_flags & FT_FACE_FLAG_SCALABLE ) )
+ size->root.metrics = size->strike_metrics;
+ }
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+ if ( face->face_flags & FT_FACE_FLAG_SCALABLE )
+ return TT_Err_Ok;
+ else
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Init_Driver */
+ /* */
+ /* <Description> */
+ /* Initializes a given TrueType driver object. */
+ /* */
+ /* <Input> */
+ /* driver :: A handle to the target driver object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Init_Driver( TT_Driver driver )
+ {
+ FT_Error error;
+
+
+ /* set `extra' in glyph loader */
+ error = FT_GlyphLoader_Create_Extra( FT_DRIVER( driver )->glyph_loader );
+
+ /* init extension registry if needed */
+
+#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
+ if ( !error )
+ return TT_Init_Extensions( driver );
+#endif
+
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Done_Driver */
+ /* */
+ /* <Description> */
+ /* Finalizes a given TrueType driver. */
+ /* */
+ /* <Input> */
+ /* driver :: A handle to the target TrueType driver. */
+ /* */
+ FT_LOCAL_DEF void
+ TT_Done_Driver( TT_Driver driver )
+ {
+ /* destroy extensions registry if needed */
+
+#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
+
+ TT_Done_Extensions( driver );
+
+#endif
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+ /* destroy the execution context */
+ if ( driver->context )
+ {
+ TT_Destroy_Context( driver->context, driver->root.root.memory );
+ driver->context = NULL;
+ }
+#else
+ FT_UNUSED( driver );
+#endif
+
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ttpload.c */
+/* */
+/* TrueType glyph data/program tables loader (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TAGS_H
+
+#include "ttpload.h"
+
+#include "tterrors.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ttpload
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_Locations */
+ /* */
+ /* <Description> */
+ /* Loads the locations table. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* <Input> */
+ /* stream :: The input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Load_Locations( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+ FT_Short LongOffsets;
+ FT_ULong table_len;
+
+
+ FT_TRACE2(( "Locations " ));
+ LongOffsets = face->header.Index_To_Loc_Format;
+
+ error = face->goto_table( face, TTAG_loca, stream, &table_len );
+ if ( error )
+ {
+ error = TT_Err_Locations_Missing;
+ goto Exit;
+ }
+
+ if ( LongOffsets != 0 )
+ {
+ face->num_locations = (FT_UShort)( table_len >> 2 );
+
+ FT_TRACE2(( "(32bit offsets): %12d ", face->num_locations ));
+
+ if ( ALLOC_ARRAY( face->glyph_locations,
+ face->num_locations,
+ FT_Long ) )
+ goto Exit;
+
+ if ( ACCESS_Frame( face->num_locations * 4L ) )
+ goto Exit;
+
+ {
+ FT_Long* loc = face->glyph_locations;
+ FT_Long* limit = loc + face->num_locations;
+
+
+ for ( ; loc < limit; loc++ )
+ *loc = GET_Long();
+ }
+
+ FORGET_Frame();
+ }
+ else
+ {
+ face->num_locations = (FT_UShort)( table_len >> 1 );
+
+ FT_TRACE2(( "(16bit offsets): %12d ", face->num_locations ));
+
+ if ( ALLOC_ARRAY( face->glyph_locations,
+ face->num_locations,
+ FT_Long ) )
+ goto Exit;
+
+ if ( ACCESS_Frame( face->num_locations * 2L ) )
+ goto Exit;
+ {
+ FT_Long* loc = face->glyph_locations;
+ FT_Long* limit = loc + face->num_locations;
+
+
+ for ( ; loc < limit; loc++ )
+ *loc = (FT_Long)( (FT_ULong)GET_UShort() * 2 );
+ }
+ FORGET_Frame();
+ }
+
+ FT_TRACE2(( "loaded\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_CVT */
+ /* */
+ /* <Description> */
+ /* Loads the control value table into a face object. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* <Input> */
+ /* stream :: A handle to the input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Load_CVT( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+ FT_ULong table_len;
+
+
+ FT_TRACE2(( "CVT " ));
+
+ error = face->goto_table( face, TTAG_cvt, stream, &table_len );
+ if ( error )
+ {
+ FT_TRACE2(( "is missing!\n" ));
+
+ face->cvt_size = 0;
+ face->cvt = NULL;
+ error = TT_Err_Ok;
+
+ goto Exit;
+ }
+
+ face->cvt_size = table_len / 2;
+
+ if ( ALLOC_ARRAY( face->cvt,
+ face->cvt_size,
+ FT_Short ) )
+ goto Exit;
+
+ if ( ACCESS_Frame( face->cvt_size * 2L ) )
+ goto Exit;
+
+ {
+ FT_Short* cur = face->cvt;
+ FT_Short* limit = cur + face->cvt_size;
+
+
+ for ( ; cur < limit; cur++ )
+ *cur = GET_Short();
+ }
+
+ FORGET_Frame();
+ FT_TRACE2(( "loaded\n" ));
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_Progams */
+ /* */
+ /* <Description> */
+ /* Loads the font program and the cvt program. */
+ /* */
+ /* <InOut> */
+ /* face :: A handle to the target face object. */
+ /* */
+ /* <Input> */
+ /* stream :: A handle to the input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Load_Programs( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_ULong table_len;
+
+
+ FT_TRACE2(( "Font program " ));
+
+ /* The font program is optional */
+ error = face->goto_table( face, TTAG_fpgm, stream, &table_len );
+ if ( error )
+ {
+ face->font_program = NULL;
+ face->font_program_size = 0;
+
+ FT_TRACE2(( "is missing!\n" ));
+ }
+ else
+ {
+ face->font_program_size = table_len;
+ if ( EXTRACT_Frame( table_len, face->font_program ) )
+ goto Exit;
+
+ FT_TRACE2(( "loaded, %12d bytes\n", face->font_program_size ));
+ }
+
+ FT_TRACE2(( "Prep program " ));
+
+ error = face->goto_table( face, TTAG_prep, stream, &table_len );
+ if ( error )
+ {
+ face->cvt_program = NULL;
+ face->cvt_program_size = 0;
+ error = TT_Err_Ok;
+
+ FT_TRACE2(( "is missing!\n" ));
+ }
+ else
+ {
+ face->cvt_program_size = table_len;
+ if ( EXTRACT_Frame( table_len, face->cvt_program ) )
+ goto Exit;
+
+ FT_TRACE2(( "loaded, %12d bytes\n", face->cvt_program_size ));
+ }
+
+ Exit:
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ttpost.c */
+/* */
+/* Postcript name table processing for TrueType and OpenType fonts */
+/* (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* The post table is not completely loaded by the core engine. This */
+ /* file loads the missing PS glyph names and implements an API to access */
+ /* them. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TAGS_H
+#include "ttpost.h"
+#include "ttload.h"
+
+#include "sferrors.h"
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ttpost
+
+
+ /* If this configuration macro is defined, we rely on the `PSNames' */
+ /* module to grab the glyph names. */
+
+#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
+
+
+#include <freetype/internal/psnames.h>
+
+#define MAC_NAME( x ) ( (FT_String*)psnames->macintosh_name( x ) )
+
+
+#else /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */
+
+
+ /* Otherwise, we ignore the `PSNames' module, and provide our own */
+ /* table of Mac names. Thus, it is possible to build a version of */
+ /* FreeType without the Type 1 driver & PSNames module. */
+
+#define MAC_NAME( x ) TT_Post_Default_Names[x]
+
+ /* the 258 default Mac PS glyph names */
+
+ FT_String* TT_Post_Default_Names[258] =
+ {
+ /* 0 */
+ ".notdef", ".null", "CR", "space", "exclam",
+ "quotedbl", "numbersign", "dollar", "percent", "ampersand",
+ /* 10 */
+ "quotesingle", "parenleft", "parenright", "asterisk", "plus",
+ "comma", "hyphen", "period", "slash", "zero",
+ /* 20 */
+ "one", "two", "three", "four", "five",
+ "six", "seven", "eight", "nine", "colon",
+ /* 30 */
+ "semicolon", "less", "equal", "greater", "question",
+ "at", "A", "B", "C", "D",
+ /* 40 */
+ "E", "F", "G", "H", "I",
+ "J", "K", "L", "M", "N",
+ /* 50 */
+ "O", "P", "Q", "R", "S",
+ "T", "U", "V", "W", "X",
+ /* 60 */
+ "Y", "Z", "bracketleft", "backslash", "bracketright",
+ "asciicircum", "underscore", "grave", "a", "b",
+ /* 70 */
+ "c", "d", "e", "f", "g",
+ "h", "i", "j", "k", "l",
+ /* 80 */
+ "m", "n", "o", "p", "q",
+ "r", "s", "t", "u", "v",
+ /* 90 */
+ "w", "x", "y", "z", "braceleft",
+ "bar", "braceright", "asciitilde", "Adieresis", "Aring",
+ /* 100 */
+ "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis",
+ "aacute", "agrave", "acircumflex", "adieresis", "atilde",
+ /* 110 */
+ "aring", "ccedilla", "eacute", "egrave", "ecircumflex",
+ "edieresis", "iacute", "igrave", "icircumflex", "idieresis",
+ /* 120 */
+ "ntilde", "oacute", "ograve", "ocircumflex", "odieresis",
+ "otilde", "uacute", "ugrave", "ucircumflex", "udieresis",
+ /* 130 */
+ "dagger", "degree", "cent", "sterling", "section",
+ "bullet", "paragraph", "germandbls", "registered", "copyright",
+ /* 140 */
+ "trademark", "acute", "dieresis", "notequal", "AE",
+ "Oslash", "infinity", "plusminus", "lessequal", "greaterequal",
+ /* 150 */
+ "yen", "mu", "partialdiff", "summation", "product",
+ "pi", "integral", "ordfeminine", "ordmasculine", "Omega",
+ /* 160 */
+ "ae", "oslash", "questiondown", "exclamdown", "logicalnot",
+ "radical", "florin", "approxequal", "Delta", "guillemotleft",
+ /* 170 */
+ "guillemotright", "ellipsis", "nbspace", "Agrave", "Atilde",
+ "Otilde", "OE", "oe", "endash", "emdash",
+ /* 180 */
+ "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide",
+ "lozenge", "ydieresis", "Ydieresis", "fraction", "currency",
+ /* 190 */
+ "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl",
+ "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
+ /* 200 */
+ "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute",
+ "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex",
+ /* 210 */
+ "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave",
+ "dotlessi", "circumflex", "tilde", "macron", "breve",
+ /* 220 */
+ "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek",
+ "caron", "Lslash", "lslash", "Scaron", "scaron",
+ /* 230 */
+ "Zcaron", "zcaron", "brokenbar", "Eth", "eth",
+ "Yacute", "yacute", "Thorn", "thorn", "minus",
+ /* 240 */
+ "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf",
+ "onequarter", "threequarters", "franc", "Gbreve", "gbreve",
+ /* 250 */
+ "Idot", "Scedilla", "scedilla", "Cacute", "cacute",
+ "Ccaron", "ccaron", "dmacron",
+ };
+
+
+#endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */
+
+
+ static FT_Error
+ Load_Format_20( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Memory memory = stream->memory;
+ FT_Error error;
+
+ FT_Int num_glyphs;
+ FT_UShort num_names;
+
+ FT_UShort* glyph_indices = 0;
+ FT_Char** name_strings = 0;
+
+
+ if ( READ_UShort( num_glyphs ) )
+ goto Exit;
+
+ /* UNDOCUMENTED! The number of glyphs in this table can be smaller */
+ /* than the value in the maxp table (cf. cyberbit.ttf). */
+
+ /* There already exist fonts which have more than 32768 glyph names */
+ /* in this table, so the test for this threshold has been dropped. */
+
+ if ( num_glyphs > face->root.num_glyphs )
+ {
+ error = SFNT_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* load the indices */
+ {
+ FT_Int n;
+
+
+ if ( ALLOC_ARRAY ( glyph_indices, num_glyphs, FT_UShort ) ||
+ ACCESS_Frame( num_glyphs * 2L ) )
+ goto Fail;
+
+ for ( n = 0; n < num_glyphs; n++ )
+ glyph_indices[n] = GET_UShort();
+
+ FORGET_Frame();
+ }
+
+ /* compute number of names stored in table */
+ {
+ FT_Int n;
+
+
+ num_names = 0;
+
+ for ( n = 0; n < num_glyphs; n++ )
+ {
+ FT_Int index;
+
+
+ index = glyph_indices[n];
+ if ( index >= 258 )
+ {
+ index -= 257;
+ if ( index > num_names )
+ num_names = (FT_UShort)index;
+ }
+ }
+ }
+
+ /* now load the name strings */
+ {
+ FT_UShort n;
+
+
+ if ( ALLOC_ARRAY( name_strings, num_names, FT_Char* ) )
+ goto Fail;
+
+ for ( n = 0; n < num_names; n++ )
+ {
+ FT_UInt len;
+
+
+ if ( READ_Byte ( len ) ||
+ ALLOC_ARRAY( name_strings[n], len + 1, FT_Char ) ||
+ FILE_Read ( name_strings[n], len ) )
+ goto Fail1;
+
+ name_strings[n][len] = '\0';
+ }
+ }
+
+ /* all right, set table fields and exit successfuly */
+ {
+ TT_Post_20* table = &face->postscript_names.names.format_20;
+
+
+ table->num_glyphs = (FT_UShort)num_glyphs;
+ table->num_names = (FT_UShort)num_names;
+ table->glyph_indices = glyph_indices;
+ table->glyph_names = name_strings;
+ }
+ return SFNT_Err_Ok;
+
+
+ Fail1:
+ {
+ FT_UShort n;
+
+
+ for ( n = 0; n < num_names; n++ )
+ FREE( name_strings[n] );
+ }
+
+ Fail:
+ FREE( name_strings );
+ FREE( glyph_indices );
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ Load_Format_25( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Memory memory = stream->memory;
+ FT_Error error;
+
+ FT_Int num_glyphs;
+ FT_Char* offset_table = 0;
+
+
+ /* UNDOCUMENTED! This value appears only in the Apple TT specs. */
+ if ( READ_UShort( num_glyphs ) )
+ goto Exit;
+
+ /* check the number of glyphs */
+ if ( num_glyphs > face->root.num_glyphs || num_glyphs > 258 )
+ {
+ error = SFNT_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ if ( ALLOC ( offset_table, num_glyphs ) ||
+ FILE_Read( offset_table, num_glyphs ) )
+ goto Fail;
+
+ /* now check the offset table */
+ {
+ FT_Int n;
+
+
+ for ( n = 0; n < num_glyphs; n++ )
+ {
+ FT_Long index = (FT_Long)n + offset_table[n];
+
+
+ if ( index < 0 || index > num_glyphs )
+ {
+ error = SFNT_Err_Invalid_File_Format;
+ goto Fail;
+ }
+ }
+ }
+
+ /* OK, set table fields and exit successfuly */
+ {
+ TT_Post_25* table = &face->postscript_names.names.format_25;
+
+
+ table->num_glyphs = (FT_UShort)num_glyphs;
+ table->offsets = offset_table;
+ }
+
+ return SFNT_Err_Ok;
+
+ Fail:
+ FREE( offset_table );
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ Load_Post_Names( TT_Face face )
+ {
+ FT_Stream stream;
+ FT_Error error;
+ FT_Fixed format;
+
+
+ /* get a stream for the face's resource */
+ stream = face->root.stream;
+
+ /* seek to the beginning of the PS names table */
+ error = face->goto_table( face, TTAG_post, stream, 0 );
+ if ( error )
+ goto Exit;
+
+ format = face->postscript.FormatType;
+
+ /* go to beginning of subtable */
+ if ( FILE_Skip( 32 ) )
+ goto Exit;
+
+ /* now read postscript table */
+ switch ( format )
+ {
+ case 0x00020000L:
+ error = Load_Format_20( face, stream );
+ break;
+
+ case 0x00028000L:
+ error = Load_Format_25( face, stream );
+ break;
+
+ default:
+ error = SFNT_Err_Invalid_File_Format;
+ }
+
+ face->postscript_names.loaded = 1;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF void
+ TT_Free_Post_Names( TT_Face face )
+ {
+ FT_Memory memory = face->root.memory;
+ TT_Post_Names* names = &face->postscript_names;
+
+
+ if ( names->loaded )
+ {
+ switch ( face->postscript.FormatType )
+ {
+ case 0x00020000L:
+ {
+ TT_Post_20* table = &names->names.format_20;
+ FT_UShort n;
+
+
+ FREE( table->glyph_indices );
+ table->num_glyphs = 0;
+
+ for ( n = 0; n < table->num_names; n++ )
+ FREE( table->glyph_names[n] );
+
+ FREE( table->glyph_names );
+ table->num_names = 0;
+ }
+ break;
+
+ case 0x00028000L:
+ {
+ TT_Post_25* table = &names->names.format_25;
+
+
+ FREE( table->offsets );
+ table->num_glyphs = 0;
+ }
+ break;
+ }
+ }
+ names->loaded = 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Get_PS_Name */
+ /* */
+ /* <Description> */
+ /* Gets the PostScript glyph name of a glyph. */
+ /* */
+ /* <Input> */
+ /* face :: A handle to the parent face. */
+ /* */
+ /* index :: The glyph index. */
+ /* */
+ /* PSname :: The address of a string pointer. Will be NULL in case */
+ /* of error, otherwise it is a pointer to the glyph name. */
+ /* */
+ /* You must not modify the returned string! */
+ /* */
+ /* <Output> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Get_PS_Name( TT_Face face,
+ FT_UInt index,
+ FT_String** PSname )
+ {
+ FT_Error error;
+ TT_Post_Names* names;
+
+#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
+ PSNames_Interface* psnames;
+#endif
+
+
+ if ( !face )
+ return SFNT_Err_Invalid_Face_Handle;
+
+ if ( index >= (FT_UInt)face->root.num_glyphs )
+ return SFNT_Err_Invalid_Glyph_Index;
+
+#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
+ psnames = (PSNames_Interface*)face->psnames;
+ if ( !psnames )
+ return SFNT_Err_Unimplemented_Feature;
+#endif
+
+ names = &face->postscript_names;
+
+ /* `.notdef' by default */
+ *PSname = MAC_NAME( 0 );
+
+ switch ( face->postscript.FormatType )
+ {
+ case 0x00010000L:
+ if ( index < 258 ) /* paranoid checking */
+ *PSname = MAC_NAME( index );
+ break;
+
+ case 0x00020000L:
+ {
+ TT_Post_20* table = &names->names.format_20;
+
+
+ if ( !names->loaded )
+ {
+ error = Load_Post_Names( face );
+ if ( error )
+ break;
+ }
+
+ if ( index < (FT_UInt)table->num_glyphs )
+ {
+ FT_UShort name_index = table->glyph_indices[index];
+
+
+ if ( name_index < 258 )
+ *PSname = MAC_NAME( name_index );
+ else
+ *PSname = (FT_String*)table->glyph_names[name_index - 258];
+ }
+ }
+ break;
+
+ case 0x00028000L:
+ {
+ TT_Post_25* table = &names->names.format_25;
+
+
+ if ( !names->loaded )
+ {
+ error = Load_Post_Names( face );
+ if ( error )
+ break;
+ }
+
+ if ( index < (FT_UInt)table->num_glyphs ) /* paranoid checking */
+ {
+ index += table->offsets[index];
+ *PSname = MAC_NAME( index );
+ }
+ }
+ break;
+
+ case 0x00030000L:
+ break; /* nothing to do */
+ }
+
+ return SFNT_Err_Ok;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* ttsbit.c */
+/* */
+/* TrueType and OpenType embedded bitmap support (body). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TAGS_H
+#include "ttsbit.h"
+
+#include "sferrors.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_ttsbit
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* blit_sbit */
+ /* */
+ /* <Description> */
+ /* Blits a bitmap from an input stream into a given target. Supports */
+ /* x and y offsets as well as byte padded lines. */
+ /* */
+ /* <Input> */
+ /* target :: The target bitmap/pixmap. */
+ /* */
+ /* source :: The input packed bitmap data. */
+ /* */
+ /* line_bits :: The number of bits per line. */
+ /* */
+ /* byte_padded :: A flag which is true if lines are byte-padded. */
+ /* */
+ /* x_offset :: The horizontal offset. */
+ /* */
+ /* y_offset :: The vertical offset. */
+ /* */
+ /* <Note> */
+ /* IMPORTANT: The x and y offsets are relative to the top corner of */
+ /* the target bitmap (unlike the normal TrueType */
+ /* convention). A positive y offset indicates a downwards */
+ /* direction! */
+ /* */
+ static void
+ blit_sbit( FT_Bitmap* target,
+ FT_Byte* source,
+ FT_Int line_bits,
+ FT_Bool byte_padded,
+ FT_Int x_offset,
+ FT_Int y_offset )
+ {
+ FT_Byte* line_buff;
+ FT_Int line_incr;
+ FT_Int height;
+
+ FT_UShort acc;
+ FT_UInt loaded;
+
+
+ /* first of all, compute starting write position */
+ line_incr = target->pitch;
+ line_buff = target->buffer;
+
+ if ( line_incr < 0 )
+ line_buff -= line_incr * ( target->rows - 1 );
+
+ line_buff += ( x_offset >> 3 ) + y_offset * line_incr;
+
+ /***********************************************************************/
+ /* */
+ /* We use the extra-classic `accumulator' trick to extract the bits */
+ /* from the source byte stream. */
+ /* */
+ /* Namely, the variable `acc' is a 16-bit accumulator containing the */
+ /* last `loaded' bits from the input stream. The bits are shifted to */
+ /* the upmost position in `acc'. */
+ /* */
+ /***********************************************************************/
+
+ acc = 0; /* clear accumulator */
+ loaded = 0; /* no bits were loaded */
+
+ for ( height = target->rows; height > 0; height-- )
+ {
+ FT_Byte* cur = line_buff; /* current write cursor */
+ FT_Int count = line_bits; /* # of bits to extract per line */
+ FT_Byte shift = (FT_Byte)( x_offset & 7 ); /* current write shift */
+ FT_Byte space = (FT_Byte)( 8 - shift );
+
+
+ /* first of all, read individual source bytes */
+ if ( count >= 8 )
+ {
+ count -= 8;
+ {
+ do
+ {
+ FT_Byte val;
+
+
+ /* ensure that there are at least 8 bits in the accumulator */
+ if ( loaded < 8 )
+ {
+ acc |= (FT_UShort)*source++ << ( 8 - loaded );
+ loaded += 8;
+ }
+
+ /* now write one byte */
+ val = (FT_Byte)( acc >> 8 );
+ if ( shift )
+ {
+ cur[0] |= val >> shift;
+ cur[1] |= val << space;
+ }
+ else
+ cur[0] |= val;
+
+ cur++;
+ acc <<= 8; /* remove bits from accumulator */
+ loaded -= 8;
+ count -= 8;
+
+ } while ( count >= 0 );
+ }
+
+ /* restore `count' to correct value */
+ count += 8;
+ }
+
+ /* now write remaining bits (count < 8) */
+ if ( count > 0 )
+ {
+ FT_Byte val;
+
+
+ /* ensure that there are at least `count' bits in the accumulator */
+ if ( (FT_Int)loaded < count )
+ {
+ acc |= (FT_UShort)*source++ << ( 8 - loaded );
+ loaded += 8;
+ }
+
+ /* now write remaining bits */
+ val = (FT_Byte)( ( (FT_Byte)( acc >> 8 ) ) & ~( 0xFF >> count ) );
+ cur[0] |= val >> shift;
+
+ if ( count > space )
+ cur[1] |= val << space;
+
+ acc <<= count;
+ loaded -= count;
+ }
+
+ /* now, skip to next line */
+ if ( byte_padded )
+ {
+ acc = 0;
+ loaded = 0; /* clear accumulator on byte-padded lines */
+ }
+
+ line_buff += line_incr;
+ }
+ }
+
+
+ const FT_Frame_Field sbit_metrics_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_SBit_Metrics
+
+ FT_FRAME_START( 8 ),
+ FT_FRAME_BYTE( height ),
+ FT_FRAME_BYTE( width ),
+
+ FT_FRAME_CHAR( horiBearingX ),
+ FT_FRAME_CHAR( horiBearingY ),
+ FT_FRAME_BYTE( horiAdvance ),
+
+ FT_FRAME_CHAR( vertBearingX ),
+ FT_FRAME_CHAR( vertBearingY ),
+ FT_FRAME_BYTE( vertAdvance ),
+ FT_FRAME_END
+ };
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_SBit_Const_Metrics */
+ /* */
+ /* <Description> */
+ /* Loads the metrics for `EBLC' index tables format 2 and 5. */
+ /* */
+ /* <Input> */
+ /* range :: The target range. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ Load_SBit_Const_Metrics( TT_SBit_Range* range,
+ FT_Stream stream )
+ {
+ FT_Error error;
+
+
+ if ( READ_ULong( range->image_size ) )
+ return error;
+
+ return READ_Fields( sbit_metrics_fields, &range->metrics );
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_SBit_Range_Codes */
+ /* */
+ /* <Description> */
+ /* Loads the range codes for `EBLC' index tables format 4 and 5. */
+ /* */
+ /* <Input> */
+ /* range :: The target range. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* load_offsets :: A flag whether to load the glyph offset table. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ Load_SBit_Range_Codes( TT_SBit_Range* range,
+ FT_Stream stream,
+ FT_Bool load_offsets )
+ {
+ FT_Error error;
+ FT_ULong count, n, size;
+ FT_Memory memory = stream->memory;
+
+
+ if ( READ_ULong( count ) )
+ goto Exit;
+
+ range->num_glyphs = count;
+
+ /* Allocate glyph offsets table if needed */
+ if ( load_offsets )
+ {
+ if ( ALLOC_ARRAY( range->glyph_offsets, count, FT_ULong ) )
+ goto Exit;
+
+ size = count * 4L;
+ }
+ else
+ size = count * 2L;
+
+ /* Allocate glyph codes table and access frame */
+ if ( ALLOC_ARRAY ( range->glyph_codes, count, FT_UShort ) ||
+ ACCESS_Frame( size ) )
+ goto Exit;
+
+ for ( n = 0; n < count; n++ )
+ {
+ range->glyph_codes[n] = GET_UShort();
+
+ if ( load_offsets )
+ range->glyph_offsets[n] = (FT_ULong)range->image_offset +
+ GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_SBit_Range */
+ /* */
+ /* <Description> */
+ /* Loads a given `EBLC' index/range table. */
+ /* */
+ /* <Input> */
+ /* range :: The target range. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ static FT_Error
+ Load_SBit_Range( TT_SBit_Range* range,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+
+
+ switch( range->index_format )
+ {
+ case 1: /* variable metrics with 4-byte offsets */
+ case 3: /* variable metrics with 2-byte offsets */
+ {
+ FT_ULong num_glyphs, n;
+ FT_Int size_elem;
+ FT_Bool large = FT_BOOL( range->index_format == 1 );
+
+
+ num_glyphs = range->last_glyph - range->first_glyph + 1L;
+ range->num_glyphs = num_glyphs;
+ num_glyphs++; /* XXX: BEWARE - see spec */
+
+ size_elem = large ? 4 : 2;
+
+ if ( ALLOC_ARRAY( range->glyph_offsets,
+ num_glyphs, FT_ULong ) ||
+ ACCESS_Frame( num_glyphs * size_elem ) )
+ goto Exit;
+
+ for ( n = 0; n < num_glyphs; n++ )
+ range->glyph_offsets[n] = (FT_ULong)( range->image_offset +
+ ( large ? GET_ULong()
+ : GET_UShort() ) );
+ FORGET_Frame();
+ }
+ break;
+
+ case 2: /* all glyphs have identical metrics */
+ error = Load_SBit_Const_Metrics( range, stream );
+ break;
+
+ case 4:
+ error = Load_SBit_Range_Codes( range, stream, 1 );
+ break;
+
+ case 5:
+ error = Load_SBit_Const_Metrics( range, stream ) ||
+ Load_SBit_Range_Codes( range, stream, 0 );
+ break;
+
+ default:
+ error = SFNT_Err_Invalid_File_Format;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_SBit_Strikes */
+ /* */
+ /* <Description> */
+ /* Loads the table of embedded bitmap sizes for this face. */
+ /* */
+ /* <Input> */
+ /* face :: The target face object. */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Load_SBit_Strikes( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error = 0;
+ FT_Memory memory = stream->memory;
+ FT_Fixed version;
+ FT_ULong num_strikes;
+ FT_ULong table_base;
+
+ const FT_Frame_Field sbit_line_metrics_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_SBit_Line_Metrics
+
+ /* no FT_FRAME_START */
+ FT_FRAME_CHAR( ascender ),
+ FT_FRAME_CHAR( descender ),
+ FT_FRAME_BYTE( max_width ),
+
+ FT_FRAME_CHAR( caret_slope_numerator ),
+ FT_FRAME_CHAR( caret_slope_denominator ),
+ FT_FRAME_CHAR( caret_offset ),
+
+ FT_FRAME_CHAR( min_origin_SB ),
+ FT_FRAME_CHAR( min_advance_SB ),
+ FT_FRAME_CHAR( max_before_BL ),
+ FT_FRAME_CHAR( min_after_BL ),
+ FT_FRAME_CHAR( pads[0] ),
+ FT_FRAME_CHAR( pads[1] ),
+ FT_FRAME_END
+ };
+
+ const FT_Frame_Field strike_start_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_SBit_Strike
+
+ /* no FT_FRAME_START */
+ FT_FRAME_ULONG( ranges_offset ),
+ FT_FRAME_SKIP_LONG,
+ FT_FRAME_ULONG( num_ranges ),
+ FT_FRAME_ULONG( color_ref ),
+ FT_FRAME_END
+ };
+
+ const FT_Frame_Field strike_end_fields[] =
+ {
+ /* no FT_FRAME_START */
+ FT_FRAME_USHORT( start_glyph ),
+ FT_FRAME_USHORT( end_glyph ),
+ FT_FRAME_BYTE ( x_ppem ),
+ FT_FRAME_BYTE ( y_ppem ),
+ FT_FRAME_BYTE ( bit_depth ),
+ FT_FRAME_CHAR ( flags ),
+ FT_FRAME_END
+ };
+
+
+ face->num_sbit_strikes = 0;
+
+ /* this table is optional */
+ error = face->goto_table( face, TTAG_EBLC, stream, 0 );
+ if ( error )
+ error = face->goto_table( face, TTAG_bloc, stream, 0 );
+ if ( error )
+ goto Exit;
+
+ table_base = FILE_Pos();
+ if ( ACCESS_Frame( 8L ) )
+ goto Exit;
+
+ version = GET_Long();
+ num_strikes = GET_ULong();
+
+ FORGET_Frame();
+
+ /* check version number and strike count */
+ if ( version != 0x00020000L ||
+ num_strikes >= 0x10000L )
+ {
+ FT_ERROR(( "TT_Load_SBit_Strikes: invalid table version!\n" ));
+ error = SFNT_Err_Invalid_File_Format;
+
+ goto Exit;
+ }
+
+ /* allocate the strikes table */
+ if ( ALLOC_ARRAY( face->sbit_strikes, num_strikes, TT_SBit_Strike ) )
+ goto Exit;
+
+ face->num_sbit_strikes = num_strikes;
+
+ /* now read each strike table separately */
+ {
+ TT_SBit_Strike* strike = face->sbit_strikes;
+ FT_ULong count = num_strikes;
+
+
+ if ( ACCESS_Frame( 48L * num_strikes ) )
+ goto Exit;
+
+ while ( count > 0 )
+ {
+ if ( READ_Fields( strike_start_fields, strike ) ||
+ READ_Fields( sbit_line_metrics_fields, &strike->hori ) ||
+ READ_Fields( sbit_line_metrics_fields, &strike->vert ) ||
+ READ_Fields( strike_end_fields, strike ) )
+ break;
+
+ count--;
+ strike++;
+ }
+
+ FORGET_Frame();
+ }
+
+ /* allocate the index ranges for each strike table */
+ {
+ TT_SBit_Strike* strike = face->sbit_strikes;
+ FT_ULong count = num_strikes;
+
+
+ while ( count > 0 )
+ {
+ TT_SBit_Range* range;
+ FT_ULong count2 = strike->num_ranges;
+
+
+ if ( ALLOC_ARRAY( strike->sbit_ranges,
+ strike->num_ranges,
+ TT_SBit_Range ) )
+ goto Exit;
+
+ /* read each range */
+ if ( FILE_Seek( table_base + strike->ranges_offset ) ||
+ ACCESS_Frame( strike->num_ranges * 8L ) )
+ goto Exit;
+
+ range = strike->sbit_ranges;
+ while ( count2 > 0 )
+ {
+ range->first_glyph = GET_UShort();
+ range->last_glyph = GET_UShort();
+ range->table_offset = table_base + strike->ranges_offset
+ + GET_ULong();
+ count2--;
+ range++;
+ }
+
+ FORGET_Frame();
+
+ /* Now, read each index table */
+ count2 = strike->num_ranges;
+ range = strike->sbit_ranges;
+ while ( count2 > 0 )
+ {
+ /* Read the header */
+ if ( FILE_Seek( range->table_offset ) ||
+ ACCESS_Frame( 8L ) )
+ goto Exit;
+
+ range->index_format = GET_UShort();
+ range->image_format = GET_UShort();
+ range->image_offset = GET_ULong();
+
+ FORGET_Frame();
+
+ error = Load_SBit_Range( range, stream );
+ if ( error )
+ goto Exit;
+
+ count2--;
+ range++;
+ }
+
+ count--;
+ strike++;
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Free_SBit_Strikes */
+ /* */
+ /* <Description> */
+ /* Releases the embedded bitmap tables. */
+ /* */
+ /* <Input> */
+ /* face :: The target face object. */
+ /* */
+ FT_LOCAL_DEF void
+ TT_Free_SBit_Strikes( TT_Face face )
+ {
+ FT_Memory memory = face->root.memory;
+ TT_SBit_Strike* strike = face->sbit_strikes;
+ TT_SBit_Strike* strike_limit = strike + face->num_sbit_strikes;
+
+
+ if ( strike )
+ {
+ for ( ; strike < strike_limit; strike++ )
+ {
+ TT_SBit_Range* range = strike->sbit_ranges;
+ TT_SBit_Range* range_limit = range + strike->num_ranges;
+
+
+ if ( range )
+ {
+ for ( ; range < range_limit; range++ )
+ {
+ /* release the glyph offsets and codes tables */
+ /* where appropriate */
+ FREE( range->glyph_offsets );
+ FREE( range->glyph_codes );
+ }
+ }
+ FREE( strike->sbit_ranges );
+ strike->num_ranges = 0;
+ }
+ FREE( face->sbit_strikes );
+ }
+ face->num_sbit_strikes = 0;
+ }
+
+
+ FT_LOCAL_DEF FT_Error
+ TT_Set_SBit_Strike( TT_Face face,
+ FT_Int x_ppem,
+ FT_Int y_ppem,
+ FT_ULong *astrike_index )
+ {
+ FT_Int i;
+
+
+ if ( x_ppem < 0 || x_ppem > 255 ||
+ y_ppem < 1 || y_ppem > 255 )
+ return SFNT_Err_Invalid_PPem;
+
+ for ( i = 0; i < face->num_sbit_strikes; i++ )
+ {
+ if ( ( face->sbit_strikes[i].y_ppem == y_ppem ) &&
+ ( ( x_ppem == 0 ) ||
+ ( face->sbit_strikes[i].x_ppem == x_ppem ) ) )
+ {
+ *astrike_index = i;
+ return SFNT_Err_Ok;
+ }
+ }
+
+ return SFNT_Err_Invalid_PPem;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Find_SBit_Range */
+ /* */
+ /* <Description> */
+ /* Scans a given strike's ranges and return, for a given glyph */
+ /* index, the corresponding sbit range, and `EBDT' offset. */
+ /* */
+ /* <Input> */
+ /* glyph_index :: The glyph index. */
+ /* */
+ /* strike :: The source/current sbit strike. */
+ /* */
+ /* <Output> */
+ /* arange :: The sbit range containing the glyph index. */
+ /* */
+ /* aglyph_offset :: The offset of the glyph data in `EBDT' table. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means the glyph index was found. */
+ /* */
+ static FT_Error
+ Find_SBit_Range( FT_UInt glyph_index,
+ TT_SBit_Strike* strike,
+ TT_SBit_Range** arange,
+ FT_ULong* aglyph_offset )
+ {
+ TT_SBit_Range *range, *range_limit;
+
+
+ /* check whether the glyph index is within this strike's */
+ /* glyph range */
+ if ( glyph_index < (FT_UInt)strike->start_glyph ||
+ glyph_index > (FT_UInt)strike->end_glyph )
+ goto Fail;
+
+ /* scan all ranges in strike */
+ range = strike->sbit_ranges;
+ range_limit = range + strike->num_ranges;
+ if ( !range )
+ goto Fail;
+
+ for ( ; range < range_limit; range++ )
+ {
+ if ( glyph_index >= (FT_UInt)range->first_glyph &&
+ glyph_index <= (FT_UInt)range->last_glyph )
+ {
+ FT_UShort delta = (FT_UShort)( glyph_index - range->first_glyph );
+
+
+ switch ( range->index_format )
+ {
+ case 1:
+ case 3:
+ *aglyph_offset = range->glyph_offsets[delta];
+ break;
+
+ case 2:
+ *aglyph_offset = range->image_offset +
+ range->image_size * delta;
+ break;
+
+ case 4:
+ case 5:
+ {
+ FT_ULong n;
+
+
+ for ( n = 0; n < range->num_glyphs; n++ )
+ {
+ if ( (FT_UInt)range->glyph_codes[n] == glyph_index )
+ {
+ if ( range->index_format == 4 )
+ *aglyph_offset = range->glyph_offsets[n];
+ else
+ *aglyph_offset = range->image_offset +
+ n * range->image_size;
+ goto Found;
+ }
+ }
+ }
+
+ /* fall-through */
+ default:
+ goto Fail;
+ }
+
+ Found:
+ /* return successfully! */
+ *arange = range;
+ return 0;
+ }
+ }
+
+ Fail:
+ *arange = 0;
+ *aglyph_offset = 0;
+
+ return SFNT_Err_Invalid_Argument;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Find_SBit_Image */
+ /* */
+ /* <Description> */
+ /* Checks whether an embedded bitmap (an `sbit') exists for a given */
+ /* glyph, at a given strike. */
+ /* */
+ /* <Input> */
+ /* face :: The target face object. */
+ /* */
+ /* glyph_index :: The glyph index. */
+ /* */
+ /* strike_index :: The current strike index. */
+ /* */
+ /* <Output> */
+ /* arange :: The SBit range containing the glyph index. */
+ /* */
+ /* astrike :: The SBit strike containing the glyph index. */
+ /* */
+ /* aglyph_offset :: The offset of the glyph data in `EBDT' table. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. Returns */
+ /* SFNT_Err_Invalid_Argument if no sbit exists for the requested */
+ /* glyph. */
+ /* */
+ static FT_Error
+ Find_SBit_Image( TT_Face face,
+ FT_UInt glyph_index,
+ FT_ULong strike_index,
+ TT_SBit_Range* *arange,
+ TT_SBit_Strike* *astrike,
+ FT_ULong *aglyph_offset )
+ {
+ FT_Error error;
+ TT_SBit_Strike* strike;
+
+
+ if ( !face->sbit_strikes ||
+ ( face->num_sbit_strikes <= (FT_Int)strike_index ) )
+ goto Fail;
+
+ strike = &face->sbit_strikes[strike_index];
+
+ error = Find_SBit_Range( glyph_index, strike,
+ arange, aglyph_offset );
+ if ( error )
+ goto Fail;
+
+ *astrike = strike;
+
+ return SFNT_Err_Ok;
+
+ Fail:
+ /* no embedded bitmap for this glyph in face */
+ *arange = 0;
+ *astrike = 0;
+ *aglyph_offset = 0;
+
+ return SFNT_Err_Invalid_Argument;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Load_SBit_Metrics */
+ /* */
+ /* <Description> */
+ /* Gets the big metrics for a given SBit. */
+ /* */
+ /* <Input> */
+ /* stream :: The input stream. */
+ /* */
+ /* range :: The SBit range containing the glyph. */
+ /* */
+ /* <Output> */
+ /* big_metrics :: A big SBit metrics structure for the glyph. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* The stream cursor must be positioned at the glyph's offset within */
+ /* the `EBDT' table before the call. */
+ /* */
+ /* If the image format uses variable metrics, the stream cursor is */
+ /* positioned just after the metrics header in the `EBDT' table on */
+ /* function exit. */
+ /* */
+ static FT_Error
+ Load_SBit_Metrics( FT_Stream stream,
+ TT_SBit_Range* range,
+ TT_SBit_Metrics* metrics )
+ {
+ FT_Error error = SFNT_Err_Ok;
+
+
+ switch ( range->image_format )
+ {
+ case 1:
+ case 2:
+ case 8:
+ /* variable small metrics */
+ {
+ TT_SBit_Small_Metrics smetrics;
+
+ const FT_Frame_Field sbit_small_metrics_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE TT_SBit_Small_Metrics
+
+ FT_FRAME_START( 5 ),
+ FT_FRAME_BYTE( height ),
+ FT_FRAME_BYTE( width ),
+ FT_FRAME_CHAR( bearingX ),
+ FT_FRAME_CHAR( bearingY ),
+ FT_FRAME_BYTE( advance ),
+ FT_FRAME_END
+ };
+
+
+ /* read small metrics */
+ if ( READ_Fields( sbit_small_metrics_fields, &smetrics ) )
+ goto Exit;
+
+ /* convert it to a big metrics */
+ metrics->height = smetrics.height;
+ metrics->width = smetrics.width;
+ metrics->horiBearingX = smetrics.bearingX;
+ metrics->horiBearingY = smetrics.bearingY;
+ metrics->horiAdvance = smetrics.advance;
+
+ /* these metrics are made up at a higher level when */
+ /* needed. */
+ metrics->vertBearingX = 0;
+ metrics->vertBearingY = 0;
+ metrics->vertAdvance = 0;
+ }
+ break;
+
+ case 6:
+ case 7:
+ case 9:
+ /* variable big metrics */
+ if ( READ_Fields( sbit_metrics_fields, metrics ) )
+ goto Exit;
+ break;
+
+ case 5:
+ default: /* constant metrics */
+ if ( range->index_format == 2 || range->index_format == 5 )
+ *metrics = range->metrics;
+ else
+ return SFNT_Err_Invalid_File_Format;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* Crop_Bitmap */
+ /* */
+ /* <Description> */
+ /* Crops a bitmap to its tightest bounding box, and adjusts its */
+ /* metrics. */
+ /* */
+ /* <InOut> */
+ /* map :: The bitmap. */
+ /* */
+ /* metrics :: The corresponding metrics structure. */
+ /* */
+ static void
+ Crop_Bitmap( FT_Bitmap* map,
+ TT_SBit_Metrics* metrics )
+ {
+ /***********************************************************************/
+ /* */
+ /* In this situation, some bounding boxes of embedded bitmaps are too */
+ /* large. We need to crop it to a reasonable size. */
+ /* */
+ /* --------- */
+ /* | | ----- */
+ /* | *** | |***| */
+ /* | * | | * | */
+ /* | * | ------> | * | */
+ /* | * | | * | */
+ /* | * | | * | */
+ /* | *** | |***| */
+ /* --------- ----- */
+ /* */
+ /***********************************************************************/
+
+ FT_Int rows, count;
+ FT_Long line_len;
+ FT_Byte* line;
+
+
+ /***********************************************************************/
+ /* */
+ /* first of all, check the top-most lines of the bitmap, and remove */
+ /* them if they're empty. */
+ /* */
+ {
+ line = (FT_Byte*)map->buffer;
+ rows = map->rows;
+ line_len = map->pitch;
+
+
+ for ( count = 0; count < rows; count++ )
+ {
+ FT_Byte* cur = line;
+ FT_Byte* limit = line + line_len;
+
+
+ for ( ; cur < limit; cur++ )
+ if ( cur[0] )
+ goto Found_Top;
+
+ /* the current line was empty - skip to next one */
+ line = limit;
+ }
+
+ Found_Top:
+ /* check that we have at least one filled line */
+ if ( count >= rows )
+ goto Empty_Bitmap;
+
+ /* now, crop the empty upper lines */
+ if ( count > 0 )
+ {
+ line = (FT_Byte*)map->buffer;
+
+ MEM_Move( line, line + count * line_len,
+ ( rows - count ) * line_len );
+
+ metrics->height = (FT_Byte)( metrics->height - count );
+ metrics->horiBearingY = (FT_Char)( metrics->horiBearingY - count );
+ metrics->vertBearingY = (FT_Char)( metrics->vertBearingY - count );
+
+ map->rows -= count;
+ rows -= count;
+ }
+ }
+
+ /***********************************************************************/
+ /* */
+ /* second, crop the lower lines */
+ /* */
+ {
+ line = (FT_Byte*)map->buffer + ( rows - 1 ) * line_len;
+
+ for ( count = 0; count < rows; count++ )
+ {
+ FT_Byte* cur = line;
+ FT_Byte* limit = line + line_len;
+
+
+ for ( ; cur < limit; cur++ )
+ if ( cur[0] )
+ goto Found_Bottom;
+
+ /* the current line was empty - skip to previous one */
+ line -= line_len;
+ }
+
+ Found_Bottom:
+ if ( count > 0 )
+ {
+ metrics->height = (FT_Byte)( metrics->height - count );
+ rows -= count;
+ map->rows -= count;
+ }
+ }
+
+ /***********************************************************************/
+ /* */
+ /* third, get rid of the space on the left side of the glyph */
+ /* */
+ do
+ {
+ FT_Byte* limit;
+
+
+ line = (FT_Byte*)map->buffer;
+ limit = line + rows * line_len;
+
+ for ( ; line < limit; line += line_len )
+ if ( line[0] & 0x80 )
+ goto Found_Left;
+
+ /* shift the whole glyph one pixel to the left */
+ line = (FT_Byte*)map->buffer;
+ limit = line + rows * line_len;
+
+ for ( ; line < limit; line += line_len )
+ {
+ FT_Int n, width = map->width;
+ FT_Byte old;
+ FT_Byte* cur = line;
+
+
+ old = (FT_Byte)(cur[0] << 1);
+ for ( n = 8; n < width; n += 8 )
+ {
+ FT_Byte val;
+
+
+ val = cur[1];
+ cur[0] = (FT_Byte)( old | ( val >> 7 ) );
+ old = (FT_Byte)( val << 1 );
+ cur++;
+ }
+ cur[0] = old;
+ }
+
+ map->width--;
+ metrics->horiBearingX++;
+ metrics->vertBearingX++;
+ metrics->width--;
+
+ } while ( map->width > 0 );
+
+ Found_Left:
+
+ /***********************************************************************/
+ /* */
+ /* finally, crop the bitmap width to get rid of the space on the right */
+ /* side of the glyph. */
+ /* */
+ do
+ {
+ FT_Int right = map->width - 1;
+ FT_Byte* limit;
+ FT_Byte mask;
+
+
+ line = (FT_Byte*)map->buffer + ( right >> 3 );
+ limit = line + rows * line_len;
+ mask = (FT_Byte)( 0x80 >> ( right & 7 ) );
+
+ for ( ; line < limit; line += line_len )
+ if ( line[0] & mask )
+ goto Found_Right;
+
+ /* crop the whole glyph to the right */
+ map->width--;
+ metrics->width--;
+
+ } while ( map->width > 0 );
+
+ Found_Right:
+ /* all right, the bitmap was cropped */
+ return;
+
+ Empty_Bitmap:
+ map->width = 0;
+ map->rows = 0;
+ map->pitch = 0;
+ map->pixel_mode = ft_pixel_mode_mono;
+ }
+
+
+ static FT_Error
+ Load_SBit_Single( FT_Bitmap* map,
+ FT_Int x_offset,
+ FT_Int y_offset,
+ FT_Int pix_bits,
+ FT_UShort image_format,
+ TT_SBit_Metrics* metrics,
+ FT_Stream stream )
+ {
+ FT_Error error;
+
+
+ /* check that the source bitmap fits into the target pixmap */
+ if ( x_offset < 0 || x_offset + metrics->width > map->width ||
+ y_offset < 0 || y_offset + metrics->height > map->rows )
+ {
+ error = SFNT_Err_Invalid_Argument;
+
+ goto Exit;
+ }
+
+ {
+ FT_Int glyph_width = metrics->width;
+ FT_Int glyph_height = metrics->height;
+ FT_Int glyph_size;
+ FT_Int line_bits = pix_bits * glyph_width;
+ FT_Bool pad_bytes = 0;
+
+
+ /* compute size of glyph image */
+ switch ( image_format )
+ {
+ case 1: /* byte-padded formats */
+ case 6:
+ {
+ FT_Int line_length;
+
+
+ switch ( pix_bits )
+ {
+ case 1: line_length = ( glyph_width + 7 ) >> 3; break;
+ case 2: line_length = ( glyph_width + 3 ) >> 2; break;
+ case 4: line_length = ( glyph_width + 1 ) >> 1; break;
+ default: line_length = glyph_width;
+ }
+
+ glyph_size = glyph_height * line_length;
+ pad_bytes = 1;
+ }
+ break;
+
+ case 2:
+ case 5:
+ case 7:
+ line_bits = glyph_width * pix_bits;
+ glyph_size = ( glyph_height * line_bits + 7 ) >> 3;
+ break;
+
+ default: /* invalid format */
+ return SFNT_Err_Invalid_File_Format;
+ }
+
+ /* Now read data and draw glyph into target pixmap */
+ if ( ACCESS_Frame( glyph_size ) )
+ goto Exit;
+
+ /* don't forget to multiply `x_offset' by `map->pix_bits' as */
+ /* the sbit blitter doesn't make a difference between pixmap */
+ /* depths. */
+ blit_sbit( map, (FT_Byte*)stream->cursor, line_bits, pad_bytes,
+ x_offset * pix_bits, y_offset );
+
+ FORGET_Frame();
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ Load_SBit_Image( TT_SBit_Strike* strike,
+ TT_SBit_Range* range,
+ FT_ULong ebdt_pos,
+ FT_ULong glyph_offset,
+ FT_Bitmap* map,
+ FT_Int x_offset,
+ FT_Int y_offset,
+ FT_Stream stream,
+ TT_SBit_Metrics* metrics )
+ {
+ FT_Memory memory = stream->memory;
+ FT_Error error;
+
+
+ /* place stream at beginning of glyph data and read metrics */
+ if ( FILE_Seek( ebdt_pos + glyph_offset ) )
+ goto Exit;
+
+ error = Load_SBit_Metrics( stream, range, metrics );
+ if ( error )
+ goto Exit;
+
+ /* this function is recursive. At the top-level call, the */
+ /* field map.buffer is NULL. We thus begin by finding the */
+ /* dimensions of the higher-level glyph to allocate the */
+ /* final pixmap buffer */
+ if ( map->buffer == 0 )
+ {
+ FT_Long size;
+
+
+ map->width = metrics->width;
+ map->rows = metrics->height;
+
+ switch ( strike->bit_depth )
+ {
+ case 1:
+ map->pixel_mode = ft_pixel_mode_mono;
+ map->pitch = ( map->width + 7 ) >> 3;
+ break;
+
+ case 2:
+ map->pixel_mode = ft_pixel_mode_pal2;
+ map->pitch = ( map->width + 3 ) >> 2;
+ break;
+
+ case 4:
+ map->pixel_mode = ft_pixel_mode_pal4;
+ map->pitch = ( map->width + 1 ) >> 1;
+ break;
+
+ case 8:
+ map->pixel_mode = ft_pixel_mode_grays;
+ map->pitch = map->width;
+ break;
+
+ default:
+ return SFNT_Err_Invalid_File_Format;
+ }
+
+ size = map->rows * map->pitch;
+
+ /* check that there is no empty image */
+ if ( size == 0 )
+ goto Exit; /* exit successfully! */
+
+ if ( ALLOC( map->buffer, size ) )
+ goto Exit;
+ }
+
+ switch ( range->image_format )
+ {
+ case 1: /* single sbit image - load it */
+ case 2:
+ case 5:
+ case 6:
+ case 7:
+ return Load_SBit_Single( map, x_offset, y_offset, strike->bit_depth,
+ range->image_format, metrics, stream );
+
+ case 8: /* compound format */
+ FT_Skip_Stream( stream, 1L );
+ /* fallthrough */
+
+ case 9:
+ break;
+
+ default: /* invalid image format */
+ return SFNT_Err_Invalid_File_Format;
+ }
+
+ /* All right, we have a compound format. First of all, read */
+ /* the array of elements. */
+ {
+ TT_SBit_Component* components;
+ TT_SBit_Component* comp;
+ FT_UShort num_components, count;
+
+
+ if ( READ_UShort( num_components ) ||
+ ALLOC_ARRAY( components, num_components, TT_SBit_Component ) )
+ goto Exit;
+
+ count = num_components;
+
+ if ( ACCESS_Frame( 4L * num_components ) )
+ goto Fail_Memory;
+
+ for ( comp = components; count > 0; count--, comp++ )
+ {
+ comp->glyph_code = GET_UShort();
+ comp->x_offset = GET_Char();
+ comp->y_offset = GET_Char();
+ }
+
+ FORGET_Frame();
+
+ /* Now recursively load each element glyph */
+ count = num_components;
+ comp = components;
+ for ( ; count > 0; count--, comp++ )
+ {
+ TT_SBit_Range* elem_range;
+ TT_SBit_Metrics elem_metrics;
+ FT_ULong elem_offset;
+
+
+ /* find the range for this element */
+ error = Find_SBit_Range( comp->glyph_code,
+ strike,
+ &elem_range,
+ &elem_offset );
+ if ( error )
+ goto Fail_Memory;
+
+ /* now load the element, recursively */
+ error = Load_SBit_Image( strike,
+ elem_range,
+ ebdt_pos,
+ elem_offset,
+ map,
+ x_offset + comp->x_offset,
+ y_offset + comp->y_offset,
+ stream,
+ &elem_metrics );
+ if ( error )
+ goto Fail_Memory;
+ }
+
+ Fail_Memory:
+ FREE( components );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_SBit_Image */
+ /* */
+ /* <Description> */
+ /* Loads a given glyph sbit image from the font resource. This also */
+ /* returns its metrics. */
+ /* */
+ /* <Input> */
+ /* face :: The target face object. */
+ /* */
+ /* strike_index :: The current strike index. */
+ /* */
+ /* glyph_index :: The current glyph index. */
+ /* */
+ /* load_flags :: The glyph load flags (the code checks for the flag */
+ /* FT_LOAD_CROP_BITMAP). */
+ /* */
+ /* stream :: The input stream. */
+ /* */
+ /* <Output> */
+ /* map :: The target pixmap. */
+ /* */
+ /* metrics :: A big sbit metrics structure for the glyph image. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. Returns an error if no */
+ /* glyph sbit exists for the index. */
+ /* */
+ /* <Note> */
+ /* The `map.buffer' field is always freed before the glyph is loaded. */
+ /* */
+ FT_LOCAL_DEF FT_Error
+ TT_Load_SBit_Image( TT_Face face,
+ FT_ULong strike_index,
+ FT_UInt glyph_index,
+ FT_UInt load_flags,
+ FT_Stream stream,
+ FT_Bitmap *map,
+ TT_SBit_Metrics *metrics )
+ {
+ FT_Error error;
+ FT_Memory memory = stream->memory;
+ FT_ULong ebdt_pos, glyph_offset;
+
+ TT_SBit_Strike* strike;
+ TT_SBit_Range* range;
+
+
+ /* Check whether there is a glyph sbit for the current index */
+ error = Find_SBit_Image( face, glyph_index, strike_index,
+ &range, &strike, &glyph_offset );
+ if ( error )
+ goto Exit;
+
+ /* now, find the location of the `EBDT' table in */
+ /* the font file */
+ error = face->goto_table( face, TTAG_EBDT, stream, 0 );
+ if ( error )
+ error = face->goto_table( face, TTAG_bdat, stream, 0 );
+ if (error)
+ goto Exit;
+
+ ebdt_pos = FILE_Pos();
+
+ /* clear the bitmap & load the bitmap */
+ if ( face->root.glyph->flags & ft_glyph_own_bitmap )
+ FREE( map->buffer );
+
+ map->rows = map->pitch = map->width = 0;
+
+ error = Load_SBit_Image( strike, range, ebdt_pos, glyph_offset,
+ map, 0, 0, stream, metrics );
+ if ( error )
+ goto Exit;
+
+ /* the glyph slot owns this bitmap buffer */
+ face->root.glyph->flags |= ft_glyph_own_bitmap;
+
+ /* setup vertical metrics if needed */
+ if ( strike->flags & 1 )
+ {
+ /* in case of a horizontal strike only */
+ FT_Int advance;
+
+
+ advance = strike->hori.ascender - strike->hori.descender;
+
+ /* some heuristic values */
+
+ metrics->vertBearingX = (FT_Char)(-metrics->width / 2 );
+ metrics->vertBearingY = (FT_Char)( advance / 10 );
+ metrics->vertAdvance = (FT_Char)( advance * 12 / 10 );
+ }
+
+ /* Crop the bitmap now, unless specified otherwise */
+ if ( load_flags & FT_LOAD_CROP_BITMAP )
+ Crop_Bitmap( map, metrics );
+
+ Exit:
+ return error;
+ }
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* type1.c */
+/* */
+/* FreeType Type 1 driver component (body only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "t1parse.c"
+#include "t1load.c"
+#include "t1objs.c"
+#include "t1driver.c"
+#include "t1gload.c"
+
+#ifndef T1_CONFIG_OPTION_NO_AFM
+#include "t1afm.c"
+#endif
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* type1cid.c */
+/* */
+/* FreeType OpenType driver component (body only). */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "cidparse.c"
+#include "cidload.c"
+#include "cidobjs.c"
+#include "cidriver.c"
+#include "cidgload.c"
+
+
+/* END */
--- /dev/null
+/***************************************************************************/
+/* */
+/* winfnt.c */
+/* */
+/* FreeType font driver for Windows FNT/FON files */
+/* */
+/* Copyright 1996-2001 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_FNT_TYPES_H
+
+#include "winfnt.h"
+
+#include "fnterrs.h"
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_winfnt
+
+
+ static
+ const FT_Frame_Field winmz_header_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE WinMZ_Header
+
+ FT_FRAME_START( 64 ),
+ FT_FRAME_USHORT_LE ( magic ),
+ FT_FRAME_SKIP_BYTES( 29 * 2 ),
+ FT_FRAME_ULONG_LE ( lfanew ),
+ FT_FRAME_END
+ };
+
+ static
+ const FT_Frame_Field winne_header_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE WinNE_Header
+
+ FT_FRAME_START( 40 ),
+ FT_FRAME_USHORT_LE ( magic ),
+ FT_FRAME_SKIP_BYTES( 34 ),
+ FT_FRAME_USHORT_LE ( resource_tab_offset ),
+ FT_FRAME_USHORT_LE ( rname_tab_offset ),
+ FT_FRAME_END
+ };
+
+ static
+ const FT_Frame_Field winfnt_header_fields[] =
+ {
+#undef FT_STRUCTURE
+#define FT_STRUCTURE WinFNT_Header
+
+ FT_FRAME_START( 134 ),
+ FT_FRAME_USHORT_LE( version ),
+ FT_FRAME_ULONG_LE ( file_size ),
+ FT_FRAME_BYTES ( copyright, 60 ),
+ FT_FRAME_USHORT_LE( file_type ),
+ FT_FRAME_USHORT_LE( nominal_point_size ),
+ FT_FRAME_USHORT_LE( vertical_resolution ),
+ FT_FRAME_USHORT_LE( horizontal_resolution ),
+ FT_FRAME_USHORT_LE( ascent ),
+ FT_FRAME_USHORT_LE( internal_leading ),
+ FT_FRAME_USHORT_LE( external_leading ),
+ FT_FRAME_BYTE ( italic ),
+ FT_FRAME_BYTE ( underline ),
+ FT_FRAME_BYTE ( strike_out ),
+ FT_FRAME_USHORT_LE( weight ),
+ FT_FRAME_BYTE ( charset ),
+ FT_FRAME_USHORT_LE( pixel_width ),
+ FT_FRAME_USHORT_LE( pixel_height ),
+ FT_FRAME_BYTE ( pitch_and_family ),
+ FT_FRAME_USHORT_LE( avg_width ),
+ FT_FRAME_USHORT_LE( max_width ),
+ FT_FRAME_BYTE ( first_char ),
+ FT_FRAME_BYTE ( last_char ),
+ FT_FRAME_BYTE ( default_char ),
+ FT_FRAME_BYTE ( break_char ),
+ FT_FRAME_USHORT_LE( bytes_per_row ),
+ FT_FRAME_ULONG_LE ( device_offset ),
+ FT_FRAME_ULONG_LE ( face_name_offset ),
+ FT_FRAME_ULONG_LE ( bits_pointer ),
+ FT_FRAME_ULONG_LE ( bits_offset ),
+ FT_FRAME_BYTE ( reserved ),
+ FT_FRAME_ULONG_LE ( flags ),
+ FT_FRAME_USHORT_LE( A_space ),
+ FT_FRAME_USHORT_LE( B_space ),
+ FT_FRAME_USHORT_LE( C_space ),
+ FT_FRAME_USHORT_LE( color_table_offset ),
+ FT_FRAME_BYTES ( reserved, 4 ),
+ FT_FRAME_END
+ };
+
+
+ static void
+ fnt_font_done( FNT_Font* font,
+ FT_Stream stream )
+ {
+ if ( font->fnt_frame )
+ RELEASE_Frame( font->fnt_frame );
+
+ font->fnt_size = 0;
+ font->fnt_frame = 0;
+ }
+
+
+ static FT_Error
+ fnt_font_load( FNT_Font* font,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ WinFNT_Header* header = &font->header;
+
+
+ /* first of all, read the FNT header */
+ if ( FILE_Seek( font->offset ) ||
+ READ_Fields( winfnt_header_fields, header ) )
+ goto Exit;
+
+ /* check header */
+ if ( header->version != 0x200 &&
+ header->version != 0x300 )
+ {
+ FT_TRACE2(( "[not a valid FNT file]\n" ));
+ error = FNT_Err_Unknown_File_Format;
+ goto Exit;
+ }
+
+ if ( header->file_type & 1 )
+ {
+ FT_TRACE2(( "[can't handle vector FNT fonts]\n" ));
+ error = FNT_Err_Unknown_File_Format;
+ goto Exit;
+ }
+
+ /* small fixup -- some fonts have the `pixel_width' field set to 0 */
+ if ( header->pixel_width == 0 )
+ header->pixel_width = header->pixel_height;
+
+ /* this is a FNT file/table, we now extract its frame */
+ if ( FILE_Seek( font->offset ) ||
+ EXTRACT_Frame( header->file_size, font->fnt_frame ) )
+ goto Exit;
+
+ Exit:
+ return error;
+ }
+
+
+ static void
+ fnt_face_done_fonts( FNT_Face face )
+ {
+ FT_Memory memory = FT_FACE(face)->memory;
+ FT_Stream stream = FT_FACE(face)->stream;
+ FNT_Font* cur = face->fonts;
+ FNT_Font* limit = cur + face->num_fonts;
+
+
+ for ( ; cur < limit; cur++ )
+ fnt_font_done( cur, stream );
+
+ FREE( face->fonts );
+ face->num_fonts = 0;
+ }
+
+
+ static FT_Error
+ fnt_face_get_dll_fonts( FNT_Face face )
+ {
+ FT_Error error;
+ FT_Stream stream = FT_FACE(face)->stream;
+ FT_Memory memory = FT_FACE(face)->memory;
+ WinMZ_Header mz_header;
+
+
+ face->fonts = 0;
+ face->num_fonts = 0;
+
+ /* does it begin with a MZ header? */
+ if ( FILE_Seek( 0 ) ||
+ READ_Fields( winmz_header_fields, &mz_header ) )
+ goto Exit;
+
+ error = FNT_Err_Unknown_File_Format;
+ if ( mz_header.magic == WINFNT_MZ_MAGIC )
+ {
+ /* yes, now look for a NE header in the file */
+ WinNE_Header ne_header;
+
+
+ if ( FILE_Seek( mz_header.lfanew ) ||
+ READ_Fields( winne_header_fields, &ne_header ) )
+ goto Exit;
+
+ error = FNT_Err_Unknown_File_Format;
+ if ( ne_header.magic == WINFNT_NE_MAGIC )
+ {
+ /* good, now look in the resource table for each FNT resource */
+ FT_ULong res_offset = mz_header.lfanew +
+ ne_header.resource_tab_offset;
+
+ FT_UShort size_shift;
+ FT_UShort font_count = 0;
+ FT_ULong font_offset = 0;
+
+
+ if ( FILE_Seek( res_offset ) ||
+ ACCESS_Frame( ne_header.rname_tab_offset -
+ ne_header.resource_tab_offset ) )
+ goto Exit;
+
+ size_shift = GET_UShortLE();
+
+ for (;;)
+ {
+ FT_UShort type_id, count;
+
+
+ type_id = GET_UShortLE();
+ if ( !type_id )
+ break;
+
+ count = GET_UShortLE();
+
+ if ( type_id == 0x8008 )
+ {
+ font_count = count;
+ font_offset = (FT_ULong)( FILE_Pos() + 4 +
+ ( stream->cursor - stream->limit ) );
+ break;
+ }
+
+ stream->cursor += 4 + count * 12;
+ }
+ FORGET_Frame();
+
+ if ( !font_count || !font_offset )
+ {
+ FT_TRACE2(( "this file doesn't contain any FNT resources!\n" ));
+ error = FNT_Err_Unknown_File_Format;
+ goto Exit;
+ }
+
+ if ( FILE_Seek( font_offset ) ||
+ ALLOC_ARRAY( face->fonts, font_count, FNT_Font ) )
+ goto Exit;
+
+ face->num_fonts = font_count;
+
+ if ( ACCESS_Frame( (FT_Long)font_count * 12 ) )
+ goto Exit;
+
+ /* now read the offset and position of each FNT font */
+ {
+ FNT_Font* cur = face->fonts;
+ FNT_Font* limit = cur + font_count;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ cur->offset = (FT_ULong)GET_UShortLE() << size_shift;
+ cur->fnt_size = (FT_ULong)GET_UShortLE() << size_shift;
+ cur->size_shift = size_shift;
+ stream->cursor += 8;
+ }
+ }
+ FORGET_Frame();
+
+ /* finally, try to load each font there */
+ {
+ FNT_Font* cur = face->fonts;
+ FNT_Font* limit = cur + font_count;
+
+
+ for ( ; cur < limit; cur++ )
+ {
+ error = fnt_font_load( cur, stream );
+ if ( error )
+ goto Fail;
+ }
+ }
+ }
+ }
+
+ Fail:
+ if ( error )
+ fnt_face_done_fonts( face );
+
+ Exit:
+ return error;
+ }
+
+
+ static void
+ FNT_Face_Done( FNT_Face face )
+ {
+ FT_Memory memory = FT_FACE_MEMORY( face );
+
+
+ fnt_face_done_fonts( face );
+
+ FREE( face->root.available_sizes );
+ face->root.num_fixed_sizes = 0;
+ }
+
+
+ static FT_Error
+ FNT_Face_Init( FT_Stream stream,
+ FNT_Face face,
+ FT_Int face_index,
+ FT_Int num_params,
+ FT_Parameter* params )
+ {
+ FT_Error error;
+ FT_Memory memory = FT_FACE_MEMORY( face );
+
+ FT_UNUSED( num_params );
+ FT_UNUSED( params );
+ FT_UNUSED( face_index );
+
+
+ /* try to load several fonts from a DLL */
+ error = fnt_face_get_dll_fonts( face );
+ if ( error )
+ {
+ /* this didn't work, now try to load a single FNT font */
+ FNT_Font* font;
+
+ if ( ALLOC( face->fonts, sizeof ( *face->fonts ) ) )
+ goto Exit;
+
+ face->num_fonts = 1;
+ font = face->fonts;
+
+ font->offset = 0;
+ font->fnt_size = stream->size;
+
+ error = fnt_font_load( font, stream );
+ if ( error )
+ goto Fail;
+ }
+
+ /* all right, one or more fonts were loaded; we now need to */
+ /* fill the root FT_Face fields with relevant information */
+ {
+ FT_Face root = FT_FACE( face );
+ FNT_Font* fonts = face->fonts;
+ FNT_Font* limit = fonts + face->num_fonts;
+ FNT_Font* cur;
+
+
+ root->num_faces = 1;
+ root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
+ FT_FACE_FLAG_HORIZONTAL;
+
+ if ( fonts->header.avg_width == fonts->header.max_width )
+ root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+ if ( fonts->header.italic )
+ root->style_flags |= FT_STYLE_FLAG_ITALIC;
+
+ if ( fonts->header.weight >= 800 )
+ root->style_flags |= FT_STYLE_FLAG_BOLD;
+
+ /* Setup the `fixed_sizes' array */
+ if ( ALLOC_ARRAY( root->available_sizes, face->num_fonts,
+ FT_Bitmap_Size ) )
+ goto Fail;
+
+ root->num_fixed_sizes = face->num_fonts;
+
+ {
+ FT_Bitmap_Size* size = root->available_sizes;
+
+
+ for ( cur = fonts; cur < limit; cur++, size++ )
+ {
+ size->width = cur->header.pixel_width;
+ size->height = cur->header.pixel_height;
+ }
+ }
+
+ /* Setup the `charmaps' array */
+ root->charmaps = &face->charmap_handle;
+ root->num_charmaps = 1;
+
+ face->charmap.encoding = ft_encoding_unicode;
+ face->charmap.platform_id = 3;
+ face->charmap.encoding_id = 1;
+ face->charmap.face = root;
+
+ face->charmap_handle = &face->charmap;
+
+ root->charmap = face->charmap_handle;
+
+ /* setup remaining flags */
+ root->num_glyphs = fonts->header.last_char -
+ fonts->header.first_char + 1;
+
+ root->family_name = (FT_String*)fonts->fnt_frame +
+ fonts->header.face_name_offset;
+ root->style_name = (char *)"Regular";
+
+ if ( root->style_flags & FT_STYLE_FLAG_BOLD )
+ {
+ if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
+ root->style_name = (char *)"Bold Italic";
+ else
+ root->style_name = (char *)"Bold";
+ }
+ else if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
+ root->style_name = (char *)"Italic";
+ }
+
+ Fail:
+ if ( error )
+ FNT_Face_Done( face );
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ FNT_Size_Set_Pixels( FNT_Size size )
+ {
+ /* look up a font corresponding to the current pixel size */
+ FNT_Face face = (FNT_Face)FT_SIZE_FACE( size );
+ FNT_Font* cur = face->fonts;
+ FNT_Font* limit = cur + face->num_fonts;
+
+
+ size->font = 0;
+ for ( ; cur < limit; cur++ )
+ {
+ /* we only compare the character height, as fonts used some strange */
+ /* values */
+ if ( cur->header.pixel_height == size->root.metrics.y_ppem )
+ {
+ size->font = cur;
+
+ size->root.metrics.ascender = cur->header.ascent * 64;
+ size->root.metrics.descender = ( cur->header.pixel_height -
+ cur->header.ascent ) * 64;
+ size->root.metrics.height = cur->header.pixel_height * 64;
+ break;
+ }
+ }
+
+ return ( size->font ? FNT_Err_Ok : FNT_Err_Invalid_Pixel_Size );
+ }
+
+
+ static FT_UInt
+ FNT_Get_Char_Index( FT_CharMap charmap,
+ FT_Long char_code )
+ {
+ FT_Long result = char_code;
+
+
+ if ( charmap )
+ {
+ FNT_Font* font = ((FNT_Face)charmap->face)->fonts;
+ FT_Long first = font->header.first_char;
+ FT_Long count = font->header.last_char - first + 1;
+
+
+ char_code -= first;
+ if ( char_code < count )
+ result = char_code + 1;
+ else
+ result = 0;
+ }
+
+ return result;
+ }
+
+
+ static FT_Error
+ FNT_Load_Glyph( FT_GlyphSlot slot,
+ FNT_Size size,
+ FT_UInt glyph_index,
+ FT_Int load_flags )
+ {
+ FNT_Font* font = size->font;
+ FT_Error error = 0;
+ FT_Byte* p;
+ FT_Int len;
+ FT_Bitmap* bitmap = &slot->bitmap;
+ FT_ULong offset;
+ FT_Bool new_format;
+
+ FT_UNUSED( slot );
+ FT_UNUSED( load_flags );
+
+
+ if ( !font )
+ {
+ error = FNT_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ if ( glyph_index > 0 )
+ glyph_index--;
+ else
+ glyph_index = font->header.default_char - font->header.first_char;
+
+ new_format = FT_BOOL( font->header.version == 0x300 );
+ len = new_format ? 6 : 4;
+
+ /* jump to glyph entry */
+ p = font->fnt_frame + 118 + len * glyph_index;
+
+ bitmap->width = NEXT_ShortLE(p);
+
+ if ( new_format )
+ offset = NEXT_ULongLE(p);
+ else
+ offset = NEXT_UShortLE(p);
+
+ /* jump to glyph data */
+ p = font->fnt_frame + /* font->header.bits_offset */ + offset;
+
+ /* allocate and build bitmap */
+ {
+ FT_Memory memory = FT_FACE_MEMORY( slot->face );
+ FT_Int pitch = ( bitmap->width + 7 ) >> 3;
+ FT_Byte* column;
+ FT_Byte* write;
+
+
+ bitmap->pitch = pitch;
+ bitmap->rows = font->header.pixel_height;
+ bitmap->pixel_mode = ft_pixel_mode_mono;
+
+ if ( ALLOC( bitmap->buffer, pitch * bitmap->rows ) )
+ goto Exit;
+
+ column = (FT_Byte*)bitmap->buffer;
+
+ for ( ; pitch > 0; pitch--, column++ )
+ {
+ FT_Byte* limit = p + bitmap->rows;
+
+
+ for ( write = column; p < limit; p++, write += bitmap->pitch )
+ write[0] = p[0];
+ }
+ }
+
+ slot->flags = ft_glyph_own_bitmap;
+ slot->bitmap_left = 0;
+ slot->bitmap_top = font->header.ascent;
+ slot->format = ft_glyph_format_bitmap;
+
+ /* now set up metrics */
+ slot->metrics.horiAdvance = bitmap->width << 6;
+ slot->metrics.horiBearingX = 0;
+ slot->metrics.horiBearingY = slot->bitmap_top << 6;
+
+ slot->linearHoriAdvance = (FT_Fixed)bitmap->width << 16;
+ slot->format = ft_glyph_format_bitmap;
+
+ Exit:
+ return error;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Driver_Class winfnt_driver_class =
+ {
+ {
+ ft_module_font_driver,
+ sizeof ( FT_DriverRec ),
+
+ "winfonts",
+ 0x10000L,
+ 0x20000L,
+
+ 0,
+
+ (FT_Module_Constructor)0,
+ (FT_Module_Destructor) 0,
+ (FT_Module_Requester) 0
+ },
+
+ sizeof( FNT_FaceRec ),
+ sizeof( FNT_SizeRec ),
+ sizeof( FT_GlyphSlotRec ),
+
+ (FTDriver_initFace) FNT_Face_Init,
+ (FTDriver_doneFace) FNT_Face_Done,
+ (FTDriver_initSize) 0,
+ (FTDriver_doneSize) 0,
+ (FTDriver_initGlyphSlot)0,
+ (FTDriver_doneGlyphSlot)0,
+
+ (FTDriver_setCharSizes) FNT_Size_Set_Pixels,
+ (FTDriver_setPixelSizes)FNT_Size_Set_Pixels,
+
+ (FTDriver_loadGlyph) FNT_Load_Glyph,
+ (FTDriver_getCharIndex) FNT_Get_Char_Index,
+
+ (FTDriver_getKerning) 0,
+ (FTDriver_attachFile) 0,
+ (FTDriver_getAdvances) 0
+ };
+
+
+#ifdef FT_CONFIG_OPTION_DYNAMIC_DRIVERS
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* getDriverClass */
+ /* */
+ /* <Description> */
+ /* This function is used when compiling the TrueType driver as a */
+ /* shared library (`.DLL' or `.so'). It will be used by the */
+ /* high-level library of FreeType to retrieve the address of the */
+ /* driver's generic interface. */
+ /* */
+ /* It shouldn't be implemented in a static build, as each driver must */
+ /* have the same function as an exported entry point. */
+ /* */
+ /* <Return> */
+ /* The address of the TrueType's driver generic interface. The */
+ /* format-specific interface can then be retrieved through the method */
+ /* interface->get_format_interface. */
+ /* */
+ FT_EXPORT_DEF( const FT_Driver_Class* )
+ getDriverClass( void )
+ {
+ return &winfnt_driver_class;
+ }
+
+
+#endif /* FT_CONFIG_OPTION_DYNAMIC_DRIVERS */
+
+
+/* END */
--- /dev/null
+Raph Levien <raph@acm.org>
--- /dev/null
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+\f
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+2001-10-31 Anders Carlsson <andersca@gnu.org>
+
+ * Release 2.3.7
+
+2001-10-15 Raph Levien <raph@pixel.artofcode.com>
+
+ * art_svp_intersect.c (art_svp_intersect_horiz): Minor
+ logic fix so that horiz segments successfully cross
+ zero length segments in the active list.
+
+ (art_svp_intersect_test_cross): Flags indicating whether to
+ do add_point (potentially breaking neighbors) to left and
+ to right.
+
+ (art_svp_intersect_insert_cross): Provide ART_BREAK_LEFT and
+ ART_BREAK_RIGHT flags to art_svp_intersect_test_cross,
+ depending on direction of search.
+
+ (art_svp_intersect_advance_cursor): Provide flags (allow
+ both left and right breaking) to test_cross.
+
+2001-10-15 Raph Levien <raph@pixel.artofcode.com>
+
+ * art_svp_intersect.c (CHEAP_SANITYCHECK): Added an inexpensive
+ sanitycheck to detect multiple insertions of a segment into the
+ horiz list.
+
+ (art_svp_writer_rewind_add_point): Avoid breaking lines below
+ their bottom point.
+
+ (art_svp_intersect_test_cross): Handle cases correctly where
+ intersection point matches y0 of left or right segment. These _do_
+ happen in real world examples. Also, do add_point on newly
+ inserted intersection point.
+
+2001-10-14 Raph Levien <raph@pixel.artofcode.com>
+
+ * art_svp_intersect.c (art_svp_intersect_add_point): Fixed
+ rather subtle logic bug that misplaced insertion point
+ when seg argument was NULL.
+
+2001-10-11 Raph Levien <raph@pixel.artofcode.com>
+
+ * art_svp_render_aa.c (art_svp_render_aa_iter_step): Got rid
+ of qsort of steps, and now keep the step list in sorted order.
+ Further, we combine duplicate steps with the same x value,
+ which bounds the size of the step list to x1 - x0, so we
+ don't need to dynamically resize it. Thanks greatly to
+ Bruce Q. Hammond for the original version of this patch.
+
+2001-10-09 Raph Levien <raph@pixel.artofcode.com>
+
+ * art_svp_intersect.c (art_svp_intersect_test_cross): Breaks
+ bottom part of line segments in "too close" cases.
+
+2001-10-09 Raph Levien <raph@pixel.artofcode.com>
+
+ * art_svp_intersect.c (art_svp_writer_rewind_add_point): Fixed
+ bbox computation.
+ (art_svp_intersector): Handle degenerate case where input
+ SVP has 0 segments.
+
+ * art_svp_intersect.h: Moved definition of art_svp_intersector
+ inside #ifdef __cplusplus, so it links properly against C++
+
+2001-10-09 Raph Levien <raph@pixel.artofcode.com>
+
+ * art_svp_intersect.c (art_svp_intersect_break): Handle
+ case when break y equals sweep line correctly. Also adds
+ first try at winding number sanitychecker, but that makes
+ too many false positives.
+
+2001-10-07 Raph Levien <raph@pixel.artofcode.com>
+
+ * art_svp.c (EPSILON): Set to zero if new intersector is
+ in use - we want svp's to be in strict sorted order.
+
+ * art_svp_intersect.c (art_svp_intersect_test_cross): Explicitly
+ check that top points are equal, and swap immediately if b is out
+ of order.
+ (art_svp_intersect_horiz): Break segments that intersect
+ horizontal lines. Now passes "two squares with offset" test.
+
+2001-10-05 Raph Levien <raph@pixel.artofcode.com>
+
+ * art_svp_intersect.c: Major changes to accommodate
+ horizontal lines. Intersections of horizontal lines
+ aren't fully processed, but should work a lot better
+ than before.
+
+ * testart.c: Minor tweaks. testpat now frees memory
+ so it can be run under memprof to detect leaks.
+
+2001-10-03 Raph Levien <raph@pixel.artofcode.com>
+
+ * art_svp_intersect.c (art_svp_intersect_advance_cursor):
+ Made test_cross for inserted segments common between
+ intersection processing and cursor advance, and also took
+ care of a case that hadn't been handled before. Also added
+ invariant sanitychecker for debugging purposes.
+
+2001-10-02 Raph Levien <raph@pixel.artofcode.com>
+
+ * art_svp_ops.c: ART_USE_NEW_INTERSECTOR variants of svp
+ ops changed to do shallow free of merged svp.
+
+2001-10-01 Raph Levien <raph@acm.org>
+
+ * art_svp_intersect.c:
+ * art_svp_intersect.h:
+ * Makefile.am:
+ * art_misc.h:
+ * art_svp_wind.h: First commit of new intersector code. It is
+ turned off by default, but can be enabled by #defining
+ ART_USE_NEW_INTERSECTOR in art_misc.h.
+
+ * art_svp_ops.c: Make svp ops use new intersector if enabled.
+
+ * art_svp_vpath_stroke.c: Make vpath stroking use new intersector
+ if enabled.
+
+ * testart.c: New test case for intersector.
+
+Wed Sep 26 03:48:13 2001 George Lebl <jirka@5z.com>
+
+ * Release 2.3.6
+
+Wed Sep 26 03:11:40 2001 George Lebl <jirka@5z.com>
+
+ * gen_art_config.c: Fix 64bit issues, cast sizeof return when
+ using %d to print it.
+
+2001-09-13 Havoc Pennington <hp@redhat.com>
+
+ * Makefile.am: rename library to libart_lgpl_2
+
+ * libart-2.0.pc.in (Cflags): move includes
+
+ * libart-config.in: move includes
+
+ * Makefile.am: delete libartConf.sh, rename libart-config
+ (EXTRA_DIST): don't install m4 files
+ (libart_lgplincdir): move headers
+
+2001-08-03 Michael Meeks <michael@ximian.com>
+
+ * Version 2.3.5 for the API freeze.
+
+2001-07-12 Darin Adler <darin@bentspoon.com>
+
+ * art_affine.c: (art_affine_expansion): Fix handling of
+ negative numbers. We ran into this bug a while back when
+ figuring out why librsvg couldn't handle certain svg files.
+
+2001-07-12 Darin Adler <darin@bentspoon.com>
+
+ * art_misc.h: Change art_expand macro so it's a single
+ statement, using the do while (0) trick, which gets rid
+ of some warnings.
+ * art_pixbuf.c: Add a missing include.
+ * art_vpath_svp.c: (art_vpath_from_svp): Initialize a
+ variable to avoid a compiler warning.
+ * gen_art_config.c: Add a missing include.
+
+2001-03-24 Martin Baulig <baulig@suse.de>
+
+ Applied the patch from Alexander Larsson which was sitting
+ in gnome-libs/patches/libart.diff since February.
+ [FIXME: Alex, can you please provide a ChangeLog?])
+
+ * art_rgb_a_affine.[ch]: New files.
+
+2001-01-07 Hans Breuer <Hans@Breuer.Org>
+ * art_misc.c : embryonic change to use libart_lgpl on win32
+ * libart.def : new file, exported functions for win32 dll
+ * makefile.msc : handwritten for MSVC compiler
+
+2000-09-30 Martin Baulig <baulig@suse.de>
+
+ * libart-2.0.pc.in: Provide pkg-config script.
+
+ * configure.in: Create libart-2.0.pc from libart-2.0.pc.in.
+ * Makefile.am (pkgconfig_DATA): Install the libart-2.0.pc
+ script in `$(libdir)/pkgconfig'.
+
+2000-08-15 Raph Levien <raph@acm.org>
+
+ * art_render.c (art_render_image_solid_negotiate): Only
+ sets ART_IMAGE_SOURCE_CAN_COMPOSITE when a compositing
+ callback is selected. Previously was causing segfaults on
+ non-alpha images. Thanks to Leonard Rosenthol for spotting
+ the bug.
+
+Fri Jun 30 22:56:58 2000 Raph Levien <raph@acm.org>
+
+ * art_render.c (art_render_composite): Fixed a bug that caused
+ it to ignore the alpha setting. Also art_render_composite_8().
+
+2000-06-01 John Sullivan <sullivan@eazel.com>
+
+ * art_svp_render_aa.c: (art_svp_render_aa_iter_step):
+ Made it build by correcting struct member name from
+ Raph's previous checkin.
+
+Wed May 31 11:10:58 2000 Raph Levien <raph@acm.org>
+
+ * art_svp_render_aa.c (art_svp_render_aa_iter_step): Updated
+ n_steps_max in iter structure after steps reallocation.
+
+Tue May 30 10:33:13 2000 Raph Levien <raph@acm.org>
+
+ * art_svp_render_aa.c (art_svp_render_aa_iter_step): Fixed not
+ updating iter->steps when steps gets reallocated.
+
+2000-05-30 Pavel Cisler <pavel@eazel.com>
+
+ * art_rgba.c:
+ Make it build -- fix a broken include.
+
+Tue May 30 00:09:21 2000 Raph Levien <raph@acm.org>
+
+ * art_render_gradient.c (art_render_gradient_setpix): Fixed
+ an off-by-one loop error.
+
+Mon May 29 15:00:39 2000 Raph Levien <raph@acm.org>
+
+ * Makefile.am: Moved relevant .h files into HEADERS stanza.
+
+Mon May 29 13:48:49 2000 Raph Levien <raph@acm.org>
+
+ This is a fairly major commit, as it adds both the new, modular
+ rendering architecture and gradients. Quite a bit of the code
+ feels like "reference code" now, in that it is (hopefully)
+ correct, but not necessarily very fast. In addition, there remain
+ a few things not done, including the use of SVP's as non-driver
+ mask sources. AlphaGamma and filter level also remain
+ unimplemented. No compositing modes other than ART_NORMAL are
+ implemented. All in good time!
+
+ * configure.in: added -Wmissing-prototypes flag. Bumped version
+ number to 2.3.0.
+
+ * art_render.h:
+ * art_render.c: Added new rendering architecture.
+
+ * art_render_svp.h:
+ * art_render_svp.c: Added renderers to use SVP's as mask
+ sources in new rendering architecture.
+
+ * art_render_gradient.h:
+ * art_render_gradient.c: Added linear and radial gradients
+ as image sources in new rendering architecture.
+
+ * art_rgba.h:
+ * art_rgba.c: Added functions for manipulating and compositing
+ RGBA pixels.
+
+ * art_svp_wind.c: Added static to trap_epsilon(), #ifdef'd out
+ traverse().
+
+ * art_uta_ops.c: Added #include "art_uta_ops.h".
+
+ * art_uta_rect.c: Added #include "art_uta_rect.h".
+
+ * art_uta_svp.h: fixed __ART_UTA_SVP_H__ name.
+
+ * art_misc.h: Added ART_GNUC_NORETURN attribute, added that
+ to the prototype for art_die(). Added "static" to function
+ declarations to avoid warnings when compiled with
+
+ * testart.c: Added gradient test.
+
+Thu May 25 23:30:39 2000 Raph Levien <raph@acm.org>
+
+ * art_svp_render_aa.h:
+ * art_svp_render_aa.c: Added art_svp_render_aa_iter functions,
+ suitable for iterative rendering of an svp, one scan line at a
+ time.
+
+ * configure.in: Bumped version to 2.2.0.
+
+Tue May 16 15:03:35 2000 Raph Levien <raph@acm.org>
+
+ * art_rgb_pixbuf_affine.c: Included corresponding .h file.
+
+ * art_rgb_pixbuf_affine.h: Put recursive #includes inside
+ LIBART_COMPILATION test.
+
+ * art_gray_svp.c:
+ * art_rgb_svp.c: Explicit casts for callback data. Also removed
+ "render the steps into tmpbuf" comment.
+
+ * gen_art_config.c:
+ * Makefile.am:
+ * configure.in: Added code to automatically generate an
+ art_config.h file, to be installed in libart's include dir. This
+ file defines ART_SIZEOF_{CHAR,SHORT,INT,LONG} and art_u{8,16,32}.
+
+ * art_misc.h: Moved definition of art_u8 and art_u32 into
+ art_config.h. Added GCC printf format attributes.
+
+ * art_svp_wind.c (traverse): Fixed UMR bug here. The function
+ isn't actually used, so it's just for cleanliness.
+
+2000-04-18 Lauris Kaplinski <lauris@ariman.ee>
+
+ * art_affine.c (art_affine_to_string): Replaced snprinf with
+ art_ftoa to avoid localisation of generated numbers
+
+2000-04-18 ERDI Gergo <cactus@cactus.rulez.org>
+
+ * art_rgb_pixbuf_affine.h: Included the ArtPixBuf declaration
+
+Fri Apr 14 16:33:55 2000 Raph Levien <raph@acm.org>
+
+ * art_svp_wind.c (art_svp_uncross, art_svp_rewind_uncrossed):
+ Fixed uninitialized memory reads when inserting new segment into
+ active_segs.
+
+ * art_bpath.c (art_bpath_affine_transform): Made it avoid
+ potential uninitialized memory reads when not all the coordinates
+ are needed. Thanks to Morten Welinder for spotting both of these
+ problems.
+
+2000-04-05 Raph Levien <raph@gimp.org>
+
+ * art_svp_wind.c: Make "colinear" warnings go to stderr instead
+ of stdout. Of course, when I finish the new intersector, these
+ will go away entirely.
+
+2000-04-04 Raph Levien <raph@gimp.org>
+
+ * art_uta_vpath.c (art_uta_add_line): Fixed bug that was causing
+ segfaults on alphas. Thanks to msw for localizing it.
+
+2000-01-17 Raph Levien <raph@gimp.org>
+
+ * art_svp_vpath_stroke.c (art_svp_vpath_stroke): Typo in api
+ header (thanks rak).
+
+2000-01-16 Timur Bakeyev <timur@gnu.org>
+
+ * autoconf.sh: Instead of jumping between srdir and builddir just process
+ all the auto* staff in srcdir. In fact, just saying the same things in
+ other words.
+
+2000-01-10 Elliot Lee <sopwith@redhat.com>
+
+ * Makefile.am, *.h: Add rather bad hacks to the header files to allow compilation
+
+ * Makefile.am: Distribute libart-config.in
+
+2000-01-09 Raph Levien <raph@gimp.org>
+
+ art_rgb_pixbuf_affine.c, art_rgb_rgba_affine.c, art_rgb_svp.c,
+ art_svp.c, art_svp_ops.c, art_svp_point.c, art_svp_render_aa.c,
+ art_svp_vpath.c, art_svp_vpath_stroke.c, art_svp_wind.c,
+ art_uta.c, art_uta_ops.c, art_uta_rect.c, art_uta_svp.c,
+ art_uta_vpath.c, art_vpath.c, art_vpath_bpath.c, art_vpath_dash.c,
+ art_vpath_svp.c: Added API documentation.
+
+Fri Sep 24 17:53:21 1999 Raph Levien <raph@acm.org>
+
+ * art_svp_render_aa.c (art_svp_render_insert_active): Avoid
+ reading undefined memory (thanks to Morten Welinder).
+
+1999-09-19 Raph Levien <raph@gimp.org>
+
+ * art_pixbuf.c (art_pixbuf_duplicate): Added a duplicate function
+ at the request of Michael Meeks.
+
+1999-09-11 Raph Levien <raph@gimp.org>
+
+ * art_affine.c (art_affine_to_string): Tightened the predicate for
+ matching rotate-only affines, which was too weak. Thanks to lewing
+ for spotting it!
+
+1999-09-01 Raph Levien <raph@gimp.org>
+
+ * art_affine.c, art_alphagamma.c, art_bpath.c, art_gray_svp.c,
+ art_misc.c, art_pixbuf.c, art_rect.c, art_rect_svp.c,
+ art_rect_uta.c, art_rgb.c, art_rgb_affine.c,
+ art_rgb_bitmap_affine.c: Updates to api doc headers.
+
+1999-08-24 Raph Levien <raph@gimp.org>
+
+ * art_affine.c, art_alphagamma.c, art_alphagamma.h, art_bpath.c,
+ art_bpath.h, art_gray_svp.c, art_misc.c, art_pixbuf.c,
+ art_pixbuf.h, art_point.h, art_rect.c, art_rect.h: Added api
+ documentation headers.
+
+ * testart.c: Added "dash" test, for testing the vpath_dash
+ functions.
+
+ * art_rgb_pixbuf_affine.h: Fixed the #ifdef for conditional
+ inclusion. Thanks to Kristian Hogsberg Kristensen for spotting
+ the bug.
+
+1999-08-24 Raph Levien <raph@gimp.org>
+
+ * art_svp_render_aa.c (art_svp_render_aa): Added some tests to
+ avoid NaN for infinite slopes, which were causing problems on
+ Alphas. Closes bug #1966.
+
+1999-08-20 Federico Mena Quintero <federico@redhat.com>
+
+ * configure.in: Fixed library's libtool version number.
+
+1999-08-03 Larry Ewing <lewing@gimp.org>
+
+ * art_vpath_dash.c (art_vpath_dash): fix a bug/typo that was causing
+ certain paths to loop infinitely.
+
+1999-07-28 Raph Levien <raph@gimp.org>
+
+ * art_vpath_dash.[ch]: Added a function to add a dash style
+ to vpaths. It is tested, but has a couple of rough edges (see
+ code for details).
+
+ * testart.c: added tests for the new vpath_dash functionality.
+
+ * Makefile.am: added art_vpath_dash.[ch] files.
+
+1999-07-26 Raph Levien <raph@gimp.org>
+
+ * art_rgb.c (art_rgb_fill_run): fixed incorrect test for
+ big-endianness. Thanks to Michael Zucchi for spotting it.
+
+Fri Jul 16 23:42:59 1999 Tim Janik <timj@gtk.org>
+
+ * art_affine.c (art_affine_flip): flip translation matrixes as well, by
+ inverting matrix[4] if (horz) and inverting matrix[5] if (vert).
+
+Fri Jul 16 23:03:26 1999 Tim Janik <timj@gtk.org>
+
+ * art_pixbuf.[hc]: deprecated art_pixbuf_free_shallow(), people should
+ always free pixbufs with art_pixbuf_free() and use the _dnotify variants
+ for specific destruction behaviour.
+ added art_pixbuf_new_rgb_dnotify() and art_pixbuf_new_rgba_dnotify()
+ which allow for a destruction notification function. (this involved
+ adding two extra pointers to the ArtPixBuf structure, and removal of
+ the recently introduced int flags field).
+
+Mon Jul 12 01:13:23 1999 Tim Janik <timj@gtk.org>
+
+ * art_affine.[hc]: added art_affine_equal(), which checks two
+ matrixes for equality within grid alignment.
+
+Fri Jul 9 17:50:19 1999 Tim Janik <timj@gtk.org>
+
+ * art_affine.[hc]: added art_affine_flip() to flip a matrix horizontally
+ and/or vertically, or just copy it.
+ added art_affine_shear() to setup a shearing matrix.
+
+Tue Jul 6 19:03:39 1999 Tim Janik <timj@gtk.org>
+
+ * art_pixbuf.h: added an int flags; member to the end of the
+ structure, it currently only holds information about whether the
+ pixels member should be freed. (raph: i think flags is more generic
+ than free_pixels, so we can reuse that field if further demands popup
+ in the future).
+
+ * art_pixbuf.c:
+ (art_pixbuf_new_const_rgba):
+ (art_pixbuf_new_const_rgb): new functions that prevent the pixels
+ member from being freed upon art_pixbuf_free ().
+ (art_pixbuf_free): only free the pixels member if it is non-NULL and
+ the PIXBUF_FLAG_DESTROY_PIXELS is set.
+
+1999-07-02 Raph Levien <raph@gimp.org>
+
+ * art_vpath_bpath.c (art_vpath_render_bez): Bad bad uninitialized
+ variables.
+
+ * configure.in: added compile warnings. Guess why :)
+
+1999-06-28 Raph Levien <raph@gimp.org>
+
+ * art_svp_point.h:
+ * art_svp_point.c: Added methods for insideness and distance
+ testing, very useful for ::point methods in canvas items.
+
+ * testart.c: test code to exercise the art_svp_point functions.
+
+ * Makefile.am: Additional entries for art_svp_point.
+
+1999-06-28 Raph Levien <raph@gimp.org>
+
+ * art_svp_render_aa.c (art_svp_render_aa): Subtle boundary
+ case in realloc code -- was causing nasty segfaults.
+
+Wed Jun 23 15:05:43 1999 Raph Levien <raph@gimp.org>
+
+ * art_rgb_svp.c (art_rgb_svp_alpha_opaque_callback): Missed a
+ case in the anti-segfault crusade. Thanks lewing!
+
+Wed Jun 23 11:16:42 1999 Raph Levien <raph@gimp.org>
+
+ * art_rgb_svp.c: Made these routines so they won't segfault even
+ if alpha is out of range. Of course, that begs the question of
+ fixing the render routines so they won't _make_ alpha go out of
+ range, but all in good time.
+
+Fri Jun 18 17:32:34 1999 Raph Levien <raph@acm.org>
+
+ * art_vpath_bpath.c (art_bez_path_to_vec): Switched to a new
+ adaptive subdivision algorithm, which (finally!) takes flatness
+ into account. This should result in both smoother curves and
+ faster operation.
+
+Sun Jun 13 21:07:20 1999 Raph Levien <raph@gimp.org>
+
+ * art_svp_wind.c (art_svp_rewind_uncrossed): Made the winding
+ rule logic even more correct :). I somehow missed the fact that
+ a clockwise path should be given a winding number of zero;
+ last night's commit tried to make it -1 (which worked for the
+ test cases I was using).
+
+Sun Jun 13 01:23:14 1999 Raph Levien <raph@gimp.org>
+
+ * art_svp_wind.c (art_svp_rewind_uncrossed): Change to winding
+ rule logic so that it correctly handles the case where the
+ leftmost segment is negative.
+
+ * Makefile.am (libart_lgplinc_HEADERS): made art_svp_wind.h
+ a public headerfile. This is needed for the bpath canvas item.
+ I'm not sure this is the correct way to do it, but it will do
+ for now.
+
+ * art_vpath_bpath.h:
+ * art_vpath_bpath.c (art_bez_path_to_vec): Added const to arg.
+
+ * art_vpath_bpath.h: Embarrassing typo.
+
+ * art_bpath.h: Minor tweaks to the #include paths. It is now
+ consistent with the other header files.
+
+Wed Jun 9 20:24:45 1999 Raph Levien <raph@gimp.org>
+
+ * art_svp_vpath_stroke.c: Added all remaining line join and cap
+ types, including round, which takes flatness into account. Several
+ new internal functions (art_svp_vpath_stroke_arc) and added
+ flatness argument to a few internal functions. I might want to
+ change the BEVEL join type to MITER for very small turn angles
+ (i.e. within a flatness threshold) for efficiency.
+
+ * art_misc.h: Added M_SQRT2 constant.
+
+Wed Jun 2 21:56:30 1999 Raph Levien <raph@gimp.org>
+
+ * art_svp_vpath_stroke.c (art_svp_vpath_stroke_raw): Made the
+ closed path detection capable of PostScript semantics (i.e. it
+ now senses the difference between ART_MOVETO and ART_MOVETO_OPEN).
+
+ * art_svp_vpath_stroke.c (art_svp_vpath_stroke_raw): it now
+ filters out successive points that are (nearly) coincident. This
+ fixes some of the crashes and hangs, including Tim Janik's
+ singularity (trying to stroke MOVETO 50, 50; LINETO 50, 50; END).
+
+ * art_svp_wind.c (art_svp_rewind_uncrossed): added a test to
+ correctly handle empty input svp's.
+
+ * art_svp_wind.c (art_svp_uncross): added a test to correctly
+ handle empty input svp's.
+
+Sun Jan 17 20:53:40 1999 Jeff Garzik <jgarzik@pobox.com>
+
+ * art_affine.c:
+ Include string.h for memcpy.
+
+ * art_svp_vpath.c:
+ Remove conflicting static func definition.
+
+ * art_uta_svp.c:
+ Include art_vpath_svp.h for func definition.
+
+Mon Jan 4 12:47:47 1999 Raph Levien <raph@acm.org>
+
+ * art_bpath.c (art_bpath_affine_transform): Stupid misnaming
+ of this function (forgot the "art_").
+
+Thu Dec 31 09:04:23 1998 Raph Levien <raph@gimp.org>
+
+ * art_affine.c (art_affine_rectilinear): Added this function.
+
+ * art_rect.c (art_drect_affine_transform): Corrected the name (it
+ was right in the .h). Also made it work with non-rectilinear
+ transforms, while I was at it.
+
+Thu Dec 17 11:58:24 1998 Raph Levien <raph@acm.org>
+
+ * art_alphagamma.h:
+ * art_alphagamma.c: The real code for alphagamma.
+
+Wed Dec 16 14:18:46 1998 Raph Levien <raph@gimp.org>
+
+ * art_alphagamma.h:
+ * art_alphagamma.c: Added. At present, it only contains a dummy
+ stub. When the real code is added, it supports doing alpha
+ compositing in a gamma-corrected color space (suppressing
+ jaggies).
+
+ * art_pixbuf.h:
+ * art_pixbuf.c: Added. This is a virtualization layer over
+ a few different kinds of image formats.
+
+ * art_rgb_pixbuf_affine.h:
+ * art_rgb_pixbuf_affine.c: Added. Supports compositing of
+ generic images over an rgb buffer.
+
+ * art_affine.h:
+ * art_affine.c (art_affine_expansion): Added this function,
+ which reports the exact scale factor in the case of rotation,
+ scaling, and transformation (an approximate number in the
+ case of shearing or anamorphic distortion).
+
+ * art_misc.h:
+ * art_misc.c (art_warn): Added.
+
+ * art_rgb_affine.h:
+ * art_rgb_affine.c: Added alphagamma argument (not yet implemented).
+
+ * art_rgb_affine_private.c: Fixed typo bug that was causing
+ repaint problems for nonsquare images.
+
+ * art_rgb_bitmap_affine.h:
+ * art_rgb_bitmap_affine.c: Major speed improvement, probably fixed
+ correctness while I was at it. Added alphagamma argument (not yet
+ implemented).
+
+ * art_rgb_svp.h:
+ * art_rgb_svp.c: Added alphagamma argument (only implemented
+ in aa case, not yet alpha case).
+
+ * art_vpath.c: increased perturbation to 2e-3, because the old
+ value (1e-6) was too small.
+
+ * testart.c: added alphagamma.
+
+ * Makefile.am: added new files
+
+Sun Dec 27 21:45:03 1998 Raph Levien <raph@gimp.org>
+
+ * art_rect.h:
+ * art_rect.c: Added DRect versions of the basic ops (double
+ rather than int).
+
+ * art_rect_svp.h:
+ * art_rect_svp.c: Added. This computes the bounding box of
+ an svp.
+
+Wed Dec 16 14:18:46 1998 Raph Levien <raph@gimp.org>
+
+ * art_alphagamma.h:
+ * art_alphagamma.c: Added. At present, it only contains a dummy
+ stub. When the real code is added, it supports doing alpha
+ compositing in a gamma-corrected color space (suppressing
+ jaggies).
+
+ * art_pixbuf.h:
+ * art_pixbuf.c: Added. This is a virtualization layer over
+ a few different kinds of image formats.
+
+ * art_rgb_pixbuf_affine.h:
+ * art_rgb_pixbuf_affine.c: Added. Supports compositing of
+ generic images over an rgb buffer.
+
+ * art_affine.h:
+ * art_affine.c (art_affine_expansion): Added this function,
+ which reports the exact scale factor in the case of rotation,
+ scaling, and transformation (an approximate number in the
+ case of shearing or anamorphic distortion).
+
+ * art_misc.h:
+ * art_misc.c (art_warn): Added.
+
+ * art_rgb_affine.h:
+ * art_rgb_affine.c: Added alphagamma argument (not yet implemented).
+
+ * art_rgb_affine_private.c: Fixed typo bug that was causing
+ repaint problems for nonsquare images.
+
+ * art_rgb_bitmap_affine.h:
+ * art_rgb_bitmap_affine.c: Major speed improvement, probably fixed
+ correctness while I was at it. Added alphagamma argument (not yet
+ implemented).
+
+ * art_rgb_svp.h:
+ * art_rgb_svp.c: Added alphagamma argument (only implemented
+ in aa case, not yet alpha case).
+
+ * art_vpath.c: increased perturbation to 2e-3, because the old
+ value (1e-6) was too small.
+
+ * testart.c: added alphagamma.
+
+ * Makefile.am: added new files
+
+Mon Dec 14 00:16:53 1998 Raph Levien <raph@gimp.org>
+
+ * art_affine.c (art_affine_to_string): re-added the "scale" method
+ that was accidentally deleted before check-in.
+
+ * Makefile.am: added new files
+
+Sun Dec 13 00:52:39 1998 Raph Levien <raph@gimp.org>
+
+ * art_affine.h:
+ * art_affine.c: Added. Everything you ever wanted to do with an
+ affine transform. Especially check the functions that generate
+ concise PostScript strings for affine transforms.
+
+ * art_filterlevel.h: A simple enum for selecting filtering
+ style.
+
+ * art_rgb_affine.h:
+ * art_rgb_affine.c (art_rgb_affine): Added. This function
+ composites an (opaque) rgb image over an rgb pixel buffer. At
+ present, it's slow and only nearest neighbor filtering is enabled.
+
+ * art_rgb_rgba_affine.h:
+ * art_rgb_rgba_affine.c: Analogous, but for compositing rgba
+ images.
+
+ * art_rgb_bitmap_affine.h:
+ * art_rgb_bitmap_affine.c: Analogous, but for compositing bitmap
+ images.
+
+ * art_rgb_affine_private.c (art_rgb_affine_run): Added. This is
+ a common function used by all the rgb_affine modules to move
+ testing for source image bbox out of the inner loop.
+
+ * Makefile.am: added the new files
+
+ * testart.c: exercise the image compositors
+
+Wed Dec 9 23:36:35 1998 Raph Levien <raph@gimp.org>
+
+ * art_vpath.c (art_vpath_perturb): Made it deal correctly
+ with closed paths (the MOVETO and closing LINETO have to
+ agree).
+
+ * art_svp_wind.c: Made the bbox calculations for the resulting
+ svp's correct.
+
+ * art_svp.h:
+ * art_svp.c: The art_svp_seg_compare function moved here, because
+ it's required in art_svp_ops.
+
+ * art_svp.c (art_svp_add_segment): It now does bbox calculations.
+
+ * art_svp_ops.h:
+ * art_svp_ops.c: Added. Populated with basic union, intersection,
+ and diff functions.
+
+ * art_vpath_svp.h:
+ * art_vpath_svp.c: Added. Populated with a function to convert
+ from sorted to unsorted vector paths
+
+ * Makefile.am: added the new files
+
+ * testart.c: exercise the stroke outline and vector path
+ operations.
+
+1998-12-08 Herbert Valerio Riedel <hvr@hvrlab.ml.org>
+
+ * art_svp_wind.c: added #include <string.h> for memcpy()
+
+Sun Dec 6 22:15:12 1998 Raph Levien <raph@gimp.org>
+
+ * art_svp_wind.[ch], art_svp_vpath_stroke.[ch]: Added, but it
+ doesn't work yet. These will do stroke outline and basic
+ vector ops like union, intersect, etc.
+
+ * art_svp_render_aa.c: Added a simple speedup based on bbox
+ culling. I will want to do more speedups, but none of this is
+ necessary for the freeze.
+
+ * art_svp_vpath.c: Fixed some bugs in the art_svp_from_vpath in
+ cases where there is more than one subpath.
+
+ * art_vpath.h:
+ * art_vpath.c (art_vpath_perturb): Added this function. This will
+ help cheat as long as the basic vector ops have numerical
+ stability problems.
+
+Fri Dec 4 18:00:38 1998 Raph Levien <raph@gimp.org>
+
+ * art_svp_render_aa.c (art_svp_render_aa): Changed the api
+ slightly, to guarantee that the steps are all within the range
+ from x0 (inclusive) to x1 (exclusive).
+
+ * art_gray_svp.c, art_gray_svp.h: Added. Populated with functions
+ to render into a simple graymap.
+
+ * art_rgb.c, art_rgb.c: Added. Populated with fill_run and
+ run_alpha methods.
+
+ * art_rgb_svp.c, art_rgb_svp.h: Added. Populated with functions to
+ render into an RGB buffer, and to composite over an RGB buffer.
+
+ * Makefile.am: added art_gray_svp, art_rgb, and art_rgb_svp.
+
+ * testart.c: test the color and layered rendering.
+
+Mon Nov 30 01:30:25 1998 Raph Levien <raph@gimp.org>
+
+ * testart.c: added vector path rendering stuff. Some of it needs
+ to go out of the test framework and into the module, but the
+ api hasn't settled down entirely yet (in the real code, all
+ x's in the step field are within bounds).
+
+ * art_svp_render_aa.c, art_svp_render_aa.c.h: added.
+
+ * art_svp_vpath.c, art_svp_vpath.h: added.
+
+ * art_pathcode.h: added ART_MOVETO_OPEN (libart uses an
+ ART_MOVETO_OPEN code at the beginning to indicate an open path,
+ while PostScript uses the lack of a closepath at the end).
+
+ * art_vpath_bpath.c, art_vpath_bpath.h: fixed it up, added
+ flatness arg to api.
+
+ * Makefile.am: added new source files.
+
+Wed Nov 25 17:19:44 1998 Raph Levien <raph@gimp.org>
+
+ * art_svp.h, art_svp.c: added, basic constructors for sorted
+ vector paths.
+
+Sun Nov 22 23:21:09 1998 Raph Levien <raph@gimp.org>
+
+ * Makefile.am (libart_lgplincdir): Fixed stupid bug in naming of
+ the variable.
+
+Sun Nov 22 21:41:13 1998 Raph Levien <raph@gimp.org>
+
+ * art_uta_vpath.c: moved art_uta_union into art_uta_ops.
+
+ * art_uta_ops.[ch]: added, populated with art_uta_union.
+
+Thu Nov 19 00:19:40 1998 Raph Levien <raph@gimp.org>
+
+ * libartConf.sh.in: added
+
+ * Makefile.am: added creation of libartConf.sh, added -version-info
+ * configure.in: added LIBART_VERSION_INFO, support for libartConf.sh
+
+ * libart.m4: updated version history :)
+
+Wed Nov 18 18:15:20 1998 Raph Levien <raph@gimp.org>
+
+ * configure.in (LIBART_VERSION): set this, so that libart-config
+ --version now works.
+
+Wed Nov 18 16:50:58 1998 Raph Levien <raph@gimp.org>
+
+ * libart.m4: added (just copied from esound)
+ * configure.in, Makefile.am: added support for libart-config
+ * libart-config.in: added (mostly copied from esound)
+
+Tue Nov 10 12:43:30 1998 Raph Levien <raph@acm.org>
+
+ * Getting the library in shape for initial checkin to CVS.
+
+
--- /dev/null
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
--- /dev/null
+# Makefile.in generated automatically by automake 1.5 from Makefile.am.
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+SHELL = /bin/sh
+
+srcdir = .
+top_srcdir = ../..
+
+prefix = /usr/local/rrdtool-1.1.0
+exec_prefix = ${prefix}
+
+bindir = ${exec_prefix}/bin
+sbindir = ${exec_prefix}/sbin
+libexecdir = ${exec_prefix}/libexec
+datadir = ${prefix}/share
+sysconfdir = ${prefix}/etc
+sharedstatedir = ${prefix}/com
+localstatedir = ${prefix}/var
+libdir = ${exec_prefix}/lib
+infodir = ${prefix}/info
+mandir = ${prefix}/man
+includedir = ${prefix}/include
+oldincludedir = /usr/include
+pkgdatadir = $(datadir)/rrdtool
+pkglibdir = $(libdir)/rrdtool
+pkgincludedir = $(includedir)/rrdtool
+top_builddir = ../..
+
+ACLOCAL = ${SHELL} /home/oetiker/data/projects/cvs-checkout/rrdtool/program/config/missing --run aclocal
+AUTOCONF = ${SHELL} /home/oetiker/data/projects/cvs-checkout/rrdtool/program/config/missing --run autoconf
+AUTOMAKE = ${SHELL} /home/oetiker/data/projects/cvs-checkout/rrdtool/program/config/missing --run automake
+AUTOHEADER = ${SHELL} /home/oetiker/data/projects/cvs-checkout/rrdtool/program/config/missing --run autoheader
+
+INSTALL = /usr/sepp/bin/ginstall -c
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = s,x,x,
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias =
+host_triplet = sparc-sun-solaris2.8
+AMTAR = ${SHELL} /home/oetiker/data/projects/cvs-checkout/rrdtool/program/config/missing --run tar
+ART_LIB_DIR = libraries/libart_lgpl-2.3.7
+AS = @AS@
+AWK = gawk
+CC = gcc
+CGI_LIB_DIR = libraries/cgilib-0.4
+COMP_PERL = perl_piped perl_shared
+CPP = gcc -E
+DEPDIR = .deps
+DLLTOOL = @DLLTOOL@
+ECHO = /usr/ucb/echo
+EXEEXT =
+FREETYPE_LIB_DIR = libraries/freetype-2.0.5
+INSTALL_STRIP_PROGRAM = ${SHELL} $(install_sh) -c -s
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LN_S = ln -s
+NROFF = /usr/sepp/bin/gnroff
+OBJDUMP = @OBJDUMP@
+OBJEXT = o
+PACKAGE = rrdtool
+PERL = /usr/bin/perl
+PERLFLAGS =
+PERL_MAKE_OPTIONS =
+PNG_LIB_DIR = libraries/libpng-1.2.0
+RANLIB = ranlib
+SO_EXT = so
+STRIP = strip
+TCL_LD_SEARCH_FLAGS =
+TCL_PACKAGE_PATH =
+TCL_PREFIX =
+TCL_SHLIB_CFLAGS =
+TCL_SHLIB_LD =
+TCL_SHLIB_SUFFIX =
+TROFF = /usr/sepp/bin/groff
+VERSION = 1.1.0
+ZLIB_CFLAGS = -g -O2 -Wall -pedantic -Wshadow -Wpointer-arith -Wcast-align -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline -fPIC
+ZLIB_LIB_DIR = libraries/zlib-1.1.3
+am__include = include
+am__quote =
+install_sh = /home/oetiker/data/projects/cvs-checkout/rrdtool/program/config/install-sh
+
+noinst_LTLIBRARIES = librrd_art.la
+noinst_PROGRAMS = gen_art_config
+
+BUILT_SOURCES = art_config.h
+
+EXTRA_DIST = \
+ libart-config.in \
+ libart-2.0.pc.in
+
+
+librrd_art_la_SOURCES = \
+ art_affine.c \
+ art_alphagamma.c \
+ art_bpath.c \
+ art_gray_svp.c \
+ art_misc.c \
+ art_pixbuf.c \
+ art_rect.c \
+ art_rect_svp.c \
+ art_rect_uta.c \
+ art_render.c \
+ art_render_gradient.c \
+ art_render_svp.c \
+ art_rgb.c \
+ art_rgb_affine.c \
+ art_rgb_affine_private.c \
+ art_rgb_affine_private.h \
+ art_rgb_bitmap_affine.c \
+ art_rgb_pixbuf_affine.c \
+ art_rgb_rgba_affine.c \
+ art_rgb_a_affine.c \
+ art_rgba.c \
+ art_rgb_svp.c \
+ art_svp.c \
+ art_svp_intersect.c \
+ art_svp_ops.c \
+ art_svp_point.c \
+ art_svp_render_aa.c \
+ art_svp_vpath.c \
+ art_svp_vpath_stroke.c \
+ art_svp_wind.c \
+ art_uta.c \
+ art_uta_ops.c \
+ art_uta_rect.c \
+ art_uta_vpath.c \
+ art_uta_svp.c \
+ art_vpath.c \
+ art_vpath_bpath.c \
+ art_vpath_dash.c \
+ art_vpath_svp.c \
+ libart-features.c
+
+
+librrd_artincdir = $(includedir)/libart-2.0/libart_lgpl
+librrd_artinc_HEADERS = \
+ art_affine.h \
+ art_alphagamma.h \
+ art_bpath.h \
+ art_config.h \
+ art_filterlevel.h \
+ art_gray_svp.h \
+ art_misc.h \
+ art_pathcode.h \
+ art_pixbuf.h \
+ art_point.h \
+ art_rect.h \
+ art_rect_svp.h \
+ art_rect_uta.h \
+ art_render.h \
+ art_render_gradient.h \
+ art_render_svp.h \
+ art_rgb.h \
+ art_rgb_affine.h \
+ art_rgb_bitmap_affine.h \
+ art_rgb_pixbuf_affine.h \
+ art_rgb_rgba_affine.h \
+ art_rgb_a_affine.h \
+ art_rgb_svp.h \
+ art_rgba.h \
+ art_svp.h \
+ art_svp_intersect.h \
+ art_svp_ops.h \
+ art_svp_point.h \
+ art_svp_render_aa.h \
+ art_svp_vpath.h \
+ art_svp_vpath_stroke.h \
+ art_svp_wind.h \
+ art_uta.h \
+ art_uta_ops.h \
+ art_uta_rect.h \
+ art_uta_vpath.h \
+ art_uta_svp.h \
+ art_vpath.h \
+ art_vpath_bpath.h \
+ art_vpath_dash.h \
+ art_vpath_svp.h \
+ libart.h \
+ libart-features.h
+
+
+INCLUDES = -I$(top_srcdir) -I$(top_builddir) -DLIBART_COMPILATION
+subdir = libraries/libart_lgpl-2.3.7
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config/config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+
+librrd_art_la_LDFLAGS =
+librrd_art_la_LIBADD =
+am_librrd_art_la_OBJECTS = art_affine.lo art_alphagamma.lo art_bpath.lo \
+ art_gray_svp.lo art_misc.lo art_pixbuf.lo art_rect.lo \
+ art_rect_svp.lo art_rect_uta.lo art_render.lo \
+ art_render_gradient.lo art_render_svp.lo art_rgb.lo \
+ art_rgb_affine.lo art_rgb_affine_private.lo \
+ art_rgb_bitmap_affine.lo art_rgb_pixbuf_affine.lo \
+ art_rgb_rgba_affine.lo art_rgb_a_affine.lo art_rgba.lo \
+ art_rgb_svp.lo art_svp.lo art_svp_intersect.lo art_svp_ops.lo \
+ art_svp_point.lo art_svp_render_aa.lo art_svp_vpath.lo \
+ art_svp_vpath_stroke.lo art_svp_wind.lo art_uta.lo \
+ art_uta_ops.lo art_uta_rect.lo art_uta_vpath.lo art_uta_svp.lo \
+ art_vpath.lo art_vpath_bpath.lo art_vpath_dash.lo \
+ art_vpath_svp.lo libart-features.lo
+librrd_art_la_OBJECTS = $(am_librrd_art_la_OBJECTS)
+noinst_PROGRAMS = gen_art_config$(EXEEXT)
+PROGRAMS = $(noinst_PROGRAMS)
+
+gen_art_config_SOURCES = gen_art_config.c
+gen_art_config_OBJECTS = gen_art_config.$(OBJEXT)
+gen_art_config_LDADD = $(LDADD)
+gen_art_config_DEPENDENCIES =
+gen_art_config_LDFLAGS =
+
+DEFS = -DHAVE_CONFIG_H
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/config
+CPPFLAGS =
+LDFLAGS =
+LIBS = -lm
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+DEP_FILES = $(DEPDIR)/art_affine.Plo \
+ $(DEPDIR)/art_alphagamma.Plo \
+ $(DEPDIR)/art_bpath.Plo $(DEPDIR)/art_gray_svp.Plo \
+ $(DEPDIR)/art_misc.Plo $(DEPDIR)/art_pixbuf.Plo \
+ $(DEPDIR)/art_rect.Plo $(DEPDIR)/art_rect_svp.Plo \
+ $(DEPDIR)/art_rect_uta.Plo $(DEPDIR)/art_render.Plo \
+ $(DEPDIR)/art_render_gradient.Plo \
+ $(DEPDIR)/art_render_svp.Plo $(DEPDIR)/art_rgb.Plo \
+ $(DEPDIR)/art_rgb_a_affine.Plo \
+ $(DEPDIR)/art_rgb_affine.Plo \
+ $(DEPDIR)/art_rgb_affine_private.Plo \
+ $(DEPDIR)/art_rgb_bitmap_affine.Plo \
+ $(DEPDIR)/art_rgb_pixbuf_affine.Plo \
+ $(DEPDIR)/art_rgb_rgba_affine.Plo \
+ $(DEPDIR)/art_rgb_svp.Plo $(DEPDIR)/art_rgba.Plo \
+ $(DEPDIR)/art_svp.Plo \
+ $(DEPDIR)/art_svp_intersect.Plo \
+ $(DEPDIR)/art_svp_ops.Plo \
+ $(DEPDIR)/art_svp_point.Plo \
+ $(DEPDIR)/art_svp_render_aa.Plo \
+ $(DEPDIR)/art_svp_vpath.Plo \
+ $(DEPDIR)/art_svp_vpath_stroke.Plo \
+ $(DEPDIR)/art_svp_wind.Plo $(DEPDIR)/art_uta.Plo \
+ $(DEPDIR)/art_uta_ops.Plo \
+ $(DEPDIR)/art_uta_rect.Plo \
+ $(DEPDIR)/art_uta_svp.Plo \
+ $(DEPDIR)/art_uta_vpath.Plo $(DEPDIR)/art_vpath.Plo \
+ $(DEPDIR)/art_vpath_bpath.Plo \
+ $(DEPDIR)/art_vpath_dash.Plo \
+ $(DEPDIR)/art_vpath_svp.Plo \
+ $(DEPDIR)/gen_art_config.Po \
+ $(DEPDIR)/libart-features.Plo
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) \
+ $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+CFLAGS = -g -O2 -Wall -pedantic -Wshadow -Wpointer-arith -Wcast-align -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline -fPIC
+DIST_SOURCES = $(librrd_art_la_SOURCES) gen_art_config.c
+HEADERS = $(librrd_artinc_HEADERS)
+
+DIST_COMMON = README $(librrd_artinc_HEADERS) AUTHORS COPYING ChangeLog \
+ INSTALL Makefile.am Makefile.in NEWS install-sh missing \
+ mkinstalldirs
+SOURCES = $(librrd_art_la_SOURCES) gen_art_config.c
+
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4)
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign libraries/libart_lgpl-2.3.7/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) && \
+ CONFIG_HEADERS= CONFIG_LINKS= \
+ CONFIG_FILES=$(subdir)/$@ $(SHELL) ./config.status
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+librrd_art.la: $(librrd_art_la_OBJECTS) $(librrd_art_la_DEPENDENCIES)
+ $(LINK) $(librrd_art_la_LDFLAGS) $(librrd_art_la_OBJECTS) $(librrd_art_la_LIBADD) $(LIBS)
+
+clean-noinstPROGRAMS:
+ -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
+gen_art_config$(EXEEXT): $(gen_art_config_OBJECTS) $(gen_art_config_DEPENDENCIES)
+ @rm -f gen_art_config$(EXEEXT)
+ $(LINK) $(gen_art_config_LDFLAGS) $(gen_art_config_OBJECTS) $(gen_art_config_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+ -rm -f *.tab.c
+
+include $(DEPDIR)/art_affine.Plo
+include $(DEPDIR)/art_alphagamma.Plo
+include $(DEPDIR)/art_bpath.Plo
+include $(DEPDIR)/art_gray_svp.Plo
+include $(DEPDIR)/art_misc.Plo
+include $(DEPDIR)/art_pixbuf.Plo
+include $(DEPDIR)/art_rect.Plo
+include $(DEPDIR)/art_rect_svp.Plo
+include $(DEPDIR)/art_rect_uta.Plo
+include $(DEPDIR)/art_render.Plo
+include $(DEPDIR)/art_render_gradient.Plo
+include $(DEPDIR)/art_render_svp.Plo
+include $(DEPDIR)/art_rgb.Plo
+include $(DEPDIR)/art_rgb_a_affine.Plo
+include $(DEPDIR)/art_rgb_affine.Plo
+include $(DEPDIR)/art_rgb_affine_private.Plo
+include $(DEPDIR)/art_rgb_bitmap_affine.Plo
+include $(DEPDIR)/art_rgb_pixbuf_affine.Plo
+include $(DEPDIR)/art_rgb_rgba_affine.Plo
+include $(DEPDIR)/art_rgb_svp.Plo
+include $(DEPDIR)/art_rgba.Plo
+include $(DEPDIR)/art_svp.Plo
+include $(DEPDIR)/art_svp_intersect.Plo
+include $(DEPDIR)/art_svp_ops.Plo
+include $(DEPDIR)/art_svp_point.Plo
+include $(DEPDIR)/art_svp_render_aa.Plo
+include $(DEPDIR)/art_svp_vpath.Plo
+include $(DEPDIR)/art_svp_vpath_stroke.Plo
+include $(DEPDIR)/art_svp_wind.Plo
+include $(DEPDIR)/art_uta.Plo
+include $(DEPDIR)/art_uta_ops.Plo
+include $(DEPDIR)/art_uta_rect.Plo
+include $(DEPDIR)/art_uta_svp.Plo
+include $(DEPDIR)/art_uta_vpath.Plo
+include $(DEPDIR)/art_vpath.Plo
+include $(DEPDIR)/art_vpath_bpath.Plo
+include $(DEPDIR)/art_vpath_dash.Plo
+include $(DEPDIR)/art_vpath_svp.Plo
+include $(DEPDIR)/gen_art_config.Po
+include $(DEPDIR)/libart-features.Plo
+
+distclean-depend:
+ -rm -rf $(DEPDIR)
+
+.c.o:
+ source='$<' object='$@' libtool=no \
+ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' \
+ $(CCDEPMODE) $(depcomp) \
+ $(COMPILE) -c `test -f $< || echo '$(srcdir)/'`$<
+
+.c.obj:
+ source='$<' object='$@' libtool=no \
+ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' \
+ $(CCDEPMODE) $(depcomp) \
+ $(COMPILE) -c `cygpath -w $<`
+
+.c.lo:
+ source='$<' object='$@' libtool=yes \
+ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' \
+ $(CCDEPMODE) $(depcomp) \
+ $(LTCOMPILE) -c -o $@ `test -f $< || echo '$(srcdir)/'`$<
+CCDEPMODE = depmode=gcc
+uninstall-info-am:
+install-librrd_artincHEADERS: $(librrd_artinc_HEADERS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(librrd_artincdir)
+ @list='$(librrd_artinc_HEADERS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f="`echo $$p | sed -e 's|^.*/||'`"; \
+ echo " $(INSTALL_HEADER) $$d$$p $(DESTDIR)$(librrd_artincdir)/$$f"; \
+ $(INSTALL_HEADER) $$d$$p $(DESTDIR)$(librrd_artincdir)/$$f; \
+ done
+
+uninstall-librrd_artincHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(librrd_artinc_HEADERS)'; for p in $$list; do \
+ f="`echo $$p | sed -e 's|^.*/||'`"; \
+ echo " rm -f $(DESTDIR)$(librrd_artincdir)/$$f"; \
+ rm -f $(DESTDIR)$(librrd_artincdir)/$$f; \
+ done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || etags $(ETAGS_ARGS) $$tags $$unique $(LISP)
+
+GTAGS:
+ here=`CDPATH=: && cd $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH
+
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ../..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ if test -f $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ $(mkinstalldirs) "$(distdir)/$$dir"; \
+ fi; \
+ if test -d $$d/$$file; then \
+ cp -pR $$d/$$file $(distdir) \
+ || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS)
+
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(librrd_artincdir)
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES) stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ clean-noinstPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-compile distclean-depend \
+ distclean-generic distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-librrd_artincHEADERS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+uninstall-am: uninstall-info-am uninstall-librrd_artincHEADERS
+
+.PHONY: GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES clean-noinstPROGRAMS \
+ distclean distclean-compile distclean-depend distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am info \
+ info-am install install-am install-data install-data-am \
+ install-exec install-exec-am install-info install-info-am \
+ install-librrd_artincHEADERS install-man install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool tags uninstall \
+ uninstall-am uninstall-info-am uninstall-librrd_artincHEADERS
+
+
+art_config.h: gen_art_config
+ ./gen_art_config > art_config.h
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+noinst_LTLIBRARIES = librrd_art.la
+noinst_PROGRAMS = gen_art_config
+
+BUILT_SOURCES = art_config.h
+
+art_config.h: gen_art_config
+ ./gen_art_config > art_config.h
+
+EXTRA_DIST = \
+ libart-config.in \
+ libart-2.0.pc.in
+
+librrd_art_la_SOURCES = \
+ art_affine.c \
+ art_alphagamma.c \
+ art_bpath.c \
+ art_gray_svp.c \
+ art_misc.c \
+ art_pixbuf.c \
+ art_rect.c \
+ art_rect_svp.c \
+ art_rect_uta.c \
+ art_render.c \
+ art_render_gradient.c \
+ art_render_svp.c \
+ art_rgb.c \
+ art_rgb_affine.c \
+ art_rgb_affine_private.c \
+ art_rgb_affine_private.h \
+ art_rgb_bitmap_affine.c \
+ art_rgb_pixbuf_affine.c \
+ art_rgb_rgba_affine.c \
+ art_rgb_a_affine.c \
+ art_rgba.c \
+ art_rgb_svp.c \
+ art_svp.c \
+ art_svp_intersect.c \
+ art_svp_ops.c \
+ art_svp_point.c \
+ art_svp_render_aa.c \
+ art_svp_vpath.c \
+ art_svp_vpath_stroke.c \
+ art_svp_wind.c \
+ art_uta.c \
+ art_uta_ops.c \
+ art_uta_rect.c \
+ art_uta_vpath.c \
+ art_uta_svp.c \
+ art_vpath.c \
+ art_vpath_bpath.c \
+ art_vpath_dash.c \
+ art_vpath_svp.c \
+ libart-features.c
+
+librrd_artincdir = $(includedir)/libart-2.0/libart_lgpl
+librrd_artinc_HEADERS = \
+ art_affine.h \
+ art_alphagamma.h \
+ art_bpath.h \
+ art_config.h \
+ art_filterlevel.h \
+ art_gray_svp.h \
+ art_misc.h \
+ art_pathcode.h \
+ art_pixbuf.h \
+ art_point.h \
+ art_rect.h \
+ art_rect_svp.h \
+ art_rect_uta.h \
+ art_render.h \
+ art_render_gradient.h \
+ art_render_svp.h \
+ art_rgb.h \
+ art_rgb_affine.h \
+ art_rgb_bitmap_affine.h \
+ art_rgb_pixbuf_affine.h \
+ art_rgb_rgba_affine.h \
+ art_rgb_a_affine.h \
+ art_rgb_svp.h \
+ art_rgba.h \
+ art_svp.h \
+ art_svp_intersect.h \
+ art_svp_ops.h \
+ art_svp_point.h \
+ art_svp_render_aa.h \
+ art_svp_vpath.h \
+ art_svp_vpath_stroke.h \
+ art_svp_wind.h \
+ art_uta.h \
+ art_uta_ops.h \
+ art_uta_rect.h \
+ art_uta_vpath.h \
+ art_uta_svp.h \
+ art_vpath.h \
+ art_vpath_bpath.h \
+ art_vpath_dash.h \
+ art_vpath_svp.h \
+ libart.h \
+ libart-features.h
+
+INCLUDES = -I$(top_srcdir) -I$(top_builddir) -DLIBART_COMPILATION
+
--- /dev/null
+# Makefile.in generated automatically by automake 1.5 from Makefile.am.
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = @program_transform_name@
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+AMTAR = @AMTAR@
+ART_LIB_DIR = @ART_LIB_DIR@
+AS = @AS@
+AWK = @AWK@
+CC = @CC@
+CGI_LIB_DIR = @CGI_LIB_DIR@
+COMP_PERL = @COMP_PERL@
+CPP = @CPP@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+ECHO = @ECHO@
+EXEEXT = @EXEEXT@
+FREETYPE_LIB_DIR = @FREETYPE_LIB_DIR@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+NROFF = @NROFF@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PERL = @PERL@
+PERLFLAGS = @PERLFLAGS@
+PERL_MAKE_OPTIONS = @PERL_MAKE_OPTIONS@
+PNG_LIB_DIR = @PNG_LIB_DIR@
+RANLIB = @RANLIB@
+SO_EXT = @SO_EXT@
+STRIP = @STRIP@
+TCL_LD_SEARCH_FLAGS = @TCL_LD_SEARCH_FLAGS@
+TCL_PACKAGE_PATH = @TCL_PACKAGE_PATH@
+TCL_PREFIX = @TCL_PREFIX@
+TCL_SHLIB_CFLAGS = @TCL_SHLIB_CFLAGS@
+TCL_SHLIB_LD = @TCL_SHLIB_LD@
+TCL_SHLIB_SUFFIX = @TCL_SHLIB_SUFFIX@
+TROFF = @TROFF@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIB_DIR = @ZLIB_LIB_DIR@
+am__include = @am__include@
+am__quote = @am__quote@
+install_sh = @install_sh@
+
+noinst_LTLIBRARIES = librrd_art.la
+noinst_PROGRAMS = gen_art_config
+
+BUILT_SOURCES = art_config.h
+
+EXTRA_DIST = \
+ libart-config.in \
+ libart-2.0.pc.in
+
+
+librrd_art_la_SOURCES = \
+ art_affine.c \
+ art_alphagamma.c \
+ art_bpath.c \
+ art_gray_svp.c \
+ art_misc.c \
+ art_pixbuf.c \
+ art_rect.c \
+ art_rect_svp.c \
+ art_rect_uta.c \
+ art_render.c \
+ art_render_gradient.c \
+ art_render_svp.c \
+ art_rgb.c \
+ art_rgb_affine.c \
+ art_rgb_affine_private.c \
+ art_rgb_affine_private.h \
+ art_rgb_bitmap_affine.c \
+ art_rgb_pixbuf_affine.c \
+ art_rgb_rgba_affine.c \
+ art_rgb_a_affine.c \
+ art_rgba.c \
+ art_rgb_svp.c \
+ art_svp.c \
+ art_svp_intersect.c \
+ art_svp_ops.c \
+ art_svp_point.c \
+ art_svp_render_aa.c \
+ art_svp_vpath.c \
+ art_svp_vpath_stroke.c \
+ art_svp_wind.c \
+ art_uta.c \
+ art_uta_ops.c \
+ art_uta_rect.c \
+ art_uta_vpath.c \
+ art_uta_svp.c \
+ art_vpath.c \
+ art_vpath_bpath.c \
+ art_vpath_dash.c \
+ art_vpath_svp.c \
+ libart-features.c
+
+
+librrd_artincdir = $(includedir)/libart-2.0/libart_lgpl
+librrd_artinc_HEADERS = \
+ art_affine.h \
+ art_alphagamma.h \
+ art_bpath.h \
+ art_config.h \
+ art_filterlevel.h \
+ art_gray_svp.h \
+ art_misc.h \
+ art_pathcode.h \
+ art_pixbuf.h \
+ art_point.h \
+ art_rect.h \
+ art_rect_svp.h \
+ art_rect_uta.h \
+ art_render.h \
+ art_render_gradient.h \
+ art_render_svp.h \
+ art_rgb.h \
+ art_rgb_affine.h \
+ art_rgb_bitmap_affine.h \
+ art_rgb_pixbuf_affine.h \
+ art_rgb_rgba_affine.h \
+ art_rgb_a_affine.h \
+ art_rgb_svp.h \
+ art_rgba.h \
+ art_svp.h \
+ art_svp_intersect.h \
+ art_svp_ops.h \
+ art_svp_point.h \
+ art_svp_render_aa.h \
+ art_svp_vpath.h \
+ art_svp_vpath_stroke.h \
+ art_svp_wind.h \
+ art_uta.h \
+ art_uta_ops.h \
+ art_uta_rect.h \
+ art_uta_vpath.h \
+ art_uta_svp.h \
+ art_vpath.h \
+ art_vpath_bpath.h \
+ art_vpath_dash.h \
+ art_vpath_svp.h \
+ libart.h \
+ libart-features.h
+
+
+INCLUDES = -I$(top_srcdir) -I$(top_builddir) -DLIBART_COMPILATION
+subdir = libraries/libart_lgpl-2.3.7
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config/config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+
+librrd_art_la_LDFLAGS =
+librrd_art_la_LIBADD =
+am_librrd_art_la_OBJECTS = art_affine.lo art_alphagamma.lo art_bpath.lo \
+ art_gray_svp.lo art_misc.lo art_pixbuf.lo art_rect.lo \
+ art_rect_svp.lo art_rect_uta.lo art_render.lo \
+ art_render_gradient.lo art_render_svp.lo art_rgb.lo \
+ art_rgb_affine.lo art_rgb_affine_private.lo \
+ art_rgb_bitmap_affine.lo art_rgb_pixbuf_affine.lo \
+ art_rgb_rgba_affine.lo art_rgb_a_affine.lo art_rgba.lo \
+ art_rgb_svp.lo art_svp.lo art_svp_intersect.lo art_svp_ops.lo \
+ art_svp_point.lo art_svp_render_aa.lo art_svp_vpath.lo \
+ art_svp_vpath_stroke.lo art_svp_wind.lo art_uta.lo \
+ art_uta_ops.lo art_uta_rect.lo art_uta_vpath.lo art_uta_svp.lo \
+ art_vpath.lo art_vpath_bpath.lo art_vpath_dash.lo \
+ art_vpath_svp.lo libart-features.lo
+librrd_art_la_OBJECTS = $(am_librrd_art_la_OBJECTS)
+noinst_PROGRAMS = gen_art_config$(EXEEXT)
+PROGRAMS = $(noinst_PROGRAMS)
+
+gen_art_config_SOURCES = gen_art_config.c
+gen_art_config_OBJECTS = gen_art_config.$(OBJEXT)
+gen_art_config_LDADD = $(LDADD)
+gen_art_config_DEPENDENCIES =
+gen_art_config_LDFLAGS =
+
+DEFS = @DEFS@
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/config
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+@AMDEP_TRUE@DEP_FILES = $(DEPDIR)/art_affine.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_alphagamma.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_bpath.Plo $(DEPDIR)/art_gray_svp.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_misc.Plo $(DEPDIR)/art_pixbuf.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_rect.Plo $(DEPDIR)/art_rect_svp.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_rect_uta.Plo $(DEPDIR)/art_render.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_render_gradient.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_render_svp.Plo $(DEPDIR)/art_rgb.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_rgb_a_affine.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_rgb_affine.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_rgb_affine_private.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_rgb_bitmap_affine.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_rgb_pixbuf_affine.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_rgb_rgba_affine.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_rgb_svp.Plo $(DEPDIR)/art_rgba.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_svp.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_svp_intersect.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_svp_ops.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_svp_point.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_svp_render_aa.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_svp_vpath.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_svp_vpath_stroke.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_svp_wind.Plo $(DEPDIR)/art_uta.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_uta_ops.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_uta_rect.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_uta_svp.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_uta_vpath.Plo $(DEPDIR)/art_vpath.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_vpath_bpath.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_vpath_dash.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/art_vpath_svp.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/gen_art_config.Po \
+@AMDEP_TRUE@ $(DEPDIR)/libart-features.Plo
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) \
+ $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+DIST_SOURCES = $(librrd_art_la_SOURCES) gen_art_config.c
+HEADERS = $(librrd_artinc_HEADERS)
+
+DIST_COMMON = README $(librrd_artinc_HEADERS) AUTHORS COPYING ChangeLog \
+ INSTALL Makefile.am Makefile.in NEWS install-sh missing \
+ mkinstalldirs
+SOURCES = $(librrd_art_la_SOURCES) gen_art_config.c
+
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4)
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign libraries/libart_lgpl-2.3.7/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) && \
+ CONFIG_HEADERS= CONFIG_LINKS= \
+ CONFIG_FILES=$(subdir)/$@ $(SHELL) ./config.status
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+librrd_art.la: $(librrd_art_la_OBJECTS) $(librrd_art_la_DEPENDENCIES)
+ $(LINK) $(librrd_art_la_LDFLAGS) $(librrd_art_la_OBJECTS) $(librrd_art_la_LIBADD) $(LIBS)
+
+clean-noinstPROGRAMS:
+ -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
+gen_art_config$(EXEEXT): $(gen_art_config_OBJECTS) $(gen_art_config_DEPENDENCIES)
+ @rm -f gen_art_config$(EXEEXT)
+ $(LINK) $(gen_art_config_LDFLAGS) $(gen_art_config_OBJECTS) $(gen_art_config_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_affine.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_alphagamma.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_bpath.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_gray_svp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_misc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_pixbuf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_rect.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_rect_svp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_rect_uta.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_render.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_render_gradient.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_render_svp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_rgb.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_rgb_a_affine.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_rgb_affine.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_rgb_affine_private.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_rgb_bitmap_affine.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_rgb_pixbuf_affine.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_rgb_rgba_affine.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_rgb_svp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_rgba.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_svp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_svp_intersect.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_svp_ops.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_svp_point.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_svp_render_aa.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_svp_vpath.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_svp_vpath_stroke.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_svp_wind.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_uta.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_uta_ops.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_uta_rect.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_uta_svp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_uta_vpath.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_vpath.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_vpath_bpath.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_vpath_dash.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/art_vpath_svp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/gen_art_config.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/libart-features.Plo@am__quote@
+
+distclean-depend:
+ -rm -rf $(DEPDIR)
+
+.c.o:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(COMPILE) -c `test -f $< || echo '$(srcdir)/'`$<
+
+.c.obj:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(COMPILE) -c `cygpath -w $<`
+
+.c.lo:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(LTCOMPILE) -c -o $@ `test -f $< || echo '$(srcdir)/'`$<
+CCDEPMODE = @CCDEPMODE@
+uninstall-info-am:
+install-librrd_artincHEADERS: $(librrd_artinc_HEADERS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(librrd_artincdir)
+ @list='$(librrd_artinc_HEADERS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f="`echo $$p | sed -e 's|^.*/||'`"; \
+ echo " $(INSTALL_HEADER) $$d$$p $(DESTDIR)$(librrd_artincdir)/$$f"; \
+ $(INSTALL_HEADER) $$d$$p $(DESTDIR)$(librrd_artincdir)/$$f; \
+ done
+
+uninstall-librrd_artincHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(librrd_artinc_HEADERS)'; for p in $$list; do \
+ f="`echo $$p | sed -e 's|^.*/||'`"; \
+ echo " rm -f $(DESTDIR)$(librrd_artincdir)/$$f"; \
+ rm -f $(DESTDIR)$(librrd_artincdir)/$$f; \
+ done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || etags $(ETAGS_ARGS) $$tags $$unique $(LISP)
+
+GTAGS:
+ here=`CDPATH=: && cd $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH
+
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ../..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ if test -f $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ $(mkinstalldirs) "$(distdir)/$$dir"; \
+ fi; \
+ if test -d $$d/$$file; then \
+ cp -pR $$d/$$file $(distdir) \
+ || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS)
+
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(librrd_artincdir)
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES) stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ clean-noinstPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-compile distclean-depend \
+ distclean-generic distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-librrd_artincHEADERS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+uninstall-am: uninstall-info-am uninstall-librrd_artincHEADERS
+
+.PHONY: GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES clean-noinstPROGRAMS \
+ distclean distclean-compile distclean-depend distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am info \
+ info-am install install-am install-data install-data-am \
+ install-exec install-exec-am install-info install-info-am \
+ install-librrd_artincHEADERS install-man install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool tags uninstall \
+ uninstall-am uninstall-info-am uninstall-librrd_artincHEADERS
+
+
+art_config.h: gen_art_config
+ ./gen_art_config > art_config.h
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+Please see http://www.levien.com/libart/ for the latest news.
--- /dev/null
+This is the LGPL'd component of libart. All functions needed for
+running the Gnome canvas, and for printing support, will be going in
+here. The GPL'd component will be getting various enhanced functions
+for specific applications.
+
+Libart is free software. It is also for sale. For information about
+licensing libart, please contact Raph Levien
+<raph@acm.org>. Contributions to the codebase are also very welcome,
+but the copyright must be assigned in writing to preserve the
+licensing flexibility.
+
+
+For more information about libart, see the web page:
+
+ http://www.levien.com/libart/
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Simple manipulations with affine transformations */
+
+#include <math.h>
+#include <stdio.h> /* for sprintf */
+#include <string.h> /* for strcpy */
+#include "art_misc.h"
+#include "art_point.h"
+#include "art_affine.h"
+
+
+/* According to a strict interpretation of the libart structure, this
+ routine should go into its own module, art_point_affine. However,
+ it's only two lines of code, and it can be argued that it is one of
+ the natural basic functions of an affine transformation.
+*/
+
+/**
+ * art_affine_point: Do an affine transformation of a point.
+ * @dst: Where the result point is stored.
+ * @src: The original point.
+ @ @affine: The affine transformation.
+ **/
+void
+art_affine_point (ArtPoint *dst, const ArtPoint *src,
+ const double affine[6])
+{
+ double x, y;
+
+ x = src->x;
+ y = src->y;
+ dst->x = x * affine[0] + y * affine[2] + affine[4];
+ dst->y = x * affine[1] + y * affine[3] + affine[5];
+}
+
+/**
+ * art_affine_invert: Find the inverse of an affine transformation.
+ * @dst: Where the resulting affine is stored.
+ * @src: The original affine transformation.
+ *
+ * All non-degenerate affine transforms are invertible. If the original
+ * affine is degenerate or nearly so, expect numerical instability and
+ * very likely core dumps on Alpha and other fp-picky architectures.
+ * Otherwise, @dst multiplied with @src, or @src multiplied with @dst
+ * will be (to within roundoff error) the identity affine.
+ **/
+void
+art_affine_invert (double dst[6], const double src[6])
+{
+ double r_det;
+
+ r_det = 1.0 / (src[0] * src[3] - src[1] * src[2]);
+ dst[0] = src[3] * r_det;
+ dst[1] = -src[1] * r_det;
+ dst[2] = -src[2] * r_det;
+ dst[3] = src[0] * r_det;
+ dst[4] = -src[4] * dst[0] - src[5] * dst[2];
+ dst[5] = -src[4] * dst[1] - src[5] * dst[3];
+}
+
+/**
+ * art_affine_flip: Flip an affine transformation horizontally and/or vertically.
+ * @dst_affine: Where the resulting affine is stored.
+ * @src_affine: The original affine transformation.
+ * @horiz: Whether or not to flip horizontally.
+ * @vert: Whether or not to flip horizontally.
+ *
+ * Flips the affine transform. FALSE for both @horiz and @vert implements
+ * a simple copy operation. TRUE for both @horiz and @vert is a
+ * 180 degree rotation. It is ok for @src_affine and @dst_affine to
+ * be equal pointers.
+ **/
+void
+art_affine_flip (double dst_affine[6], const double src_affine[6], int horz, int vert)
+{
+ dst_affine[0] = horz ? - src_affine[0] : src_affine[0];
+ dst_affine[1] = horz ? - src_affine[1] : src_affine[1];
+ dst_affine[2] = vert ? - src_affine[2] : src_affine[2];
+ dst_affine[3] = vert ? - src_affine[3] : src_affine[3];
+ dst_affine[4] = horz ? - src_affine[4] : src_affine[4];
+ dst_affine[5] = vert ? - src_affine[5] : src_affine[5];
+}
+
+#define EPSILON 1e-6
+
+/* It's ridiculous I have to write this myself. This is hardcoded to
+ six digits of precision, which is good enough for PostScript.
+
+ The return value is the number of characters (i.e. strlen (str)).
+ It is no more than 12. */
+static int
+art_ftoa (char str[80], double x)
+{
+ char *p = str;
+ int i, j;
+
+ p = str;
+ if (fabs (x) < EPSILON / 2)
+ {
+ strcpy (str, "0");
+ return 1;
+ }
+ if (x < 0)
+ {
+ *p++ = '-';
+ x = -x;
+ }
+ if ((int)floor ((x + EPSILON / 2) < 1))
+ {
+ *p++ = '0';
+ *p++ = '.';
+ i = sprintf (p, "%06d", (int)floor ((x + EPSILON / 2) * 1e6));
+ while (i && p[i - 1] == '0')
+ i--;
+ if (i == 0)
+ i--;
+ p += i;
+ }
+ else if (x < 1e6)
+ {
+ i = sprintf (p, "%d", (int)floor (x + EPSILON / 2));
+ p += i;
+ if (i < 6)
+ {
+ int ix;
+
+ *p++ = '.';
+ x -= floor (x + EPSILON / 2);
+ for (j = i; j < 6; j++)
+ x *= 10;
+ ix = floor (x + 0.5);
+
+ for (j = 0; j < i; j++)
+ ix *= 10;
+
+ /* A cheap hack, this routine can round wrong for fractions
+ near one. */
+ if (ix == 1000000)
+ ix = 999999;
+
+ sprintf (p, "%06d", ix);
+ i = 6 - i;
+ while (i && p[i - 1] == '0')
+ i--;
+ if (i == 0)
+ i--;
+ p += i;
+ }
+ }
+ else
+ p += sprintf (p, "%g", x);
+
+ *p = '\0';
+ return p - str;
+}
+
+
+
+#include <stdlib.h>
+/**
+ * art_affine_to_string: Convert affine transformation to concise PostScript string representation.
+ * @str: Where to store the resulting string.
+ * @src: The affine transform.
+ *
+ * Converts an affine transform into a bit of PostScript code that
+ * implements the transform. Special cases of scaling, rotation, and
+ * translation are detected, and the corresponding PostScript
+ * operators used (this greatly aids understanding the output
+ * generated). The identity transform is mapped to the null string.
+ **/
+void
+art_affine_to_string (char str[128], const double src[6])
+{
+ char tmp[80];
+ int i, ix;
+
+#if 0
+ for (i = 0; i < 1000; i++)
+ {
+ double d = rand () * .1 / RAND_MAX;
+ art_ftoa (tmp, d);
+ printf ("%g %f %s\n", d, d, tmp);
+ }
+#endif
+ if (fabs (src[4]) < EPSILON && fabs (src[5]) < EPSILON)
+ {
+ /* could be scale or rotate */
+ if (fabs (src[1]) < EPSILON && fabs (src[2]) < EPSILON)
+ {
+ /* scale */
+ if (fabs (src[0] - 1) < EPSILON && fabs (src[3] - 1) < EPSILON)
+ {
+ /* identity transform */
+ str[0] = '\0';
+ return;
+ }
+ else
+ {
+ ix = 0;
+ ix += art_ftoa (str + ix, src[0]);
+ str[ix++] = ' ';
+ ix += art_ftoa (str + ix, src[3]);
+ strcpy (str + ix, " scale");
+ return;
+ }
+ }
+ else
+ {
+ /* could be rotate */
+ if (fabs (src[0] - src[3]) < EPSILON &&
+ fabs (src[1] + src[2]) < EPSILON &&
+ fabs (src[0] * src[0] + src[1] * src[1] - 1) < 2 * EPSILON)
+ {
+ double theta;
+
+ theta = (180 / M_PI) * atan2 (src[1], src[0]);
+ art_ftoa (tmp, theta);
+ sprintf (str, "%s rotate", tmp);
+ return;
+ }
+ }
+ }
+ else
+ {
+ /* could be translate */
+ if (fabs (src[0] - 1) < EPSILON && fabs (src[1]) < EPSILON &&
+ fabs (src[2]) < EPSILON && fabs (src[3] - 1) < EPSILON)
+ {
+ ix = 0;
+ ix += art_ftoa (str + ix, src[4]);
+ str[ix++] = ' ';
+ ix += art_ftoa (str + ix, src[5]);
+ strcpy (str + ix, " translate");
+ return;
+ }
+ }
+
+ ix = 0;
+ str[ix++] = '[';
+ str[ix++] = ' ';
+ for (i = 0; i < 6; i++)
+ {
+ ix += art_ftoa (str + ix, src[i]);
+ str[ix++] = ' ';
+ }
+ strcpy (str + ix, "] concat");
+}
+
+/**
+ * art_affine_multiply: Multiply two affine transformation matrices.
+ * @dst: Where to store the result.
+ * @src1: The first affine transform to multiply.
+ * @src2: The second affine transform to multiply.
+ *
+ * Multiplies two affine transforms together, i.e. the resulting @dst
+ * is equivalent to doing first @src1 then @src2. Note that the
+ * PostScript concat operator multiplies on the left, i.e. "M concat"
+ * is equivalent to "CTM = multiply (M, CTM)";
+ *
+ * It is safe to call this function with @dst equal to @src1 or @src2.
+ **/
+void
+art_affine_multiply (double dst[6], const double src1[6], const double src2[6])
+{
+ double d0, d1, d2, d3, d4, d5;
+
+ d0 = src1[0] * src2[0] + src1[1] * src2[2];
+ d1 = src1[0] * src2[1] + src1[1] * src2[3];
+ d2 = src1[2] * src2[0] + src1[3] * src2[2];
+ d3 = src1[2] * src2[1] + src1[3] * src2[3];
+ d4 = src1[4] * src2[0] + src1[5] * src2[2] + src2[4];
+ d5 = src1[4] * src2[1] + src1[5] * src2[3] + src2[5];
+ dst[0] = d0;
+ dst[1] = d1;
+ dst[2] = d2;
+ dst[3] = d3;
+ dst[4] = d4;
+ dst[5] = d5;
+}
+
+/**
+ * art_affine_identity: Set up the identity matrix.
+ * @dst: Where to store the resulting affine transform.
+ *
+ * Sets up an identity matrix.
+ **/
+void
+art_affine_identity (double dst[6])
+{
+ dst[0] = 1;
+ dst[1] = 0;
+ dst[2] = 0;
+ dst[3] = 1;
+ dst[4] = 0;
+ dst[5] = 0;
+}
+
+
+/**
+ * art_affine_scale: Set up a scaling matrix.
+ * @dst: Where to store the resulting affine transform.
+ * @sx: X scale factor.
+ * @sy: Y scale factor.
+ *
+ * Sets up a scaling matrix.
+ **/
+void
+art_affine_scale (double dst[6], double sx, double sy)
+{
+ dst[0] = sx;
+ dst[1] = 0;
+ dst[2] = 0;
+ dst[3] = sy;
+ dst[4] = 0;
+ dst[5] = 0;
+}
+
+/**
+ * art_affine_rotate: Set up a rotation affine transform.
+ * @dst: Where to store the resulting affine transform.
+ * @theta: Rotation angle in degrees.
+ *
+ * Sets up a rotation matrix. In the standard libart coordinate
+ * system, in which increasing y moves downward, this is a
+ * counterclockwise rotation. In the standard PostScript coordinate
+ * system, which is reversed in the y direction, it is a clockwise
+ * rotation.
+ **/
+void
+art_affine_rotate (double dst[6], double theta)
+{
+ double s, c;
+
+ s = sin (theta * M_PI / 180.0);
+ c = cos (theta * M_PI / 180.0);
+ dst[0] = c;
+ dst[1] = s;
+ dst[2] = -s;
+ dst[3] = c;
+ dst[4] = 0;
+ dst[5] = 0;
+}
+
+/**
+ * art_affine_shear: Set up a shearing matrix.
+ * @dst: Where to store the resulting affine transform.
+ * @theta: Shear angle in degrees.
+ *
+ * Sets up a shearing matrix. In the standard libart coordinate system
+ * and a small value for theta, || becomes \\. Horizontal lines remain
+ * unchanged.
+ **/
+void
+art_affine_shear (double dst[6], double theta)
+{
+ double t;
+
+ t = tan (theta * M_PI / 180.0);
+ dst[0] = 1;
+ dst[1] = 0;
+ dst[2] = t;
+ dst[3] = 1;
+ dst[4] = 0;
+ dst[5] = 0;
+}
+
+/**
+ * art_affine_translate: Set up a translation matrix.
+ * @dst: Where to store the resulting affine transform.
+ * @tx: X translation amount.
+ * @tx: Y translation amount.
+ *
+ * Sets up a translation matrix.
+ **/
+void
+art_affine_translate (double dst[6], double tx, double ty)
+{
+ dst[0] = 1;
+ dst[1] = 0;
+ dst[2] = 0;
+ dst[3] = 1;
+ dst[4] = tx;
+ dst[5] = ty;
+}
+
+/**
+ * art_affine_expansion: Find the affine's expansion factor.
+ * @src: The affine transformation.
+ *
+ * Finds the expansion factor, i.e. the square root of the factor
+ * by which the affine transform affects area. In an affine transform
+ * composed of scaling, rotation, shearing, and translation, returns
+ * the amount of scaling.
+ *
+ * Return value: the expansion factor.
+ **/
+double
+art_affine_expansion (const double src[6])
+{
+ return sqrt (fabs (src[0] * src[3] - src[1] * src[2]));
+}
+
+/**
+ * art_affine_rectilinear: Determine whether the affine transformation is rectilinear.
+ * @src: The original affine transformation.
+ *
+ * Determines whether @src is rectilinear, i.e. grid-aligned
+ * rectangles are transformed to other grid-aligned rectangles. The
+ * implementation has epsilon-tolerance for roundoff errors.
+ *
+ * Return value: TRUE if @src is rectilinear.
+ **/
+int
+art_affine_rectilinear (const double src[6])
+{
+ return ((fabs (src[1]) < EPSILON && fabs (src[2]) < EPSILON) ||
+ (fabs (src[0]) < EPSILON && fabs (src[3]) < EPSILON));
+}
+
+/**
+ * art_affine_equal: Determine whether two affine transformations are equal.
+ * @matrix1: An affine transformation.
+ * @matrix2: Another affine transformation.
+ *
+ * Determines whether @matrix1 and @matrix2 are equal, with
+ * epsilon-tolerance for roundoff errors.
+ *
+ * Return value: TRUE if @matrix1 and @matrix2 are equal.
+ **/
+int
+art_affine_equal (double matrix1[6], double matrix2[6])
+{
+ return (fabs (matrix1[0] - matrix2[0]) < EPSILON &&
+ fabs (matrix1[1] - matrix2[1]) < EPSILON &&
+ fabs (matrix1[2] - matrix2[2]) < EPSILON &&
+ fabs (matrix1[3] - matrix2[3]) < EPSILON &&
+ fabs (matrix1[4] - matrix2[4]) < EPSILON &&
+ fabs (matrix1[5] - matrix2[5]) < EPSILON);
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_AFFINE_H__
+#define __ART_AFFINE_H__
+
+#ifdef LIBART_COMPILATION
+#include "art_point.h"
+#else
+#include <art_point.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+void
+art_affine_point (ArtPoint *dst, const ArtPoint *src,
+ const double affine[6]);
+
+void
+art_affine_invert (double dst_affine[6], const double src_affine[6]);
+
+/* flip the matrix, FALSE, FALSE is a simple copy operation, and
+ TRUE, TRUE equals a rotation by 180 degrees */
+void
+art_affine_flip (double dst_affine[6], const double src_affine[6],
+ int horz, int vert);
+
+void
+art_affine_to_string (char str[128], const double src[6]);
+
+void
+art_affine_multiply (double dst[6],
+ const double src1[6], const double src2[6]);
+
+/* set up the identity matrix */
+void
+art_affine_identity (double dst[6]);
+
+/* set up a scaling matrix */
+void
+art_affine_scale (double dst[6], double sx, double sy);
+
+/* set up a rotation matrix; theta is given in degrees */
+void
+art_affine_rotate (double dst[6], double theta);
+
+/* set up a shearing matrix; theta is given in degrees */
+void
+art_affine_shear (double dst[6], double theta);
+
+/* set up a translation matrix */
+void
+art_affine_translate (double dst[6], double tx, double ty);
+
+
+/* find the affine's "expansion factor", i.e. the scale amount */
+double
+art_affine_expansion (const double src[6]);
+
+/* Determine whether the affine transformation is rectilinear,
+ i.e. whether a rectangle aligned to the grid is transformed into
+ another rectangle aligned to the grid. */
+int
+art_affine_rectilinear (const double src[6]);
+
+/* Determine whether two affine transformations are equal within grid allignment */
+int
+art_affine_equal (double matrix1[6], double matrix2[6]);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_AFFINE_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Some functions to build alphagamma tables */
+
+#include <math.h>
+#include "art_misc.h"
+
+#include "art_alphagamma.h"
+
+/**
+ * art_alphagamma_new: Create a new #ArtAlphaGamma.
+ * @gamma: Gamma value.
+ *
+ * Create a new #ArtAlphaGamma for a specific value of @gamma. When
+ * correctly implemented (which is generally not the case in libart),
+ * alpha compositing with an alphagamma parameter is equivalent to
+ * applying the gamma transformation to source images, doing the alpha
+ * compositing (in linear intensity space), then applying the inverse
+ * gamma transformation, bringing it back to a gamma-adjusted
+ * intensity space.
+ *
+ * Return value: The newly created #ArtAlphaGamma.
+ **/
+ArtAlphaGamma *
+art_alphagamma_new (double gamma)
+{
+ int tablesize;
+ ArtAlphaGamma *alphagamma;
+ int i;
+ int *table;
+ art_u8 *invtable;
+ double s, r_gamma;
+
+ tablesize = ceil (gamma * 8);
+ if (tablesize < 10)
+ tablesize = 10;
+
+ alphagamma = (ArtAlphaGamma *)art_alloc (sizeof(ArtAlphaGamma) +
+ ((1 << tablesize) - 1) *
+ sizeof(art_u8));
+ alphagamma->gamma = gamma;
+ alphagamma->invtable_size = tablesize;
+
+ table = alphagamma->table;
+ for (i = 0; i < 256; i++)
+ table[i] = (int)floor (((1 << tablesize) - 1) *
+ pow (i * (1.0 / 255), gamma) + 0.5);
+
+ invtable = alphagamma->invtable;
+ s = 1.0 / ((1 << tablesize) - 1);
+ r_gamma = 1.0 / gamma;
+ for (i = 0; i < 1 << tablesize; i++)
+ invtable[i] = (int)floor (255 * pow (i * s, r_gamma) + 0.5);
+
+ return alphagamma;
+}
+
+/**
+ * art_alphagamma_free: Free an #ArtAlphaGamma.
+ * @alphagamma: An #ArtAlphaGamma.
+ *
+ * Frees the #ArtAlphaGamma.
+ **/
+void
+art_alphagamma_free (ArtAlphaGamma *alphagamma)
+{
+ art_free (alphagamma);
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_ALPHAGAMMA_H__
+#define __ART_ALPHAGAMMA_H__
+
+/* Alphagamma tables */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifdef LIBART_COMPILATION
+#include "art_misc.h"
+#else
+#include <art_misc.h>
+#endif
+
+typedef struct _ArtAlphaGamma ArtAlphaGamma;
+
+struct _ArtAlphaGamma {
+ /*< private >*/
+ double gamma;
+ int invtable_size;
+ int table[256];
+ art_u8 invtable[1];
+};
+
+ArtAlphaGamma *
+art_alphagamma_new (double gamma);
+
+void
+art_alphagamma_free (ArtAlphaGamma *alphagamma);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_SVP_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Basic constructors and operations for bezier paths */
+
+#include <math.h>
+
+#include "art_misc.h"
+
+#include "art_bpath.h"
+
+/**
+ * art_bpath_affine_transform: Affine transform an #ArtBpath.
+ * @src: The source #ArtBpath.
+ * @matrix: The affine transform.
+ *
+ * Affine transform the bezpath, returning a newly allocated #ArtBpath
+ * (allocated using art_alloc()).
+ *
+ * Result (x', y') = (matrix[0] * x + matrix[2] * y + matrix[4],
+ * matrix[1] * x + matrix[3] * y + matrix[5])
+ *
+ * Return value: the transformed #ArtBpath.
+ **/
+ArtBpath *
+art_bpath_affine_transform (const ArtBpath *src, const double matrix[6])
+{
+ int i;
+ int size;
+ ArtBpath *new;
+ ArtPathcode code;
+ double x, y;
+
+ for (i = 0; src[i].code != ART_END; i++);
+ size = i;
+
+ new = art_new (ArtBpath, size + 1);
+
+ for (i = 0; i < size; i++)
+ {
+ code = src[i].code;
+ new[i].code = code;
+ if (code == ART_CURVETO)
+ {
+ x = src[i].x1;
+ y = src[i].y1;
+ new[i].x1 = matrix[0] * x + matrix[2] * y + matrix[4];
+ new[i].y1 = matrix[1] * x + matrix[3] * y + matrix[5];
+ x = src[i].x2;
+ y = src[i].y2;
+ new[i].x2 = matrix[0] * x + matrix[2] * y + matrix[4];
+ new[i].y2 = matrix[1] * x + matrix[3] * y + matrix[5];
+ }
+ else
+ {
+ new[i].x1 = 0;
+ new[i].y1 = 0;
+ new[i].x2 = 0;
+ new[i].y2 = 0;
+ }
+ x = src[i].x3;
+ y = src[i].y3;
+ new[i].x3 = matrix[0] * x + matrix[2] * y + matrix[4];
+ new[i].y3 = matrix[1] * x + matrix[3] * y + matrix[5];
+ }
+ new[i].code = ART_END;
+ new[i].x1 = 0;
+ new[i].y1 = 0;
+ new[i].x2 = 0;
+ new[i].y2 = 0;
+ new[i].x3 = 0;
+ new[i].y3 = 0;
+
+ return new;
+}
+
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_BPATH_H__
+#define __ART_BPATH_H__
+
+#ifdef LIBART_COMPILATION
+#include "art_point.h"
+#include "art_pathcode.h"
+#else
+#include <art_point.h>
+#include <art_pathcode.h>
+#endif
+
+/* Basic data structures and constructors for bezier paths */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct _ArtBpath ArtBpath;
+
+struct _ArtBpath {
+ /*< public >*/
+ ArtPathcode code;
+ double x1;
+ double y1;
+ double x2;
+ double y2;
+ double x3;
+ double y3;
+};
+
+ArtBpath *
+art_bpath_affine_transform (const ArtBpath *src, const double matrix[6]);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_BPATH_H__ */
--- /dev/null
+/* Automatically generated by gen_art_config.c */
+
+#define ART_SIZEOF_CHAR 1
+#define ART_SIZEOF_SHORT 2
+#define ART_SIZEOF_INT 4
+#define ART_SIZEOF_LONG 4
+
+typedef unsigned char art_u8;
+typedef unsigned short art_u16;
+typedef unsigned int art_u32;
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_FILTERLEVEL_H__
+#define __ART_FILTERLEVEL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef enum {
+ ART_FILTER_NEAREST,
+ ART_FILTER_TILES,
+ ART_FILTER_BILINEAR,
+ ART_FILTER_HYPER
+} ArtFilterLevel;
+
+/* NEAREST is nearest neighbor. It is the fastest and lowest quality.
+
+ TILES is an accurate simulation of the PostScript image operator
+ without any interpolation enabled; each pixel is rendered as a tiny
+ parallelogram of solid color, the edges of which are implemented
+ with antialiasing. It resembles nearest neighbor for enlargement,
+ and bilinear for reduction.
+
+ BILINEAR is bilinear interpolation. For enlargement, it is
+ equivalent to point-sampling the ideal bilinear-interpolated
+ image. For reduction, it is equivalent to laying down small tiles
+ and integrating over the coverage area.
+
+ HYPER is the highest quality reconstruction function. It is derived
+ from the hyperbolic filters in Wolberg's "Digital Image Warping,"
+ and is formally defined as the hyperbolic-filter sampling the ideal
+ hyperbolic-filter interpolated image (the filter is designed to be
+ idempotent for 1:1 pixel mapping). It is the slowest and highest
+ quality.
+
+ Note: at this stage of implementation, most filter modes are likely
+ not to be implemented.
+
+ Note: cubic filtering is missing from this list, because there isn't
+ much point - hyper is just as fast to implement and slightly better
+ in quality.
+
+*/
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_PATHCODE_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Render a sorted vector path into a graymap. */
+
+#include <string.h> /* for memset */
+#include "art_misc.h"
+
+#include "art_svp.h"
+#include "art_svp_render_aa.h"
+#include "art_gray_svp.h"
+
+typedef struct _ArtGraySVPData ArtGraySVPData;
+
+struct _ArtGraySVPData {
+ art_u8 *buf;
+ int rowstride;
+ int x0, x1;
+};
+
+static void
+art_gray_svp_callback (void *callback_data, int y,
+ int start, ArtSVPRenderAAStep *steps, int n_steps)
+{
+ ArtGraySVPData *data = (ArtGraySVPData *)callback_data;
+ art_u8 *linebuf;
+ int run_x0, run_x1;
+ int running_sum = start;
+ int x0, x1;
+ int k;
+
+#if 0
+ printf ("start = %d", start);
+ running_sum = start;
+ for (k = 0; k < n_steps; k++)
+ {
+ running_sum += steps[k].delta;
+ printf (" %d:%d", steps[k].x, running_sum >> 16);
+ }
+ printf ("\n");
+#endif
+
+ linebuf = data->buf;
+ x0 = data->x0;
+ x1 = data->x1;
+
+ if (n_steps > 0)
+ {
+ run_x1 = steps[0].x;
+ if (run_x1 > x0)
+ memset (linebuf, running_sum >> 16, run_x1 - x0);
+
+ for (k = 0; k < n_steps - 1; k++)
+ {
+ running_sum += steps[k].delta;
+ run_x0 = run_x1;
+ run_x1 = steps[k + 1].x;
+ if (run_x1 > run_x0)
+ memset (linebuf + run_x0 - x0, running_sum >> 16, run_x1 - run_x0);
+ }
+ running_sum += steps[k].delta;
+ if (x1 > run_x1)
+ memset (linebuf + run_x1 - x0, running_sum >> 16, x1 - run_x1);
+ }
+ else
+ {
+ memset (linebuf, running_sum >> 16, x1 - x0);
+ }
+
+ data->buf += data->rowstride;
+}
+
+/**
+ * art_gray_svp_aa: Render the vector path into the bytemap.
+ * @svp: The SVP to render.
+ * @x0: The view window's left coord.
+ * @y0: The view window's top coord.
+ * @x1: The view window's right coord.
+ * @y1: The view window's bottom coord.
+ * @buf: The buffer where the bytemap is stored.
+ * @rowstride: the rowstride for @buf.
+ *
+ * Each pixel gets a value proportional to the area within the pixel
+ * overlapping the (filled) SVP. Pixel (x, y) is stored at:
+ *
+ * @buf[(y - * @y0) * @rowstride + (x - @x0)]
+ *
+ * All pixels @x0 <= x < @x1, @y0 <= y < @y1 are generated. A
+ * stored value of zero is no coverage, and a value of 255 is full
+ * coverage. The area within the pixel (x, y) is the region covered
+ * by [x..x+1] and [y..y+1].
+ **/
+void
+art_gray_svp_aa (const ArtSVP *svp,
+ int x0, int y0, int x1, int y1,
+ art_u8 *buf, int rowstride)
+{
+ ArtGraySVPData data;
+
+ data.buf = buf;
+ data.rowstride = rowstride;
+ data.x0 = x0;
+ data.x1 = x1;
+ art_svp_render_aa (svp, x0, y0, x1, y1, art_gray_svp_callback, &data);
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Render a sorted vector path into a graymap. */
+
+#ifndef __ART_GRAY_SVP_H__
+#define __ART_GRAY_SVP_H__
+
+#ifdef LIBART_COMPILATION
+#include "art_svp.h"
+#else
+#include <art_svp.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+void
+art_gray_svp_aa (const ArtSVP *svp,
+ int x0, int y0, int x1, int y1,
+ art_u8 *buf, int rowstride);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_GRAY_SVP_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Various utility functions RLL finds useful. */
+
+#include "config.h"
+#ifdef HAVE_UINSTD_H
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <stdarg.h>
+#include "art_misc.h"
+
+/**
+ * art_die: Print the error message to stderr and exit with a return code of 1.
+ * @fmt: The printf-style format for the error message.
+ *
+ * Used for dealing with severe errors.
+ **/
+void
+art_die (const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ vfprintf (stderr, fmt, ap);
+ va_end (ap);
+ exit (1);
+}
+
+/**
+ * art_die: Print the error message to stderr.
+ * @fmt: The printf-style format for the error message.
+ *
+ * Used for generating warnings.
+ **/
+void
+art_warn (const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ vfprintf (stderr, fmt, ap);
+ va_end (ap);
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Simple macros to set up storage allocation and basic types for libart
+ functions. */
+
+#ifndef __ART_MISC_H__
+#define __ART_MISC_H__
+
+#include <stdlib.h> /* for malloc, etc. */
+
+/* The art_config.h file is automatically generated by
+ gen_art_config.c and contains definitions of
+ ART_SIZEOF_{CHAR,SHORT,INT,LONG} and art_u{8,16,32}. */
+#ifdef LIBART_COMPILATION
+#include "art_config.h"
+#else
+#include <art_config.h>
+#endif
+
+#define art_alloc malloc
+#define art_free free
+#define art_realloc realloc
+
+/* These aren't, strictly speaking, configuration macros, but they're
+ damn handy to have around, and may be worth playing with for
+ debugging. */
+#define art_new(type, n) ((type *)art_alloc ((n) * sizeof(type)))
+
+#define art_renew(p, type, n) ((type *)art_realloc (p, (n) * sizeof(type)))
+
+/* This one must be used carefully - in particular, p and max should
+ be variables. They can also be pstruct->el lvalues. */
+#define art_expand(p, type, max) do { if(max) { p = art_renew (p, type, max <<= 1); } else { max = 1; p = art_new(type, 1); } } while (0)
+
+typedef int art_boolean;
+#define ART_FALSE 0
+#define ART_TRUE 1
+
+/* define pi */
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif /* M_PI */
+
+#ifndef M_SQRT2
+#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */
+#endif /* M_SQRT2 */
+
+/* Provide macros to feature the GCC function attribute.
+ */
+#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4))
+#define ART_GNUC_PRINTF( format_idx, arg_idx ) \
+ __attribute__((format (printf, format_idx, arg_idx)))
+#define ART_GNUC_NORETURN \
+ __attribute__((noreturn))
+#else /* !__GNUC__ */
+#define ART_GNUC_PRINTF( format_idx, arg_idx )
+#define ART_GNUC_NORETURN
+#endif /* !__GNUC__ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void ART_GNUC_NORETURN
+art_die (const char *fmt, ...) ART_GNUC_PRINTF (1, 2);
+
+void
+art_warn (const char *fmt, ...) ART_GNUC_PRINTF (1, 2);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Currently, the use of the new intersector is a compile-time option.
+ I'll leave it unset in CVS until I have considerable confidence in
+ the new intersector. */
+#define noART_USE_NEW_INTERSECTOR
+
+#endif /* __ART_MISC_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_PATHCODE_H__
+#define __ART_PATHCODE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef enum {
+ ART_MOVETO,
+ ART_MOVETO_OPEN,
+ ART_CURVETO,
+ ART_LINETO,
+ ART_END
+} ArtPathcode;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_PATHCODE_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "art_misc.h"
+#include "art_pixbuf.h"
+#include <string.h>
+
+/**
+ * art_pixbuf_new_rgb_dnotify: Create a new RGB #ArtPixBuf with explicit destroy notification.
+ * @pixels: A buffer containing the actual pixel data.
+ * @width: The width of the pixbuf.
+ * @height: The height of the pixbuf.
+ * @rowstride: The rowstride of the pixbuf.
+ * @dfunc_data: The private data passed to @dfunc.
+ * @dfunc: The destroy notification function.
+ *
+ * Creates a generic data structure for holding a buffer of RGB
+ * pixels. It is possible to think of an #ArtPixBuf as a
+ * virtualization over specific pixel buffer formats.
+ *
+ * @dfunc is called with @dfunc_data and @pixels as arguments when the
+ * #ArtPixBuf is destroyed. Using a destroy notification function
+ * allows a wide range of memory management disciplines for the pixel
+ * memory. A NULL value for @dfunc is also allowed and means that no
+ * special action will be taken on destruction.
+ *
+ * Return value: The newly created #ArtPixBuf.
+ **/
+ArtPixBuf *
+art_pixbuf_new_rgb_dnotify (art_u8 *pixels, int width, int height, int rowstride,
+ void *dfunc_data, ArtDestroyNotify dfunc)
+{
+ ArtPixBuf *pixbuf;
+
+ pixbuf = art_new (ArtPixBuf, 1);
+
+ pixbuf->format = ART_PIX_RGB;
+ pixbuf->n_channels = 3;
+ pixbuf->has_alpha = 0;
+ pixbuf->bits_per_sample = 8;
+
+ pixbuf->pixels = (art_u8 *) pixels;
+ pixbuf->width = width;
+ pixbuf->height = height;
+ pixbuf->rowstride = rowstride;
+ pixbuf->destroy_data = dfunc_data;
+ pixbuf->destroy = dfunc;
+
+ return pixbuf;
+}
+
+/**
+ * art_pixbuf_new_rgba_dnotify: Create a new RGBA #ArtPixBuf with explicit destroy notification.
+ * @pixels: A buffer containing the actual pixel data.
+ * @width: The width of the pixbuf.
+ * @height: The height of the pixbuf.
+ * @rowstride: The rowstride of the pixbuf.
+ * @dfunc_data: The private data passed to @dfunc.
+ * @dfunc: The destroy notification function.
+ *
+ * Creates a generic data structure for holding a buffer of RGBA
+ * pixels. It is possible to think of an #ArtPixBuf as a
+ * virtualization over specific pixel buffer formats.
+ *
+ * @dfunc is called with @dfunc_data and @pixels as arguments when the
+ * #ArtPixBuf is destroyed. Using a destroy notification function
+ * allows a wide range of memory management disciplines for the pixel
+ * memory. A NULL value for @dfunc is also allowed and means that no
+ * special action will be taken on destruction.
+ *
+ * Return value: The newly created #ArtPixBuf.
+ **/
+ArtPixBuf *
+art_pixbuf_new_rgba_dnotify (art_u8 *pixels, int width, int height, int rowstride,
+ void *dfunc_data, ArtDestroyNotify dfunc)
+{
+ ArtPixBuf *pixbuf;
+
+ pixbuf = art_new (ArtPixBuf, 1);
+
+ pixbuf->format = ART_PIX_RGB;
+ pixbuf->n_channels = 4;
+ pixbuf->has_alpha = 1;
+ pixbuf->bits_per_sample = 8;
+
+ pixbuf->pixels = (art_u8 *) pixels;
+ pixbuf->width = width;
+ pixbuf->height = height;
+ pixbuf->rowstride = rowstride;
+ pixbuf->destroy_data = dfunc_data;
+ pixbuf->destroy = dfunc;
+
+ return pixbuf;
+}
+
+/**
+ * art_pixbuf_new_const_rgb: Create a new RGB #ArtPixBuf with constant pixel data.
+ * @pixels: A buffer containing the actual pixel data.
+ * @width: The width of the pixbuf.
+ * @height: The height of the pixbuf.
+ * @rowstride: The rowstride of the pixbuf.
+ *
+ * Creates a generic data structure for holding a buffer of RGB
+ * pixels. It is possible to think of an #ArtPixBuf as a
+ * virtualization over specific pixel buffer formats.
+ *
+ * No action is taken when the #ArtPixBuf is destroyed. Thus, this
+ * function is useful when the pixel data is constant or statically
+ * allocated.
+ *
+ * Return value: The newly created #ArtPixBuf.
+ **/
+ArtPixBuf *
+art_pixbuf_new_const_rgb (const art_u8 *pixels, int width, int height, int rowstride)
+{
+ return art_pixbuf_new_rgb_dnotify ((art_u8 *) pixels, width, height, rowstride, NULL, NULL);
+}
+
+/**
+ * art_pixbuf_new_const_rgba: Create a new RGBA #ArtPixBuf with constant pixel data.
+ * @pixels: A buffer containing the actual pixel data.
+ * @width: The width of the pixbuf.
+ * @height: The height of the pixbuf.
+ * @rowstride: The rowstride of the pixbuf.
+ *
+ * Creates a generic data structure for holding a buffer of RGBA
+ * pixels. It is possible to think of an #ArtPixBuf as a
+ * virtualization over specific pixel buffer formats.
+ *
+ * No action is taken when the #ArtPixBuf is destroyed. Thus, this
+ * function is suitable when the pixel data is constant or statically
+ * allocated.
+ *
+ * Return value: The newly created #ArtPixBuf.
+ **/
+ArtPixBuf *
+art_pixbuf_new_const_rgba (const art_u8 *pixels, int width, int height, int rowstride)
+{
+ return art_pixbuf_new_rgba_dnotify ((art_u8 *) pixels, width, height, rowstride, NULL, NULL);
+}
+
+static void
+art_pixel_destroy (void *func_data, void *data)
+{
+ art_free (data);
+}
+
+/**
+ * art_pixbuf_new_rgb: Create a new RGB #ArtPixBuf.
+ * @pixels: A buffer containing the actual pixel data.
+ * @width: The width of the pixbuf.
+ * @height: The height of the pixbuf.
+ * @rowstride: The rowstride of the pixbuf.
+ *
+ * Creates a generic data structure for holding a buffer of RGB
+ * pixels. It is possible to think of an #ArtPixBuf as a
+ * virtualization over specific pixel buffer formats.
+ *
+ * The @pixels buffer is freed with art_free() when the #ArtPixBuf is
+ * destroyed. Thus, this function is suitable when the pixel data is
+ * allocated with art_alloc().
+ *
+ * Return value: The newly created #ArtPixBuf.
+ **/
+ArtPixBuf *
+art_pixbuf_new_rgb (art_u8 *pixels, int width, int height, int rowstride)
+{
+ return art_pixbuf_new_rgb_dnotify (pixels, width, height, rowstride, NULL, art_pixel_destroy);
+}
+
+/**
+ * art_pixbuf_new_rgba: Create a new RGBA #ArtPixBuf.
+ * @pixels: A buffer containing the actual pixel data.
+ * @width: The width of the pixbuf.
+ * @height: The height of the pixbuf.
+ * @rowstride: The rowstride of the pixbuf.
+ *
+ * Creates a generic data structure for holding a buffer of RGBA
+ * pixels. It is possible to think of an #ArtPixBuf as a
+ * virtualization over specific pixel buffer formats.
+ *
+ * The @pixels buffer is freed with art_free() when the #ArtPixBuf is
+ * destroyed. Thus, this function is suitable when the pixel data is
+ * allocated with art_alloc().
+ *
+ * Return value: The newly created #ArtPixBuf.
+ **/
+ArtPixBuf *
+art_pixbuf_new_rgba (art_u8 *pixels, int width, int height, int rowstride)
+{
+ return art_pixbuf_new_rgba_dnotify (pixels, width, height, rowstride, NULL, art_pixel_destroy);
+}
+
+/**
+ * art_pixbuf_free: Destroy an #ArtPixBuf.
+ * @pixbuf: The #ArtPixBuf to be destroyed.
+ *
+ * Destroys the #ArtPixBuf, calling the destroy notification function
+ * (if non-NULL) so that the memory for the pixel buffer can be
+ * properly reclaimed.
+ **/
+void
+art_pixbuf_free (ArtPixBuf *pixbuf)
+{
+ ArtDestroyNotify destroy = pixbuf->destroy;
+ void *destroy_data = pixbuf->destroy_data;
+ art_u8 *pixels = pixbuf->pixels;
+
+ pixbuf->pixels = NULL;
+ pixbuf->destroy = NULL;
+ pixbuf->destroy_data = NULL;
+
+ if (destroy)
+ destroy (destroy_data, pixels);
+
+ art_free (pixbuf);
+}
+
+/**
+ * art_pixbuf_free_shallow:
+ * @pixbuf: The #ArtPixBuf to be destroyed.
+ *
+ * Destroys the #ArtPixBuf without calling the destroy notification function.
+ *
+ * This function is deprecated. Use the _dnotify variants for
+ * allocation instead.
+ **/
+void
+art_pixbuf_free_shallow (ArtPixBuf *pixbuf)
+{
+ art_free (pixbuf);
+}
+
+/**
+ * art_pixbuf_duplicate: Duplicate a pixbuf.
+ * @pixbuf: The #ArtPixBuf to duplicate.
+ *
+ * Duplicates a pixbuf, including duplicating the buffer.
+ *
+ * Return value: The duplicated pixbuf.
+ **/
+ArtPixBuf *
+art_pixbuf_duplicate (const ArtPixBuf *pixbuf)
+{
+ ArtPixBuf *result;
+ int size;
+
+ result = art_new (ArtPixBuf, 1);
+
+ result->format = pixbuf->format;
+ result->n_channels = pixbuf->n_channels;
+ result->has_alpha = pixbuf->has_alpha;
+ result->bits_per_sample = pixbuf->bits_per_sample;
+
+ size = (pixbuf->height - 1) * pixbuf->rowstride +
+ pixbuf->width * ((pixbuf->n_channels * pixbuf->bits_per_sample + 7) >> 3);
+ result->pixels = art_alloc (size);
+ memcpy (result->pixels, pixbuf->pixels, size);
+
+ result->width = pixbuf->width;
+ result->height = pixbuf->height;
+ result->rowstride = pixbuf->rowstride;
+ result->destroy_data = NULL;
+ result->destroy = art_pixel_destroy;
+
+ return result;
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_PIXBUF_H__
+#define __ART_PIXBUF_H__
+
+/* A generic data structure for holding a buffer of pixels. One way
+ to think about this module is as a virtualization over specific
+ pixel buffer formats. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef void (*ArtDestroyNotify) (void *func_data, void *data);
+
+typedef struct _ArtPixBuf ArtPixBuf;
+
+typedef enum {
+ ART_PIX_RGB
+ /* gray, cmyk, lab, ... ? */
+} ArtPixFormat;
+
+
+/* The pixel buffer consists of width * height pixels, each of which
+ has n_channels samples. It is stored in simple packed format. */
+
+struct _ArtPixBuf {
+ /*< public >*/
+ ArtPixFormat format;
+ int n_channels;
+ int has_alpha;
+ int bits_per_sample;
+
+ art_u8 *pixels;
+ int width;
+ int height;
+ int rowstride;
+ void *destroy_data;
+ ArtDestroyNotify destroy;
+};
+
+/* allocate an ArtPixBuf from art_alloc()ed pixels (automated destruction) */
+ArtPixBuf *
+art_pixbuf_new_rgb (art_u8 *pixels, int width, int height, int rowstride);
+
+ArtPixBuf *
+art_pixbuf_new_rgba (art_u8 *pixels, int width, int height, int rowstride);
+
+/* allocate an ArtPixBuf from constant pixels (no destruction) */
+ArtPixBuf *
+art_pixbuf_new_const_rgb (const art_u8 *pixels, int width, int height, int rowstride);
+
+ArtPixBuf *
+art_pixbuf_new_const_rgba (const art_u8 *pixels, int width, int height, int rowstride);
+
+/* allocate an ArtPixBuf and notify creator upon destruction */
+ArtPixBuf *
+art_pixbuf_new_rgb_dnotify (art_u8 *pixels, int width, int height, int rowstride,
+ void *dfunc_data, ArtDestroyNotify dfunc);
+
+ArtPixBuf *
+art_pixbuf_new_rgba_dnotify (art_u8 *pixels, int width, int height, int rowstride,
+ void *dfunc_data, ArtDestroyNotify dfunc);
+
+/* free an ArtPixBuf with destroy notification */
+void
+art_pixbuf_free (ArtPixBuf *pixbuf);
+
+/* deprecated function, use the _dnotify variants for allocation instead */
+void
+art_pixbuf_free_shallow (ArtPixBuf *pixbuf);
+
+ArtPixBuf *
+art_pixbuf_duplicate (const ArtPixBuf *pixbuf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_POINT_H__
+#define __ART_POINT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct _ArtPoint ArtPoint;
+
+struct _ArtPoint {
+ /*< public >*/
+ double x, y;
+};
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_POINT_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <math.h>
+#include "art_misc.h"
+#include "art_rect.h"
+
+#ifndef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif /* MAX */
+
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif /* MIN */
+
+/* rectangle primitives stolen from gzilla */
+
+/**
+ * art_irect_copy: Make a copy of an integer rectangle.
+ * @dest: Where the copy is stored.
+ * @src: The source rectangle.
+ *
+ * Copies the rectangle.
+ **/
+void
+art_irect_copy (ArtIRect *dest, const ArtIRect *src) {
+ dest->x0 = src->x0;
+ dest->y0 = src->y0;
+ dest->x1 = src->x1;
+ dest->y1 = src->y1;
+}
+
+/**
+ * art_irect_union: Find union of two integer rectangles.
+ * @dest: Where the result is stored.
+ * @src1: A source rectangle.
+ * @src2: Another source rectangle.
+ *
+ * Finds the smallest rectangle that includes @src1 and @src2.
+ **/
+void
+art_irect_union (ArtIRect *dest, const ArtIRect *src1, const ArtIRect *src2) {
+ if (art_irect_empty (src1)) {
+ art_irect_copy (dest, src2);
+ } else if (art_irect_empty (src2)) {
+ art_irect_copy (dest, src1);
+ } else {
+ dest->x0 = MIN (src1->x0, src2->x0);
+ dest->y0 = MIN (src1->y0, src2->y0);
+ dest->x1 = MAX (src1->x1, src2->x1);
+ dest->y1 = MAX (src1->y1, src2->y1);
+ }
+}
+
+/**
+ * art_irect_intersection: Find intersection of two integer rectangles.
+ * @dest: Where the result is stored.
+ * @src1: A source rectangle.
+ * @src2: Another source rectangle.
+ *
+ * Finds the intersection of @src1 and @src2.
+ **/
+void
+art_irect_intersect (ArtIRect *dest, const ArtIRect *src1, const ArtIRect *src2) {
+ dest->x0 = MAX (src1->x0, src2->x0);
+ dest->y0 = MAX (src1->y0, src2->y0);
+ dest->x1 = MIN (src1->x1, src2->x1);
+ dest->y1 = MIN (src1->y1, src2->y1);
+}
+
+/**
+ * art_irect_empty: Determine whether integer rectangle is empty.
+ * @src: The source rectangle.
+ *
+ * Return value: TRUE if @src is an empty rectangle, FALSE otherwise.
+ **/
+int
+art_irect_empty (const ArtIRect *src) {
+ return (src->x1 <= src->x0 || src->y1 <= src->y0);
+}
+
+#if 0
+gboolean irect_point_inside (ArtIRect *rect, GzwPoint *point) {
+ return (point->x >= rect->x0 && point->y >= rect->y0 &&
+ point->x < rect->x1 && point->y < rect->y1);
+}
+#endif
+
+/**
+ * art_drect_copy: Make a copy of a rectangle.
+ * @dest: Where the copy is stored.
+ * @src: The source rectangle.
+ *
+ * Copies the rectangle.
+ **/
+void
+art_drect_copy (ArtDRect *dest, const ArtDRect *src) {
+ dest->x0 = src->x0;
+ dest->y0 = src->y0;
+ dest->x1 = src->x1;
+ dest->y1 = src->y1;
+}
+
+/**
+ * art_drect_union: Find union of two rectangles.
+ * @dest: Where the result is stored.
+ * @src1: A source rectangle.
+ * @src2: Another source rectangle.
+ *
+ * Finds the smallest rectangle that includes @src1 and @src2.
+ **/
+void
+art_drect_union (ArtDRect *dest, const ArtDRect *src1, const ArtDRect *src2) {
+ if (art_drect_empty (src1)) {
+ art_drect_copy (dest, src2);
+ } else if (art_drect_empty (src2)) {
+ art_drect_copy (dest, src1);
+ } else {
+ dest->x0 = MIN (src1->x0, src2->x0);
+ dest->y0 = MIN (src1->y0, src2->y0);
+ dest->x1 = MAX (src1->x1, src2->x1);
+ dest->y1 = MAX (src1->y1, src2->y1);
+ }
+}
+
+/**
+ * art_drect_intersection: Find intersection of two rectangles.
+ * @dest: Where the result is stored.
+ * @src1: A source rectangle.
+ * @src2: Another source rectangle.
+ *
+ * Finds the intersection of @src1 and @src2.
+ **/
+void
+art_drect_intersect (ArtDRect *dest, const ArtDRect *src1, const ArtDRect *src2) {
+ dest->x0 = MAX (src1->x0, src2->x0);
+ dest->y0 = MAX (src1->y0, src2->y0);
+ dest->x1 = MIN (src1->x1, src2->x1);
+ dest->y1 = MIN (src1->y1, src2->y1);
+}
+
+/**
+ * art_irect_empty: Determine whether rectangle is empty.
+ * @src: The source rectangle.
+ *
+ * Return value: TRUE if @src is an empty rectangle, FALSE otherwise.
+ **/
+int
+art_drect_empty (const ArtDRect *src) {
+ return (src->x1 <= src->x0 || src->y1 <= src->y0);
+}
+
+/**
+ * art_drect_affine_transform: Affine transform rectangle.
+ * @dst: Where to store the result.
+ * @src: The source rectangle.
+ * @matrix: The affine transformation.
+ *
+ * Find the smallest rectangle enclosing the affine transformed @src.
+ * The result is exactly the affine transformation of @src when
+ * @matrix specifies a rectilinear affine transformation, otherwise it
+ * is a conservative approximation.
+ **/
+void
+art_drect_affine_transform (ArtDRect *dst, const ArtDRect *src, const double matrix[6])
+{
+ double x00, y00, x10, y10;
+ double x01, y01, x11, y11;
+
+ x00 = src->x0 * matrix[0] + src->y0 * matrix[2] + matrix[4];
+ y00 = src->x0 * matrix[1] + src->y0 * matrix[3] + matrix[5];
+ x10 = src->x1 * matrix[0] + src->y0 * matrix[2] + matrix[4];
+ y10 = src->x1 * matrix[1] + src->y0 * matrix[3] + matrix[5];
+ x01 = src->x0 * matrix[0] + src->y1 * matrix[2] + matrix[4];
+ y01 = src->x0 * matrix[1] + src->y1 * matrix[3] + matrix[5];
+ x11 = src->x1 * matrix[0] + src->y1 * matrix[2] + matrix[4];
+ y11 = src->x1 * matrix[1] + src->y1 * matrix[3] + matrix[5];
+ dst->x0 = MIN (MIN (x00, x10), MIN (x01, x11));
+ dst->y0 = MIN (MIN (y00, y10), MIN (y01, y11));
+ dst->x1 = MAX (MAX (x00, x10), MAX (x01, x11));
+ dst->y1 = MAX (MAX (y00, y10), MAX (y01, y11));
+}
+
+/**
+ * art_drect_to_irect: Convert rectangle to integer rectangle.
+ * @dst: Where to store resulting integer rectangle.
+ * @src: The source rectangle.
+ *
+ * Find the smallest integer rectangle that encloses @src.
+ **/
+void
+art_drect_to_irect (ArtIRect *dst, ArtDRect *src)
+{
+ dst->x0 = floor (src->x0);
+ dst->y0 = floor (src->y0);
+ dst->x1 = ceil (src->x1);
+ dst->y1 = ceil (src->y1);
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_RECT_H__
+#define __ART_RECT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _ArtDRect ArtDRect;
+typedef struct _ArtIRect ArtIRect;
+
+struct _ArtDRect {
+ /*< public >*/
+ double x0, y0, x1, y1;
+};
+
+struct _ArtIRect {
+ /*< public >*/
+ int x0, y0, x1, y1;
+};
+
+/* Make a copy of the rectangle. */
+void art_irect_copy (ArtIRect *dest, const ArtIRect *src);
+
+/* Find the smallest rectangle that includes both source rectangles. */
+void art_irect_union (ArtIRect *dest,
+ const ArtIRect *src1, const ArtIRect *src2);
+
+/* Return the intersection of the two rectangles */
+void art_irect_intersect (ArtIRect *dest,
+ const ArtIRect *src1, const ArtIRect *src2);
+
+/* Return true if the rectangle is empty. */
+int art_irect_empty (const ArtIRect *src);
+
+/* Make a copy of the rectangle. */
+void art_drect_copy (ArtDRect *dest, const ArtDRect *src);
+
+/* Find the smallest rectangle that includes both source rectangles. */
+void art_drect_union (ArtDRect *dest,
+ const ArtDRect *src1, const ArtDRect *src2);
+
+/* Return the intersection of the two rectangles */
+void art_drect_intersect (ArtDRect *dest,
+ const ArtDRect *src1, const ArtDRect *src2);
+
+/* Return true if the rectangle is empty. */
+int art_drect_empty (const ArtDRect *src);
+
+void
+art_drect_affine_transform (ArtDRect *dst, const ArtDRect *src,
+ const double matrix[6]);
+
+void art_drect_to_irect (ArtIRect *dst, ArtDRect *src);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "art_misc.h"
+#include "art_svp.h"
+#include "art_rect.h"
+#include "art_rect_svp.h"
+
+/**
+ * art_drect_svp: Find the bounding box of a sorted vector path.
+ * @bbox: Where to store the bounding box.
+ * @svp: The SVP.
+ *
+ * Finds the bounding box of the SVP.
+ **/
+void
+art_drect_svp (ArtDRect *bbox, const ArtSVP *svp)
+{
+ int i;
+
+ bbox->x0 = 0;
+ bbox->y0 = 0;
+ bbox->x1 = 0;
+ bbox->y1 = 0;
+
+ for (i = 0; i < svp->n_segs; i++)
+ {
+ art_drect_union (bbox, bbox, &svp->segs[i].bbox);
+ }
+}
+
+/**
+ * art_drect_svp_union: Compute the bounding box of the svp and union it in to the existing bounding box.
+ * @bbox: Initial boundin box and where to store the bounding box.
+ * @svp: The SVP.
+ *
+ * Finds the bounding box of the SVP, computing its union with an
+ * existing bbox.
+ **/
+void
+art_drect_svp_union (ArtDRect *bbox, const ArtSVP *svp)
+{
+ int i;
+
+ for (i = 0; i < svp->n_segs; i++)
+ {
+ art_drect_union (bbox, bbox, &svp->segs[i].bbox);
+ }
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_RECT_SVP_H__
+#define __ART_RECT_SVP_H__
+
+/* Find the bounding box of a sorted vector path. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+void
+art_drect_svp (ArtDRect *bbox, const ArtSVP *svp);
+
+/* Compute the bounding box of the svp and union it in to the
+ existing bounding box. */
+void
+art_drect_svp_union (ArtDRect *bbox, const ArtSVP *svp);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_RECT_SVP_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "art_misc.h"
+#include "art_uta.h"
+#include "art_rect.h"
+#include "art_rect_uta.h"
+
+/* Functions to decompose a microtile array into a list of rectangles. */
+
+/**
+ * art_rect_list_from_uta: Decompose uta into list of rectangles.
+ * @uta: The source uta.
+ * @max_width: The maximum width of the resulting rectangles.
+ * @max_height: The maximum height of the resulting rectangles.
+ * @p_nrects: Where to store the number of returned rectangles.
+ *
+ * Allocates a new list of rectangles, sets *@p_nrects to the number
+ * in the list. This list should be freed with art_free().
+ *
+ * Each rectangle bounded in size by (@max_width, @max_height).
+ * However, these bounds must be at least the size of one tile.
+ *
+ * This routine provides a precise implementation, i.e. the rectangles
+ * cover exactly the same area as the uta. It is thus appropriate in
+ * cases where the overhead per rectangle is small compared with the
+ * cost of filling in extra pixels.
+ *
+ * Return value: An array containing the resulting rectangles.
+ **/
+ArtIRect *
+art_rect_list_from_uta (ArtUta *uta, int max_width, int max_height,
+ int *p_nrects)
+{
+ ArtIRect *rects;
+ int n_rects, n_rects_max;
+ int x, y;
+ int width, height;
+ int ix;
+ int left_ix;
+ ArtUtaBbox *utiles;
+ ArtUtaBbox bb;
+ int x0, y0, x1, y1;
+ int *glom;
+ int glom_rect;
+
+ n_rects = 0;
+ n_rects_max = 1;
+ rects = art_new (ArtIRect, n_rects_max);
+
+ width = uta->width;
+ height = uta->height;
+ utiles = uta->utiles;
+
+ glom = art_new (int, width * height);
+ for (ix = 0; ix < width * height; ix++)
+ glom[ix] = -1;
+
+ ix = 0;
+ for (y = 0; y < height; y++)
+ for (x = 0; x < width; x++)
+ {
+ bb = utiles[ix];
+ if (bb)
+ {
+ x0 = ((uta->x0 + x) << ART_UTILE_SHIFT) + ART_UTA_BBOX_X0(bb);
+ y0 = ((uta->y0 + y) << ART_UTILE_SHIFT) + ART_UTA_BBOX_Y0(bb);
+ y1 = ((uta->y0 + y) << ART_UTILE_SHIFT) + ART_UTA_BBOX_Y1(bb);
+
+ left_ix = ix;
+ /* now try to extend to the right */
+ while (x != width - 1 &&
+ ART_UTA_BBOX_X1(bb) == ART_UTILE_SIZE &&
+ (((bb & 0xffffff) ^ utiles[ix + 1]) & 0xffff00ff) == 0 &&
+ (((uta->x0 + x + 1) << ART_UTILE_SHIFT) +
+ ART_UTA_BBOX_X1(utiles[ix + 1]) -
+ x0) <= max_width)
+ {
+ bb = utiles[ix + 1];
+ ix++;
+ x++;
+ }
+ x1 = ((uta->x0 + x) << ART_UTILE_SHIFT) + ART_UTA_BBOX_X1(bb);
+
+
+ /* if rectangle nonempty */
+ if ((x1 ^ x0) | (y1 ^ y0))
+ {
+ /* try to glom onto an existing rectangle */
+ glom_rect = glom[left_ix];
+ if (glom_rect != -1 &&
+ x0 == rects[glom_rect].x0 &&
+ x1 == rects[glom_rect].x1 &&
+ y0 == rects[glom_rect].y1 &&
+ y1 - rects[glom_rect].y0 <= max_height)
+ {
+ rects[glom_rect].y1 = y1;
+ }
+ else
+ {
+ if (n_rects == n_rects_max)
+ art_expand (rects, ArtIRect, n_rects_max);
+ rects[n_rects].x0 = x0;
+ rects[n_rects].y0 = y0;
+ rects[n_rects].x1 = x1;
+ rects[n_rects].y1 = y1;
+ glom_rect = n_rects;
+ n_rects++;
+ }
+ if (y != height - 1)
+ glom[left_ix + width] = glom_rect;
+ }
+ }
+ ix++;
+ }
+
+ art_free (glom);
+ *p_nrects = n_rects;
+ return rects;
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_RECT_UTA_H__
+#define __ART_RECT_UTA_H__
+
+#ifdef LIBART_COMPILATION
+#include "art_uta.h"
+#else
+#include <art_uta.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+ArtIRect *
+art_rect_list_from_uta (ArtUta *uta, int max_width, int max_height,
+ int *p_nrects);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_RECT_UTA_H__ */
--- /dev/null
+/*
+ * art_render.c: Modular rendering architecture.
+ *
+ * Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "art_misc.h"
+#include "art_alphagamma.h"
+#include "art_rgb.h"
+
+#include "art_render.h"
+
+typedef struct _ArtRenderPriv ArtRenderPriv;
+
+struct _ArtRenderPriv {
+ ArtRender super;
+
+ ArtImageSource *image_source;
+
+ int n_mask_source;
+ ArtMaskSource **mask_source;
+
+ int n_callbacks;
+ ArtRenderCallback **callbacks;
+};
+
+ArtRender *
+art_render_new (int x0, int y0, int x1, int y1,
+ art_u8 *pixels, int rowstride,
+ int n_chan, int depth, ArtAlphaType alpha_type,
+ ArtAlphaGamma *alphagamma)
+{
+ ArtRenderPriv *priv;
+ ArtRender *result;
+
+ priv = art_new (ArtRenderPriv, 1);
+ result = &priv->super;
+
+ if (n_chan > ART_MAX_CHAN)
+ {
+ art_warn ("art_render_new: n_chan = %d, exceeds %d max\n",
+ n_chan, ART_MAX_CHAN);
+ return NULL;
+ }
+ if (depth > ART_MAX_DEPTH)
+ {
+ art_warn ("art_render_new: depth = %d, exceeds %d max\n",
+ depth, ART_MAX_DEPTH);
+ return NULL;
+ }
+ if (x0 >= x1)
+ {
+ art_warn ("art_render_new: x0 >= x1 (x0 = %d, x1 = %d)\n", x0, x1);
+ return NULL;
+ }
+ result->x0 = x0;
+ result->y0 = y0;
+ result->x1 = x1;
+ result->y1 = y1;
+ result->pixels = pixels;
+ result->rowstride = rowstride;
+ result->n_chan = n_chan;
+ result->depth = depth;
+ result->alpha_type = alpha_type;
+
+ result->clear = ART_FALSE;
+ result->opacity = 0x10000;
+ result->compositing_mode = ART_COMPOSITE_NORMAL;
+ result->alphagamma = alphagamma;
+
+ result->alpha_buf = NULL;
+ result->image_buf = NULL;
+
+ result->run = NULL;
+ result->span_x = NULL;
+
+ result->need_span = ART_FALSE;
+
+ priv->image_source = NULL;
+
+ priv->n_mask_source = 0;
+ priv->mask_source = NULL;
+
+ return result;
+}
+
+/* todo on clear routines: I haven't really figured out what to do
+ with clearing the alpha channel. It _should_ be possible to clear
+ to an arbitrary RGBA color. */
+
+/**
+ * art_render_clear: Set clear color.
+ * @clear_color: Color with which to clear dest.
+ *
+ * Sets clear color, equivalent to actually clearing the destination
+ * buffer before rendering. This is the most general form.
+ **/
+void
+art_render_clear (ArtRender *render, const ArtPixMaxDepth *clear_color)
+{
+ int i;
+ int n_ch = render->n_chan + (render->alpha_type != ART_ALPHA_NONE);
+
+ render->clear = ART_TRUE;
+ for (i = 0; i < n_ch; i++)
+ render->clear_color[i] = clear_color[i];
+}
+
+/**
+ * art_render_clear_rgb: Set clear color, given in RGB format.
+ * @clear_rgb: Clear color, in 0xRRGGBB format.
+ *
+ * Sets clear color, equivalent to actually clearing the destination
+ * buffer before rendering.
+ **/
+void
+art_render_clear_rgb (ArtRender *render, art_u32 clear_rgb)
+{
+ if (render->n_chan != 3)
+ art_warn ("art_render_clear_rgb: called on render with %d channels, only works with 3\n",
+ render->n_chan);
+ else
+ {
+ int r, g, b;
+
+ render->clear = ART_TRUE;
+ r = clear_rgb >> 16;
+ g = (clear_rgb >> 8) & 0xff;
+ b = clear_rgb & 0xff;
+ render->clear_color[0] = ART_PIX_MAX_FROM_8(r);
+ render->clear_color[1] = ART_PIX_MAX_FROM_8(g);
+ render->clear_color[2] = ART_PIX_MAX_FROM_8(b);
+ }
+}
+
+static void
+art_render_nop_done (ArtRenderCallback *self, ArtRender *render)
+{
+}
+
+static void
+art_render_clear_render_rgb8 (ArtRenderCallback *self, ArtRender *render,
+ art_u8 *dest, int y)
+{
+ int width = render->x1 - render->x0;
+ art_u8 r, g, b;
+ ArtPixMaxDepth color_max;
+
+ color_max = render->clear_color[0];
+ r = ART_PIX_8_FROM_MAX (color_max);
+ color_max = render->clear_color[1];
+ g = ART_PIX_8_FROM_MAX (color_max);
+ color_max = render->clear_color[2];
+ b = ART_PIX_8_FROM_MAX (color_max);
+
+ art_rgb_fill_run (dest, r, g, b, width);
+}
+
+static void
+art_render_clear_render_8 (ArtRenderCallback *self, ArtRender *render,
+ art_u8 *dest, int y)
+{
+ int width = render->x1 - render->x0;
+ int i, j;
+ int n_ch = render->n_chan + (render->alpha_type != ART_ALPHA_NONE);
+ int ix;
+ art_u8 color[ART_MAX_CHAN + 1];
+
+ for (j = 0; j < n_ch; j++)
+ {
+ ArtPixMaxDepth color_max = render->clear_color[j];
+ color[j] = ART_PIX_8_FROM_MAX (color_max);
+ }
+
+ ix = 0;
+ for (i = 0; i < width; i++)
+ for (j = 0; j < n_ch; j++)
+ dest[ix++] = color[j];
+}
+
+const ArtRenderCallback art_render_clear_rgb8_obj =
+{
+ art_render_clear_render_rgb8,
+ art_render_nop_done
+};
+
+const ArtRenderCallback art_render_clear_8_obj =
+{
+ art_render_clear_render_8,
+ art_render_nop_done
+};
+
+#if ART_MAX_DEPTH >= 16
+
+static void
+art_render_clear_render_16 (ArtRenderCallback *self, ArtRender *render,
+ art_u8 *dest, int y)
+{
+ int width = render->x1 - render->x0;
+ int i, j;
+ int n_ch = render->n_chan + (render->alpha_type != ART_ALPHA_NONE);
+ int ix;
+ art_u16 *dest_16 = (art_u16 *)dest;
+ art_u8 color[ART_MAX_CHAN + 1];
+
+ for (j = 0; j < n_ch; j++)
+ {
+ int color_16 = render->clear_color[j];
+ color[j] = color_16;
+ }
+
+ ix = 0;
+ for (i = 0; i < width; i++)
+ for (j = 0; j < n_ch; j++)
+ dest_16[ix++] = color[j];
+}
+
+const ArtRenderCallback art_render_clear_16_obj =
+{
+ art_render_clear_render_16,
+ art_render_nop_done
+};
+
+#endif /* ART_MAX_DEPTH >= 16 */
+
+/* todo: inline */
+static ArtRenderCallback *
+art_render_choose_clear_callback (ArtRender *render)
+{
+ ArtRenderCallback *clear_callback;
+
+ if (render->depth == 8)
+ {
+ if (render->n_chan == 3 &&
+ render->alpha_type == ART_ALPHA_NONE)
+ clear_callback = (ArtRenderCallback *)&art_render_clear_rgb8_obj;
+ else
+ clear_callback = (ArtRenderCallback *)&art_render_clear_8_obj;
+ }
+#if ART_MAX_DEPTH >= 16
+ else if (render->depth == 16)
+ clear_callback = (ArtRenderCallback *)&art_render_clear_16_obj;
+#endif
+ else
+ {
+ art_die ("art_render_choose_clear_callback: inconsistent render->depth = %d\n",
+ render->depth);
+ }
+ return clear_callback;
+}
+
+#if 0
+/* todo: get around to writing this */
+static void
+art_render_composite_render_noa_8_norm (ArtRenderCallback *self, ArtRender *render,
+ art_u8 *dest, int y)
+{
+ int width = render->x1 - render->x0;
+
+}
+#endif
+
+/* This is the most general form of the function. It is slow but
+ (hopefully) correct. Actually, I'm still worried about roundoff
+ errors in the premul case - it seems to me that an off-by-one could
+ lead to overflow. */
+static void
+art_render_composite (ArtRenderCallback *self, ArtRender *render,
+ art_u8 *dest, int y)
+{
+ ArtRenderMaskRun *run = render->run;
+ art_u32 depth = render->depth;
+ int n_run = render->n_run;
+ int x0 = render->x0;
+ int x;
+ int run_x0, run_x1;
+ art_u8 *alpha_buf = render->alpha_buf;
+ art_u8 *image_buf = render->image_buf;
+ int i, j;
+ art_u32 tmp;
+ art_u32 run_alpha;
+ art_u32 alpha;
+ int image_ix;
+ art_u16 src[ART_MAX_CHAN + 1];
+ art_u16 dst[ART_MAX_CHAN + 1];
+ int n_chan = render->n_chan;
+ ArtAlphaType alpha_type = render->alpha_type;
+ int n_ch = n_chan + (alpha_type != ART_ALPHA_NONE);
+ int dst_pixstride = n_ch * (depth >> 3);
+ int buf_depth = render->buf_depth;
+ ArtAlphaType buf_alpha = render->buf_alpha;
+ int buf_n_ch = n_chan + (buf_alpha != ART_ALPHA_NONE);
+ int buf_pixstride = buf_n_ch * (buf_depth >> 3);
+ art_u8 *bufptr;
+ art_u32 src_alpha;
+ art_u32 src_mul;
+ art_u8 *dstptr;
+ art_u32 dst_alpha;
+ art_u32 dst_mul;
+
+ image_ix = 0;
+ for (i = 0; i < n_run - 1; i++)
+ {
+ run_x0 = run[i].x;
+ run_x1 = run[i + 1].x;
+ tmp = run[i].alpha;
+ if (tmp < 0x8100)
+ continue;
+
+ run_alpha = (tmp + (tmp >> 8) + (tmp >> 16) - 0x8000) >> 8; /* range [0 .. 0x10000] */
+ bufptr = image_buf + (run_x0 - x0) * buf_pixstride;
+ dstptr = dest + (run_x0 - x0) * dst_pixstride;
+ for (x = run_x0; x < run_x1; x++)
+ {
+ if (alpha_buf)
+ {
+ if (depth == 8)
+ {
+ tmp = run_alpha * alpha_buf[x - x0] + 0x80;
+ /* range 0x80 .. 0xff0080 */
+ alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
+ }
+ else /* (depth == 16) */
+ {
+ tmp = ((art_u16 *)alpha_buf)[x - x0];
+ tmp = (run_alpha * tmp + 0x8000) >> 8;
+ /* range 0x80 .. 0xffff80 */
+ alpha = (tmp + (tmp >> 16)) >> 8;
+ }
+ }
+ else
+ alpha = run_alpha;
+ /* alpha is run_alpha * alpha_buf[x], range 0 .. 0x10000 */
+
+ /* convert (src pixel * alpha) to premul alpha form,
+ store in src as 0..0xffff range */
+ if (buf_alpha == ART_ALPHA_NONE)
+ {
+ src_alpha = alpha;
+ src_mul = src_alpha;
+ }
+ else
+ {
+ if (buf_depth == 8)
+ {
+ tmp = alpha * bufptr[n_chan] + 0x80;
+ /* range 0x80 .. 0xff0080 */
+ src_alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
+ }
+ else /* (depth == 16) */
+ {
+ tmp = ((art_u16 *)bufptr)[n_chan];
+ tmp = (alpha * tmp + 0x8000) >> 8;
+ /* range 0x80 .. 0xffff80 */
+ src_alpha = (tmp + (tmp >> 16)) >> 8;
+ }
+ if (buf_alpha == ART_ALPHA_SEPARATE)
+ src_mul = src_alpha;
+ else /* buf_alpha == (ART_ALPHA_PREMUL) */
+ src_mul = alpha;
+ }
+ /* src_alpha is the (alpha of the source pixel * alpha),
+ range 0..0x10000 */
+
+ if (buf_depth == 8)
+ {
+ src_mul *= 0x101;
+ for (j = 0; j < n_chan; j++)
+ src[j] = (bufptr[j] * src_mul + 0x8000) >> 16;
+ }
+ else if (buf_depth == 16)
+ {
+ for (j = 0; j < n_chan; j++)
+ src[j] = (((art_u16 *)bufptr)[j] * src_mul + 0x8000) >> 16;
+ }
+ bufptr += buf_pixstride;
+
+ /* src[0..n_chan - 1] (range 0..0xffff) and src_alpha (range
+ 0..0x10000) now contain the source pixel with
+ premultiplied alpha */
+
+ /* convert dst pixel to premul alpha form,
+ store in dst as 0..0xffff range */
+ if (alpha_type == ART_ALPHA_NONE)
+ {
+ dst_alpha = 0x10000;
+ dst_mul = dst_alpha;
+ }
+ else
+ {
+ if (depth == 8)
+ {
+ tmp = dstptr[n_chan];
+ /* range 0..0xff */
+ dst_alpha = (tmp << 8) + tmp + (tmp >> 7);
+ }
+ else /* (depth == 16) */
+ {
+ tmp = ((art_u16 *)bufptr)[n_chan];
+ dst_alpha = (tmp + (tmp >> 15));
+ }
+ if (alpha_type == ART_ALPHA_SEPARATE)
+ dst_mul = dst_alpha;
+ else /* (alpha_type == ART_ALPHA_PREMUL) */
+ dst_mul = 0x10000;
+ }
+ /* dst_alpha is the alpha of the dest pixel,
+ range 0..0x10000 */
+
+ if (depth == 8)
+ {
+ dst_mul *= 0x101;
+ for (j = 0; j < n_chan; j++)
+ dst[j] = (dstptr[j] * dst_mul + 0x8000) >> 16;
+ }
+ else if (buf_depth == 16)
+ {
+ for (j = 0; j < n_chan; j++)
+ dst[j] = (((art_u16 *)dstptr)[j] * dst_mul + 0x8000) >> 16;
+ }
+
+ /* do the compositing, dst = (src over dst) */
+ for (j = 0; j < n_chan; j++)
+ {
+ art_u32 srcv, dstv;
+ art_u32 tmp;
+
+ srcv = src[j];
+ dstv = dst[j];
+ tmp = ((dstv * (0x10000 - src_alpha) + 0x8000) >> 16) + srcv;
+ tmp -= tmp >> 16;
+ dst[j] = tmp;
+ }
+
+ if (alpha_type == ART_ALPHA_NONE)
+ {
+ if (depth == 8)
+ dst_mul = 0xff;
+ else /* (depth == 16) */
+ dst_mul = 0xffff;
+ }
+ else
+ {
+ if (src_alpha >= 0x10000)
+ dst_alpha = 0x10000;
+ else
+ dst_alpha += ((((0x10000 - dst_alpha) * src_alpha) >> 8) + 0x80) >> 8;
+ if (alpha_type == ART_ALPHA_PREMUL || dst_alpha == 0)
+ {
+ if (depth == 8)
+ dst_mul = 0xff;
+ else /* (depth == 16) */
+ dst_mul = 0xffff;
+ }
+ else /* (ALPHA_TYPE == ART_ALPHA_SEPARATE && dst_alpha != 0) */
+ {
+ if (depth == 8)
+ dst_mul = 0xff0000 / dst_alpha;
+ else /* (depth == 16) */
+ dst_mul = 0xffff0000 / dst_alpha;
+ }
+ }
+ if (depth == 8)
+ {
+ for (j = 0; j < n_chan; j++)
+ dstptr[j] = (dst[j] * dst_mul + 0x8000) >> 16;
+ if (alpha_type != ART_ALPHA_NONE)
+ dstptr[n_chan] = (dst_alpha * 0xff + 0x8000) >> 16;
+ }
+ else if (depth == 16)
+ {
+ for (j = 0; j < n_chan; j++)
+ ((art_u16 *)dstptr)[j] = (dst[j] * dst_mul + 0x8000) >> 16;
+ if (alpha_type != ART_ALPHA_NONE)
+ dstptr[n_chan] = (dst_alpha * 0xffff + 0x8000) >> 16;
+ }
+ dstptr += dst_pixstride;
+ }
+ }
+}
+
+const ArtRenderCallback art_render_composite_obj =
+{
+ art_render_composite,
+ art_render_nop_done
+};
+
+static void
+art_render_composite_8 (ArtRenderCallback *self, ArtRender *render,
+ art_u8 *dest, int y)
+{
+ ArtRenderMaskRun *run = render->run;
+ int n_run = render->n_run;
+ int x0 = render->x0;
+ int x;
+ int run_x0, run_x1;
+ art_u8 *alpha_buf = render->alpha_buf;
+ art_u8 *image_buf = render->image_buf;
+ int i, j;
+ art_u32 tmp;
+ art_u32 run_alpha;
+ art_u32 alpha;
+ int image_ix;
+ int n_chan = render->n_chan;
+ ArtAlphaType alpha_type = render->alpha_type;
+ int n_ch = n_chan + (alpha_type != ART_ALPHA_NONE);
+ int dst_pixstride = n_ch;
+ ArtAlphaType buf_alpha = render->buf_alpha;
+ int buf_n_ch = n_chan + (buf_alpha != ART_ALPHA_NONE);
+ int buf_pixstride = buf_n_ch;
+ art_u8 *bufptr;
+ art_u32 src_alpha;
+ art_u32 src_mul;
+ art_u8 *dstptr;
+ art_u32 dst_alpha;
+ art_u32 dst_mul, dst_save_mul;
+
+ image_ix = 0;
+ for (i = 0; i < n_run - 1; i++)
+ {
+ run_x0 = run[i].x;
+ run_x1 = run[i + 1].x;
+ tmp = run[i].alpha;
+ if (tmp < 0x10000)
+ continue;
+
+ run_alpha = (tmp + (tmp >> 8) + (tmp >> 16) - 0x8000) >> 8; /* range [0 .. 0x10000] */
+ bufptr = image_buf + (run_x0 - x0) * buf_pixstride;
+ dstptr = dest + (run_x0 - x0) * dst_pixstride;
+ for (x = run_x0; x < run_x1; x++)
+ {
+ if (alpha_buf)
+ {
+ tmp = run_alpha * alpha_buf[x - x0] + 0x80;
+ /* range 0x80 .. 0xff0080 */
+ alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
+ }
+ else
+ alpha = run_alpha;
+ /* alpha is run_alpha * alpha_buf[x], range 0 .. 0x10000 */
+
+ /* convert (src pixel * alpha) to premul alpha form,
+ store in src as 0..0xffff range */
+ if (buf_alpha == ART_ALPHA_NONE)
+ {
+ src_alpha = alpha;
+ src_mul = src_alpha;
+ }
+ else
+ {
+ tmp = alpha * bufptr[n_chan] + 0x80;
+ /* range 0x80 .. 0xff0080 */
+ src_alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
+
+ if (buf_alpha == ART_ALPHA_SEPARATE)
+ src_mul = src_alpha;
+ else /* buf_alpha == (ART_ALPHA_PREMUL) */
+ src_mul = alpha;
+ }
+ /* src_alpha is the (alpha of the source pixel * alpha),
+ range 0..0x10000 */
+
+ src_mul *= 0x101;
+
+ if (alpha_type == ART_ALPHA_NONE)
+ {
+ dst_alpha = 0x10000;
+ dst_mul = dst_alpha;
+ }
+ else
+ {
+ tmp = dstptr[n_chan];
+ /* range 0..0xff */
+ dst_alpha = (tmp << 8) + tmp + (tmp >> 7);
+ if (alpha_type == ART_ALPHA_SEPARATE)
+ dst_mul = dst_alpha;
+ else /* (alpha_type == ART_ALPHA_PREMUL) */
+ dst_mul = 0x10000;
+ }
+ /* dst_alpha is the alpha of the dest pixel,
+ range 0..0x10000 */
+
+ dst_mul *= 0x101;
+
+ if (alpha_type == ART_ALPHA_NONE)
+ {
+ dst_save_mul = 0xff;
+ }
+ else
+ {
+ if (src_alpha >= 0x10000)
+ dst_alpha = 0x10000;
+ else
+ dst_alpha += ((((0x10000 - dst_alpha) * src_alpha) >> 8) + 0x80) >> 8;
+ if (alpha_type == ART_ALPHA_PREMUL || dst_alpha == 0)
+ {
+ dst_save_mul = 0xff;
+ }
+ else /* (ALPHA_TYPE == ART_ALPHA_SEPARATE && dst_alpha != 0) */
+ {
+ dst_save_mul = 0xff0000 / dst_alpha;
+ }
+ }
+ for (j = 0; j < n_chan; j++)
+ {
+ art_u32 src, dst;
+ art_u32 tmp;
+
+ src = (bufptr[j] * src_mul + 0x8000) >> 16;
+ dst = (dstptr[j] * dst_mul + 0x8000) >> 16;
+ tmp = ((dst * (0x10000 - src_alpha) + 0x8000) >> 16) + src;
+ tmp -= tmp >> 16;
+ dstptr[j] = (tmp * dst_save_mul + 0x8000) >> 16;
+ }
+ if (alpha_type != ART_ALPHA_NONE)
+ dstptr[n_chan] = (dst_alpha * 0xff + 0x8000) >> 16;
+
+ bufptr += buf_pixstride;
+ dstptr += dst_pixstride;
+ }
+ }
+}
+
+const ArtRenderCallback art_render_composite_8_obj =
+{
+ art_render_composite_8,
+ art_render_nop_done
+};
+
+/* todo: inline */
+static ArtRenderCallback *
+art_render_choose_compositing_callback (ArtRender *render)
+{
+ if (render->depth == 8 && render->buf_depth == 8)
+ return (ArtRenderCallback *)&art_render_composite_8_obj;
+ return (ArtRenderCallback *)&art_render_composite_obj;
+}
+
+/**
+ * art_render_invoke_callbacks: Invoke the callbacks in the render object.
+ * @render: The render object.
+ * @y: The current Y coordinate value.
+ *
+ * Invokes the callbacks of the render object in the appropriate
+ * order. Drivers should call this routine once per scanline.
+ *
+ * todo: should management of dest devolve to this routine? very
+ * plausibly yes.
+ **/
+void
+art_render_invoke_callbacks (ArtRender *render, art_u8 *dest, int y)
+{
+ ArtRenderPriv *priv = (ArtRenderPriv *)render;
+ int i;
+
+ for (i = 0; i < priv->n_callbacks; i++)
+ {
+ ArtRenderCallback *callback;
+
+ callback = priv->callbacks[i];
+ callback->render (callback, render, dest, y);
+ }
+}
+
+/**
+ * art_render_invoke: Perform the requested rendering task.
+ * @render: The render object.
+ *
+ * Invokes the renderer and all sources associated with it, to perform
+ * the requested rendering task.
+ **/
+void
+art_render_invoke (ArtRender *render)
+{
+ ArtRenderPriv *priv = (ArtRenderPriv *)render;
+ int width;
+ int best_driver, best_score;
+ int i;
+ int n_callbacks, n_callbacks_max;
+ ArtImageSource *image_source;
+ ArtImageSourceFlags image_flags;
+ int buf_depth;
+ ArtAlphaType buf_alpha;
+ art_boolean first = ART_TRUE;
+
+ if (render == NULL)
+ {
+ art_warn ("art_render_invoke: called with render == NULL\n");
+ return;
+ }
+ if (priv->image_source == NULL)
+ {
+ art_warn ("art_render_invoke: no image source given\n");
+ return;
+ }
+
+ width = render->x1 - render->x0;
+
+ render->run = art_new (ArtRenderMaskRun, width + 1);
+
+ /* Elect a mask source as driver. */
+ best_driver = -1;
+ best_score = 0;
+ for (i = 0; i < priv->n_mask_source; i++)
+ {
+ int score;
+ ArtMaskSource *mask_source;
+
+ mask_source = priv->mask_source[i];
+ score = mask_source->can_drive (mask_source, render);
+ if (score > best_score)
+ {
+ best_score = score;
+ best_driver = i;
+ }
+ }
+
+ /* Allocate alpha buffer if needed. */
+ if (priv->n_mask_source > 1 ||
+ (priv->n_mask_source == 1 && best_driver < 0))
+ {
+ render->alpha_buf = art_new (art_u8, (width * render->depth) >> 3);
+ }
+
+ /* Negotiate image rendering and compositing. */
+ image_source = priv->image_source;
+ image_source->negotiate (image_source, render, &image_flags, &buf_depth,
+ &buf_alpha);
+
+ /* Build callback list. */
+ n_callbacks_max = priv->n_mask_source + 3;
+ priv->callbacks = art_new (ArtRenderCallback *, n_callbacks_max);
+ n_callbacks = 0;
+ for (i = 0; i < priv->n_mask_source; i++)
+ if (i != best_driver)
+ {
+ ArtMaskSource *mask_source = priv->mask_source[i];
+
+ mask_source->prepare (mask_source, render, first);
+ first = ART_FALSE;
+ priv->callbacks[n_callbacks++] = &mask_source->super;
+ }
+
+ if (render->clear && !(image_flags & ART_IMAGE_SOURCE_CAN_CLEAR))
+ priv->callbacks[n_callbacks++] =
+ art_render_choose_clear_callback (render);
+
+ priv->callbacks[n_callbacks++] = &image_source->super;
+
+ /* Allocate image buffer and add compositing callback if needed. */
+ if (!(image_flags & ART_IMAGE_SOURCE_CAN_COMPOSITE))
+ {
+ int bytespp = ((render->n_chan + (buf_alpha != ART_ALPHA_NONE)) *
+ buf_depth) >> 3;
+ render->buf_depth = buf_depth;
+ render->buf_alpha = buf_alpha;
+ render->image_buf = art_new (art_u8, width * bytespp);
+ priv->callbacks[n_callbacks++] =
+ art_render_choose_compositing_callback (render);
+ }
+
+ priv->n_callbacks = n_callbacks;
+
+ if (render->need_span)
+ render->span_x = art_new (int, width + 1);
+
+ /* Invoke the driver */
+ if (best_driver >= 0)
+ {
+ ArtMaskSource *driver;
+
+ driver = priv->mask_source[best_driver];
+ driver->invoke_driver (driver, render);
+ }
+ else
+ {
+ art_u8 *dest_ptr = render->pixels;
+ int y;
+
+ /* Dummy driver */
+ render->n_run = 2;
+ render->run[0].x = render->x0;
+ render->run[0].alpha = 0x8000 + 0xff * render->opacity;
+ render->run[1].x = render->x1;
+ render->run[1].alpha = 0x8000;
+ if (render->need_span)
+ {
+ render->n_span = 2;
+ render->span_x[0] = render->x0;
+ render->span_x[1] = render->x1;
+ }
+ for (y = render->y0; y < render->y1; y++)
+ {
+ art_render_invoke_callbacks (render, dest_ptr, y);
+ dest_ptr += render->rowstride;
+ }
+ }
+
+ if (priv->mask_source != NULL)
+ art_free (priv->mask_source);
+
+ /* clean up callbacks */
+ for (i = 0; i < priv->n_callbacks; i++)
+ {
+ ArtRenderCallback *callback;
+
+ callback = priv->callbacks[i];
+ callback->done (callback, render);
+ }
+
+ /* Tear down object */
+ if (render->alpha_buf != NULL)
+ art_free (render->alpha_buf);
+ if (render->image_buf != NULL)
+ art_free (render->image_buf);
+ art_free (render->run);
+ if (render->span_x != NULL)
+ art_free (render->span_x);
+ art_free (priv->callbacks);
+ art_free (render);
+}
+
+/**
+ * art_render_mask_solid: Add a solid translucent mask.
+ * @render: The render object.
+ * @opacity: Opacity in [0..0x10000] form.
+ *
+ * Adds a translucent mask to the rendering object.
+ **/
+void
+art_render_mask_solid (ArtRender *render, int opacity)
+{
+ art_u32 old_opacity = render->opacity;
+ art_u32 new_opacity_tmp;
+
+ if (opacity == 0x10000)
+ /* avoid potential overflow */
+ return;
+ new_opacity_tmp = old_opacity * (art_u32)opacity + 0x8000;
+ render->opacity = new_opacity_tmp >> 16;
+}
+
+/**
+ * art_render_add_mask_source: Add a mask source to the render object.
+ * @render: Render object.
+ * @mask_source: Mask source to add.
+ *
+ * This routine adds a mask source to the render object. In general,
+ * client api's for adding mask sources should just take a render object,
+ * then the mask source creation function should call this function.
+ * Clients should never have to call this function directly, unless of
+ * course they're creating custom mask sources.
+ **/
+void
+art_render_add_mask_source (ArtRender *render, ArtMaskSource *mask_source)
+{
+ ArtRenderPriv *priv = (ArtRenderPriv *)render;
+ int n_mask_source = priv->n_mask_source++;
+
+ if (n_mask_source == 0)
+ priv->mask_source = art_new (ArtMaskSource *, 1);
+ /* This predicate is true iff n_mask_source is a power of two */
+ else if (!(n_mask_source & (n_mask_source - 1)))
+ priv->mask_source = art_renew (priv->mask_source, ArtMaskSource *,
+ n_mask_source << 1);
+
+ priv->mask_source[n_mask_source] = mask_source;
+}
+
+/**
+ * art_render_add_image_source: Add a mask source to the render object.
+ * @render: Render object.
+ * @image_source: Image source to add.
+ *
+ * This routine adds an image source to the render object. In general,
+ * client api's for adding image sources should just take a render
+ * object, then the mask source creation function should call this
+ * function. Clients should never have to call this function
+ * directly, unless of course they're creating custom image sources.
+ **/
+void
+art_render_add_image_source (ArtRender *render, ArtImageSource *image_source)
+{
+ ArtRenderPriv *priv = (ArtRenderPriv *)render;
+
+ if (priv->image_source != NULL)
+ {
+ art_warn ("art_render_add_image_source: image source already present.\n");
+ return;
+ }
+ priv->image_source = image_source;
+}
+
+/* Solid image source object and methods. Perhaps this should go into a
+ separate file. */
+
+typedef struct _ArtImageSourceSolid ArtImageSourceSolid;
+
+struct _ArtImageSourceSolid {
+ ArtImageSource super;
+ ArtPixMaxDepth color[ART_MAX_CHAN];
+ art_u32 *rgbtab;
+ art_boolean init;
+};
+
+static void
+art_render_image_solid_done (ArtRenderCallback *self, ArtRender *render)
+{
+ ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
+
+ if (z->rgbtab != NULL)
+ art_free (z->rgbtab);
+ art_free (self);
+}
+
+static void
+art_render_image_solid_rgb8_opaq_init (ArtImageSourceSolid *self, ArtRender *render)
+{
+ ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
+ ArtPixMaxDepth color_max;
+ int r_fg, g_fg, b_fg;
+ int r_bg, g_bg, b_bg;
+ int r, g, b;
+ int dr, dg, db;
+ int i;
+ int tmp;
+ art_u32 *rgbtab;
+
+ rgbtab = art_new (art_u32, 256);
+ z->rgbtab = rgbtab;
+
+ color_max = self->color[0];
+ r_fg = ART_PIX_8_FROM_MAX (color_max);
+ color_max = self->color[1];
+ g_fg = ART_PIX_8_FROM_MAX (color_max);
+ color_max = self->color[2];
+ b_fg = ART_PIX_8_FROM_MAX (color_max);
+
+ color_max = render->clear_color[0];
+ r_bg = ART_PIX_8_FROM_MAX (color_max);
+ color_max = render->clear_color[1];
+ g_bg = ART_PIX_8_FROM_MAX (color_max);
+ color_max = render->clear_color[2];
+ b_bg = ART_PIX_8_FROM_MAX (color_max);
+
+ r = (r_bg << 16) + 0x8000;
+ g = (g_bg << 16) + 0x8000;
+ b = (b_bg << 16) + 0x8000;
+ tmp = ((r_fg - r_bg) << 16) + 0x80;
+ dr = (tmp + (tmp >> 8)) >> 8;
+ tmp = ((g_fg - g_bg) << 16) + 0x80;
+ dg = (tmp + (tmp >> 8)) >> 8;
+ tmp = ((b_fg - b_bg) << 16) + 0x80;
+ db = (tmp + (tmp >> 8)) >> 8;
+
+ for (i = 0; i < 256; i++)
+ {
+ rgbtab[i] = (r & 0xff0000) | ((g & 0xff0000) >> 8) | (b >> 16);
+ r += dr;
+ g += dg;
+ b += db;
+ }
+}
+
+static void
+art_render_image_solid_rgb8_opaq (ArtRenderCallback *self, ArtRender *render,
+ art_u8 *dest, int y)
+{
+ ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
+ ArtRenderMaskRun *run = render->run;
+ int n_run = render->n_run;
+ art_u32 *rgbtab = z->rgbtab;
+ art_u32 rgb;
+ int x0 = render->x0;
+ int x1 = render->x1;
+ int run_x0, run_x1;
+ int i;
+ int ix;
+
+ if (n_run > 0)
+ {
+ run_x1 = run[0].x;
+ if (run_x1 > x0)
+ {
+ rgb = rgbtab[0];
+ art_rgb_fill_run (dest,
+ rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
+ run_x1 - x0);
+ }
+ for (i = 0; i < n_run - 1; i++)
+ {
+ run_x0 = run_x1;
+ run_x1 = run[i + 1].x;
+ rgb = rgbtab[(run[i].alpha >> 16) & 0xff];
+ ix = (run_x0 - x0) * 3;
+#define OPTIMIZE_LEN_1
+#ifdef OPTIMIZE_LEN_1
+ if (run_x1 - run_x0 == 1)
+ {
+ dest[ix] = rgb >> 16;
+ dest[ix + 1] = (rgb >> 8) & 0xff;
+ dest[ix + 2] = rgb & 0xff;
+ }
+ else
+ {
+ art_rgb_fill_run (dest + ix,
+ rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
+ run_x1 - run_x0);
+ }
+#else
+ art_rgb_fill_run (dest + ix,
+ rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
+ run_x1 - run_x0);
+#endif
+ }
+ }
+ else
+ {
+ run_x1 = x0;
+ }
+ if (run_x1 < x1)
+ {
+ rgb = rgbtab[0];
+ art_rgb_fill_run (dest + (run_x1 - x0) * 3,
+ rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
+ x1 - run_x1);
+ }
+}
+
+static void
+art_render_image_solid_rgb8 (ArtRenderCallback *self, ArtRender *render,
+ art_u8 *dest, int y)
+{
+ ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
+ int width = render->x1 - render->x0;
+ art_u8 r, g, b;
+ ArtPixMaxDepth color_max;
+
+ /* todo: replace this simple test with real sparseness */
+ if (z->init)
+ return;
+ z->init = ART_TRUE;
+
+ color_max = z->color[0];
+ r = ART_PIX_8_FROM_MAX (color_max);
+ color_max = z->color[1];
+ g = ART_PIX_8_FROM_MAX (color_max);
+ color_max = z->color[2];
+ b = ART_PIX_8_FROM_MAX (color_max);
+
+ art_rgb_fill_run (render->image_buf, r, g, b, width);
+}
+
+static void
+art_render_image_solid_negotiate (ArtImageSource *self, ArtRender *render,
+ ArtImageSourceFlags *p_flags,
+ int *p_buf_depth, ArtAlphaType *p_alpha)
+{
+ ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
+ ArtImageSourceFlags flags = 0;
+ static void (*render_cbk) (ArtRenderCallback *self, ArtRender *render,
+ art_u8 *dest, int y);
+
+ render_cbk = NULL;
+
+ if (render->depth == 8 && render->n_chan == 3 &&
+ render->alpha_type == ART_ALPHA_NONE)
+ {
+ if (render->clear)
+ {
+ render_cbk = art_render_image_solid_rgb8_opaq;
+ flags |= ART_IMAGE_SOURCE_CAN_CLEAR | ART_IMAGE_SOURCE_CAN_COMPOSITE;
+ art_render_image_solid_rgb8_opaq_init (z, render);
+ }
+ }
+ if (render_cbk == NULL)
+ {
+ if (render->depth == 8)
+ {
+ render_cbk = art_render_image_solid_rgb8;
+ *p_buf_depth = 8;
+ *p_alpha = ART_ALPHA_NONE; /* todo */
+ }
+ }
+ /* todo: general case */
+ self->super.render = render_cbk;
+ *p_flags = flags;
+}
+
+/**
+ * art_render_image_solid: Add a solid color image source.
+ * @render: The render object.
+ * @color: Color.
+ *
+ * Adds an image source with the solid color given by @color. The
+ * color need not be retained in memory after this call.
+ **/
+void
+art_render_image_solid (ArtRender *render, ArtPixMaxDepth *color)
+{
+ ArtImageSourceSolid *image_source;
+ int i;
+
+ image_source = art_new (ArtImageSourceSolid, 1);
+ image_source->super.super.render = NULL;
+ image_source->super.super.done = art_render_image_solid_done;
+ image_source->super.negotiate = art_render_image_solid_negotiate;
+
+ for (i = 0; i < render->n_chan; i++)
+ image_source->color[i] = color[i];
+
+ image_source->rgbtab = NULL;
+ image_source->init = ART_FALSE;
+
+ art_render_add_image_source (render, &image_source->super);
+}
--- /dev/null
+/*
+ * art_render.h: Modular rendering architecture.
+ *
+ * Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_RENDER_H__
+#define __ART_RENDER_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Render object */
+
+#ifndef ART_MAX_DEPTH
+#define ART_MAX_DEPTH 16
+#endif
+
+#if ART_MAX_DEPTH == 16
+typedef art_u16 ArtPixMaxDepth;
+#define ART_PIX_MAX_FROM_8(x) ((x) | ((x) << 8))
+#define ART_PIX_8_FROM_MAX(x) (((x) + 0x80 - (((x) + 0x80) >> 8)) >> 8)
+#else
+#if ART_MAX_DEPTH == 8
+typedef art_u8 ArtPixMaxDepth;
+#define ART_PIX_MAX_FROM_8(x) (x)
+#define ART_PIX_8_FROM_MAX(x) (x)
+#else
+#error ART_MAX_DEPTH must be either 8 or 16
+#endif
+#endif
+
+#define ART_MAX_CHAN 16
+
+typedef struct _ArtRender ArtRender;
+typedef struct _ArtRenderCallback ArtRenderCallback;
+typedef struct _ArtRenderMaskRun ArtRenderMaskRun;
+typedef struct _ArtImageSource ArtImageSource;
+typedef struct _ArtMaskSource ArtMaskSource;
+
+typedef enum {
+ ART_ALPHA_NONE = 0,
+ ART_ALPHA_SEPARATE = 1,
+ ART_ALPHA_PREMUL = 2
+} ArtAlphaType;
+
+typedef enum {
+ ART_COMPOSITE_NORMAL,
+ ART_COMPOSITE_MULTIPLY,
+ /* todo: more */
+ ART_COMPOSITE_CUSTOM
+} ArtCompositingMode;
+
+typedef enum {
+ ART_IMAGE_SOURCE_CAN_CLEAR = 1,
+ ART_IMAGE_SOURCE_CAN_COMPOSITE = 2
+} ArtImageSourceFlags;
+
+struct _ArtRenderMaskRun {
+ int x;
+ int alpha;
+};
+
+struct _ArtRenderCallback {
+ void (*render) (ArtRenderCallback *self, ArtRender *render,
+ art_u8 *dest, int y);
+ void (*done) (ArtRenderCallback *self, ArtRender *render);
+};
+
+struct _ArtImageSource {
+ ArtRenderCallback super;
+ void (*negotiate) (ArtImageSource *self, ArtRender *render,
+ ArtImageSourceFlags *p_flags,
+ int *p_buf_depth, ArtAlphaType *p_alpha_type);
+};
+
+struct _ArtMaskSource {
+ ArtRenderCallback super;
+ int (*can_drive) (ArtMaskSource *self, ArtRender *render);
+ /* For each mask source, ::prepare() is invoked if it is not
+ a driver, or ::invoke_driver() if it is. */
+ void (*invoke_driver) (ArtMaskSource *self, ArtRender *render);
+ void (*prepare) (ArtMaskSource *self, ArtRender *render, art_boolean first);
+};
+
+struct _ArtRender {
+ /* parameters of destination image */
+ int x0, y0;
+ int x1, y1;
+ art_u8 *pixels;
+ int rowstride;
+ int n_chan;
+ int depth;
+ ArtAlphaType alpha_type;
+
+ art_boolean clear;
+ ArtPixMaxDepth clear_color[ART_MAX_CHAN + 1];
+ art_u32 opacity; /* [0..0x10000] */
+
+ ArtCompositingMode compositing_mode;
+
+ ArtAlphaGamma *alphagamma;
+
+ art_u8 *alpha_buf;
+
+ /* parameters of intermediate buffer */
+ int buf_depth;
+ ArtAlphaType buf_alpha;
+ art_u8 *image_buf;
+
+ /* driving alpha scanline data */
+ /* A "run" is a contiguous sequence of x values with the same alpha value. */
+ int n_run;
+ ArtRenderMaskRun *run;
+
+ /* A "span" is a contiguous sequence of x values with non-zero alpha. */
+ int n_span;
+ int *span_x;
+
+ art_boolean need_span;
+};
+
+ArtRender *
+art_render_new (int x0, int y0, int x1, int y1,
+ art_u8 *pixels, int rowstride,
+ int n_chan, int depth, ArtAlphaType alpha_type,
+ ArtAlphaGamma *alphagamma);
+
+void
+art_render_invoke (ArtRender *render);
+
+void
+art_render_clear (ArtRender *render, const ArtPixMaxDepth *clear_color);
+
+void
+art_render_clear_rgb (ArtRender *render, art_u32 clear_rgb);
+
+void
+art_render_mask_solid (ArtRender *render, int opacity);
+
+void
+art_render_image_solid (ArtRender *render, ArtPixMaxDepth *color);
+
+/* The next two functions are for custom mask sources only. */
+void
+art_render_add_mask_source (ArtRender *render, ArtMaskSource *mask_source);
+
+void
+art_render_invoke_callbacks (ArtRender *render, art_u8 *dest, int y);
+
+/* The following function is for custom image sources only. */
+void
+art_render_add_image_source (ArtRender *render, ArtImageSource *image_source);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_RENDER_H__ */
+
--- /dev/null
+/*
+ * art_render_gradient.c: Gradient image source for modular rendering.
+ *
+ * Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Raph Levien <raph@acm.org>
+ * Alexander Larsson <alla@lysator.liu.se>
+ */
+
+#include <math.h>
+
+#include "art_misc.h"
+#include "art_alphagamma.h"
+#include "art_filterlevel.h"
+
+#include "art_render.h"
+#include "art_render_gradient.h"
+
+typedef struct _ArtImageSourceGradLin ArtImageSourceGradLin;
+typedef struct _ArtImageSourceGradRad ArtImageSourceGradRad;
+
+struct _ArtImageSourceGradLin {
+ ArtImageSource super;
+ const ArtGradientLinear *gradient;
+};
+
+struct _ArtImageSourceGradRad {
+ ArtImageSource super;
+ const ArtGradientRadial *gradient;
+ double a;
+};
+
+#define EPSILON 1e-6
+
+/**
+ * art_render_gradient_setpix: Set a gradient pixel.
+ * @render: The render object.
+ * @dst: Pointer to destination (where to store pixel).
+ * @n_stops: Number of stops in @stops.
+ * @stops: The stops for the gradient.
+ * @offset: The offset.
+ *
+ * @n_stops must be > 0.
+ *
+ * Sets a gradient pixel, storing it at @dst.
+ **/
+static void
+art_render_gradient_setpix (ArtRender *render,
+ art_u8 *dst,
+ int n_stops, ArtGradientStop *stops,
+ double offset)
+{
+ int ix;
+ int j;
+ double off0, off1;
+ int n_ch = render->n_chan + 1;
+
+ for (ix = 0; ix < n_stops; ix++)
+ if (stops[ix].offset > offset)
+ break;
+ /* stops[ix - 1].offset < offset < stops[ix].offset */
+ if (ix > 0 && ix < n_stops)
+ {
+ off0 = stops[ix - 1].offset;
+ off1 = stops[ix].offset;
+ if (fabs (off1 - off0) > EPSILON)
+ {
+ double interp;
+
+ interp = (offset - off0) / (off1 - off0);
+ for (j = 0; j < n_ch; j++)
+ {
+ int z0, z1;
+ int z;
+ z0 = stops[ix - 1].color[j];
+ z1 = stops[ix].color[j];
+ z = floor (z0 + (z1 - z0) * interp + 0.5);
+ if (render->buf_depth == 8)
+ dst[j] = ART_PIX_8_FROM_MAX (z);
+ else /* (render->buf_depth == 16) */
+ ((art_u16 *)dst)[j] = z;
+ }
+ return;
+ }
+ }
+ else if (ix == n_stops)
+ ix--;
+
+ for (j = 0; j < n_ch; j++)
+ {
+ int z;
+ z = stops[ix].color[j];
+ if (render->buf_depth == 8)
+ dst[j] = ART_PIX_8_FROM_MAX (z);
+ else /* (render->buf_depth == 16) */
+ ((art_u16 *)dst)[j] = z;
+ }
+}
+
+static void
+art_render_gradient_linear_done (ArtRenderCallback *self, ArtRender *render)
+{
+ art_free (self);
+}
+
+static void
+art_render_gradient_linear_render (ArtRenderCallback *self, ArtRender *render,
+ art_u8 *dest, int y)
+{
+ ArtImageSourceGradLin *z = (ArtImageSourceGradLin *)self;
+ const ArtGradientLinear *gradient = z->gradient;
+ int pixstride = (render->n_chan + 1) * (render->depth >> 3);
+ int x;
+ int width = render->x1 - render->x0;
+ double offset, d_offset;
+ double actual_offset;
+ int n_stops = gradient->n_stops;
+ ArtGradientStop *stops = gradient->stops;
+ art_u8 *bufp = render->image_buf;
+ ArtGradientSpread spread = gradient->spread;
+
+ offset = render->x0 * gradient->a + y * gradient->b + gradient->c;
+ d_offset = gradient->a;
+
+ for (x = 0; x < width; x++)
+ {
+ if (spread == ART_GRADIENT_PAD)
+ actual_offset = offset;
+ else if (spread == ART_GRADIENT_REPEAT)
+ actual_offset = offset - floor (offset);
+ else /* (spread == ART_GRADIENT_REFLECT) */
+ {
+ double tmp;
+
+ tmp = offset - 2 * floor (0.5 * offset);
+ actual_offset = tmp > 1 ? 2 - tmp : tmp;
+ }
+ art_render_gradient_setpix (render, bufp, n_stops, stops, actual_offset);
+ offset += d_offset;
+ bufp += pixstride;
+ }
+}
+
+static void
+art_render_gradient_linear_negotiate (ArtImageSource *self, ArtRender *render,
+ ArtImageSourceFlags *p_flags,
+ int *p_buf_depth, ArtAlphaType *p_alpha)
+{
+ self->super.render = art_render_gradient_linear_render;
+ *p_flags = 0;
+ *p_buf_depth = render->depth;
+ *p_alpha = ART_ALPHA_PREMUL;
+}
+
+/**
+ * art_render_gradient_linear: Add a linear gradient image source.
+ * @render: The render object.
+ * @gradient: The linear gradient.
+ *
+ * Adds the linear gradient @gradient as the image source for rendering
+ * in the render object @render.
+ **/
+void
+art_render_gradient_linear (ArtRender *render,
+ const ArtGradientLinear *gradient,
+ ArtFilterLevel level)
+{
+ ArtImageSourceGradLin *image_source = art_new (ArtImageSourceGradLin, 1);
+
+ image_source->super.super.render = NULL;
+ image_source->super.super.done = art_render_gradient_linear_done;
+ image_source->super.negotiate = art_render_gradient_linear_negotiate;
+
+ image_source->gradient = gradient;
+
+ art_render_add_image_source (render, &image_source->super);
+}
+
+static void
+art_render_gradient_radial_done (ArtRenderCallback *self, ArtRender *render)
+{
+ art_free (self);
+}
+
+static void
+art_render_gradient_radial_render (ArtRenderCallback *self, ArtRender *render,
+ art_u8 *dest, int y)
+{
+ ArtImageSourceGradRad *z = (ArtImageSourceGradRad *)self;
+ const ArtGradientRadial *gradient = z->gradient;
+ int pixstride = (render->n_chan + 1) * (render->depth >> 3);
+ int x;
+ int x0 = render->x0;
+ int width = render->x1 - x0;
+ int n_stops = gradient->n_stops;
+ ArtGradientStop *stops = gradient->stops;
+ art_u8 *bufp = render->image_buf;
+ double fx = gradient->fx;
+ double fy = gradient->fy;
+ double dx, dy;
+ double *affine = gradient->affine;
+ double aff0 = affine[0];
+ double aff1 = affine[1];
+ const double a = z->a;
+ const double arecip = 1.0 / a;
+ double b, db;
+ double c, dc, ddc;
+ double b_a, db_a;
+ double rad, drad, ddrad;
+
+ dx = x0 * aff0 + y * affine[2] + affine[4] - fx;
+ dy = x0 * aff1 + y * affine[3] + affine[5] - fy;
+ b = dx * fx + dy * fy;
+ db = aff0 * fx + aff1 * fy;
+ c = dx * dx + dy * dy;
+ dc = 2 * aff0 * dx + aff0 * aff0 + 2 * aff1 * dy + aff1 * aff1;
+ ddc = 2 * aff0 * aff0 + 2 * aff1 * aff1;
+
+ b_a = b * arecip;
+ db_a = db * arecip;
+
+ rad = b_a * b_a + c * arecip;
+ drad = 2 * b_a * db_a + db_a * db_a + dc * arecip;
+ ddrad = 2 * db_a * db_a + ddc * arecip;
+
+ for (x = 0; x < width; x++)
+ {
+ double z;
+
+ if (rad > 0)
+ z = b_a + sqrt (rad);
+ else
+ z = b_a;
+ art_render_gradient_setpix (render, bufp, n_stops, stops, z);
+ bufp += pixstride;
+ b_a += db_a;
+ rad += drad;
+ drad += ddrad;
+ }
+}
+
+static void
+art_render_gradient_radial_negotiate (ArtImageSource *self, ArtRender *render,
+ ArtImageSourceFlags *p_flags,
+ int *p_buf_depth, ArtAlphaType *p_alpha)
+{
+ self->super.render = art_render_gradient_radial_render;
+ *p_flags = 0;
+ *p_buf_depth = render->depth;
+ *p_alpha = ART_ALPHA_PREMUL;
+}
+
+/**
+ * art_render_gradient_radial: Add a radial gradient image source.
+ * @render: The render object.
+ * @gradient: The radial gradient.
+ *
+ * Adds the radial gradient @gradient as the image source for rendering
+ * in the render object @render.
+ **/
+void
+art_render_gradient_radial (ArtRender *render,
+ const ArtGradientRadial *gradient,
+ ArtFilterLevel level)
+{
+ ArtImageSourceGradRad *image_source = art_new (ArtImageSourceGradRad, 1);
+ double fx = gradient->fx;
+ double fy = gradient->fy;
+
+ image_source->super.super.render = NULL;
+ image_source->super.super.done = art_render_gradient_radial_done;
+ image_source->super.negotiate = art_render_gradient_radial_negotiate;
+
+ image_source->gradient = gradient;
+ /* todo: sanitycheck fx, fy? */
+ image_source->a = 1 - fx * fx - fy * fy;
+
+ art_render_add_image_source (render, &image_source->super);
+}
--- /dev/null
+/*
+ * art_render_gradient.h: Gradient image source for modular rendering.
+ *
+ * Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Raph Levien <raph@acm.org>
+ * Alexander Larsson <alla@lysator.liu.se>
+ */
+
+#ifndef __ART_RENDER_GRADIENT_H__
+#define __ART_RENDER_GRADIENT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct _ArtGradientLinear ArtGradientLinear;
+typedef struct _ArtGradientRadial ArtGradientRadial;
+typedef struct _ArtGradientStop ArtGradientStop;
+
+typedef enum {
+ ART_GRADIENT_PAD,
+ ART_GRADIENT_REFLECT,
+ ART_GRADIENT_REPEAT
+} ArtGradientSpread;
+
+struct _ArtGradientLinear {
+ double a;
+ double b;
+ double c;
+ ArtGradientSpread spread;
+ int n_stops;
+ ArtGradientStop *stops;
+};
+
+struct _ArtGradientRadial {
+ double affine[6]; /* transforms user coordinates to unit circle */
+ double fx, fy; /* focal point in unit circle coords */
+ int n_stops;
+ ArtGradientStop *stops;
+};
+
+struct _ArtGradientStop {
+ double offset;
+ ArtPixMaxDepth color[ART_MAX_CHAN + 1];
+};
+
+void
+art_render_gradient_linear (ArtRender *render,
+ const ArtGradientLinear *gradient,
+ ArtFilterLevel level);
+
+void
+art_render_gradient_radial (ArtRender *render,
+ const ArtGradientRadial *gradient,
+ ArtFilterLevel level);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_RENDER_GRADIENT_H__ */
--- /dev/null
+/*
+ * art_render_gradient.c: SVP mask source for modular rendering.
+ *
+ * Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Raph Levien <raph@acm.org>
+ */
+
+#include "art_misc.h"
+#include "art_alphagamma.h"
+#include "art_svp.h"
+#include "art_svp_render_aa.h"
+
+#include "art_render.h"
+#include "art_render_svp.h"
+
+typedef struct _ArtMaskSourceSVP ArtMaskSourceSVP;
+
+struct _ArtMaskSourceSVP {
+ ArtMaskSource super;
+ ArtRender *render;
+ const ArtSVP *svp;
+ art_u8 *dest_ptr;
+};
+
+static void
+art_render_svp_done (ArtRenderCallback *self, ArtRender *render)
+{
+ art_free (self);
+}
+
+static int
+art_render_svp_can_drive (ArtMaskSource *self, ArtRender *render)
+{
+ return 10;
+}
+
+/* The basic art_render_svp_callback function is repeated four times,
+ for all combinations of non-unit opacity and generating spans. In
+ general, I'd consider this bad style, but in this case I plead
+ a measurable performance improvement. */
+
+static void
+art_render_svp_callback (void *callback_data, int y,
+ int start, ArtSVPRenderAAStep *steps, int n_steps)
+{
+ ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)callback_data;
+ ArtRender *render = z->render;
+ int n_run = 0;
+ int i;
+ int running_sum = start;
+ int x0 = render->x0;
+ int x1 = render->x1;
+ int run_x0, run_x1;
+ ArtRenderMaskRun *run = render->run;
+
+ if (n_steps > 0)
+ {
+ run_x1 = steps[0].x;
+ if (run_x1 > x0 && running_sum > 0x80ff)
+ {
+ run[0].x = x0;
+ run[0].alpha = running_sum;
+ n_run++;
+ }
+
+ for (i = 0; i < n_steps - 1; i++)
+ {
+ running_sum += steps[i].delta;
+ run_x0 = run_x1;
+ run_x1 = steps[i + 1].x;
+ if (run_x1 > run_x0)
+ {
+ run[n_run].x = run_x0;
+ run[n_run].alpha = running_sum;
+ n_run++;
+ }
+ }
+ if (x1 > run_x1)
+ {
+ running_sum += steps[n_steps - 1].delta;
+ run[n_run].x = run_x1;
+ run[n_run].alpha = running_sum;
+ n_run++;
+ }
+ if (running_sum > 0x80ff)
+ {
+ run[n_run].x = x1;
+ run[n_run].alpha = 0x8000;
+ n_run++;
+ }
+ }
+
+ render->n_run = n_run;
+
+ art_render_invoke_callbacks (render, z->dest_ptr, y);
+
+ z->dest_ptr += render->rowstride;
+}
+
+static void
+art_render_svp_callback_span (void *callback_data, int y,
+ int start, ArtSVPRenderAAStep *steps, int n_steps)
+{
+ ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)callback_data;
+ ArtRender *render = z->render;
+ int n_run = 0;
+ int n_span = 0;
+ int i;
+ int running_sum = start;
+ int x0 = render->x0;
+ int x1 = render->x1;
+ int run_x0, run_x1;
+ ArtRenderMaskRun *run = render->run;
+ int *span_x = render->span_x;
+
+ if (n_steps > 0)
+ {
+ run_x1 = steps[0].x;
+ if (run_x1 > x0 && running_sum > 0x80ff)
+ {
+ run[0].x = x0;
+ run[0].alpha = running_sum;
+ n_run++;
+ span_x[0] = x0;
+ n_span++;
+ }
+
+ for (i = 0; i < n_steps - 1; i++)
+ {
+ running_sum += steps[i].delta;
+ run_x0 = run_x1;
+ run_x1 = steps[i + 1].x;
+ if (run_x1 > run_x0)
+ {
+ run[n_run].x = run_x0;
+ run[n_run].alpha = running_sum;
+ n_run++;
+ if ((n_span & 1) != (running_sum > 0x80ff))
+ span_x[n_span++] = run_x0;
+ }
+ }
+ if (x1 > run_x1)
+ {
+ running_sum += steps[n_steps - 1].delta;
+ run[n_run].x = run_x1;
+ run[n_run].alpha = running_sum;
+ n_run++;
+ if ((n_span & 1) != (running_sum > 0x80ff))
+ span_x[n_span++] = run_x1;
+ }
+ if (running_sum > 0x80ff)
+ {
+ run[n_run].x = x1;
+ run[n_run].alpha = 0x8000;
+ n_run++;
+ span_x[n_span++] = x1;
+ }
+ }
+
+ render->n_run = n_run;
+ render->n_span = n_span;
+
+ art_render_invoke_callbacks (render, z->dest_ptr, y);
+
+ z->dest_ptr += render->rowstride;
+}
+
+static void
+art_render_svp_callback_opacity (void *callback_data, int y,
+ int start, ArtSVPRenderAAStep *steps, int n_steps)
+{
+ ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)callback_data;
+ ArtRender *render = z->render;
+ int n_run = 0;
+ int i;
+ art_u32 running_sum;
+ int x0 = render->x0;
+ int x1 = render->x1;
+ int run_x0, run_x1;
+ ArtRenderMaskRun *run = render->run;
+ art_u32 opacity = render->opacity;
+ art_u32 alpha;
+
+ running_sum = start - 0x7f80;
+
+ if (n_steps > 0)
+ {
+ run_x1 = steps[0].x;
+ alpha = ((running_sum >> 8) * opacity + 0x80080) >> 8;
+ if (run_x1 > x0 && alpha > 0x80ff)
+ {
+ run[0].x = x0;
+ run[0].alpha = alpha;
+ n_run++;
+ }
+
+ for (i = 0; i < n_steps - 1; i++)
+ {
+ running_sum += steps[i].delta;
+ run_x0 = run_x1;
+ run_x1 = steps[i + 1].x;
+ if (run_x1 > run_x0)
+ {
+ run[n_run].x = run_x0;
+ alpha = ((running_sum >> 8) * opacity + 0x80080) >> 8;
+ run[n_run].alpha = alpha;
+ n_run++;
+ }
+ }
+ if (x1 > run_x1)
+ {
+ running_sum += steps[n_steps - 1].delta;
+ run[n_run].x = run_x1;
+ alpha = ((running_sum >> 8) * opacity + 0x80080) >> 8;
+ run[n_run].alpha = alpha;
+ n_run++;
+ }
+ if (alpha > 0x80ff)
+ {
+ run[n_run].x = x1;
+ run[n_run].alpha = 0x8000;
+ n_run++;
+ }
+ }
+
+ render->n_run = n_run;
+
+ art_render_invoke_callbacks (render, z->dest_ptr, y);
+
+ z->dest_ptr += render->rowstride;
+}
+
+static void
+art_render_svp_callback_opacity_span (void *callback_data, int y,
+ int start, ArtSVPRenderAAStep *steps, int n_steps)
+{
+ ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)callback_data;
+ ArtRender *render = z->render;
+ int n_run = 0;
+ int n_span = 0;
+ int i;
+ art_u32 running_sum;
+ int x0 = render->x0;
+ int x1 = render->x1;
+ int run_x0, run_x1;
+ ArtRenderMaskRun *run = render->run;
+ int *span_x = render->span_x;
+ art_u32 opacity = render->opacity;
+ art_u32 alpha;
+
+ running_sum = start - 0x7f80;
+
+ if (n_steps > 0)
+ {
+ run_x1 = steps[0].x;
+ alpha = ((running_sum >> 8) * opacity + 0x800080) >> 8;
+ if (run_x1 > x0 && alpha > 0x80ff)
+ {
+ run[0].x = x0;
+ run[0].alpha = alpha;
+ n_run++;
+ span_x[0] = x0;
+ n_span++;
+ }
+
+ for (i = 0; i < n_steps - 1; i++)
+ {
+ running_sum += steps[i].delta;
+ run_x0 = run_x1;
+ run_x1 = steps[i + 1].x;
+ if (run_x1 > run_x0)
+ {
+ run[n_run].x = run_x0;
+ alpha = ((running_sum >> 8) * opacity + 0x800080) >> 8;
+ run[n_run].alpha = alpha;
+ n_run++;
+ if ((n_span & 1) != (alpha > 0x80ff))
+ span_x[n_span++] = run_x0;
+ }
+ }
+ if (x1 > run_x1)
+ {
+ running_sum += steps[n_steps - 1].delta;
+ run[n_run].x = run_x1;
+ alpha = ((running_sum >> 8) * opacity + 0x800080) >> 8;
+ run[n_run].alpha = alpha;
+ n_run++;
+ if ((n_span & 1) != (alpha > 0x80ff))
+ span_x[n_span++] = run_x1;
+ }
+ if (alpha > 0x80ff)
+ {
+ run[n_run].x = x1;
+ run[n_run].alpha = 0x8000;
+ n_run++;
+ span_x[n_span++] = x1;
+ }
+ }
+
+ render->n_run = n_run;
+ render->n_span = n_span;
+
+ art_render_invoke_callbacks (render, z->dest_ptr, y);
+
+ z->dest_ptr += render->rowstride;
+}
+
+static void
+art_render_svp_invoke_driver (ArtMaskSource *self, ArtRender *render)
+{
+ ArtMaskSourceSVP *z = (ArtMaskSourceSVP *)self;
+ void (*callback) (void *callback_data,
+ int y,
+ int start,
+ ArtSVPRenderAAStep *steps, int n_steps);
+
+ z->dest_ptr = render->pixels;
+ if (render->opacity == 0x10000)
+ {
+ if (render->need_span)
+ callback = art_render_svp_callback_span;
+ else
+ callback = art_render_svp_callback;
+ }
+ else
+ {
+ if (render->need_span)
+ callback = art_render_svp_callback_opacity_span;
+ else
+ callback = art_render_svp_callback_opacity;
+ }
+
+ art_svp_render_aa (z->svp,
+ render->x0, render->y0,
+ render->x1, render->y1, callback,
+ self);
+ art_render_svp_done (&self->super, render);
+}
+
+static void
+art_render_svp_prepare (ArtMaskSource *self, ArtRender *render,
+ art_boolean first)
+{
+ /* todo */
+ art_die ("art_render_svp non-driver mode not yet implemented.\n");
+}
+
+/**
+ * art_render_svp: Use an SVP as a render mask source.
+ * @render: Render object.
+ * @svp: SVP.
+ *
+ * Adds @svp to the render object as a mask. Note: @svp must remain
+ * allocated until art_render_invoke() is called on @render.
+ **/
+void
+art_render_svp (ArtRender *render, const ArtSVP *svp)
+{
+ ArtMaskSourceSVP *mask_source;
+ mask_source = art_new (ArtMaskSourceSVP, 1);
+
+ mask_source->super.super.render = NULL;
+ mask_source->super.super.done = art_render_svp_done;
+ mask_source->super.can_drive = art_render_svp_can_drive;
+ mask_source->super.invoke_driver = art_render_svp_invoke_driver;
+ mask_source->super.prepare = art_render_svp_prepare;
+ mask_source->render = render;
+ mask_source->svp = svp;
+
+ art_render_add_mask_source (render, &mask_source->super);
+}
--- /dev/null
+/*
+ * art_render_gradient.h: SVP mask source for modular rendering.
+ *
+ * Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Raph Levien <raph@acm.org>
+ */
+
+#ifndef __ART_RENDER_SVP_H__
+#define __ART_RENDER_SVP_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+void
+art_render_svp (ArtRender *render, const ArtSVP *svp);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_RENDER_SVP_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h> /* for memset */
+#include "art_misc.h"
+#include "art_rgb.h"
+
+#include "config.h" /* for endianness */
+
+/* Basic operators for manipulating 24-bit packed RGB buffers. */
+
+#define COLOR_RUN_COMPLEX
+
+#ifdef COLOR_RUN_SIMPLE
+/* This is really slow. Is there any way we might speed it up?
+ Two ideas:
+
+ First, maybe we should be working at 32-bit alignment. Then,
+ this can be a simple loop over word stores.
+
+ Second, we can keep working at 24-bit alignment, but have some
+ intelligence about storing. For example, we can iterate over
+ 4-pixel chunks (aligned at 4 pixels), with an inner loop
+ something like:
+
+ *buf++ = v1;
+ *buf++ = v2;
+ *buf++ = v3;
+
+ One source of extra complexity is the need to make sure linebuf is
+ aligned to a 32-bit boundary.
+
+ This second alternative has some complexity to it, but is
+ appealing because it really minimizes the memory bandwidth. */
+void
+art_rgb_fill_run (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, gint n)
+{
+ int i;
+
+ if (r == g && g == b)
+ {
+ memset (buf, g, n + n + n);
+ }
+ else
+ {
+ for (i = 0; i < n; i++)
+ {
+ *buf++ = r;
+ *buf++ = g;
+ *buf++ = b;
+ }
+ }
+}
+#endif
+
+#ifdef COLOR_RUN_COMPLEX
+/* This implements the second of the two ideas above. The test results
+ are _very_ encouraging - it seems the speed is within 10% of
+ memset, which is quite good! */
+/**
+ * art_rgb_fill_run: fill a buffer a solid RGB color.
+ * @buf: Buffer to fill.
+ * @r: Red, range 0..255.
+ * @g: Green, range 0..255.
+ * @b: Blue, range 0..255.
+ * @n: Number of RGB triples to fill.
+ *
+ * Fills a buffer with @n copies of the (@r, @g, @b) triple. Thus,
+ * locations @buf (inclusive) through @buf + 3 * @n (exclusive) are
+ * written.
+ *
+ * The implementation of this routine is very highly optimized.
+ **/
+void
+art_rgb_fill_run (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int n)
+{
+ int i;
+ unsigned int v1, v2, v3;
+
+ if (r == g && g == b)
+ {
+ memset (buf, g, n + n + n);
+ }
+ else
+ {
+ if (n < 8)
+ {
+ for (i = 0; i < n; i++)
+ {
+ *buf++ = r;
+ *buf++ = g;
+ *buf++ = b;
+ }
+ } else {
+ /* handle prefix up to byte alignment */
+ /* I'm worried about this cast on sizeof(long) != sizeof(uchar *)
+ architectures, but it _should_ work. */
+ for (i = 0; ((unsigned long)buf) & 3; i++)
+ {
+ *buf++ = r;
+ *buf++ = g;
+ *buf++ = b;
+ }
+#ifndef WORDS_BIGENDIAN
+ v1 = r | (g << 8) | (b << 16) | (r << 24);
+ v3 = (v1 << 8) | b;
+ v2 = (v3 << 8) | g;
+#else
+ v1 = (r << 24) | (g << 16) | (b << 8) | r;
+ v2 = (v1 << 8) | g;
+ v3 = (v2 << 8) | b;
+#endif
+ for (; i < n - 3; i += 4)
+ {
+ ((art_u32 *)buf)[0] = v1;
+ ((art_u32 *)buf)[1] = v2;
+ ((art_u32 *)buf)[2] = v3;
+ buf += 12;
+ }
+ /* handle postfix */
+ for (; i < n; i++)
+ {
+ *buf++ = r;
+ *buf++ = g;
+ *buf++ = b;
+ }
+ }
+ }
+}
+#endif
+
+/**
+ * art_rgb_run_alpha: Render semitransparent color over RGB buffer.
+ * @buf: Buffer for rendering.
+ * @r: Red, range 0..255.
+ * @g: Green, range 0..255.
+ * @b: Blue, range 0..255.
+ * @alpha: Alpha, range 0..256.
+ * @n: Number of RGB triples to render.
+ *
+ * Renders a sequential run of solid (@r, @g, @b) color over @buf with
+ * opacity @alpha.
+ **/
+void
+art_rgb_run_alpha (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int alpha, int n)
+{
+ int i;
+ int v;
+
+ for (i = 0; i < n; i++)
+ {
+ v = *buf;
+ *buf++ = v + (((r - v) * alpha + 0x80) >> 8);
+ v = *buf;
+ *buf++ = v + (((g - v) * alpha + 0x80) >> 8);
+ v = *buf;
+ *buf++ = v + (((b - v) * alpha + 0x80) >> 8);
+ }
+}
+
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_RGB_H__
+#define __ART_RGB_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void
+art_rgb_fill_run (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int n);
+
+void
+art_rgb_run_alpha (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int alpha,
+ int n);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <math.h>
+#include "art_misc.h"
+#include "art_point.h"
+#include "art_affine.h"
+#include "art_rgb_affine_private.h"
+#include "art_rgb_a_affine.h"
+
+/* This module handles compositing of affine-transformed alpha only images
+ over rgb pixel buffers. */
+
+/* Composite the source image over the destination image, applying the
+ affine transform. */
+
+/**
+ * art_rgb_a_affine: Affine transform source Alpha image and composite.
+ * @dst: Destination image RGB buffer.
+ * @x0: Left coordinate of destination rectangle.
+ * @y0: Top coordinate of destination rectangle.
+ * @x1: Right coordinate of destination rectangle.
+ * @y1: Bottom coordinate of destination rectangle.
+ * @dst_rowstride: Rowstride of @dst buffer.
+ * @src: Source image alpha buffer.
+ * @src_width: Width of source image.
+ * @src_height: Height of source image.
+ * @src_rowstride: Rowstride of @src buffer.
+ * @rgb: RGB foreground color, in 0xRRGGBB.
+ * @affine: Affine transform.
+ * @level: Filter level.
+ * @alphagamma: #ArtAlphaGamma for gamma-correcting the compositing.
+ *
+ * Affine transform the solid color rgb with alpha specified by the
+ * source image stored in @src, compositing over the area of destination
+ * image @dst specified by the rectangle (@x0, @y0) - (@x1, @y1).
+ * As usual in libart, the left and top edges of this rectangle are
+ * included, and the right and bottom edges are excluded.
+ *
+ * The @alphagamma parameter specifies that the alpha compositing be
+ * done in a gamma-corrected color space. In the current
+ * implementation, it is ignored.
+ *
+ * The @level parameter specifies the speed/quality tradeoff of the
+ * image interpolation. Currently, only ART_FILTER_NEAREST is
+ * implemented.
+ **/
+void
+art_rgb_a_affine (art_u8 *dst,
+ int x0, int y0, int x1, int y1, int dst_rowstride,
+ const art_u8 *src,
+ int src_width, int src_height, int src_rowstride,
+ art_u32 rgb,
+ const double affine[6],
+ ArtFilterLevel level,
+ ArtAlphaGamma *alphagamma)
+{
+ /* Note: this is a slow implementation, and is missing all filter
+ levels other than NEAREST. It is here for clarity of presentation
+ and to establish the interface. */
+ int x, y;
+ double inv[6];
+ art_u8 *dst_p, *dst_linestart;
+ const art_u8 *src_p;
+ ArtPoint pt, src_pt;
+ int src_x, src_y;
+ int alpha;
+ art_u8 bg_r, bg_g, bg_b;
+ art_u8 fg_r, fg_g, fg_b;
+ int tmp;
+ int run_x0, run_x1;
+ art_u8 r, g, b;
+
+ r = (rgb>>16)&0xff;
+ g = (rgb>>8)&0xff;
+ b = (rgb)&0xff;
+
+ dst_linestart = dst;
+ art_affine_invert (inv, affine);
+ for (y = y0; y < y1; y++)
+ {
+ pt.y = y + 0.5;
+ run_x0 = x0;
+ run_x1 = x1;
+ art_rgb_affine_run (&run_x0, &run_x1, y, src_width, src_height,
+ inv);
+ dst_p = dst_linestart + (run_x0 - x0) * 3;
+ for (x = run_x0; x < run_x1; x++)
+ {
+ pt.x = x + 0.5;
+ art_affine_point (&src_pt, &pt, inv);
+ src_x = floor (src_pt.x);
+ src_y = floor (src_pt.y);
+ src_p = src + (src_y * src_rowstride) + src_x;
+ if (src_x >= 0 && src_x < src_width &&
+ src_y >= 0 && src_y < src_height)
+ {
+
+ alpha = *src_p;
+ if (alpha)
+ {
+ if (alpha == 255)
+ {
+ dst_p[0] = r;
+ dst_p[1] = g;
+ dst_p[2] = b;
+ }
+ else
+ {
+ bg_r = dst_p[0];
+ bg_g = dst_p[1];
+ bg_b = dst_p[2];
+
+ tmp = (r - bg_r) * alpha;
+ fg_r = bg_r + ((tmp + (tmp >> 8) + 0x80) >> 8);
+ tmp = (g - bg_g) * alpha;
+ fg_g = bg_g + ((tmp + (tmp >> 8) + 0x80) >> 8);
+ tmp = (b - bg_b) * alpha;
+ fg_b = bg_b + ((tmp + (tmp >> 8) + 0x80) >> 8);
+
+ dst_p[0] = fg_r;
+ dst_p[1] = fg_g;
+ dst_p[2] = fg_b;
+ }
+ }
+ } else { dst_p[0] = 255; dst_p[1] = 0; dst_p[2] = 0; }
+ dst_p += 3;
+ }
+ dst_linestart += dst_rowstride;
+ }
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_RGB_A_AFFINE_H__
+#define __ART_RGB_A_AFFINE_H__
+
+/* This module handles compositing of affine-transformed alpha only images
+ over rgb pixel buffers. */
+
+#ifdef LIBART_COMPILATION
+#include "art_filterlevel.h"
+#include "art_alphagamma.h"
+#else
+#include <art_filterlevel.h>
+#include <art_alphagamma.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void
+art_rgb_a_affine (art_u8 *dst,
+ int x0, int y0, int x1, int y1, int dst_rowstride,
+ const art_u8 *src,
+ int src_width, int src_height, int src_rowstride,
+ art_u32 rgb,
+ const double affine[6],
+ ArtFilterLevel level,
+ ArtAlphaGamma *alphagamma);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <math.h>
+#include "art_misc.h"
+#include "art_point.h"
+#include "art_affine.h"
+#include "art_rgb_affine.h"
+#include "art_rgb_affine_private.h"
+
+/* This module handles compositing of affine-transformed rgb images
+ over rgb pixel buffers. */
+
+/**
+ * art_rgb_affine: Affine transform source RGB image and composite.
+ * @dst: Destination image RGB buffer.
+ * @x0: Left coordinate of destination rectangle.
+ * @y0: Top coordinate of destination rectangle.
+ * @x1: Right coordinate of destination rectangle.
+ * @y1: Bottom coordinate of destination rectangle.
+ * @dst_rowstride: Rowstride of @dst buffer.
+ * @src: Source image RGB buffer.
+ * @src_width: Width of source image.
+ * @src_height: Height of source image.
+ * @src_rowstride: Rowstride of @src buffer.
+ * @affine: Affine transform.
+ * @level: Filter level.
+ * @alphagamma: #ArtAlphaGamma for gamma-correcting the compositing.
+ *
+ * Affine transform the source image stored in @src, compositing over
+ * the area of destination image @dst specified by the rectangle
+ * (@x0, @y0) - (@x1, @y1). As usual in libart, the left and top edges
+ * of this rectangle are included, and the right and bottom edges are
+ * excluded.
+ *
+ * The @alphagamma parameter specifies that the alpha compositing be done
+ * in a gamma-corrected color space. Since the source image is opaque RGB,
+ * this argument only affects the edges. In the current implementation,
+ * it is ignored.
+ *
+ * The @level parameter specifies the speed/quality tradeoff of the
+ * image interpolation. Currently, only ART_FILTER_NEAREST is
+ * implemented.
+ **/
+void
+art_rgb_affine (art_u8 *dst, int x0, int y0, int x1, int y1, int dst_rowstride,
+ const art_u8 *src,
+ int src_width, int src_height, int src_rowstride,
+ const double affine[6],
+ ArtFilterLevel level,
+ ArtAlphaGamma *alphagamma)
+{
+ /* Note: this is a slow implementation, and is missing all filter
+ levels other than NEAREST. It is here for clarity of presentation
+ and to establish the interface. */
+ int x, y;
+ double inv[6];
+ art_u8 *dst_p, *dst_linestart;
+ const art_u8 *src_p;
+ ArtPoint pt, src_pt;
+ int src_x, src_y;
+ int run_x0, run_x1;
+
+ dst_linestart = dst;
+ art_affine_invert (inv, affine);
+ for (y = y0; y < y1; y++)
+ {
+ pt.y = y + 0.5;
+ run_x0 = x0;
+ run_x1 = x1;
+ art_rgb_affine_run (&run_x0, &run_x1, y, src_width, src_height,
+ inv);
+ dst_p = dst_linestart + (run_x0 - x0) * 3;
+ for (x = run_x0; x < run_x1; x++)
+ {
+ pt.x = x + 0.5;
+ art_affine_point (&src_pt, &pt, inv);
+ src_x = floor (src_pt.x);
+ src_y = floor (src_pt.y);
+ src_p = src + (src_y * src_rowstride) + src_x * 3;
+ dst_p[0] = src_p[0];
+ dst_p[1] = src_p[1];
+ dst_p[2] = src_p[2];
+ dst_p += 3;
+ }
+ dst_linestart += dst_rowstride;
+ }
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_RGB_AFFINE_H__
+#define __ART_RGB_AFFINE_H__
+
+/* This module handles compositing of affine-transformed rgb images
+ over rgb pixel buffers. */
+
+#ifdef LIBART_COMPILATION
+#include "art_filterlevel.h"
+#include "art_alphagamma.h"
+#else
+#include <art_filterlevel.h>
+#include <art_alphagamma.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void
+art_rgb_affine (art_u8 *dst, int x0, int y0, int x1, int y1, int dst_rowstride,
+ const art_u8 *src,
+ int src_width, int src_height, int src_rowstride,
+ const double affine[6],
+ ArtFilterLevel level,
+ ArtAlphaGamma *alphagamma);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <math.h>
+#include "art_misc.h"
+#include "art_point.h"
+#include "art_affine.h"
+#include "art_rgb_affine_private.h"
+
+/* Private functions for the rgb affine image compositors - primarily,
+ the determination of runs, eliminating the need for source image
+ bbox calculation in the inner loop. */
+
+/* Determine a "run", such that the inverse affine of all pixels from
+ (x0, y) inclusive to (x1, y) exclusive fit within the bounds
+ of the source image.
+
+ Initial values of x0, x1, and result values stored in first two
+ pointer arguments.
+*/
+
+#define EPSILON 1e-6
+
+void
+art_rgb_affine_run (int *p_x0, int *p_x1, int y,
+ int src_width, int src_height,
+ const double affine[6])
+{
+ int x0, x1;
+ double z;
+ double x_intercept;
+ int xi;
+
+ x0 = *p_x0;
+ x1 = *p_x1;
+
+ /* do left and right edges */
+ if (affine[0] > EPSILON)
+ {
+ z = affine[2] * (y + 0.5) + affine[4];
+ x_intercept = -z / affine[0];
+ xi = ceil (x_intercept + EPSILON - 0.5);
+ if (xi > x0)
+ x0 = xi;
+ x_intercept = (-z + src_width) / affine[0];
+ xi = ceil (x_intercept - EPSILON - 0.5);
+ if (xi < x1)
+ x1 = xi;
+ }
+ else if (affine[0] < -EPSILON)
+ {
+ z = affine[2] * (y + 0.5) + affine[4];
+ x_intercept = (-z + src_width) / affine[0];
+ xi = ceil (x_intercept + EPSILON - 0.5);
+ if (xi > x0)
+ x0 = xi;
+ x_intercept = -z / affine[0];
+ xi = ceil (x_intercept - EPSILON - 0.5);
+ if (xi < x1)
+ x1 = xi;
+ }
+ else
+ {
+ z = affine[2] * (y + 0.5) + affine[4];
+ if (z < 0 || z >= src_width)
+ {
+ *p_x1 = *p_x0;
+ return;
+ }
+ }
+
+ /* do top and bottom edges */
+ if (affine[1] > EPSILON)
+ {
+ z = affine[3] * (y + 0.5) + affine[5];
+ x_intercept = -z / affine[1];
+ xi = ceil (x_intercept + EPSILON - 0.5);
+ if (xi > x0)
+ x0 = xi;
+ x_intercept = (-z + src_height) / affine[1];
+ xi = ceil (x_intercept - EPSILON - 0.5);
+ if (xi < x1)
+ x1 = xi;
+ }
+ else if (affine[1] < -EPSILON)
+ {
+ z = affine[3] * (y + 0.5) + affine[5];
+ x_intercept = (-z + src_height) / affine[1];
+ xi = ceil (x_intercept + EPSILON - 0.5);
+ if (xi > x0)
+ x0 = xi;
+ x_intercept = -z / affine[1];
+ xi = ceil (x_intercept - EPSILON - 0.5);
+ if (xi < x1)
+ x1 = xi;
+ }
+ else
+ {
+ z = affine[3] * (y + 0.5) + affine[5];
+ if (z < 0 || z >= src_height)
+ {
+ *p_x1 = *p_x0;
+ return;
+ }
+ }
+
+ *p_x0 = x0;
+ *p_x1 = x1;
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_RGB_AFFINE_PRIVATE_H__
+#define __ART_RGB_AFFINE_PRIVATE_H__
+
+/* This module handles compositing of affine-transformed rgb images
+ over rgb pixel buffers. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void
+art_rgb_affine_run (int *p_x0, int *p_x1, int y,
+ int src_width, int src_height,
+ const double affine[6]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <math.h>
+#include "art_misc.h"
+#include "art_point.h"
+#include "art_affine.h"
+#include "art_rgb_affine_private.h"
+#include "art_rgb_bitmap_affine.h"
+
+/* This module handles compositing of affine-transformed bitmap images
+ over rgb pixel buffers. */
+
+/* Composite the source image over the destination image, applying the
+ affine transform. Foreground color is given and assumed to be
+ opaque, background color is assumed to be fully transparent. */
+
+static void
+art_rgb_bitmap_affine_opaque (art_u8 *dst,
+ int x0, int y0, int x1, int y1,
+ int dst_rowstride,
+ const art_u8 *src,
+ int src_width, int src_height, int src_rowstride,
+ art_u32 rgb,
+ const double affine[6],
+ ArtFilterLevel level,
+ ArtAlphaGamma *alphagamma)
+{
+ /* Note: this is a slow implementation, and is missing all filter
+ levels other than NEAREST. It is here for clarity of presentation
+ and to establish the interface. */
+ int x, y;
+ double inv[6];
+ art_u8 *dst_p, *dst_linestart;
+ const art_u8 *src_p;
+ ArtPoint pt, src_pt;
+ int src_x, src_y;
+ art_u8 r, g, b;
+ int run_x0, run_x1;
+
+ r = rgb >> 16;
+ g = (rgb >> 8) & 0xff;
+ b = rgb & 0xff;
+ dst_linestart = dst;
+ art_affine_invert (inv, affine);
+ for (y = y0; y < y1; y++)
+ {
+ pt.y = y + 0.5;
+ run_x0 = x0;
+ run_x1 = x1;
+ art_rgb_affine_run (&run_x0, &run_x1, y, src_width, src_height,
+ inv);
+ dst_p = dst_linestart + (run_x0 - x0) * 3;
+ for (x = run_x0; x < run_x1; x++)
+ {
+ pt.x = x + 0.5;
+ art_affine_point (&src_pt, &pt, inv);
+ src_x = floor (src_pt.x);
+ src_y = floor (src_pt.y);
+ src_p = src + (src_y * src_rowstride) + (src_x >> 3);
+ if (*src_p & (128 >> (src_x & 7)))
+ {
+ dst_p[0] = r;
+ dst_p[1] = g;
+ dst_p[2] = b;
+ }
+ dst_p += 3;
+ }
+ dst_linestart += dst_rowstride;
+ }
+}
+/* Composite the source image over the destination image, applying the
+ affine transform. Foreground color is given, background color is
+ assumed to be fully transparent. */
+
+/**
+ * art_rgb_bitmap_affine: Affine transform source bitmap image and composite.
+ * @dst: Destination image RGB buffer.
+ * @x0: Left coordinate of destination rectangle.
+ * @y0: Top coordinate of destination rectangle.
+ * @x1: Right coordinate of destination rectangle.
+ * @y1: Bottom coordinate of destination rectangle.
+ * @dst_rowstride: Rowstride of @dst buffer.
+ * @src: Source image bitmap buffer.
+ * @src_width: Width of source image.
+ * @src_height: Height of source image.
+ * @src_rowstride: Rowstride of @src buffer.
+ * @rgba: RGBA foreground color, in 0xRRGGBBAA.
+ * @affine: Affine transform.
+ * @level: Filter level.
+ * @alphagamma: #ArtAlphaGamma for gamma-correcting the compositing.
+ *
+ * Affine transform the source image stored in @src, compositing over
+ * the area of destination image @dst specified by the rectangle
+ * (@x0, @y0) - (@x1, @y1).
+ *
+ * The source bitmap stored with MSB as the leftmost pixel. Source 1
+ * bits correspond to the semitransparent color @rgba, while source 0
+ * bits are transparent.
+ *
+ * See art_rgb_affine() for a description of additional parameters.
+ **/
+void
+art_rgb_bitmap_affine (art_u8 *dst,
+ int x0, int y0, int x1, int y1, int dst_rowstride,
+ const art_u8 *src,
+ int src_width, int src_height, int src_rowstride,
+ art_u32 rgba,
+ const double affine[6],
+ ArtFilterLevel level,
+ ArtAlphaGamma *alphagamma)
+{
+ /* Note: this is a slow implementation, and is missing all filter
+ levels other than NEAREST. It is here for clarity of presentation
+ and to establish the interface. */
+ int x, y;
+ double inv[6];
+ art_u8 *dst_p, *dst_linestart;
+ const art_u8 *src_p;
+ ArtPoint pt, src_pt;
+ int src_x, src_y;
+ int alpha;
+ art_u8 bg_r, bg_g, bg_b;
+ art_u8 fg_r, fg_g, fg_b;
+ art_u8 r, g, b;
+ int run_x0, run_x1;
+
+ alpha = rgba & 0xff;
+ if (alpha == 0xff)
+ {
+ art_rgb_bitmap_affine_opaque (dst, x0, y0, x1, y1, dst_rowstride,
+ src,
+ src_width, src_height, src_rowstride,
+ rgba >> 8,
+ affine,
+ level,
+ alphagamma);
+ return;
+ }
+ /* alpha = (65536 * alpha) / 255; */
+ alpha = (alpha << 8) + alpha + (alpha >> 7);
+ r = rgba >> 24;
+ g = (rgba >> 16) & 0xff;
+ b = (rgba >> 8) & 0xff;
+ dst_linestart = dst;
+ art_affine_invert (inv, affine);
+ for (y = y0; y < y1; y++)
+ {
+ pt.y = y + 0.5;
+ run_x0 = x0;
+ run_x1 = x1;
+ art_rgb_affine_run (&run_x0, &run_x1, y, src_width, src_height,
+ inv);
+ dst_p = dst_linestart + (run_x0 - x0) * 3;
+ for (x = run_x0; x < run_x1; x++)
+ {
+ pt.x = x + 0.5;
+ art_affine_point (&src_pt, &pt, inv);
+ src_x = floor (src_pt.x);
+ src_y = floor (src_pt.y);
+ src_p = src + (src_y * src_rowstride) + (src_x >> 3);
+ if (*src_p & (128 >> (src_x & 7)))
+ {
+ bg_r = dst_p[0];
+ bg_g = dst_p[1];
+ bg_b = dst_p[2];
+
+ fg_r = bg_r + (((r - bg_r) * alpha + 0x8000) >> 16);
+ fg_g = bg_g + (((g - bg_g) * alpha + 0x8000) >> 16);
+ fg_b = bg_b + (((b - bg_b) * alpha + 0x8000) >> 16);
+
+ dst_p[0] = fg_r;
+ dst_p[1] = fg_g;
+ dst_p[2] = fg_b;
+ }
+ dst_p += 3;
+ }
+ dst_linestart += dst_rowstride;
+ }
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_RGB_BITMAP_AFFINE_H__
+#define __ART_RGB_BITMAP_AFFINE_H__
+
+/* This module handles compositing of affine-transformed bitmap images
+ over rgb pixel buffers. */
+
+#ifdef LIBART_COMPILATION
+#include "art_filterlevel.h"
+#include "art_alphagamma.h"
+#else
+#include <art_filterlevel.h>
+#include <art_alphagamma.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void
+art_rgb_bitmap_affine (art_u8 *dst,
+ int x0, int y0, int x1, int y1, int dst_rowstride,
+ const art_u8 *src,
+ int src_width, int src_height, int src_rowstride,
+ art_u32 rgba,
+ const double affine[6],
+ ArtFilterLevel level,
+ ArtAlphaGamma *alphagamma);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <math.h>
+#include "art_misc.h"
+#include "art_point.h"
+#include "art_affine.h"
+#include "art_pixbuf.h"
+#include "art_rgb_affine.h"
+#include "art_rgb_affine.h"
+#include "art_rgb_rgba_affine.h"
+#include "art_rgb_pixbuf_affine.h"
+
+/* This module handles compositing of affine-transformed generic
+ pixbuf images over rgb pixel buffers. */
+
+/* Composite the source image over the destination image, applying the
+ affine transform. */
+/**
+ * art_rgb_pixbuf_affine: Affine transform source RGB pixbuf and composite.
+ * @dst: Destination image RGB buffer.
+ * @x0: Left coordinate of destination rectangle.
+ * @y0: Top coordinate of destination rectangle.
+ * @x1: Right coordinate of destination rectangle.
+ * @y1: Bottom coordinate of destination rectangle.
+ * @dst_rowstride: Rowstride of @dst buffer.
+ * @pixbuf: source image pixbuf.
+ * @affine: Affine transform.
+ * @level: Filter level.
+ * @alphagamma: #ArtAlphaGamma for gamma-correcting the compositing.
+ *
+ * Affine transform the source image stored in @src, compositing over
+ * the area of destination image @dst specified by the rectangle
+ * (@x0, @y0) - (@x1, @y1). As usual in libart, the left and top edges
+ * of this rectangle are included, and the right and bottom edges are
+ * excluded.
+ *
+ * The @alphagamma parameter specifies that the alpha compositing be
+ * done in a gamma-corrected color space. In the current
+ * implementation, it is ignored.
+ *
+ * The @level parameter specifies the speed/quality tradeoff of the
+ * image interpolation. Currently, only ART_FILTER_NEAREST is
+ * implemented.
+ **/
+void
+art_rgb_pixbuf_affine (art_u8 *dst,
+ int x0, int y0, int x1, int y1, int dst_rowstride,
+ const ArtPixBuf *pixbuf,
+ const double affine[6],
+ ArtFilterLevel level,
+ ArtAlphaGamma *alphagamma)
+{
+ if (pixbuf->format != ART_PIX_RGB)
+ {
+ art_warn ("art_rgb_pixbuf_affine: need RGB format image\n");
+ return;
+ }
+
+ if (pixbuf->bits_per_sample != 8)
+ {
+ art_warn ("art_rgb_pixbuf_affine: need 8-bit sample data\n");
+ return;
+ }
+
+ if (pixbuf->n_channels != 3 + (pixbuf->has_alpha != 0))
+ {
+ art_warn ("art_rgb_pixbuf_affine: need 8-bit sample data\n");
+ return;
+ }
+
+ if (pixbuf->has_alpha)
+ art_rgb_rgba_affine (dst, x0, y0, x1, y1, dst_rowstride,
+ pixbuf->pixels,
+ pixbuf->width, pixbuf->height, pixbuf->rowstride,
+ affine,
+ level,
+ alphagamma);
+ else
+ art_rgb_affine (dst, x0, y0, x1, y1, dst_rowstride,
+ pixbuf->pixels,
+ pixbuf->width, pixbuf->height, pixbuf->rowstride,
+ affine,
+ level,
+ alphagamma);
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_RGB_PIXBUF_AFFINE_H__
+#define __ART_RGB_PIXBUF_AFFINE_H__
+
+/* This module handles compositing of affine-transformed generic
+ pixbuf images over rgb pixel buffers. */
+
+#ifdef LIBART_COMPILATION
+#include "art_filterlevel.h"
+#include "art_alphagamma.h"
+#include "art_pixbuf.h"
+#else
+#include <art_filterlevel.h>
+#include <art_alphagamma.h>
+#include <art_pixbuf.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void
+art_rgb_pixbuf_affine (art_u8 *dst,
+ int x0, int y0, int x1, int y1, int dst_rowstride,
+ const ArtPixBuf *pixbuf,
+ const double affine[6],
+ ArtFilterLevel level,
+ ArtAlphaGamma *alphagamma);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <math.h>
+#include "art_misc.h"
+#include "art_point.h"
+#include "art_affine.h"
+#include "art_rgb_affine_private.h"
+#include "art_rgb_rgba_affine.h"
+
+/* This module handles compositing of affine-transformed rgba images
+ over rgb pixel buffers. */
+
+/* Composite the source image over the destination image, applying the
+ affine transform. */
+
+/**
+ * art_rgb_rgba_affine: Affine transform source RGBA image and composite.
+ * @dst: Destination image RGB buffer.
+ * @x0: Left coordinate of destination rectangle.
+ * @y0: Top coordinate of destination rectangle.
+ * @x1: Right coordinate of destination rectangle.
+ * @y1: Bottom coordinate of destination rectangle.
+ * @dst_rowstride: Rowstride of @dst buffer.
+ * @src: Source image RGBA buffer.
+ * @src_width: Width of source image.
+ * @src_height: Height of source image.
+ * @src_rowstride: Rowstride of @src buffer.
+ * @affine: Affine transform.
+ * @level: Filter level.
+ * @alphagamma: #ArtAlphaGamma for gamma-correcting the compositing.
+ *
+ * Affine transform the source image stored in @src, compositing over
+ * the area of destination image @dst specified by the rectangle
+ * (@x0, @y0) - (@x1, @y1). As usual in libart, the left and top edges
+ * of this rectangle are included, and the right and bottom edges are
+ * excluded.
+ *
+ * The @alphagamma parameter specifies that the alpha compositing be
+ * done in a gamma-corrected color space. In the current
+ * implementation, it is ignored.
+ *
+ * The @level parameter specifies the speed/quality tradeoff of the
+ * image interpolation. Currently, only ART_FILTER_NEAREST is
+ * implemented.
+ **/
+void
+art_rgb_rgba_affine (art_u8 *dst,
+ int x0, int y0, int x1, int y1, int dst_rowstride,
+ const art_u8 *src,
+ int src_width, int src_height, int src_rowstride,
+ const double affine[6],
+ ArtFilterLevel level,
+ ArtAlphaGamma *alphagamma)
+{
+ /* Note: this is a slow implementation, and is missing all filter
+ levels other than NEAREST. It is here for clarity of presentation
+ and to establish the interface. */
+ int x, y;
+ double inv[6];
+ art_u8 *dst_p, *dst_linestart;
+ const art_u8 *src_p;
+ ArtPoint pt, src_pt;
+ int src_x, src_y;
+ int alpha;
+ art_u8 bg_r, bg_g, bg_b;
+ art_u8 fg_r, fg_g, fg_b;
+ int tmp;
+ int run_x0, run_x1;
+
+ dst_linestart = dst;
+ art_affine_invert (inv, affine);
+ for (y = y0; y < y1; y++)
+ {
+ pt.y = y + 0.5;
+ run_x0 = x0;
+ run_x1 = x1;
+ art_rgb_affine_run (&run_x0, &run_x1, y, src_width, src_height,
+ inv);
+ dst_p = dst_linestart + (run_x0 - x0) * 3;
+ for (x = run_x0; x < run_x1; x++)
+ {
+ pt.x = x + 0.5;
+ art_affine_point (&src_pt, &pt, inv);
+ src_x = floor (src_pt.x);
+ src_y = floor (src_pt.y);
+ src_p = src + (src_y * src_rowstride) + src_x * 4;
+ if (src_x >= 0 && src_x < src_width &&
+ src_y >= 0 && src_y < src_height)
+ {
+
+ alpha = src_p[3];
+ if (alpha)
+ {
+ if (alpha == 255)
+ {
+ dst_p[0] = src_p[0];
+ dst_p[1] = src_p[1];
+ dst_p[2] = src_p[2];
+ }
+ else
+ {
+ bg_r = dst_p[0];
+ bg_g = dst_p[1];
+ bg_b = dst_p[2];
+
+ tmp = (src_p[0] - bg_r) * alpha;
+ fg_r = bg_r + ((tmp + (tmp >> 8) + 0x80) >> 8);
+ tmp = (src_p[1] - bg_g) * alpha;
+ fg_g = bg_g + ((tmp + (tmp >> 8) + 0x80) >> 8);
+ tmp = (src_p[2] - bg_b) * alpha;
+ fg_b = bg_b + ((tmp + (tmp >> 8) + 0x80) >> 8);
+
+ dst_p[0] = fg_r;
+ dst_p[1] = fg_g;
+ dst_p[2] = fg_b;
+ }
+ }
+ } else { dst_p[0] = 255; dst_p[1] = 0; dst_p[2] = 0; }
+ dst_p += 3;
+ }
+ dst_linestart += dst_rowstride;
+ }
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_RGB_RGBA_AFFINE_H__
+#define __ART_RGB_RGBA_AFFINE_H__
+
+/* This module handles compositing of affine-transformed rgba images
+ over rgb pixel buffers. */
+
+#ifdef LIBART_COMPILATION
+#include "art_filterlevel.h"
+#include "art_alphagamma.h"
+#else
+#include <art_filterlevel.h>
+#include <art_alphagamma.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void
+art_rgb_rgba_affine (art_u8 *dst,
+ int x0, int y0, int x1, int y1, int dst_rowstride,
+ const art_u8 *src,
+ int src_width, int src_height, int src_rowstride,
+ const double affine[6],
+ ArtFilterLevel level,
+ ArtAlphaGamma *alphagamma);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Render a sorted vector path into an RGB buffer. */
+
+#include "art_misc.h"
+
+#include "art_svp.h"
+#include "art_svp_render_aa.h"
+#include "art_rgb.h"
+#include "art_rgb_svp.h"
+
+typedef struct _ArtRgbSVPData ArtRgbSVPData;
+typedef struct _ArtRgbSVPAlphaData ArtRgbSVPAlphaData;
+
+struct _ArtRgbSVPData {
+ art_u32 rgbtab[256];
+ art_u8 *buf;
+ int rowstride;
+ int x0, x1;
+};
+
+struct _ArtRgbSVPAlphaData {
+ int alphatab[256];
+ art_u8 r, g, b, alpha;
+ art_u8 *buf;
+ int rowstride;
+ int x0, x1;
+};
+
+static void
+art_rgb_svp_callback (void *callback_data, int y,
+ int start, ArtSVPRenderAAStep *steps, int n_steps)
+{
+ ArtRgbSVPData *data = (ArtRgbSVPData *)callback_data;
+ art_u8 *linebuf;
+ int run_x0, run_x1;
+ art_u32 running_sum = start;
+ art_u32 rgb;
+ int x0, x1;
+ int k;
+
+ linebuf = data->buf;
+ x0 = data->x0;
+ x1 = data->x1;
+
+ if (n_steps > 0)
+ {
+ run_x1 = steps[0].x;
+ if (run_x1 > x0)
+ {
+ rgb = data->rgbtab[(running_sum >> 16) & 0xff];
+ art_rgb_fill_run (linebuf,
+ rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
+ run_x1 - x0);
+ }
+
+ for (k = 0; k < n_steps - 1; k++)
+ {
+ running_sum += steps[k].delta;
+ run_x0 = run_x1;
+ run_x1 = steps[k + 1].x;
+ if (run_x1 > run_x0)
+ {
+ rgb = data->rgbtab[(running_sum >> 16) & 0xff];
+ art_rgb_fill_run (linebuf + (run_x0 - x0) * 3,
+ rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
+ run_x1 - run_x0);
+ }
+ }
+ running_sum += steps[k].delta;
+ if (x1 > run_x1)
+ {
+ rgb = data->rgbtab[(running_sum >> 16) & 0xff];
+ art_rgb_fill_run (linebuf + (run_x1 - x0) * 3,
+ rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
+ x1 - run_x1);
+ }
+ }
+ else
+ {
+ rgb = data->rgbtab[(running_sum >> 16) & 0xff];
+ art_rgb_fill_run (linebuf,
+ rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
+ x1 - x0);
+ }
+
+ data->buf += data->rowstride;
+}
+
+/* Render the vector path into the RGB buffer. */
+
+/**
+ * art_rgb_svp_aa: Render sorted vector path into RGB buffer.
+ * @svp: The source sorted vector path.
+ * @x0: Left coordinate of destination rectangle.
+ * @y0: Top coordinate of destination rectangle.
+ * @x1: Right coordinate of destination rectangle.
+ * @y1: Bottom coordinate of destination rectangle.
+ * @fg_color: Foreground color in 0xRRGGBB format.
+ * @bg_color: Background color in 0xRRGGBB format.
+ * @buf: Destination RGB buffer.
+ * @rowstride: Rowstride of @buf buffer.
+ * @alphagamma: #ArtAlphaGamma for gamma-correcting the rendering.
+ *
+ * Renders the shape specified with @svp into the @buf RGB buffer.
+ * @x1 - @x0 specifies the width, and @y1 - @y0 specifies the height,
+ * of the rectangle rendered. The new pixels are stored starting at
+ * the first byte of @buf. Thus, the @x0 and @y0 parameters specify
+ * an offset within @svp, and may be tweaked as a way of doing
+ * integer-pixel translations without fiddling with @svp itself.
+ *
+ * The @fg_color and @bg_color arguments specify the opaque colors to
+ * be used for rendering. For pixels of entirely 0 winding-number,
+ * @bg_color is used. For pixels of entirely 1 winding number,
+ * @fg_color is used. In between, the color is interpolated based on
+ * the fraction of the pixel with a winding number of 1. If
+ * @alphagamma is NULL, then linear interpolation (in pixel counts) is
+ * the default. Otherwise, the interpolation is as specified by
+ * @alphagamma.
+ **/
+void
+art_rgb_svp_aa (const ArtSVP *svp,
+ int x0, int y0, int x1, int y1,
+ art_u32 fg_color, art_u32 bg_color,
+ art_u8 *buf, int rowstride,
+ ArtAlphaGamma *alphagamma)
+{
+ ArtRgbSVPData data;
+
+ int r_fg, g_fg, b_fg;
+ int r_bg, g_bg, b_bg;
+ int r, g, b;
+ int dr, dg, db;
+ int i;
+
+ if (alphagamma == NULL)
+ {
+ r_fg = fg_color >> 16;
+ g_fg = (fg_color >> 8) & 0xff;
+ b_fg = fg_color & 0xff;
+
+ r_bg = bg_color >> 16;
+ g_bg = (bg_color >> 8) & 0xff;
+ b_bg = bg_color & 0xff;
+
+ r = (r_bg << 16) + 0x8000;
+ g = (g_bg << 16) + 0x8000;
+ b = (b_bg << 16) + 0x8000;
+ dr = ((r_fg - r_bg) << 16) / 255;
+ dg = ((g_fg - g_bg) << 16) / 255;
+ db = ((b_fg - b_bg) << 16) / 255;
+
+ for (i = 0; i < 256; i++)
+ {
+ data.rgbtab[i] = (r & 0xff0000) | ((g & 0xff0000) >> 8) | (b >> 16);
+ r += dr;
+ g += dg;
+ b += db;
+ }
+ }
+ else
+ {
+ int *table;
+ art_u8 *invtab;
+
+ table = alphagamma->table;
+
+ r_fg = table[fg_color >> 16];
+ g_fg = table[(fg_color >> 8) & 0xff];
+ b_fg = table[fg_color & 0xff];
+
+ r_bg = table[bg_color >> 16];
+ g_bg = table[(bg_color >> 8) & 0xff];
+ b_bg = table[bg_color & 0xff];
+
+ r = (r_bg << 16) + 0x8000;
+ g = (g_bg << 16) + 0x8000;
+ b = (b_bg << 16) + 0x8000;
+ dr = ((r_fg - r_bg) << 16) / 255;
+ dg = ((g_fg - g_bg) << 16) / 255;
+ db = ((b_fg - b_bg) << 16) / 255;
+
+ invtab = alphagamma->invtable;
+ for (i = 0; i < 256; i++)
+ {
+ data.rgbtab[i] = (invtab[r >> 16] << 16) |
+ (invtab[g >> 16] << 8) |
+ invtab[b >> 16];
+ r += dr;
+ g += dg;
+ b += db;
+ }
+ }
+ data.buf = buf;
+ data.rowstride = rowstride;
+ data.x0 = x0;
+ data.x1 = x1;
+ art_svp_render_aa (svp, x0, y0, x1, y1, art_rgb_svp_callback, &data);
+}
+
+static void
+art_rgb_svp_alpha_callback (void *callback_data, int y,
+ int start, ArtSVPRenderAAStep *steps, int n_steps)
+{
+ ArtRgbSVPAlphaData *data = (ArtRgbSVPAlphaData *)callback_data;
+ art_u8 *linebuf;
+ int run_x0, run_x1;
+ art_u32 running_sum = start;
+ int x0, x1;
+ int k;
+ art_u8 r, g, b;
+ int *alphatab;
+ int alpha;
+
+ linebuf = data->buf;
+ x0 = data->x0;
+ x1 = data->x1;
+
+ r = data->r;
+ g = data->g;
+ b = data->b;
+ alphatab = data->alphatab;
+
+ if (n_steps > 0)
+ {
+ run_x1 = steps[0].x;
+ if (run_x1 > x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if (alpha)
+ art_rgb_run_alpha (linebuf,
+ r, g, b, alphatab[alpha],
+ run_x1 - x0);
+ }
+
+ for (k = 0; k < n_steps - 1; k++)
+ {
+ running_sum += steps[k].delta;
+ run_x0 = run_x1;
+ run_x1 = steps[k + 1].x;
+ if (run_x1 > run_x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if (alpha)
+ art_rgb_run_alpha (linebuf + (run_x0 - x0) * 3,
+ r, g, b, alphatab[alpha],
+ run_x1 - run_x0);
+ }
+ }
+ running_sum += steps[k].delta;
+ if (x1 > run_x1)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if (alpha)
+ art_rgb_run_alpha (linebuf + (run_x1 - x0) * 3,
+ r, g, b, alphatab[alpha],
+ x1 - run_x1);
+ }
+ }
+ else
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if (alpha)
+ art_rgb_run_alpha (linebuf,
+ r, g, b, alphatab[alpha],
+ x1 - x0);
+ }
+
+ data->buf += data->rowstride;
+}
+
+static void
+art_rgb_svp_alpha_opaque_callback (void *callback_data, int y,
+ int start,
+ ArtSVPRenderAAStep *steps, int n_steps)
+{
+ ArtRgbSVPAlphaData *data = (ArtRgbSVPAlphaData *)callback_data;
+ art_u8 *linebuf;
+ int run_x0, run_x1;
+ art_u32 running_sum = start;
+ int x0, x1;
+ int k;
+ art_u8 r, g, b;
+ int *alphatab;
+ int alpha;
+
+ linebuf = data->buf;
+ x0 = data->x0;
+ x1 = data->x1;
+
+ r = data->r;
+ g = data->g;
+ b = data->b;
+ alphatab = data->alphatab;
+
+ if (n_steps > 0)
+ {
+ run_x1 = steps[0].x;
+ if (run_x1 > x0)
+ {
+ alpha = running_sum >> 16;
+ if (alpha)
+ {
+ if (alpha >= 255)
+ art_rgb_fill_run (linebuf,
+ r, g, b,
+ run_x1 - x0);
+ else
+ art_rgb_run_alpha (linebuf,
+ r, g, b, alphatab[alpha],
+ run_x1 - x0);
+ }
+ }
+
+ for (k = 0; k < n_steps - 1; k++)
+ {
+ running_sum += steps[k].delta;
+ run_x0 = run_x1;
+ run_x1 = steps[k + 1].x;
+ if (run_x1 > run_x0)
+ {
+ alpha = running_sum >> 16;
+ if (alpha)
+ {
+ if (alpha >= 255)
+ art_rgb_fill_run (linebuf + (run_x0 - x0) * 3,
+ r, g, b,
+ run_x1 - run_x0);
+ else
+ art_rgb_run_alpha (linebuf + (run_x0 - x0) * 3,
+ r, g, b, alphatab[alpha],
+ run_x1 - run_x0);
+ }
+ }
+ }
+ running_sum += steps[k].delta;
+ if (x1 > run_x1)
+ {
+ alpha = running_sum >> 16;
+ if (alpha)
+ {
+ if (alpha >= 255)
+ art_rgb_fill_run (linebuf + (run_x1 - x0) * 3,
+ r, g, b,
+ x1 - run_x1);
+ else
+ art_rgb_run_alpha (linebuf + (run_x1 - x0) * 3,
+ r, g, b, alphatab[alpha],
+ x1 - run_x1);
+ }
+ }
+ }
+ else
+ {
+ alpha = running_sum >> 16;
+ if (alpha)
+ {
+ if (alpha >= 255)
+ art_rgb_fill_run (linebuf,
+ r, g, b,
+ x1 - x0);
+ else
+ art_rgb_run_alpha (linebuf,
+ r, g, b, alphatab[alpha],
+ x1 - x0);
+ }
+ }
+
+ data->buf += data->rowstride;
+}
+
+/**
+ * art_rgb_svp_alpha: Alpha-composite sorted vector path over RGB buffer.
+ * @svp: The source sorted vector path.
+ * @x0: Left coordinate of destination rectangle.
+ * @y0: Top coordinate of destination rectangle.
+ * @x1: Right coordinate of destination rectangle.
+ * @y1: Bottom coordinate of destination rectangle.
+ * @rgba: Color in 0xRRGGBBAA format.
+ * @buf: Destination RGB buffer.
+ * @rowstride: Rowstride of @buf buffer.
+ * @alphagamma: #ArtAlphaGamma for gamma-correcting the compositing.
+ *
+ * Renders the shape specified with @svp over the @buf RGB buffer.
+ * @x1 - @x0 specifies the width, and @y1 - @y0 specifies the height,
+ * of the rectangle rendered. The new pixels are stored starting at
+ * the first byte of @buf. Thus, the @x0 and @y0 parameters specify
+ * an offset within @svp, and may be tweaked as a way of doing
+ * integer-pixel translations without fiddling with @svp itself.
+ *
+ * The @rgba argument specifies the color for the rendering. Pixels of
+ * entirely 0 winding number are left untouched. Pixels of entirely
+ * 1 winding number have the color @rgba composited over them (ie,
+ * are replaced by the red, green, blue components of @rgba if the alpha
+ * component is 0xff). Pixels of intermediate coverage are interpolated
+ * according to the rule in @alphagamma, or default to linear if
+ * @alphagamma is NULL.
+ **/
+void
+art_rgb_svp_alpha (const ArtSVP *svp,
+ int x0, int y0, int x1, int y1,
+ art_u32 rgba,
+ art_u8 *buf, int rowstride,
+ ArtAlphaGamma *alphagamma)
+{
+ ArtRgbSVPAlphaData data;
+ int r, g, b, alpha;
+ int i;
+ int a, da;
+
+ r = rgba >> 24;
+ g = (rgba >> 16) & 0xff;
+ b = (rgba >> 8) & 0xff;
+ alpha = rgba & 0xff;
+
+ data.r = r;
+ data.g = g;
+ data.b = b;
+ data.alpha = alpha;
+
+ a = 0x8000;
+ da = (alpha * 66051 + 0x80) >> 8; /* 66051 equals 2 ^ 32 / (255 * 255) */
+
+ for (i = 0; i < 256; i++)
+ {
+ data.alphatab[i] = a >> 16;
+ a += da;
+ }
+
+ data.buf = buf;
+ data.rowstride = rowstride;
+ data.x0 = x0;
+ data.x1 = x1;
+ if (alpha == 255)
+ art_svp_render_aa (svp, x0, y0, x1, y1, art_rgb_svp_alpha_opaque_callback,
+ &data);
+ else
+ art_svp_render_aa (svp, x0, y0, x1, y1, art_rgb_svp_alpha_callback, &data);
+}
+
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_RGB_SVP_H__
+#define __ART_RGB_SVP_H__
+
+/* Render a sorted vector path into an RGB buffer. */
+
+#ifdef LIBART_COMPILATION
+#include "art_alphagamma.h"
+#else
+#include <art_alphagamma.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+void
+art_rgb_svp_aa (const ArtSVP *svp,
+ int x0, int y0, int x1, int y1,
+ art_u32 fg_color, art_u32 bg_color,
+ art_u8 *buf, int rowstride,
+ ArtAlphaGamma *alphagamma);
+
+void
+art_rgb_svp_alpha (const ArtSVP *svp,
+ int x0, int y0, int x1, int y1,
+ art_u32 rgba,
+ art_u8 *buf, int rowstride,
+ ArtAlphaGamma *alphagamma);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_RGB_SVP_H__ */
--- /dev/null
+/*
+ * art_rgba.c: Functions for manipulating RGBA pixel data.
+ *
+ * Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include "art_misc.h"
+#include "art_rgba.h"
+
+#define ART_OPTIMIZE_SPACE
+
+#ifndef ART_OPTIMIZE_SPACE
+#include "art_rgba_table.c"
+#endif
+
+/**
+ * art_rgba_rgba_composite: Composite RGBA image over RGBA buffer.
+ * @dst: Destination RGBA buffer.
+ * @src: Source RGBA buffer.
+ * @n: Number of RGBA pixels to composite.
+ *
+ * Composites the RGBA pixels in @dst over the @src buffer.
+ **/
+void
+art_rgba_rgba_composite (art_u8 *dst, const art_u8 *src, int n)
+{
+ int i;
+#ifdef WORDS_BIGENDIAN
+ art_u32 src_rgba, dst_rgba;
+#else
+ art_u32 src_abgr, dst_abgr;
+#endif
+ art_u8 src_alpha, dst_alpha;
+
+ for (i = 0; i < n; i++)
+ {
+#ifdef WORDS_BIGENDIAN
+ src_rgba = ((art_u32 *)src)[i];
+ src_alpha = src_rgba & 0xff;
+#else
+ src_abgr = ((art_u32 *)src)[i];
+ src_alpha = (src_abgr >> 24) & 0xff;
+#endif
+ if (src_alpha)
+ {
+ if (src_alpha == 0xff ||
+ (
+#ifdef WORDS_BIGENDIAN
+ dst_rgba = ((art_u32 *)dst)[i],
+ dst_alpha = dst_rgba & 0xff,
+#else
+ dst_abgr = ((art_u32 *)dst)[i],
+ dst_alpha = (dst_abgr >> 24),
+#endif
+ dst_alpha == 0))
+#ifdef WORDS_BIGENDIAN
+ ((art_u32 *)dst)[i] = src_rgba;
+#else
+ ((art_u32 *)dst)[i] = src_abgr;
+#endif
+ else
+ {
+ int r, g, b, a;
+ int src_r, src_g, src_b;
+ int dst_r, dst_g, dst_b;
+ int tmp;
+ int c;
+
+#ifdef ART_OPTIMIZE_SPACE
+ tmp = (255 - src_alpha) * (255 - dst_alpha) + 0x80;
+ a = 255 - ((tmp + (tmp >> 8)) >> 8);
+ c = ((src_alpha << 16) + (a >> 1)) / a;
+#else
+ tmp = art_rgba_composite_table[(src_alpha << 8) + dst_alpha];
+ c = tmp & 0x1ffff;
+ a = tmp >> 24;
+#endif
+#ifdef WORDS_BIGENDIAN
+ src_r = (src_rgba >> 24) & 0xff;
+ src_g = (src_rgba >> 16) & 0xff;
+ src_b = (src_rgba >> 8) & 0xff;
+ dst_r = (dst_rgba >> 24) & 0xff;
+ dst_g = (dst_rgba >> 16) & 0xff;
+ dst_b = (dst_rgba >> 8) & 0xff;
+#else
+ src_r = src_abgr & 0xff;
+ src_g = (src_abgr >> 8) & 0xff;
+ src_b = (src_abgr >> 16) & 0xff;
+ dst_r = dst_abgr & 0xff;
+ dst_g = (dst_abgr >> 8) & 0xff;
+ dst_b = (dst_abgr >> 16) & 0xff;
+#endif
+ r = dst_r + (((src_r - dst_r) * c + 0x8000) >> 16);
+ g = dst_g + (((src_g - dst_g) * c + 0x8000) >> 16);
+ b = dst_b + (((src_b - dst_b) * c + 0x8000) >> 16);
+#ifdef WORDS_BIGENDIAN
+ ((art_u32 *)dst)[i] = (r << 24) | (g << 16) | (b << 8) | a;
+#else
+ ((art_u32 *)dst)[i] = (a << 24) | (b << 16) | (g << 8) | r;
+#endif
+ }
+ }
+#if 0
+ /* it's not clear to me this optimization really wins */
+ else
+ {
+ /* skip over run of transparent pixels */
+ for (; i < n - 1; i++)
+ {
+#ifdef WORDS_BIGENDIAN
+ src_rgba = ((art_u32 *)src)[i + 1];
+ if (src_rgba & 0xff)
+ break;
+#else
+ src_abgr = ((art_u32 *)src)[i + 1];
+ if (src_abgr & 0xff000000)
+ break;
+#endif
+ }
+ }
+#endif
+ }
+}
+
+/**
+ * art_rgba_fill_run: fill an RGBA buffer a solid RGB color.
+ * @buf: Buffer to fill.
+ * @r: Red, range 0..255.
+ * @g: Green, range 0..255.
+ * @b: Blue, range 0..255.
+ * @n: Number of RGB triples to fill.
+ *
+ * Fills a buffer with @n copies of the (@r, @g, @b) triple, solid
+ * alpha. Thus, locations @buf (inclusive) through @buf + 4 * @n
+ * (exclusive) are written.
+ **/
+void
+art_rgba_fill_run (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int n)
+{
+ int i;
+#ifdef WORDS_BIGENDIAN
+ art_u32 src_rgba;
+#else
+ art_u32 src_abgr;
+#endif
+
+#ifdef WORDS_BIGENDIAN
+ src_rgba = (r << 24) | (g << 16) | (b << 8) | 255;
+#else
+ src_abgr = (255 << 24) | (b << 16) | (g << 8) | r;
+#endif
+ for (i = 0; i < n; i++)
+ {
+#ifdef WORDS_BIGENDIAN
+ ((art_u32 *)buf)[i] = src_rgba;
+#else
+ ((art_u32 *)buf)[i] = src_abgr;
+#endif
+ }
+}
+
+/**
+ * art_rgba_run_alpha: Render semitransparent color over RGBA buffer.
+ * @buf: Buffer for rendering.
+ * @r: Red, range 0..255.
+ * @g: Green, range 0..255.
+ * @b: Blue, range 0..255.
+ * @alpha: Alpha, range 0..255.
+ * @n: Number of RGB triples to render.
+ *
+ * Renders a sequential run of solid (@r, @g, @b) color over @buf with
+ * opacity @alpha. Note that the range of @alpha is 0..255, in contrast
+ * to art_rgb_run_alpha, which has a range of 0..256.
+ **/
+void
+art_rgba_run_alpha (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int alpha, int n)
+{
+ int i;
+#ifdef WORDS_BIGENDIAN
+ art_u32 src_rgba, dst_rgba;
+#else
+ art_u32 src_abgr, dst_abgr;
+#endif
+ art_u8 dst_alpha;
+ int a;
+ int dst_r, dst_g, dst_b;
+ int tmp;
+ int c;
+
+#ifdef WORDS_BIGENDIAN
+ src_rgba = (r << 24) | (g << 16) | (b << 8) | alpha;
+#else
+ src_abgr = (alpha << 24) | (b << 16) | (g << 8) | r;
+#endif
+ for (i = 0; i < n; i++)
+ {
+#ifdef WORDS_BIGENDIAN
+ dst_rgba = ((art_u32 *)buf)[i];
+ dst_alpha = dst_rgba & 0xff;
+#else
+ dst_abgr = ((art_u32 *)buf)[i];
+ dst_alpha = (dst_abgr >> 24) & 0xff;
+#endif
+ if (dst_alpha)
+ {
+#ifdef ART_OPTIMIZE_SPACE
+ tmp = (255 - alpha) * (255 - dst_alpha) + 0x80;
+ a = 255 - ((tmp + (tmp >> 8)) >> 8);
+ c = ((alpha << 16) + (a >> 1)) / a;
+#else
+ tmp = art_rgba_composite_table[(alpha << 8) + dst_alpha];
+ c = tmp & 0x1ffff;
+ a = tmp >> 24;
+#endif
+#ifdef WORDS_BIGENDIAN
+ dst_r = (dst_rgba >> 24) & 0xff;
+ dst_g = (dst_rgba >> 16) & 0xff;
+ dst_b = (dst_rgba >> 8) & 0xff;
+#else
+ dst_r = dst_abgr & 0xff;
+ dst_g = (dst_abgr >> 8) & 0xff;
+ dst_b = (dst_abgr >> 16) & 0xff;
+#endif
+ dst_r += (((r - dst_r) * c + 0x8000) >> 16);
+ dst_g += (((g - dst_g) * c + 0x8000) >> 16);
+ dst_b += (((b - dst_b) * c + 0x8000) >> 16);
+#ifdef WORDS_BIGENDIAN
+ ((art_u32 *)buf)[i] = (dst_r << 24) | (dst_g << 16) | (dst_b << 8) | a;
+#else
+ ((art_u32 *)buf)[i] = (a << 24) | (dst_b << 16) | (dst_g << 8) | dst_r;
+#endif
+ }
+ else
+ {
+#ifdef WORDS_BIGENDIAN
+ ((art_u32 *)buf)[i] = src_rgba;
+#else
+ ((art_u32 *)buf)[i] = src_abgr;
+#endif
+ }
+ }
+}
--- /dev/null
+/*
+ * art_rgba.h: Functions for manipulating RGBA pixel data.
+ *
+ * Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_RGBA_H__
+#define __ART_RGBA_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+void
+art_rgba_rgba_composite (art_u8 *dst, const art_u8 *src, int n);
+
+void
+art_rgba_fill_run (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int n);
+
+void
+art_rgba_run_alpha (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int alpha, int n);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Basic constructors and operations for sorted vector paths */
+
+#include "art_misc.h"
+
+#include "art_rect.h"
+#include "art_svp.h"
+
+/* Add a new segment. The arguments can be zero and NULL if the caller
+ would rather fill them in later.
+
+ We also realloc one auxiliary array of ints of size n_segs if
+ desired.
+*/
+/**
+ * art_svp_add_segment: Add a segment to an #ArtSVP structure.
+ * @p_vp: Pointer to where the #ArtSVP structure is stored.
+ * @pn_segs_max: Pointer to the allocated size of *@p_vp.
+ * @pn_points_max: Pointer to where auxiliary array is stored.
+ * @n_points: Number of points for new segment.
+ * @dir: Direction for new segment; 0 is up, 1 is down.
+ * @points: Points for new segment.
+ * @bbox: Bounding box for new segment.
+ *
+ * Adds a new segment to an ArtSVP structure. This routine reallocates
+ * the structure if necessary, updating *@p_vp and *@pn_segs_max as
+ * necessary.
+ *
+ * The new segment is simply added after all other segments. Thus,
+ * this routine should be called in order consistent with the #ArtSVP
+ * sorting rules.
+ *
+ * If the @bbox argument is given, it is simply stored in the new
+ * segment. Otherwise (if it is NULL), the bounding box is computed
+ * from the @points given.
+ **/
+int
+art_svp_add_segment (ArtSVP **p_vp, int *pn_segs_max,
+ int **pn_points_max,
+ int n_points, int dir, ArtPoint *points,
+ ArtDRect *bbox)
+{
+ int seg_num;
+ ArtSVP *svp;
+ ArtSVPSeg *seg;
+
+ svp = *p_vp;
+ seg_num = svp->n_segs++;
+ if (*pn_segs_max == seg_num)
+ {
+ *pn_segs_max <<= 1;
+ svp = (ArtSVP *)art_realloc (svp, sizeof(ArtSVP) +
+ (*pn_segs_max - 1) * sizeof(ArtSVPSeg));
+ *p_vp = svp;
+ if (pn_points_max != NULL)
+ *pn_points_max = art_renew (*pn_points_max, int, *pn_segs_max);
+ }
+ seg = &svp->segs[seg_num];
+ seg->n_points = n_points;
+ seg->dir = dir;
+ seg->points = points;
+ if (bbox)
+ seg->bbox = *bbox;
+ else if (points)
+ {
+ double x_min, x_max;
+ int i;
+
+ x_min = x_max = points[0].x;
+ for (i = 1; i < n_points; i++)
+ {
+ if (x_min > points[i].x)
+ x_min = points[i].x;
+ if (x_max < points[i].x)
+ x_max = points[i].x;
+ }
+ seg->bbox.x0 = x_min;
+ seg->bbox.y0 = points[0].y;
+
+ seg->bbox.x1 = x_max;
+ seg->bbox.y1 = points[n_points - 1].y;
+ }
+ return seg_num;
+}
+
+
+/**
+ * art_svp_free: Free an #ArtSVP structure.
+ * @svp: #ArtSVP to free.
+ *
+ * Frees an #ArtSVP structure and all the segments in it.
+ **/
+void
+art_svp_free (ArtSVP *svp)
+{
+ int n_segs = svp->n_segs;
+ int i;
+
+ for (i = 0; i < n_segs; i++)
+ art_free (svp->segs[i].points);
+ art_free (svp);
+}
+
+#ifdef ART_USE_NEW_INTERSECTOR
+#define EPSILON 0
+#else
+#define EPSILON 1e-6
+#endif
+
+/**
+ * art_svp_seg_compare: Compare two segments of an svp.
+ * @seg1: First segment to compare.
+ * @seg2: Second segment to compare.
+ *
+ * Compares two segments of an svp. Return 1 if @seg2 is below or to the
+ * right of @seg1, -1 otherwise.
+ **/
+int
+art_svp_seg_compare (const void *s1, const void *s2)
+{
+ const ArtSVPSeg *seg1 = s1;
+ const ArtSVPSeg *seg2 = s2;
+
+ if (seg1->points[0].y - EPSILON > seg2->points[0].y) return 1;
+ else if (seg1->points[0].y + EPSILON < seg2->points[0].y) return -1;
+ else if (seg1->points[0].x - EPSILON > seg2->points[0].x) return 1;
+ else if (seg1->points[0].x + EPSILON < seg2->points[0].x) return -1;
+ else if ((seg1->points[1].x - seg1->points[0].x) *
+ (seg2->points[1].y - seg2->points[0].y) -
+ (seg1->points[1].y - seg1->points[0].y) *
+ (seg2->points[1].x - seg2->points[0].x) > 0) return 1;
+ else return -1;
+}
+
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_SVP_H__
+#define __ART_SVP_H__
+
+/* Basic data structures and constructors for sorted vector paths */
+
+#ifdef LIBART_COMPILATION
+#include "art_rect.h"
+#include "art_point.h"
+#else
+#include <art_rect.h>
+#include <art_point.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct _ArtSVP ArtSVP;
+typedef struct _ArtSVPSeg ArtSVPSeg;
+
+struct _ArtSVPSeg {
+ int n_points;
+ int dir; /* == 0 for "up", 1 for "down" */
+ ArtDRect bbox;
+ ArtPoint *points;
+};
+
+struct _ArtSVP {
+ int n_segs;
+ ArtSVPSeg segs[1];
+};
+
+int
+art_svp_add_segment (ArtSVP **p_vp, int *pn_segs_max,
+ int **pn_points_max,
+ int n_points, int dir, ArtPoint *points,
+ ArtDRect *bbox);
+
+void
+art_svp_free (ArtSVP *svp);
+
+int
+art_svp_seg_compare (const void *s1, const void *s2);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_SVP_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 2001 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* This file contains a testbed implementation of the new intersection
+ code.
+*/
+
+#include <math.h> /* for sqrt */
+
+/* Sanitychecking verifies the main invariant on every priority queue
+ point. Do not use in production, as it slows things down way too
+ much. */
+#define noSANITYCHECK
+
+/* This can be used in production, to prevent hangs. Eventually, it
+ should not be necessary. */
+#define CHEAP_SANITYCHECK
+
+#define noVERBOSE
+#ifdef VERBOSE
+#include <stdio.h>
+#endif
+
+#include "art_misc.h"
+#include "art_svp.h"
+#include "art_svp_intersect.h"
+
+/* A priority queue - perhaps move to a separate file if it becomes
+ needed somewhere else */
+
+#define ART_PRIQ_USE_HEAP
+
+typedef struct _ArtPriQ ArtPriQ;
+typedef struct _ArtPriPoint ArtPriPoint;
+
+struct _ArtPriQ {
+ int n_items;
+ int n_items_max;
+ ArtPriPoint **items;
+};
+
+struct _ArtPriPoint {
+ double x;
+ double y;
+ void *user_data;
+};
+
+static ArtPriQ *
+art_pri_new (void)
+{
+ ArtPriQ *result = art_new (ArtPriQ, 1);
+
+ result->n_items = 0;
+ result->n_items_max = 16;
+ result->items = art_new (ArtPriPoint *, result->n_items_max);
+ return result;
+}
+
+static void
+art_pri_free (ArtPriQ *pq)
+{
+ art_free (pq->items);
+ art_free (pq);
+}
+
+static art_boolean
+art_pri_empty (ArtPriQ *pq)
+{
+ return pq->n_items == 0;
+}
+
+#ifdef ART_PRIQ_USE_HEAP
+
+/* This heap implementation is based on Vasek Chvatal's course notes:
+ http://www.cs.rutgers.edu/~chvatal/notes/pq.html#heap */
+
+static void
+art_pri_bubble_up (ArtPriQ *pq, int vacant, ArtPriPoint *missing)
+{
+ ArtPriPoint **items = pq->items;
+ int parent;
+
+ parent = (vacant - 1) >> 1;
+ while (vacant > 0 && (missing->y < items[parent]->y ||
+ (missing->y == items[parent]->y &&
+ missing->x < items[parent]->x)))
+ {
+ items[vacant] = items[parent];
+ vacant = parent;
+ parent = (vacant - 1) >> 1;
+ }
+
+ items[vacant] = missing;
+}
+
+static void
+art_pri_insert (ArtPriQ *pq, ArtPriPoint *point)
+{
+ if (pq->n_items == pq->n_items_max)
+ art_expand (pq->items, ArtPriPoint *, pq->n_items_max);
+
+ art_pri_bubble_up (pq, pq->n_items++, point);
+}
+
+static void
+art_pri_sift_down_from_root (ArtPriQ *pq, ArtPriPoint *missing)
+{
+ ArtPriPoint **items = pq->items;
+ int vacant = 0, child = 2;
+ int n = pq->n_items;
+
+ while (child < n)
+ {
+ if (items[child - 1]->y < items[child]->y ||
+ (items[child - 1]->y == items[child]->y &&
+ items[child - 1]->x < items[child]->x))
+ child--;
+ items[vacant] = items[child];
+ vacant = child;
+ child = (vacant + 1) << 1;
+ }
+ if (child == n)
+ {
+ items[vacant] = items[n - 1];
+ vacant = n - 1;
+ }
+
+ art_pri_bubble_up (pq, vacant, missing);
+}
+
+static ArtPriPoint *
+art_pri_choose (ArtPriQ *pq)
+{
+ ArtPriPoint *result = pq->items[0];
+
+ art_pri_sift_down_from_root (pq, pq->items[--pq->n_items]);
+ return result;
+}
+
+#else
+
+/* Choose least point in queue */
+static ArtPriPoint *
+art_pri_choose (ArtPriQ *pq)
+{
+ int i;
+ int best = 0;
+ double best_x, best_y;
+ double y;
+ ArtPriPoint *result;
+
+ if (pq->n_items == 0)
+ return NULL;
+
+ best_x = pq->items[best]->x;
+ best_y = pq->items[best]->y;
+
+ for (i = 1; i < pq->n_items; i++)
+ {
+ y = pq->items[i]->y;
+ if (y < best_y || (y == best_y && pq->items[i]->x < best_x))
+ {
+ best = i;
+ best_x = pq->items[best]->x;
+ best_y = y;
+ }
+ }
+ result = pq->items[best];
+ pq->items[best] = pq->items[--pq->n_items];
+ return result;
+}
+
+static void
+art_pri_insert (ArtPriQ *pq, ArtPriPoint *point)
+{
+ if (pq->n_items == pq->n_items_max)
+ art_expand (pq->items, ArtPriPoint *, pq->n_items_max);
+
+ pq->items[pq->n_items++] = point;
+}
+
+#endif
+
+#ifdef TEST_PRIQ
+
+#include <stdlib.h> /* for rand() */
+#include <stdio.h>
+
+static double
+double_rand (double lo, double hi, int quant)
+{
+ int tmp = rand () / (RAND_MAX * (1.0 / quant)) + 0.5;
+ return lo + tmp * ((hi - lo) / quant);
+}
+
+/*
+ * This custom allocator for priority queue points is here so I can
+ * test speed. It doesn't look like it will be that significant, but
+ * if I want a small improvement later, it's something.
+ */
+
+typedef ArtPriPoint *ArtPriPtPool;
+
+static ArtPriPtPool *
+art_pri_pt_pool_new (void)
+{
+ ArtPriPtPool *result = art_new (ArtPriPtPool, 1);
+ *result = NULL;
+ return result;
+}
+
+static ArtPriPoint *
+art_pri_pt_alloc (ArtPriPtPool *pool)
+{
+ ArtPriPoint *result = *pool;
+ if (result == NULL)
+ return art_new (ArtPriPoint, 1);
+ else
+ {
+ *pool = result->user_data;
+ return result;
+ }
+}
+
+static void
+art_pri_pt_free (ArtPriPtPool *pool, ArtPriPoint *pt)
+{
+ pt->user_data = *pool;
+ *pool = pt;
+}
+
+static void
+art_pri_pt_pool_free (ArtPriPtPool *pool)
+{
+ ArtPriPoint *pt = *pool;
+ while (pt != NULL)
+ {
+ ArtPriPoint *next = pt->user_data;
+ art_free (pt);
+ pt = next;
+ }
+ art_free (pool);
+}
+
+int
+main (int argc, char **argv)
+{
+ ArtPriPtPool *pool = art_pri_pt_pool_new ();
+ ArtPriQ *pq;
+ int i, j;
+ const int n_iter = 1;
+ const int pq_size = 100;
+
+ for (j = 0; j < n_iter; j++)
+ {
+ pq = art_pri_new ();
+
+ for (i = 0; i < pq_size; i++)
+ {
+ ArtPriPoint *pt = art_pri_pt_alloc (pool);
+ pt->x = double_rand (0, 1, 100);
+ pt->y = double_rand (0, 1, 100);
+ pt->user_data = (void *)i;
+ art_pri_insert (pq, pt);
+ }
+
+ while (!art_pri_empty (pq))
+ {
+ ArtPriPoint *pt = art_pri_choose (pq);
+ if (n_iter == 1)
+ printf ("(%g, %g), %d\n", pt->x, pt->y, (int)pt->user_data);
+ art_pri_pt_free (pool, pt);
+ }
+
+ art_pri_free (pq);
+ }
+ art_pri_pt_pool_free (pool);
+ return 0;
+}
+
+#else /* TEST_PRIQ */
+
+/* A virtual class for an "svp writer". A client of this object creates an
+ SVP by repeatedly calling "add segment" and "add point" methods on it.
+*/
+
+typedef struct _ArtSvpWriterRewind ArtSvpWriterRewind;
+
+/* An implementation of the svp writer virtual class that applies the
+ winding rule. */
+
+struct _ArtSvpWriterRewind {
+ ArtSvpWriter super;
+ ArtWindRule rule;
+ ArtSVP *svp;
+ int n_segs_max;
+ int *n_points_max;
+};
+
+static int
+art_svp_writer_rewind_add_segment (ArtSvpWriter *self, int wind_left,
+ int delta_wind, double x, double y)
+{
+ ArtSvpWriterRewind *swr = (ArtSvpWriterRewind *)self;
+ ArtSVP *svp;
+ ArtSVPSeg *seg;
+ art_boolean left_filled, right_filled;
+ int wind_right = wind_left + delta_wind;
+ int seg_num;
+ const int init_n_points_max = 4;
+
+ switch (swr->rule)
+ {
+ case ART_WIND_RULE_NONZERO:
+ left_filled = (wind_left != 0);
+ right_filled = (wind_right != 0);
+ break;
+ case ART_WIND_RULE_INTERSECT:
+ left_filled = (wind_left > 1);
+ right_filled = (wind_right > 1);
+ break;
+ case ART_WIND_RULE_ODDEVEN:
+ left_filled = (wind_left & 1);
+ right_filled = (wind_right & 1);
+ break;
+ case ART_WIND_RULE_POSITIVE:
+ left_filled = (wind_left > 0);
+ right_filled = (wind_right > 0);
+ break;
+ default:
+ art_die ("Unknown wind rule %d\n", swr->rule);
+ }
+ if (left_filled == right_filled)
+ {
+ /* discard segment now */
+#ifdef VERBOSE
+ printf ("swr add_segment: %d += %d (%g, %g) --> -1\n",
+ wind_left, delta_wind, x, y);
+#endif
+ return -1;
+ }
+
+ svp = swr->svp;
+ seg_num = svp->n_segs++;
+ if (swr->n_segs_max == seg_num)
+ {
+ swr->n_segs_max <<= 1;
+ svp = (ArtSVP *)art_realloc (svp, sizeof(ArtSVP) +
+ (swr->n_segs_max - 1) *
+ sizeof(ArtSVPSeg));
+ swr->svp = svp;
+ swr->n_points_max = art_renew (swr->n_points_max, int,
+ swr->n_segs_max);
+ }
+ seg = &svp->segs[seg_num];
+ seg->n_points = 1;
+ seg->dir = right_filled;
+ swr->n_points_max[seg_num] = init_n_points_max;
+ seg->bbox.x0 = x;
+ seg->bbox.y0 = y;
+ seg->bbox.x1 = x;
+ seg->bbox.y1 = y;
+ seg->points = art_new (ArtPoint, init_n_points_max);
+ seg->points[0].x = x;
+ seg->points[0].y = y;
+#ifdef VERBOSE
+ printf ("swr add_segment: %d += %d (%g, %g) --> %d(%s)\n",
+ wind_left, delta_wind, x, y, seg_num,
+ seg->dir ? "v" : "^");
+#endif
+ return seg_num;
+}
+
+static void
+art_svp_writer_rewind_add_point (ArtSvpWriter *self, int seg_id,
+ double x, double y)
+{
+ ArtSvpWriterRewind *swr = (ArtSvpWriterRewind *)self;
+ ArtSVPSeg *seg;
+ int n_points;
+
+#ifdef VERBOSE
+ printf ("swr add_point: %d (%g, %g)\n", seg_id, x, y);
+#endif
+ if (seg_id < 0)
+ /* omitted segment */
+ return;
+
+ seg = &swr->svp->segs[seg_id];
+ n_points = seg->n_points++;
+ if (swr->n_points_max[seg_id] == n_points)
+ art_expand (seg->points, ArtPoint, swr->n_points_max[seg_id]);
+ seg->points[n_points].x = x;
+ seg->points[n_points].y = y;
+ if (x < seg->bbox.x0)
+ seg->bbox.x0 = x;
+ if (x > seg->bbox.x1)
+ seg->bbox.x1 = x;
+ seg->bbox.y1 = y;
+}
+
+static void
+art_svp_writer_rewind_close_segment (ArtSvpWriter *self, int seg_id)
+{
+ /* Not needed for this simple implementation. A potential future
+ optimization is to merge segments that can be merged safely. */
+#ifdef SANITYCHECK
+ ArtSvpWriterRewind *swr = (ArtSvpWriterRewind *)self;
+ ArtSVPSeg *seg;
+
+ if (seg_id >= 0)
+ {
+ seg = &swr->svp->segs[seg_id];
+ if (seg->n_points < 2)
+ art_warn ("*** closing segment %d with only %d point%s\n",
+ seg_id, seg->n_points, seg->n_points == 1 ? "" : "s");
+ }
+#endif
+
+#ifdef VERBOSE
+ printf ("swr close_segment: %d\n", seg_id);
+#endif
+}
+
+ArtSVP *
+art_svp_writer_rewind_reap (ArtSvpWriter *self)
+{
+ ArtSvpWriterRewind *swr = (ArtSvpWriterRewind *)self;
+ ArtSVP *result = swr->svp;
+
+ art_free (swr->n_points_max);
+ art_free (swr);
+ return result;
+}
+
+ArtSvpWriter *
+art_svp_writer_rewind_new (ArtWindRule rule)
+{
+ ArtSvpWriterRewind *result = art_new (ArtSvpWriterRewind, 1);
+
+ result->super.add_segment = art_svp_writer_rewind_add_segment;
+ result->super.add_point = art_svp_writer_rewind_add_point;
+ result->super.close_segment = art_svp_writer_rewind_close_segment;
+
+ result->rule = rule;
+ result->n_segs_max = 16;
+ result->svp = art_alloc (sizeof(ArtSVP) +
+ (result->n_segs_max - 1) * sizeof(ArtSVPSeg));
+ result->svp->n_segs = 0;
+ result->n_points_max = art_new (int, result->n_segs_max);
+
+ return &result->super;
+}
+
+/* Now, data structures for the active list */
+
+typedef struct _ArtActiveSeg ArtActiveSeg;
+
+/* Note: BNEG is 1 for \ lines, and 0 for /. Thus,
+ x[(flags & BNEG) ^ 1] <= x[flags & BNEG] */
+#define ART_ACTIVE_FLAGS_BNEG 1
+
+/* This flag is set if the segment has been inserted into the active
+ list. */
+#define ART_ACTIVE_FLAGS_IN_ACTIVE 2
+
+/* This flag is set when the segment is to be deleted in the
+ horiz commit process. */
+#define ART_ACTIVE_FLAGS_DEL 4
+
+/* This flag is set if the seg_id is a valid output segment. */
+#define ART_ACTIVE_FLAGS_OUT 8
+
+/* This flag is set if the segment is in the horiz list. */
+#define ART_ACTIVE_FLAGS_IN_HORIZ 16
+
+struct _ArtActiveSeg {
+ int flags;
+ int wind_left, delta_wind;
+ ArtActiveSeg *left, *right; /* doubly linked list structure */
+
+ const ArtSVPSeg *in_seg;
+ int in_curs;
+
+ double x[2];
+ double y0, y1;
+ double a, b, c; /* line equation; ax+by+c = 0 for the line, a^2 + b^2 = 1,
+ and a>0 */
+
+ /* bottom point and intersection point stack */
+ int n_stack;
+ int n_stack_max;
+ ArtPoint *stack;
+
+ /* horiz commit list */
+ ArtActiveSeg *horiz_left, *horiz_right;
+ double horiz_x;
+ int horiz_delta_wind;
+ int seg_id;
+};
+
+typedef struct _ArtIntersectCtx ArtIntersectCtx;
+
+struct _ArtIntersectCtx {
+ const ArtSVP *in;
+ ArtSvpWriter *out;
+
+ ArtPriQ *pq;
+
+ ArtActiveSeg *active_head;
+
+ double y;
+ ArtActiveSeg *horiz_first;
+ ArtActiveSeg *horiz_last;
+
+ /* segment index of next input segment to be added to pri q */
+ int in_curs;
+};
+
+#define EPSILON_A 1e-5 /* Threshold for breaking lines at point insertions */
+
+/**
+ * art_svp_intersect_setup_seg: Set up an active segment from input segment.
+ * @seg: Active segment.
+ * @pri_pt: Priority queue point to initialize.
+ *
+ * Sets the x[], a, b, c, flags, and stack fields according to the
+ * line from the current cursor value. Sets the priority queue point
+ * to the bottom point of this line. Also advances the input segment
+ * cursor.
+ **/
+static void
+art_svp_intersect_setup_seg (ArtActiveSeg *seg, ArtPriPoint *pri_pt)
+{
+ const ArtSVPSeg *in_seg = seg->in_seg;
+ int in_curs = seg->in_curs++;
+ double x0, y0, x1, y1;
+ double dx, dy, s;
+ double a, b, r2;
+
+ x0 = in_seg->points[in_curs].x;
+ y0 = in_seg->points[in_curs].y;
+ x1 = in_seg->points[in_curs + 1].x;
+ y1 = in_seg->points[in_curs + 1].y;
+ pri_pt->x = x1;
+ pri_pt->y = y1;
+ dx = x1 - x0;
+ dy = y1 - y0;
+ r2 = dx * dx + dy * dy;
+ s = r2 == 0 ? 1 : 1 / sqrt (r2);
+ seg->a = a = dy * s;
+ seg->b = b = -dx * s;
+ seg->c = -(a * x0 + b * y0);
+ seg->flags = (seg->flags & ~ART_ACTIVE_FLAGS_BNEG) | (dx > 0);
+ seg->x[0] = x0;
+ seg->x[1] = x1;
+ seg->y0 = y0;
+ seg->y1 = y1;
+ seg->n_stack = 1;
+ seg->stack[0].x = x1;
+ seg->stack[0].y = y1;
+}
+
+/**
+ * art_svp_intersect_add_horiz: Add point to horizontal list.
+ * @ctx: Intersector context.
+ * @seg: Segment with point to insert into horizontal list.
+ *
+ * Inserts @seg into horizontal list, keeping it in ascending horiz_x
+ * order.
+ *
+ * Note: the horiz_commit routine processes "clusters" of segs in the
+ * horiz list, all sharing the same horiz_x value. The cluster is
+ * processed in active list order, rather than horiz list order. Thus,
+ * the order of segs in the horiz list sharing the same horiz_x
+ * _should_ be irrelevant. Even so, we use b as a secondary sorting key,
+ * as a "belt and suspenders" defensive coding tactic.
+ **/
+static void
+art_svp_intersect_add_horiz (ArtIntersectCtx *ctx, ArtActiveSeg *seg)
+{
+ ArtActiveSeg **pp = &ctx->horiz_last;
+ ArtActiveSeg *place;
+ ArtActiveSeg *place_right = NULL;
+
+
+#ifdef CHEAP_SANITYCHECK
+ if (seg->flags & ART_ACTIVE_FLAGS_IN_HORIZ)
+ {
+ art_warn ("*** attempt to put segment in horiz list twice\n");
+ return;
+ }
+ seg->flags |= ART_ACTIVE_FLAGS_IN_HORIZ;
+#endif
+
+#ifdef VERBOSE
+ printf ("add_horiz %lx, x = %g\n", (unsigned long) seg, seg->horiz_x);
+#endif
+ for (place = *pp; place != NULL && (place->horiz_x > seg->horiz_x ||
+ (place->horiz_x == seg->horiz_x &&
+ place->b < seg->b));
+ place = *pp)
+ {
+ place_right = place;
+ pp = &place->horiz_left;
+ }
+ *pp = seg;
+ seg->horiz_left = place;
+ seg->horiz_right = place_right;
+ if (place == NULL)
+ ctx->horiz_first = seg;
+ else
+ place->horiz_right = seg;
+}
+
+static void
+art_svp_intersect_push_pt (ArtIntersectCtx *ctx, ArtActiveSeg *seg,
+ double x, double y)
+{
+ ArtPriPoint *pri_pt;
+ int n_stack = seg->n_stack;
+
+ if (n_stack == seg->n_stack_max)
+ art_expand (seg->stack, ArtPoint, seg->n_stack_max);
+ seg->stack[n_stack].x = x;
+ seg->stack[n_stack].y = y;
+ seg->n_stack++;
+
+ seg->x[1] = x;
+ seg->y1 = y;
+
+ pri_pt = art_new (ArtPriPoint, 1);
+ pri_pt->x = x;
+ pri_pt->y = y;
+ pri_pt->user_data = seg;
+ art_pri_insert (ctx->pq, pri_pt);
+}
+
+/**
+ * art_svp_intersect_break: Break an active segment.
+ *
+ * Note: y must be greater than the top point's y, and less than
+ * the bottom's.
+ *
+ * Return value: x coordinate of break point.
+ */
+static double
+art_svp_intersect_break (ArtIntersectCtx *ctx, ArtActiveSeg *seg,
+ double y)
+{
+ double x0, y0, x1, y1;
+ const ArtSVPSeg *in_seg = seg->in_seg;
+ int in_curs = seg->in_curs;
+ double x;
+
+ x0 = in_seg->points[in_curs - 1].x;
+ y0 = in_seg->points[in_curs - 1].y;
+ x1 = in_seg->points[in_curs].x;
+ y1 = in_seg->points[in_curs].y;
+ x = x0 + (x1 - x0) * ((y - y0) / (y1 - y0));
+
+ /* I think we can count on min(x0, x1) <= x <= max(x0, x1) with sane
+ arithmetic, but it might be worthwhile to check just in case. */
+
+ if (y > ctx->y)
+ art_svp_intersect_push_pt (ctx, seg, x, y);
+ else
+ {
+ seg->x[0] = x;
+ seg->y0 = y;
+ seg->horiz_x = x;
+ art_svp_intersect_add_horiz (ctx, seg);
+ }
+
+ return x;
+}
+
+/**
+ * art_svp_intersect_add_point: Add a point, breaking nearby neighbors.
+ * @ctx: Intersector context.
+ * @x: X coordinate of point to add.
+ * @y: Y coordinate of point to add.
+ * @seg: "nearby" segment, or NULL if leftmost.
+ *
+ * Return value: Segment immediately to the left of the new point, or
+ * NULL if the new point is leftmost.
+ **/
+static ArtActiveSeg *
+art_svp_intersect_add_point (ArtIntersectCtx *ctx, double x, double y,
+ ArtActiveSeg *seg)
+{
+ ArtActiveSeg *left, *right;
+ double x_min = x, x_max = x;
+ art_boolean left_live, right_live;
+ double d;
+ double new_x;
+ ArtActiveSeg *test, *result = NULL;
+ double x_test;
+
+ left = seg;
+ if (left == NULL)
+ right = ctx->active_head;
+ else
+ right = left->right;
+ left_live = (left != NULL);
+ right_live = (right != NULL);
+ while (left_live || right_live)
+ {
+ if (left_live)
+ {
+ if (x <= left->x[left->flags & ART_ACTIVE_FLAGS_BNEG] &&
+ /* It may be that one of these conjuncts turns out to be always
+ true. We test both anyway, to be defensive. */
+ y != left->y0 && y < left->y1)
+ {
+ d = x_min * left->a + y * left->b + left->c;
+ if (d < EPSILON_A)
+ {
+ new_x = art_svp_intersect_break (ctx, left, y);
+ if (new_x > x_max)
+ {
+ x_max = new_x;
+ right_live = (right != NULL);
+ }
+ else if (new_x < x_min)
+ x_min = new_x;
+ left = left->left;
+ left_live = (left != NULL);
+ }
+ else
+ left_live = ART_FALSE;
+ }
+ else
+ left_live = ART_FALSE;
+ }
+ else if (right_live)
+ {
+ if (x <= right->x[(right->flags & ART_ACTIVE_FLAGS_BNEG) ^ 1] &&
+ /* It may be that one of these conjuncts turns out to be always
+ true. We test both anyway, to be defensive. */
+ y != right->y0 && y < right->y1)
+ {
+ d = x_max * right->a + y * right->b + right->c;
+ if (d > -EPSILON_A)
+ {
+ new_x = art_svp_intersect_break (ctx, right, y);
+ if (new_x < x_min)
+ {
+ x_min = new_x;
+ left_live = (left != NULL);
+ }
+ else if (new_x >= x_max)
+ x_max = new_x;
+ right = right->right;
+ right_live = (right != NULL);
+ }
+ else
+ right_live = ART_FALSE;
+ }
+ else
+ right_live = ART_FALSE;
+ }
+ }
+
+ /* Now, (left, right) defines an interval of segments broken. Sort
+ into ascending x order. */
+ test = left == NULL ? ctx->active_head : left->right;
+ result = left;
+ if (test != NULL && test != right)
+ {
+ x_test = test->x[1];
+ for (;;)
+ {
+ if (x_test <= x)
+ result = test;
+ test = test->right;
+ if (test == right)
+ break;
+ new_x = test->x[1];
+ if (new_x < x_test)
+ {
+ art_warn ("art_svp_intersect_add_point: non-ascending x\n");
+ }
+ x_test = new_x;
+ }
+ }
+ return result;
+}
+
+static void
+art_svp_intersect_swap_active (ArtIntersectCtx *ctx,
+ ArtActiveSeg *left_seg, ArtActiveSeg *right_seg)
+{
+ right_seg->left = left_seg->left;
+ if (right_seg->left != NULL)
+ right_seg->left->right = right_seg;
+ else
+ ctx->active_head = right_seg;
+ left_seg->right = right_seg->right;
+ if (left_seg->right != NULL)
+ left_seg->right->left = left_seg;
+ left_seg->left = right_seg;
+ right_seg->right = left_seg;
+}
+
+typedef enum {
+ ART_BREAK_LEFT = 1,
+ ART_BREAK_RIGHT = 2
+} ArtBreakFlags;
+
+/**
+ * art_svp_intersect_test_cross: Test crossing of a pair of active segments.
+ * @ctx: Intersector context.
+ * @left_seg: Left segment of the pair.
+ * @right_seg: Right segment of the pair.
+ * @break_flags: Flags indicating whether to break neighbors.
+ *
+ * Tests crossing of @left_seg and @right_seg. If there is a crossing,
+ * inserts the intersection point into both segments.
+ *
+ * Return value: True if the intersection took place at the current
+ * scan line, indicating further iteration is needed.
+ **/
+static art_boolean
+art_svp_intersect_test_cross (ArtIntersectCtx *ctx,
+ ArtActiveSeg *left_seg, ArtActiveSeg *right_seg,
+ ArtBreakFlags break_flags)
+{
+ double left_x0, left_y0, left_x1;
+ double left_y1 = left_seg->y1;
+ double right_y1 = right_seg->y1;
+ double d;
+
+ const ArtSVPSeg *in_seg;
+ int in_curs;
+ double d0, d1, t;
+ double x, y; /* intersection point */
+
+#ifdef VERBOSE
+ static int count = 0;
+
+ printf ("art_svp_intersect_test_cross %lx <-> %lx: count=%d\n",
+ (unsigned long)left_seg, (unsigned long)right_seg, count++);
+#endif
+
+ if (left_seg->y0 == right_seg->y0 && left_seg->x[0] == right_seg->x[0])
+ {
+ if (left_seg->b < right_seg->b)
+ {
+ art_svp_intersect_swap_active (ctx, left_seg, right_seg);
+ return ART_TRUE;
+ }
+ else
+ return ART_FALSE;
+ }
+
+ if (left_y1 < right_y1)
+ {
+ /* Test left (x1, y1) against right segment */
+ double left_x1 = left_seg->x[1];
+
+ if (left_x1 <
+ right_seg->x[(right_seg->flags & ART_ACTIVE_FLAGS_BNEG) ^ 1] ||
+ left_y1 == right_seg->y0)
+ return ART_FALSE;
+ d = left_x1 * right_seg->a + left_y1 * right_seg->b + right_seg->c;
+ if (d < -EPSILON_A)
+ return ART_FALSE;
+ else if (d < EPSILON_A)
+ {
+ double right_x1 = art_svp_intersect_break (ctx, right_seg, left_y1);
+ if (left_x1 <= right_x1)
+ return ART_FALSE;
+ }
+ }
+ else if (left_y1 > right_y1)
+ {
+ /* Test right (x1, y1) against left segment */
+ double right_x1 = right_seg->x[1];
+
+ if (right_x1 > left_seg->x[left_seg->flags & ART_ACTIVE_FLAGS_BNEG] ||
+ right_y1 == left_seg->y0)
+ return ART_FALSE;
+ d = right_x1 * left_seg->a + right_y1 * left_seg->b + left_seg->c;
+ if (d > EPSILON_A)
+ return ART_FALSE;
+ else if (d > -EPSILON_A)
+ {
+ double left_x1 = art_svp_intersect_break (ctx, left_seg, right_y1);
+ if (left_x1 <= right_x1)
+ return ART_FALSE;
+ }
+ }
+ else /* left_y1 == right_y1 */
+ {
+ double left_x1 = left_seg->x[1];
+ double right_x1 = right_seg->x[1];
+
+ if (left_x1 <= right_x1)
+ return ART_FALSE;
+ }
+
+ /* The segments cross. Find the intersection point. */
+
+ in_seg = left_seg->in_seg;
+ in_curs = left_seg->in_curs;
+ left_x0 = in_seg->points[in_curs - 1].x;
+ left_y0 = in_seg->points[in_curs - 1].y;
+ left_x1 = in_seg->points[in_curs].x;
+ left_y1 = in_seg->points[in_curs].y;
+ d0 = left_x0 * right_seg->a + left_y0 * right_seg->b + right_seg->c;
+ d1 = left_x1 * right_seg->a + left_y1 * right_seg->b + right_seg->c;
+ if (d0 == d1)
+ {
+ x = left_x0;
+ y = left_y0;
+ }
+ else
+ {
+ /* Is this division always safe? It could possibly overflow. */
+ t = d0 / (d0 - d1);
+ if (t <= 0)
+ {
+ x = left_x0;
+ y = left_y0;
+ }
+ else if (t >= 1)
+ {
+ x = left_x1;
+ y = left_y1;
+ }
+ else
+ {
+ x = left_x0 + t * (left_x1 - left_x0);
+ y = left_y0 + t * (left_y1 - left_y0);
+ }
+ }
+
+ /* Make sure intersection point is within bounds of right seg. */
+ if (y < right_seg->y0)
+ {
+ x = right_seg->x[0];
+ y = right_seg->y0;
+ }
+ else if (y > right_seg->y1)
+ {
+ x = right_seg->x[1];
+ y = right_seg->y1;
+ }
+ else if (x < right_seg->x[(right_seg->flags & ART_ACTIVE_FLAGS_BNEG) ^ 1])
+ x = right_seg->x[(right_seg->flags & ART_ACTIVE_FLAGS_BNEG) ^ 1];
+ else if (x > right_seg->x[right_seg->flags & ART_ACTIVE_FLAGS_BNEG])
+ x = right_seg->x[right_seg->flags & ART_ACTIVE_FLAGS_BNEG];
+
+ if (y == left_seg->y0)
+ {
+ if (y != right_seg->y0)
+ {
+#ifdef VERBOSE
+ printf ("art_svp_intersect_test_cross: intersection (%g, %g) matches former y0 of %lx, %lx\n",
+ x, y, (unsigned long)left_seg, (unsigned long)right_seg);
+#endif
+ art_svp_intersect_push_pt (ctx, right_seg, x, y);
+ if ((break_flags & ART_BREAK_RIGHT) && right_seg->right != NULL)
+ art_svp_intersect_add_point (ctx, x, y, right_seg->right);
+ }
+ else
+ {
+ /* Intersection takes place at current scan line; process
+ immediately rather than queueing intersection point into
+ priq. */
+
+ /* Choose "most vertical" segement */
+ if (left_seg->a > right_seg->a)
+ x = left_seg->x[0];
+ else
+ x = right_seg->x[0];
+ /* todo: fudge x */
+
+ art_svp_intersect_swap_active (ctx, left_seg, right_seg);
+ return ART_TRUE;
+ }
+ }
+ else if (y == right_seg->y0)
+ {
+#ifdef VERBOSE
+ printf ("*** art_svp_intersect_test_cross: intersection (%g, %g) matches latter y0 of %lx, %lx\n",
+ x, y, (unsigned long)left_seg, (unsigned long)right_seg);
+#endif
+ art_svp_intersect_push_pt (ctx, left_seg, x, y);
+ if ((break_flags & ART_BREAK_LEFT) && left_seg->left != NULL)
+ art_svp_intersect_add_point (ctx, x, y, left_seg->left);
+ }
+ else
+ {
+#ifdef VERBOSE
+ printf ("Inserting (%g, %g) into %lx, %lx\n",
+ x, y, (unsigned long)left_seg, (unsigned long)right_seg);
+#endif
+ /* Insert the intersection point into both segments. */
+ art_svp_intersect_push_pt (ctx, left_seg, x, y);
+ art_svp_intersect_push_pt (ctx, right_seg, x, y);
+ if ((break_flags & ART_BREAK_LEFT) && left_seg->left != NULL)
+ art_svp_intersect_add_point (ctx, x, y, left_seg->left);
+ if ((break_flags & ART_BREAK_RIGHT) && right_seg->right != NULL)
+ art_svp_intersect_add_point (ctx, x, y, right_seg->right);
+ }
+ return ART_FALSE;
+}
+
+/**
+ * art_svp_intersect_active_delete: Delete segment from active list.
+ * @ctx: Intersection context.
+ * @seg: Segment to delete.
+ *
+ * Deletes @seg from the active list.
+ **/
+static /* todo inline */ void
+art_svp_intersect_active_delete (ArtIntersectCtx *ctx, ArtActiveSeg *seg)
+{
+ ArtActiveSeg *left = seg->left, *right = seg->right;
+
+ if (left != NULL)
+ left->right = right;
+ else
+ ctx->active_head = right;
+ if (right != NULL)
+ right->left = left;
+}
+
+/**
+ * art_svp_intersect_active_free: Free an active segment.
+ * @seg: Segment to delete.
+ *
+ * Frees @seg.
+ **/
+static /* todo inline */ void
+art_svp_intersect_active_free (ArtActiveSeg *seg)
+{
+ art_free (seg->stack);
+#ifdef VERBOSE
+ printf ("Freeing %lx\n", (unsigned long) seg);
+#endif
+ art_free (seg);
+}
+
+/**
+ * art_svp_intersect_insert_cross: Test crossings of newly inserted line.
+ *
+ * Tests @seg against its left and right neighbors for intersections.
+ * Precondition: the line in @seg is not purely horizontal.
+ **/
+static void
+art_svp_intersect_insert_cross (ArtIntersectCtx *ctx,
+ ArtActiveSeg *seg)
+{
+ ArtActiveSeg *left = seg, *right = seg;
+
+ for (;;)
+ {
+ if (left != NULL && left->left != NULL)
+ {
+ if (art_svp_intersect_test_cross (ctx, left->left, left,
+ ART_BREAK_LEFT))
+ {
+ if (left == right || right == NULL)
+ right = left->right;
+ }
+ else
+ {
+ left = NULL;
+ }
+ }
+ else if (right != NULL && right->right != NULL)
+ {
+ if (art_svp_intersect_test_cross (ctx, right, right->right,
+ ART_BREAK_RIGHT))
+ {
+ if (left == right || left == NULL)
+ left = right->left;
+ }
+ else
+ {
+ right = NULL;
+ }
+ }
+ else
+ break;
+ }
+}
+
+/**
+ * art_svp_intersect_horiz: Add horizontal line segment.
+ * @ctx: Intersector context.
+ * @seg: Segment on which to add horizontal line.
+ * @x0: Old x position.
+ * @x1: New x position.
+ *
+ * Adds a horizontal line from @x0 to @x1, and updates the current
+ * location of @seg to @x1.
+ **/
+static void
+art_svp_intersect_horiz (ArtIntersectCtx *ctx, ArtActiveSeg *seg,
+ double x0, double x1)
+{
+ ArtActiveSeg *hs;
+
+ if (x0 == x1)
+ return;
+
+ hs = art_new (ArtActiveSeg, 1);
+
+ hs->flags = ART_ACTIVE_FLAGS_DEL | (seg->flags & ART_ACTIVE_FLAGS_OUT);
+ if (seg->flags & ART_ACTIVE_FLAGS_OUT)
+ {
+ ArtSvpWriter *swr = ctx->out;
+
+ swr->add_point (swr, seg->seg_id, x0, ctx->y);
+ }
+ hs->seg_id = seg->seg_id;
+ hs->horiz_x = x0;
+ hs->horiz_delta_wind += seg->delta_wind;
+ hs->stack = NULL;
+ hs->horiz_delta_wind = 0;
+ seg->horiz_delta_wind -= seg->delta_wind;
+
+ art_svp_intersect_add_horiz (ctx, hs);
+
+ if (x0 > x1)
+ {
+ ArtActiveSeg *left;
+
+ for (left = seg->left; left != NULL; left = seg->left)
+ {
+ int left_bneg = left->flags & ART_ACTIVE_FLAGS_BNEG;
+
+ if (left->x[left_bneg] <= x1)
+ break;
+ if (left->x[left_bneg ^ 1] <= x1 &&
+ x1 * left->a + ctx->y * left->b + left->c >= 0)
+ break;
+ if (left->y0 != ctx->y && left->y1 != ctx->y)
+ {
+ art_svp_intersect_break (ctx, left, ctx->y);
+ }
+#ifdef VERBOSE
+ printf ("x0=%g > x1=%g, swapping %lx, %lx\n",
+ x0, x1, (unsigned long)left, (unsigned long)seg);
+#endif
+ art_svp_intersect_swap_active (ctx, left, seg);
+ }
+ }
+ else
+ {
+ ArtActiveSeg *right;
+
+ for (right = seg->right; right != NULL; right = seg->right)
+ {
+ int right_bneg = right->flags & ART_ACTIVE_FLAGS_BNEG;
+
+ if (right->x[right_bneg ^ 1] >= x1)
+ break;
+ if (right->x[right_bneg] >= x1 &&
+ x1 * right->a + ctx->y * right->b + right->c <= 0)
+ break;
+ if (right->y0 != ctx->y && right->y1 != ctx->y)
+ {
+ art_svp_intersect_break (ctx, right, ctx->y);
+ }
+#ifdef VERBOSE
+ printf ("x0=%g < x1=%g, swapping %lx, %lx\n",
+ x0, x1, (unsigned long)seg, (unsigned long)right);
+#endif
+ art_svp_intersect_swap_active (ctx, seg, right);
+ }
+ }
+
+ seg->x[0] = x1;
+ seg->x[1] = x1;
+ seg->horiz_x = x1;
+ seg->flags &= ~ART_ACTIVE_FLAGS_OUT;
+}
+
+/**
+ * art_svp_intersect_insert_line: Insert a line into the active list.
+ * @ctx: Intersector context.
+ * @seg: Segment containing line to insert.
+ *
+ * Inserts the line into the intersector context, taking care of any
+ * intersections, and adding the appropriate horizontal points to the
+ * active list.
+ **/
+static void
+art_svp_intersect_insert_line (ArtIntersectCtx *ctx, ArtActiveSeg *seg)
+{
+ if (seg->y1 == seg->y0)
+ {
+#ifdef VERBOSE
+ printf ("art_svp_intersect_insert_line: %lx is horizontal\n",
+ (unsigned long)seg);
+#endif
+ art_svp_intersect_horiz (ctx, seg, seg->x[0], seg->x[1]);
+ }
+ else
+ {
+ art_svp_intersect_insert_cross (ctx, seg);
+ art_svp_intersect_add_horiz (ctx, seg);
+ }
+}
+
+static void
+art_svp_intersect_process_intersection (ArtIntersectCtx *ctx,
+ ArtActiveSeg *seg)
+{
+ int n_stack = --seg->n_stack;
+ seg->x[1] = seg->stack[n_stack - 1].x;
+ seg->y1 = seg->stack[n_stack - 1].y;
+ seg->x[0] = seg->stack[n_stack].x;
+ seg->y0 = seg->stack[n_stack].y;
+ seg->horiz_x = seg->x[0];
+ art_svp_intersect_insert_line (ctx, seg);
+}
+
+static void
+art_svp_intersect_advance_cursor (ArtIntersectCtx *ctx, ArtActiveSeg *seg,
+ ArtPriPoint *pri_pt)
+{
+ const ArtSVPSeg *in_seg = seg->in_seg;
+ int in_curs = seg->in_curs;
+ ArtSvpWriter *swr = seg->flags & ART_ACTIVE_FLAGS_OUT ? ctx->out : NULL;
+
+ if (swr != NULL)
+ swr->add_point (swr, seg->seg_id, seg->x[1], seg->y1);
+ if (in_curs + 1 == in_seg->n_points)
+ {
+ ArtActiveSeg *left = seg->left, *right = seg->right;
+
+#if 0
+ if (swr != NULL)
+ swr->close_segment (swr, seg->seg_id);
+ seg->flags &= ~ART_ACTIVE_FLAGS_OUT;
+#endif
+ seg->flags |= ART_ACTIVE_FLAGS_DEL;
+ art_svp_intersect_add_horiz (ctx, seg);
+ art_svp_intersect_active_delete (ctx, seg);
+ if (left != NULL && right != NULL)
+ art_svp_intersect_test_cross (ctx, left, right,
+ ART_BREAK_LEFT | ART_BREAK_RIGHT);
+ art_free (pri_pt);
+ }
+ else
+ {
+ seg->horiz_x = seg->x[1];
+
+ art_svp_intersect_setup_seg (seg, pri_pt);
+ art_pri_insert (ctx->pq, pri_pt);
+ art_svp_intersect_insert_line (ctx, seg);
+ }
+}
+
+static void
+art_svp_intersect_add_seg (ArtIntersectCtx *ctx, const ArtSVPSeg *in_seg)
+{
+ ArtActiveSeg *seg = art_new (ArtActiveSeg, 1);
+ ArtActiveSeg *test;
+ double x0, y0;
+ ArtActiveSeg *beg_range;
+ ArtActiveSeg *last = NULL;
+ ArtActiveSeg *left, *right;
+ ArtPriPoint *pri_pt = art_new (ArtPriPoint, 1);
+
+ seg->flags = 0;
+ seg->in_seg = in_seg;
+ seg->in_curs = 0;
+
+ seg->n_stack_max = 4;
+ seg->stack = art_new (ArtPoint, seg->n_stack_max);
+
+ seg->horiz_delta_wind = 0;
+
+ pri_pt->user_data = seg;
+ art_svp_intersect_setup_seg (seg, pri_pt);
+ art_pri_insert (ctx->pq, pri_pt);
+
+ /* Find insertion place for new segment */
+ /* This is currently a left-to-right scan, but should be replaced
+ with a binary search as soon as it's validated. */
+
+ x0 = in_seg->points[0].x;
+ y0 = in_seg->points[0].y;
+ beg_range = NULL;
+ for (test = ctx->active_head; test != NULL; test = test->right)
+ {
+ double d;
+ int test_bneg = test->flags & ART_ACTIVE_FLAGS_BNEG;
+
+ if (x0 < test->x[test_bneg])
+ {
+ if (x0 < test->x[test_bneg ^ 1])
+ break;
+ d = x0 * test->a + y0 * test->b + test->c;
+ if (d < 0)
+ break;
+ }
+ last = test;
+ }
+
+ left = art_svp_intersect_add_point (ctx, x0, y0, last);
+ seg->left = left;
+ if (left == NULL)
+ {
+ right = ctx->active_head;
+ ctx->active_head = seg;
+ }
+ else
+ {
+ right = left->right;
+ left->right = seg;
+ }
+ seg->right = right;
+ if (right != NULL)
+ right->left = seg;
+
+ seg->delta_wind = in_seg->dir ? 1 : -1;
+ seg->horiz_x = x0;
+
+ art_svp_intersect_insert_line (ctx, seg);
+}
+
+#ifdef SANITYCHECK
+static void
+art_svp_intersect_sanitycheck_winding (ArtIntersectCtx *ctx)
+{
+#if 0
+ /* At this point, we seem to be getting false positives, so it's
+ turned off for now. */
+
+ ArtActiveSeg *seg;
+ int winding_number = 0;
+
+ for (seg = ctx->active_head; seg != NULL; seg = seg->right)
+ {
+ /* Check winding number consistency. */
+ if (seg->flags & ART_ACTIVE_FLAGS_OUT)
+ {
+ if (winding_number != seg->wind_left)
+ art_warn ("*** art_svp_intersect_sanitycheck_winding: seg %lx has wind_left of %d, expected %d\n",
+ (unsigned long) seg, seg->wind_left, winding_number);
+ winding_number = seg->wind_left + seg->delta_wind;
+ }
+ }
+ if (winding_number != 0)
+ art_warn ("*** art_svp_intersect_sanitycheck_winding: non-balanced winding number %d\n",
+ winding_number);
+#endif
+}
+#endif
+
+/**
+ * art_svp_intersect_horiz_commit: Commit points in horiz list to output.
+ * @ctx: Intersection context.
+ *
+ * The main function of the horizontal commit is to output new
+ * points to the output writer.
+ *
+ * This "commit" pass is also where winding numbers are assigned,
+ * because doing it here provides much greater tolerance for inputs
+ * which are not in strict SVP order.
+ *
+ * Each cluster in the horiz_list contains both segments that are in
+ * the active list (ART_ACTIVE_FLAGS_DEL is false) and that are not,
+ * and are scheduled to be deleted (ART_ACTIVE_FLAGS_DEL is true). We
+ * need to deal with both.
+ **/
+static void
+art_svp_intersect_horiz_commit (ArtIntersectCtx *ctx)
+{
+ ArtActiveSeg *seg;
+ int winding_number = 0; /* initialization just to avoid warning */
+ int horiz_wind = 0;
+ double last_x = 0; /* initialization just to avoid warning */
+
+#ifdef VERBOSE
+ printf ("art_svp_intersect_horiz_commit: y=%g\n", ctx->y);
+ for (seg = ctx->horiz_first; seg != NULL; seg = seg->horiz_right)
+ printf (" %lx: %g %+d\n",
+ (unsigned long)seg, seg->horiz_x, seg->horiz_delta_wind);
+#endif
+
+ /* Output points to svp writer. */
+ for (seg = ctx->horiz_first; seg != NULL;)
+ {
+ /* Find a cluster with common horiz_x, */
+ ArtActiveSeg *curs;
+ double x = seg->horiz_x;
+
+ /* Generate any horizontal segments. */
+ if (horiz_wind != 0)
+ {
+ ArtSvpWriter *swr = ctx->out;
+ int seg_id;
+
+ seg_id = swr->add_segment (swr, winding_number, horiz_wind,
+ last_x, ctx->y);
+ swr->add_point (swr, seg_id, x, ctx->y);
+ swr->close_segment (swr, seg_id);
+ }
+
+ /* Find first active segment in cluster. */
+
+ for (curs = seg; curs != NULL && curs->horiz_x == x;
+ curs = curs->horiz_right)
+ if (!(curs->flags & ART_ACTIVE_FLAGS_DEL))
+ break;
+
+ if (curs != NULL && curs->horiz_x == x)
+ {
+ /* There exists at least one active segment in this cluster. */
+
+ /* Find beginning of cluster. */
+ for (; curs->left != NULL; curs = curs->left)
+ if (curs->left->horiz_x != x)
+ break;
+
+ if (curs->left != NULL)
+ winding_number = curs->left->wind_left + curs->left->delta_wind;
+ else
+ winding_number = 0;
+
+ do
+ {
+#ifdef VERBOSE
+ printf (" winding_number = %d += %d\n",
+ winding_number, curs->delta_wind);
+#endif
+ if (!(curs->flags & ART_ACTIVE_FLAGS_OUT) ||
+ curs->wind_left != winding_number)
+ {
+ ArtSvpWriter *swr = ctx->out;
+
+ if (curs->flags & ART_ACTIVE_FLAGS_OUT)
+ {
+ swr->add_point (swr, curs->seg_id,
+ curs->horiz_x, ctx->y);
+ swr->close_segment (swr, curs->seg_id);
+ }
+
+ curs->seg_id = swr->add_segment (swr, winding_number,
+ curs->delta_wind,
+ x, ctx->y);
+ curs->flags |= ART_ACTIVE_FLAGS_OUT;
+ }
+ curs->wind_left = winding_number;
+ winding_number += curs->delta_wind;
+ curs = curs->right;
+ }
+ while (curs != NULL && curs->horiz_x == x);
+ }
+
+ /* Skip past cluster. */
+ do
+ {
+ ArtActiveSeg *next = seg->horiz_right;
+
+ seg->flags &= ~ART_ACTIVE_FLAGS_IN_HORIZ;
+ horiz_wind += seg->horiz_delta_wind;
+ seg->horiz_delta_wind = 0;
+ if (seg->flags & ART_ACTIVE_FLAGS_DEL)
+ {
+ if (seg->flags & ART_ACTIVE_FLAGS_OUT)
+ {
+ ArtSvpWriter *swr = ctx->out;
+ swr->close_segment (swr, seg->seg_id);
+ }
+ art_svp_intersect_active_free (seg);
+ }
+ seg = next;
+ }
+ while (seg != NULL && seg->horiz_x == x);
+
+ last_x = x;
+ }
+ ctx->horiz_first = NULL;
+ ctx->horiz_last = NULL;
+#ifdef SANITYCHECK
+ art_svp_intersect_sanitycheck_winding (ctx);
+#endif
+}
+
+#ifdef VERBOSE
+static void
+art_svp_intersect_print_active (ArtIntersectCtx *ctx)
+{
+ ArtActiveSeg *seg;
+
+ printf ("Active list (y = %g):\n", ctx->y);
+ for (seg = ctx->active_head; seg != NULL; seg = seg->right)
+ {
+ printf (" %lx: (%g, %g)-(%g, %g), (a, b, c) = (%g, %g, %g)\n",
+ (unsigned long)seg,
+ seg->x[0], seg->y0, seg->x[1], seg->y1,
+ seg->a, seg->b, seg->c);
+ }
+}
+#endif
+
+#ifdef SANITYCHECK
+static void
+art_svp_intersect_sanitycheck (ArtIntersectCtx *ctx)
+{
+ ArtActiveSeg *seg;
+ ArtActiveSeg *last = NULL;
+ double d;
+
+ for (seg = ctx->active_head; seg != NULL; seg = seg->right)
+ {
+ if (seg->left != last)
+ {
+ art_warn ("*** art_svp_intersect_sanitycheck: last=%lx, seg->left=%lx\n",
+ (unsigned long)last, (unsigned long)seg->left);
+ }
+ if (last != NULL)
+ {
+ /* pairwise compare with previous seg */
+
+ /* First the top. */
+ if (last->y0 < seg->y0)
+ {
+ }
+ else
+ {
+ }
+
+ /* Then the bottom. */
+ if (last->y1 < seg->y1)
+ {
+ if (!((last->x[1] <
+ seg->x[(seg->flags & ART_ACTIVE_FLAGS_BNEG) ^ 1]) ||
+ last->y1 == seg->y0))
+ {
+ d = last->x[1] * seg->a + last->y1 * seg->b + seg->c;
+ if (d >= -EPSILON_A)
+ art_warn ("*** bottom (%g, %g) of %lx is not clear of %lx to right (d = %g)\n",
+ last->x[1], last->y1, (unsigned long) last,
+ (unsigned long) seg, d);
+ }
+ }
+ else if (last->y1 > seg->y1)
+
+ {
+ if (!((seg->x[1] >
+ last->x[last->flags & ART_ACTIVE_FLAGS_BNEG]) ||
+ seg->y1 == last->y0))
+ {
+ d = seg->x[1] * last->a + seg->y1 * last->b + last->c;
+ if (d <= EPSILON_A)
+ art_warn ("*** bottom (%g, %g) of %lx is not clear of %lx to left (d = %g)\n",
+ seg->x[1], seg->y1, (unsigned long) seg,
+ (unsigned long) last, d);
+ }
+ }
+ else
+ {
+ if (last->x[1] > seg->x[1])
+ art_warn ("*** bottoms (%g, %g) of %lx and (%g, %g) of %lx out of order\n",
+ last->x[1], last->y1, (unsigned long)last,
+ seg->x[1], seg->y1, (unsigned long)seg);
+ }
+ }
+ last = seg;
+ }
+}
+#endif
+
+void
+art_svp_intersector (const ArtSVP *in, ArtSvpWriter *out)
+{
+ ArtIntersectCtx *ctx;
+ ArtPriQ *pq;
+ ArtPriPoint *first_point;
+#ifdef VERBOSE
+ int count = 0;
+#endif
+
+ if (in->n_segs == 0)
+ return;
+
+ ctx = art_new (ArtIntersectCtx, 1);
+ ctx->in = in;
+ ctx->out = out;
+ pq = art_pri_new ();
+ ctx->pq = pq;
+
+ ctx->active_head = NULL;
+
+ ctx->horiz_first = NULL;
+ ctx->horiz_last = NULL;
+
+ ctx->in_curs = 0;
+ first_point = art_new (ArtPriPoint, 1);
+ first_point->x = in->segs[0].points[0].x;
+ first_point->y = in->segs[0].points[0].y;
+ first_point->user_data = NULL;
+ ctx->y = first_point->y;
+ art_pri_insert (pq, first_point);
+
+ while (!art_pri_empty (pq))
+ {
+ ArtPriPoint *pri_point = art_pri_choose (pq);
+ ArtActiveSeg *seg = (ArtActiveSeg *)pri_point->user_data;
+
+#ifdef VERBOSE
+ printf ("\nIntersector step %d\n", count++);
+ art_svp_intersect_print_active (ctx);
+ printf ("priq choose (%g, %g) %lx\n", pri_point->x, pri_point->y,
+ (unsigned long)pri_point->user_data);
+#endif
+#ifdef SANITYCHECK
+ art_svp_intersect_sanitycheck(ctx);
+#endif
+
+ if (ctx->y != pri_point->y)
+ {
+ art_svp_intersect_horiz_commit (ctx);
+ ctx->y = pri_point->y;
+ }
+
+ if (seg == NULL)
+ {
+ /* Insert new segment from input */
+ const ArtSVPSeg *in_seg = &in->segs[ctx->in_curs++];
+ art_svp_intersect_add_seg (ctx, in_seg);
+ if (ctx->in_curs < in->n_segs)
+ {
+ const ArtSVPSeg *next_seg = &in->segs[ctx->in_curs];
+ pri_point->x = next_seg->points[0].x;
+ pri_point->y = next_seg->points[0].y;
+ /* user_data is already NULL */
+ art_pri_insert (pq, pri_point);
+ }
+ else
+ art_free (pri_point);
+ }
+ else
+ {
+ int n_stack = seg->n_stack;
+
+ if (n_stack > 1)
+ {
+ art_svp_intersect_process_intersection (ctx, seg);
+ art_free (pri_point);
+ }
+ else
+ {
+ art_svp_intersect_advance_cursor (ctx, seg, pri_point);
+ }
+ }
+ }
+
+ art_svp_intersect_horiz_commit (ctx);
+
+ art_pri_free (pq);
+ art_free (ctx);
+}
+
+#endif /* not TEST_PRIQ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 2001 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_SVP_INTERSECT_H__
+#define __ART_SVP_INTERSECT_H__
+
+/* The funky new SVP intersector. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifndef ART_WIND_RULE_DEFINED
+#define ART_WIND_RULE_DEFINED
+typedef enum {
+ ART_WIND_RULE_NONZERO,
+ ART_WIND_RULE_INTERSECT,
+ ART_WIND_RULE_ODDEVEN,
+ ART_WIND_RULE_POSITIVE
+} ArtWindRule;
+#endif
+
+typedef struct _ArtSvpWriter ArtSvpWriter;
+
+struct _ArtSvpWriter {
+ int (*add_segment) (ArtSvpWriter *self, int wind_left, int delta_wind,
+ double x, double y);
+ void (*add_point) (ArtSvpWriter *self, int seg_id, double x, double y);
+ void (*close_segment) (ArtSvpWriter *self, int seg_id);
+};
+
+ArtSvpWriter *
+art_svp_writer_rewind_new (ArtWindRule rule);
+
+ArtSVP *
+art_svp_writer_rewind_reap (ArtSvpWriter *self);
+
+int
+art_svp_seg_compare (const void *s1, const void *s2);
+
+void
+art_svp_intersector (const ArtSVP *in, ArtSvpWriter *out);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_SVP_INTERSECT_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998-2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#define noVERBOSE
+
+/* Vector path set operations, over sorted vpaths. */
+
+#include "art_misc.h"
+
+#include "art_svp.h"
+#include "art_vpath.h"
+#include "art_svp_vpath.h"
+#include "art_svp.h"
+#ifdef ART_USE_NEW_INTERSECTOR
+#include "art_svp_intersect.h"
+#else
+#include "art_svp_wind.h"
+#endif
+#include "art_svp_ops.h"
+#include "art_vpath_svp.h"
+
+/* Merge the segments of the two svp's. The resulting svp will share
+ segments with args passed in, so be super-careful with the
+ allocation. */
+/**
+ * art_svp_merge: Merge the segments of two svp's.
+ * @svp1: One svp to merge.
+ * @svp2: The other svp to merge.
+ *
+ * Merges the segments of two SVP's into a new one. The resulting
+ * #ArtSVP data structure will share the segments of the argument
+ * svp's, so it is probably a good idea to free it shallowly,
+ * especially if the arguments will be freed with art_svp_free().
+ *
+ * Return value: The merged #ArtSVP.
+ **/
+static ArtSVP *
+art_svp_merge (const ArtSVP *svp1, const ArtSVP *svp2)
+{
+ ArtSVP *svp_new;
+ int ix;
+ int ix1, ix2;
+
+ svp_new = (ArtSVP *)art_alloc (sizeof(ArtSVP) +
+ (svp1->n_segs + svp2->n_segs - 1) *
+ sizeof(ArtSVPSeg));
+ ix1 = 0;
+ ix2 = 0;
+ for (ix = 0; ix < svp1->n_segs + svp2->n_segs; ix++)
+ {
+ if (ix1 < svp1->n_segs &&
+ (ix2 == svp2->n_segs ||
+ art_svp_seg_compare (&svp1->segs[ix1], &svp2->segs[ix2]) < 1))
+ svp_new->segs[ix] = svp1->segs[ix1++];
+ else
+ svp_new->segs[ix] = svp2->segs[ix2++];
+ }
+
+ svp_new->n_segs = ix;
+ return svp_new;
+}
+
+#ifdef VERBOSE
+
+#define XOFF 50
+#define YOFF 700
+
+static void
+print_ps_vpath (ArtVpath *vpath)
+{
+ int i;
+
+ for (i = 0; vpath[i].code != ART_END; i++)
+ {
+ switch (vpath[i].code)
+ {
+ case ART_MOVETO:
+ printf ("%g %g moveto\n", XOFF + vpath[i].x, YOFF - vpath[i].y);
+ break;
+ case ART_LINETO:
+ printf ("%g %g lineto\n", XOFF + vpath[i].x, YOFF - vpath[i].y);
+ break;
+ default:
+ break;
+ }
+ }
+ printf ("stroke showpage\n");
+}
+
+#define DELT 4
+
+static void
+print_ps_svp (ArtSVP *vpath)
+{
+ int i, j;
+
+ printf ("%% begin\n");
+ for (i = 0; i < vpath->n_segs; i++)
+ {
+ printf ("%g setgray\n", vpath->segs[i].dir ? 0.7 : 0);
+ for (j = 0; j < vpath->segs[i].n_points; j++)
+ {
+ printf ("%g %g %s\n",
+ XOFF + vpath->segs[i].points[j].x,
+ YOFF - vpath->segs[i].points[j].y,
+ j ? "lineto" : "moveto");
+ }
+ printf ("%g %g moveto %g %g lineto %g %g lineto %g %g lineto stroke\n",
+ XOFF + vpath->segs[i].points[0].x - DELT,
+ YOFF - DELT - vpath->segs[i].points[0].y,
+ XOFF + vpath->segs[i].points[0].x - DELT,
+ YOFF - vpath->segs[i].points[0].y,
+ XOFF + vpath->segs[i].points[0].x + DELT,
+ YOFF - vpath->segs[i].points[0].y,
+ XOFF + vpath->segs[i].points[0].x + DELT,
+ YOFF - DELT - vpath->segs[i].points[0].y);
+ printf ("%g %g moveto %g %g lineto %g %g lineto %g %g lineto stroke\n",
+ XOFF + vpath->segs[i].points[j - 1].x - DELT,
+ YOFF + DELT - vpath->segs[i].points[j - 1].y,
+ XOFF + vpath->segs[i].points[j - 1].x - DELT,
+ YOFF - vpath->segs[i].points[j - 1].y,
+ XOFF + vpath->segs[i].points[j - 1].x + DELT,
+ YOFF - vpath->segs[i].points[j - 1].y,
+ XOFF + vpath->segs[i].points[j - 1].x + DELT,
+ YOFF + DELT - vpath->segs[i].points[j - 1].y);
+ printf ("stroke\n");
+ }
+
+ printf ("showpage\n");
+}
+#endif
+
+#ifndef ART_USE_NEW_INTERSECTOR
+static ArtSVP *
+art_svp_merge_perturbed (const ArtSVP *svp1, const ArtSVP *svp2)
+{
+ ArtVpath *vpath1, *vpath2;
+ ArtVpath *vpath1_p, *vpath2_p;
+ ArtSVP *svp1_p, *svp2_p;
+ ArtSVP *svp_new;
+
+ vpath1 = art_vpath_from_svp (svp1);
+ vpath1_p = art_vpath_perturb (vpath1);
+ art_free (vpath1);
+ svp1_p = art_svp_from_vpath (vpath1_p);
+ art_free (vpath1_p);
+
+ vpath2 = art_vpath_from_svp (svp2);
+ vpath2_p = art_vpath_perturb (vpath2);
+ art_free (vpath2);
+ svp2_p = art_svp_from_vpath (vpath2_p);
+ art_free (vpath2_p);
+
+ svp_new = art_svp_merge (svp1_p, svp2_p);
+#ifdef VERBOSE
+ print_ps_svp (svp1_p);
+ print_ps_svp (svp2_p);
+ print_ps_svp (svp_new);
+#endif
+ art_free (svp1_p);
+ art_free (svp2_p);
+
+ return svp_new;
+}
+#endif
+
+/* Compute the union of two vector paths.
+
+ Status of this routine:
+
+ Basic correctness: Seems to work.
+
+ Numerical stability: We cheat (adding random perturbation). Thus,
+ it seems very likely that no numerical stability problems will be
+ seen in practice.
+
+ Speed: Would be better if we didn't go to unsorted vector path
+ and back to add the perturbation.
+
+ Precision: The perturbation fuzzes the coordinates slightly. In
+ cases of butting segments, razor thin long holes may appear.
+
+*/
+/**
+ * art_svp_union: Compute the union of two sorted vector paths.
+ * @svp1: One sorted vector path.
+ * @svp2: The other sorted vector path.
+ *
+ * Computes the union of the two argument svp's. Given two svp's with
+ * winding numbers of 0 and 1 everywhere, the resulting winding number
+ * will be 1 where either (or both) of the argument svp's has a
+ * winding number 1, 0 otherwise. The result is newly allocated.
+ *
+ * Currently, this routine has accuracy problems pending the
+ * implementation of the new intersector.
+ *
+ * Return value: The union of @svp1 and @svp2.
+ **/
+ArtSVP *
+art_svp_union (const ArtSVP *svp1, const ArtSVP *svp2)
+{
+#ifdef ART_USE_NEW_INTERSECTOR
+ ArtSVP *svp3, *svp_new;
+ ArtSvpWriter *swr;
+
+ svp3 = art_svp_merge (svp1, svp2);
+ swr = art_svp_writer_rewind_new (ART_WIND_RULE_POSITIVE);
+ art_svp_intersector (svp3, swr);
+ svp_new = art_svp_writer_rewind_reap (swr);
+ art_free (svp3); /* shallow free because svp3 contains shared segments */
+
+ return svp_new;
+#else
+ ArtSVP *svp3, *svp4, *svp_new;
+
+ svp3 = art_svp_merge_perturbed (svp1, svp2);
+ svp4 = art_svp_uncross (svp3);
+ art_svp_free (svp3);
+
+ svp_new = art_svp_rewind_uncrossed (svp4, ART_WIND_RULE_POSITIVE);
+#ifdef VERBOSE
+ print_ps_svp (svp4);
+ print_ps_svp (svp_new);
+#endif
+ art_svp_free (svp4);
+ return svp_new;
+#endif
+}
+
+/* Compute the intersection of two vector paths.
+
+ Status of this routine:
+
+ Basic correctness: Seems to work.
+
+ Numerical stability: We cheat (adding random perturbation). Thus,
+ it seems very likely that no numerical stability problems will be
+ seen in practice.
+
+ Speed: Would be better if we didn't go to unsorted vector path
+ and back to add the perturbation.
+
+ Precision: The perturbation fuzzes the coordinates slightly. In
+ cases of butting segments, razor thin long isolated segments may
+ appear.
+
+*/
+
+/**
+ * art_svp_intersect: Compute the intersection of two sorted vector paths.
+ * @svp1: One sorted vector path.
+ * @svp2: The other sorted vector path.
+ *
+ * Computes the intersection of the two argument svp's. Given two
+ * svp's with winding numbers of 0 and 1 everywhere, the resulting
+ * winding number will be 1 where both of the argument svp's has a
+ * winding number 1, 0 otherwise. The result is newly allocated.
+ *
+ * Currently, this routine has accuracy problems pending the
+ * implementation of the new intersector.
+ *
+ * Return value: The intersection of @svp1 and @svp2.
+ **/
+ArtSVP *
+art_svp_intersect (const ArtSVP *svp1, const ArtSVP *svp2)
+{
+#ifdef ART_USE_NEW_INTERSECTOR
+ ArtSVP *svp3, *svp_new;
+ ArtSvpWriter *swr;
+
+ svp3 = art_svp_merge (svp1, svp2);
+ swr = art_svp_writer_rewind_new (ART_WIND_RULE_INTERSECT);
+ art_svp_intersector (svp3, swr);
+ svp_new = art_svp_writer_rewind_reap (swr);
+ art_free (svp3); /* shallow free because svp3 contains shared segments */
+
+ return svp_new;
+#else
+ ArtSVP *svp3, *svp4, *svp_new;
+
+ svp3 = art_svp_merge_perturbed (svp1, svp2);
+ svp4 = art_svp_uncross (svp3);
+ art_svp_free (svp3);
+
+ svp_new = art_svp_rewind_uncrossed (svp4, ART_WIND_RULE_INTERSECT);
+ art_svp_free (svp4);
+ return svp_new;
+#endif
+}
+
+/* Compute the symmetric difference of two vector paths.
+
+ Status of this routine:
+
+ Basic correctness: Seems to work.
+
+ Numerical stability: We cheat (adding random perturbation). Thus,
+ it seems very likely that no numerical stability problems will be
+ seen in practice.
+
+ Speed: We could do a lot better by scanning through the svp
+ representations and culling out any segments that are exactly
+ identical. It would also be better if we didn't go to unsorted
+ vector path and back to add the perturbation.
+
+ Precision: Awful. In the case of inputs which are similar (the
+ common case for canvas display), the entire outline is "hairy." In
+ addition, the perturbation fuzzes the coordinates slightly. It can
+ be used as a conservative approximation.
+
+*/
+
+/**
+ * art_svp_diff: Compute the symmetric difference of two sorted vector paths.
+ * @svp1: One sorted vector path.
+ * @svp2: The other sorted vector path.
+ *
+ * Computes the symmetric of the two argument svp's. Given two svp's
+ * with winding numbers of 0 and 1 everywhere, the resulting winding
+ * number will be 1 where either, but not both, of the argument svp's
+ * has a winding number 1, 0 otherwise. The result is newly allocated.
+ *
+ * Currently, this routine has accuracy problems pending the
+ * implementation of the new intersector.
+ *
+ * Return value: The symmetric difference of @svp1 and @svp2.
+ **/
+ArtSVP *
+art_svp_diff (const ArtSVP *svp1, const ArtSVP *svp2)
+{
+#ifdef ART_USE_NEW_INTERSECTOR
+ ArtSVP *svp3, *svp_new;
+ ArtSvpWriter *swr;
+
+ svp3 = art_svp_merge (svp1, svp2);
+ swr = art_svp_writer_rewind_new (ART_WIND_RULE_ODDEVEN);
+ art_svp_intersector (svp3, swr);
+ svp_new = art_svp_writer_rewind_reap (swr);
+ art_free (svp3); /* shallow free because svp3 contains shared segments */
+
+ return svp_new;
+#else
+ ArtSVP *svp3, *svp4, *svp_new;
+
+ svp3 = art_svp_merge_perturbed (svp1, svp2);
+ svp4 = art_svp_uncross (svp3);
+ art_svp_free (svp3);
+
+ svp_new = art_svp_rewind_uncrossed (svp4, ART_WIND_RULE_ODDEVEN);
+ art_svp_free (svp4);
+ return svp_new;
+#endif
+}
+
+/* todo: implement minus */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_SVP_OPS_H__
+#define __ART_SVP_OPS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Vector path set operations, over sorted vpaths. */
+
+ArtSVP *art_svp_union (const ArtSVP *svp1, const ArtSVP *svp2);
+ArtSVP *art_svp_intersect (const ArtSVP *svp1, const ArtSVP *svp2);
+ArtSVP *art_svp_diff (const ArtSVP *svp1, const ArtSVP *svp2);
+ArtSVP *art_svp_minus (const ArtSVP *svp1, const ArtSVP *svp2);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_SVP_OPS_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1999 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <math.h>
+#include "art_misc.h"
+
+#include "art_svp.h"
+#include "art_svp_point.h"
+
+/* Determine whether a point is inside, or near, an svp. */
+
+/* return winding number of point wrt svp */
+/**
+ * art_svp_point_wind: Determine winding number of a point with respect to svp.
+ * @svp: The svp.
+ * @x: The X coordinate of the point.
+ * @y: The Y coordinate of the point.
+ *
+ * Determine the winding number of the point @x, @y with respect to @svp.
+ *
+ * Return value: the winding number.
+ **/
+int
+art_svp_point_wind (ArtSVP *svp, double x, double y)
+{
+ int i, j;
+ int wind = 0;
+
+ for (i = 0; i < svp->n_segs; i++)
+ {
+ ArtSVPSeg *seg = &svp->segs[i];
+
+ if (seg->bbox.y0 > y)
+ break;
+
+ if (seg->bbox.y1 > y)
+ {
+ if (seg->bbox.x1 < x)
+ wind += seg->dir ? 1 : -1;
+ else if (seg->bbox.x0 <= x)
+ {
+ double x0, y0, x1, y1, dx, dy;
+
+ for (j = 0; j < seg->n_points - 1; j++)
+ {
+ if (seg->points[j + 1].y > y)
+ break;
+ }
+ x0 = seg->points[j].x;
+ y0 = seg->points[j].y;
+ x1 = seg->points[j + 1].x;
+ y1 = seg->points[j + 1].y;
+
+ dx = x1 - x0;
+ dy = y1 - y0;
+ if ((x - x0) * dy > (y - y0) * dx)
+ wind += seg->dir ? 1 : -1;
+ }
+ }
+ }
+
+ return wind;
+}
+
+/**
+ * art_svp_point_dist: Determine distance between point and svp.
+ * @svp: The svp.
+ * @x: The X coordinate of the point.
+ * @y: The Y coordinate of the point.
+ *
+ * Determines the distance of the point @x, @y to the closest edge in
+ * @svp. A large number is returned if @svp is empty.
+ *
+ * Return value: the distance.
+ **/
+double
+art_svp_point_dist (ArtSVP *svp, double x, double y)
+{
+ int i, j;
+ double dist_sq;
+ double best_sq = -1;
+
+ for (i = 0; i < svp->n_segs; i++)
+ {
+ ArtSVPSeg *seg = &svp->segs[i];
+ for (j = 0; j < seg->n_points - 1; j++)
+ {
+ double x0 = seg->points[j].x;
+ double y0 = seg->points[j].y;
+ double x1 = seg->points[j + 1].x;
+ double y1 = seg->points[j + 1].y;
+
+ double dx = x1 - x0;
+ double dy = y1 - y0;
+
+ double dxx0 = x - x0;
+ double dyy0 = y - y0;
+
+ double dot = dxx0 * dx + dyy0 * dy;
+
+ if (dot < 0)
+ dist_sq = dxx0 * dxx0 + dyy0 * dyy0;
+ else
+ {
+ double rr = dx * dx + dy * dy;
+
+ if (dot > rr)
+ dist_sq = (x - x1) * (x - x1) + (y - y1) * (y - y1);
+ else
+ {
+ double perp = (y - y0) * dx - (x - x0) * dy;
+
+ dist_sq = perp * perp / rr;
+ }
+ }
+ if (best_sq < 0 || dist_sq < best_sq)
+ best_sq = dist_sq;
+ }
+ }
+
+ if (best_sq >= 0)
+ return sqrt (best_sq);
+ else
+ return 1e12;
+}
+
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1999 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_SVP_POINT_H__
+#define __ART_SVP_POINT_H__
+
+/* Determine whether a point is inside, or near, an svp. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+int
+art_svp_point_wind (ArtSVP *svp, double x, double y);
+
+double
+art_svp_point_dist (ArtSVP *svp, double x, double y);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_SVP_H__ */
+
+
+
+
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998-2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* The spiffy antialiased renderer for sorted vector paths. */
+
+#include <math.h>
+#include <string.h> /* for memmove */
+#include "art_misc.h"
+
+#include "art_rect.h"
+#include "art_svp.h"
+
+#include "art_svp_render_aa.h"
+#include "stdio.h"
+
+typedef double artfloat;
+
+struct _ArtSVPRenderAAIter {
+ const ArtSVP *svp;
+ int x0, x1;
+ int y;
+ int seg_ix;
+
+ int *active_segs;
+ int n_active_segs;
+ int *cursor;
+ artfloat *seg_x;
+ artfloat *seg_dx;
+
+ ArtSVPRenderAAStep *steps;
+};
+
+static void
+art_svp_render_insert_active (int i, int *active_segs, int n_active_segs,
+ artfloat *seg_x, artfloat *seg_dx)
+{
+ int j;
+ artfloat x;
+ int tmp1, tmp2;
+
+ /* this is a cheap hack to get ^'s sorted correctly */
+ x = seg_x[i] + 0.001 * seg_dx[i];
+ for (j = 0; j < n_active_segs && seg_x[active_segs[j]] < x; j++);
+
+ tmp1 = i;
+ while (j < n_active_segs)
+ {
+ tmp2 = active_segs[j];
+ active_segs[j] = tmp1;
+ tmp1 = tmp2;
+ j++;
+ }
+ active_segs[j] = tmp1;
+}
+
+static void
+art_svp_render_delete_active (int *active_segs, int j, int n_active_segs)
+{
+ int k;
+
+ for (k = j; k < n_active_segs; k++)
+ active_segs[k] = active_segs[k + 1];
+}
+
+#define EPSILON 1e-6
+
+/* Render the sorted vector path in the given rectangle, antialiased.
+
+ This interface uses a callback for the actual pixel rendering. The
+ callback is called y1 - y0 times (once for each scan line). The y
+ coordinate is given as an argument for convenience (it could be
+ stored in the callback's private data and incremented on each
+ call).
+
+ The rendered polygon is represented in a semi-runlength format: a
+ start value and a sequence of "steps". Each step has an x
+ coordinate and a value delta. The resulting value at position x is
+ equal to the sum of the start value and all step delta values for
+ which the step x coordinate is less than or equal to x. An
+ efficient algorithm will traverse the steps left to right, keeping
+ a running sum.
+
+ All x coordinates in the steps are guaranteed to be x0 <= x < x1.
+ (This guarantee is a change from the gfonted vpaar renderer, and is
+ designed to simplify the callback).
+
+ There is now a further guarantee that no two steps will have the
+ same x value. This may allow for further speedup and simplification
+ of renderers.
+
+ The value 0x8000 represents 0% coverage by the polygon, while
+ 0xff8000 represents 100% coverage. This format is designed so that
+ >> 16 results in a standard 0x00..0xff value range, with nice
+ rounding.
+
+ Status of this routine:
+
+ Basic correctness: OK
+
+ Numerical stability: pretty good, although probably not
+ bulletproof.
+
+ Speed: Needs more aggressive culling of bounding boxes. Can
+ probably speed up the [x0,x1) clipping of step values. Can do more
+ of the step calculation in fixed point.
+
+ Precision: No known problems, although it should be tested
+ thoroughly, especially for symmetry.
+
+*/
+
+ArtSVPRenderAAIter *
+art_svp_render_aa_iter (const ArtSVP *svp,
+ int x0, int y0, int x1, int y1)
+{
+ ArtSVPRenderAAIter *iter = art_new (ArtSVPRenderAAIter, 1);
+
+ iter->svp = svp;
+ iter->y = y0;
+ iter->x0 = x0;
+ iter->x1 = x1;
+ iter->seg_ix = 0;
+
+ iter->active_segs = art_new (int, svp->n_segs);
+ iter->cursor = art_new (int, svp->n_segs);
+ iter->seg_x = art_new (artfloat, svp->n_segs);
+ iter->seg_dx = art_new (artfloat, svp->n_segs);
+ iter->steps = art_new (ArtSVPRenderAAStep, x1 - x0);
+ iter->n_active_segs = 0;
+
+ return iter;
+}
+
+#define ADD_STEP(xpos, xdelta) \
+ /* stereotype code fragment for adding a step */ \
+ if (n_steps == 0 || steps[n_steps - 1].x < xpos) \
+ { \
+ sx = n_steps; \
+ steps[sx].x = xpos; \
+ steps[sx].delta = xdelta; \
+ n_steps++; \
+ } \
+ else \
+ { \
+ for (sx = n_steps; sx > 0; sx--) \
+ { \
+ if (steps[sx - 1].x == xpos) \
+ { \
+ steps[sx - 1].delta += xdelta; \
+ sx = n_steps; \
+ break; \
+ } \
+ else if (steps[sx - 1].x < xpos) \
+ { \
+ break; \
+ } \
+ } \
+ if (sx < n_steps) \
+ { \
+ memmove (&steps[sx + 1], &steps[sx], \
+ (n_steps - sx) * sizeof(steps[0])); \
+ steps[sx].x = xpos; \
+ steps[sx].delta = xdelta; \
+ n_steps++; \
+ } \
+ }
+
+void
+art_svp_render_aa_iter_step (ArtSVPRenderAAIter *iter, int *p_start,
+ ArtSVPRenderAAStep **p_steps, int *p_n_steps)
+{
+ const ArtSVP *svp = iter->svp;
+ int *active_segs = iter->active_segs;
+ int n_active_segs = iter->n_active_segs;
+ int *cursor = iter->cursor;
+ artfloat *seg_x = iter->seg_x;
+ artfloat *seg_dx = iter->seg_dx;
+ int i = iter->seg_ix;
+ int j;
+ int x0 = iter->x0;
+ int x1 = iter->x1;
+ int y = iter->y;
+ int seg_index;
+
+ int x;
+ ArtSVPRenderAAStep *steps = iter->steps;
+ int n_steps;
+ artfloat y_top, y_bot;
+ artfloat x_top, x_bot;
+ artfloat x_min, x_max;
+ int ix_min, ix_max;
+ artfloat delta; /* delta should be int too? */
+ int last, this;
+ int xdelta;
+ artfloat rslope, drslope;
+ int start;
+ const ArtSVPSeg *seg;
+ int curs;
+ artfloat dy;
+
+ int sx;
+
+ /* insert new active segments */
+ for (; i < svp->n_segs && svp->segs[i].bbox.y0 < y + 1; i++)
+ {
+ if (svp->segs[i].bbox.y1 > y &&
+ svp->segs[i].bbox.x0 < x1)
+ {
+ seg = &svp->segs[i];
+ /* move cursor to topmost vector which overlaps [y,y+1) */
+ for (curs = 0; seg->points[curs + 1].y < y; curs++);
+ cursor[i] = curs;
+ dy = seg->points[curs + 1].y - seg->points[curs].y;
+ if (fabs (dy) >= EPSILON)
+ seg_dx[i] = (seg->points[curs + 1].x - seg->points[curs].x) /
+ dy;
+ else
+ seg_dx[i] = 1e12;
+ seg_x[i] = seg->points[curs].x +
+ (y - seg->points[curs].y) * seg_dx[i];
+ art_svp_render_insert_active (i, active_segs, n_active_segs++,
+ seg_x, seg_dx);
+ }
+ }
+
+ n_steps = 0;
+
+ /* render the runlengths, advancing and deleting as we go */
+ start = 0x8000;
+
+ for (j = 0; j < n_active_segs; j++)
+ {
+ seg_index = active_segs[j];
+ seg = &svp->segs[seg_index];
+ curs = cursor[seg_index];
+ while (curs != seg->n_points - 1 &&
+ seg->points[curs].y < y + 1)
+ {
+ y_top = y;
+ if (y_top < seg->points[curs].y)
+ y_top = seg->points[curs].y;
+ y_bot = y + 1;
+ if (y_bot > seg->points[curs + 1].y)
+ y_bot = seg->points[curs + 1].y;
+ if (y_top != y_bot) {
+ delta = (seg->dir ? 16711680.0 : -16711680.0) *
+ (y_bot - y_top);
+ x_top = seg_x[seg_index] + (y_top - y) * seg_dx[seg_index];
+ x_bot = seg_x[seg_index] + (y_bot - y) * seg_dx[seg_index];
+ if (x_top < x_bot)
+ {
+ x_min = x_top;
+ x_max = x_bot;
+ }
+ else
+ {
+ x_min = x_bot;
+ x_max = x_top;
+ }
+ ix_min = floor (x_min);
+ ix_max = floor (x_max);
+ if (ix_min >= x1)
+ {
+ /* skip; it starts to the right of the render region */
+ }
+ else if (ix_max < x0)
+ /* it ends to the left of the render region */
+ start += delta;
+ else if (ix_min == ix_max)
+ {
+ /* case 1, antialias a single pixel */
+ xdelta = (ix_min + 1 - (x_min + x_max) * 0.5) * delta;
+
+ ADD_STEP(ix_min, xdelta)
+
+ if (ix_min + 1 < x1)
+ {
+ xdelta = delta - xdelta;
+
+ ADD_STEP(ix_min + 1, xdelta)
+ }
+ }
+ else
+ {
+ /* case 2, antialias a run */
+ rslope = 1.0 / fabs (seg_dx[seg_index]);
+ drslope = delta * rslope;
+ last =
+ drslope * 0.5 *
+ (ix_min + 1 - x_min) * (ix_min + 1 - x_min);
+ xdelta = last;
+ if (ix_min >= x0)
+ {
+ ADD_STEP(ix_min, xdelta)
+
+ x = ix_min + 1;
+ }
+ else
+ {
+ start += last;
+ x = x0;
+ }
+ if (ix_max > x1)
+ ix_max = x1;
+ for (; x < ix_max; x++)
+ {
+ this = (seg->dir ? 16711680.0 : -16711680.0) * rslope *
+ (x + 0.5 - x_min);
+ xdelta = this - last;
+ last = this;
+
+ ADD_STEP(x, xdelta)
+ }
+ if (x < x1)
+ {
+ this =
+ delta * (1 - 0.5 *
+ (x_max - ix_max) * (x_max - ix_max) *
+ rslope);
+ xdelta = this - last;
+ last = this;
+
+ ADD_STEP(x, xdelta)
+
+ if (x + 1 < x1)
+ {
+ xdelta = delta - last;
+
+ ADD_STEP(x + 1, xdelta)
+ }
+ }
+ }
+ }
+ curs++;
+ if (curs != seg->n_points - 1 &&
+ seg->points[curs].y < y + 1)
+ {
+ dy = seg->points[curs + 1].y - seg->points[curs].y;
+ if (fabs (dy) >= EPSILON)
+ seg_dx[seg_index] = (seg->points[curs + 1].x -
+ seg->points[curs].x) / dy;
+ else
+ seg_dx[seg_index] = 1e12;
+ seg_x[seg_index] = seg->points[curs].x +
+ (y - seg->points[curs].y) * seg_dx[seg_index];
+ }
+ /* break here, instead of duplicating predicate in while? */
+ }
+ if (seg->points[curs].y >= y + 1)
+ {
+ curs--;
+ cursor[seg_index] = curs;
+ seg_x[seg_index] += seg_dx[seg_index];
+ }
+ else
+ {
+ art_svp_render_delete_active (active_segs, j--,
+ --n_active_segs);
+ }
+ }
+
+ *p_start = start;
+ *p_steps = steps;
+ *p_n_steps = n_steps;
+
+ iter->seg_ix = i;
+ iter->n_active_segs = n_active_segs;
+ iter->y++;
+}
+
+void
+art_svp_render_aa_iter_done (ArtSVPRenderAAIter *iter)
+{
+ art_free (iter->steps);
+
+ art_free (iter->seg_dx);
+ art_free (iter->seg_x);
+ art_free (iter->cursor);
+ art_free (iter->active_segs);
+ art_free (iter);
+}
+
+/**
+ * art_svp_render_aa: Render SVP antialiased.
+ * @svp: The #ArtSVP to render.
+ * @x0: Left coordinate of destination rectangle.
+ * @y0: Top coordinate of destination rectangle.
+ * @x1: Right coordinate of destination rectangle.
+ * @y1: Bottom coordinate of destination rectangle.
+ * @callback: The callback which actually paints the pixels.
+ * @callback_data: Private data for @callback.
+ *
+ * Renders the sorted vector path in the given rectangle, antialiased.
+ *
+ * This interface uses a callback for the actual pixel rendering. The
+ * callback is called @y1 - @y0 times (once for each scan line). The y
+ * coordinate is given as an argument for convenience (it could be
+ * stored in the callback's private data and incremented on each
+ * call).
+ *
+ * The rendered polygon is represented in a semi-runlength format: a
+ * start value and a sequence of "steps". Each step has an x
+ * coordinate and a value delta. The resulting value at position x is
+ * equal to the sum of the start value and all step delta values for
+ * which the step x coordinate is less than or equal to x. An
+ * efficient algorithm will traverse the steps left to right, keeping
+ * a running sum.
+ *
+ * All x coordinates in the steps are guaranteed to be @x0 <= x < @x1.
+ * (This guarantee is a change from the gfonted vpaar renderer from
+ * which this routine is derived, and is designed to simplify the
+ * callback).
+ *
+ * The value 0x8000 represents 0% coverage by the polygon, while
+ * 0xff8000 represents 100% coverage. This format is designed so that
+ * >> 16 results in a standard 0x00..0xff value range, with nice
+ * rounding.
+ *
+ **/
+void
+art_svp_render_aa (const ArtSVP *svp,
+ int x0, int y0, int x1, int y1,
+ void (*callback) (void *callback_data,
+ int y,
+ int start,
+ ArtSVPRenderAAStep *steps, int n_steps),
+ void *callback_data)
+{
+ ArtSVPRenderAAIter *iter;
+ int y;
+ int start;
+ ArtSVPRenderAAStep *steps;
+ int n_steps;
+
+ iter = art_svp_render_aa_iter (svp, x0, y0, x1, y1);
+
+
+ for (y = y0; y < y1; y++)
+ {
+ art_svp_render_aa_iter_step (iter, &start, &steps, &n_steps);
+ (*callback) (callback_data, y, start, steps, n_steps);
+ }
+
+ art_svp_render_aa_iter_done (iter);
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_SVP_RENDER_AA_H__
+#define __ART_SVP_RENDER_AA_H__
+
+/* The spiffy antialiased renderer for sorted vector paths. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct _ArtSVPRenderAAStep ArtSVPRenderAAStep;
+typedef struct _ArtSVPRenderAAIter ArtSVPRenderAAIter;
+
+struct _ArtSVPRenderAAStep {
+ int x;
+ int delta; /* stored with 16 fractional bits */
+};
+
+ArtSVPRenderAAIter *
+art_svp_render_aa_iter (const ArtSVP *svp,
+ int x0, int y0, int x1, int y1);
+
+void
+art_svp_render_aa_iter_step (ArtSVPRenderAAIter *iter, int *p_start,
+ ArtSVPRenderAAStep **p_steps, int *p_n_steps);
+
+void
+art_svp_render_aa_iter_done (ArtSVPRenderAAIter *iter);
+
+void
+art_svp_render_aa (const ArtSVP *svp,
+ int x0, int y0, int x1, int y1,
+ void (*callback) (void *callback_data,
+ int y,
+ int start,
+ ArtSVPRenderAAStep *steps, int n_steps),
+ void *callback_data);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_SVP_RENDER_AA_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998-2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Sort vector paths into sorted vector paths */
+
+#include <stdlib.h>
+#include <math.h>
+
+#include "art_misc.h"
+
+#include "art_vpath.h"
+#include "art_svp.h"
+#include "art_svp_vpath.h"
+
+
+/* reverse a list of points in place */
+static void
+reverse_points (ArtPoint *points, int n_points)
+{
+ int i;
+ ArtPoint tmp_p;
+
+ for (i = 0; i < (n_points >> 1); i++)
+ {
+ tmp_p = points[i];
+ points[i] = points[n_points - (i + 1)];
+ points[n_points - (i + 1)] = tmp_p;
+ }
+}
+
+/**
+ * art_svp_from_vpath: Convert a vpath to a sorted vector path.
+ * @vpath: #ArtVPath to convert.
+ *
+ * Converts a vector path into sorted vector path form. The svp form is
+ * more efficient for rendering and other vector operations.
+ *
+ * Basically, the implementation is to traverse the vector path,
+ * generating a new segment for each "run" of points in the vector
+ * path with monotonically increasing Y values. All the resulting
+ * values are then sorted.
+ *
+ * Note: I'm not sure that the sorting rule is correct with respect
+ * to numerical stability issues.
+ *
+ * Return value: Resulting sorted vector path.
+ **/
+ArtSVP *
+art_svp_from_vpath (ArtVpath *vpath)
+{
+ int n_segs, n_segs_max;
+ ArtSVP *svp;
+ int dir;
+ int new_dir;
+ int i;
+ ArtPoint *points;
+ int n_points, n_points_max;
+ double x, y;
+ double x_min, x_max;
+
+ n_segs = 0;
+ n_segs_max = 16;
+ svp = (ArtSVP *)art_alloc (sizeof(ArtSVP) +
+ (n_segs_max - 1) * sizeof(ArtSVPSeg));
+
+ dir = 0;
+ n_points = 0;
+ n_points_max = 0;
+ points = NULL;
+ i = 0;
+
+ x = y = 0; /* unnecessary, given "first code must not be LINETO" invariant,
+ but it makes gcc -Wall -ansi -pedantic happier */
+ x_min = x_max = 0; /* same */
+
+ while (vpath[i].code != ART_END) {
+ if (vpath[i].code == ART_MOVETO || vpath[i].code == ART_MOVETO_OPEN)
+ {
+ if (points != NULL && n_points >= 2)
+ {
+ if (n_segs == n_segs_max)
+ {
+ n_segs_max <<= 1;
+ svp = (ArtSVP *)art_realloc (svp, sizeof(ArtSVP) +
+ (n_segs_max - 1) *
+ sizeof(ArtSVPSeg));
+ }
+ svp->segs[n_segs].n_points = n_points;
+ svp->segs[n_segs].dir = (dir > 0);
+ if (dir < 0)
+ reverse_points (points, n_points);
+ svp->segs[n_segs].points = points;
+ svp->segs[n_segs].bbox.x0 = x_min;
+ svp->segs[n_segs].bbox.x1 = x_max;
+ svp->segs[n_segs].bbox.y0 = points[0].y;
+ svp->segs[n_segs].bbox.y1 = points[n_points - 1].y;
+ n_segs++;
+ points = NULL;
+ }
+
+ if (points == NULL)
+ {
+ n_points_max = 4;
+ points = art_new (ArtPoint, n_points_max);
+ }
+
+ n_points = 1;
+ points[0].x = x = vpath[i].x;
+ points[0].y = y = vpath[i].y;
+ x_min = x;
+ x_max = x;
+ dir = 0;
+ }
+ else /* must be LINETO */
+ {
+ new_dir = (vpath[i].y > y ||
+ (vpath[i].y == y && vpath[i].x > x)) ? 1 : -1;
+ if (dir && dir != new_dir)
+ {
+ /* new segment */
+ x = points[n_points - 1].x;
+ y = points[n_points - 1].y;
+ if (n_segs == n_segs_max)
+ {
+ n_segs_max <<= 1;
+ svp = (ArtSVP *)art_realloc (svp, sizeof(ArtSVP) +
+ (n_segs_max - 1) *
+ sizeof(ArtSVPSeg));
+ }
+ svp->segs[n_segs].n_points = n_points;
+ svp->segs[n_segs].dir = (dir > 0);
+ if (dir < 0)
+ reverse_points (points, n_points);
+ svp->segs[n_segs].points = points;
+ svp->segs[n_segs].bbox.x0 = x_min;
+ svp->segs[n_segs].bbox.x1 = x_max;
+ svp->segs[n_segs].bbox.y0 = points[0].y;
+ svp->segs[n_segs].bbox.y1 = points[n_points - 1].y;
+ n_segs++;
+
+ n_points = 1;
+ n_points_max = 4;
+ points = art_new (ArtPoint, n_points_max);
+ points[0].x = x;
+ points[0].y = y;
+ x_min = x;
+ x_max = x;
+ }
+
+ if (points != NULL)
+ {
+ if (n_points == n_points_max)
+ art_expand (points, ArtPoint, n_points_max);
+ points[n_points].x = x = vpath[i].x;
+ points[n_points].y = y = vpath[i].y;
+ if (x < x_min) x_min = x;
+ else if (x > x_max) x_max = x;
+ n_points++;
+ }
+ dir = new_dir;
+ }
+ i++;
+ }
+
+ if (points != NULL)
+ {
+ if (n_points >= 2)
+ {
+ if (n_segs == n_segs_max)
+ {
+ n_segs_max <<= 1;
+ svp = (ArtSVP *)art_realloc (svp, sizeof(ArtSVP) +
+ (n_segs_max - 1) *
+ sizeof(ArtSVPSeg));
+ }
+ svp->segs[n_segs].n_points = n_points;
+ svp->segs[n_segs].dir = (dir > 0);
+ if (dir < 0)
+ reverse_points (points, n_points);
+ svp->segs[n_segs].points = points;
+ svp->segs[n_segs].bbox.x0 = x_min;
+ svp->segs[n_segs].bbox.x1 = x_max;
+ svp->segs[n_segs].bbox.y0 = points[0].y;
+ svp->segs[n_segs].bbox.y1 = points[n_points - 1].y;
+ n_segs++;
+ }
+ else
+ art_free (points);
+ }
+
+ svp->n_segs = n_segs;
+
+ qsort (&svp->segs, n_segs, sizeof (ArtSVPSeg), art_svp_seg_compare);
+
+ return svp;
+}
+
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_SVP_VPATH_H__
+#define __ART_SVP_VPATH_H__
+
+#ifdef LIBART_COMPILATION
+#include "art_vpath.h"
+#else
+#include <art_vpath.h>
+#endif
+
+/* Sort vector paths into sorted vector paths. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+ArtSVP *
+art_svp_from_vpath (ArtVpath *vpath);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_SVP_VPATH_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998-2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#include <stdlib.h>
+#include <math.h>
+
+#include "art_misc.h"
+
+#include "art_vpath.h"
+#include "art_svp.h"
+#ifdef ART_USE_NEW_INTERSECTOR
+#include "art_svp_intersect.h"
+#else
+#include "art_svp_wind.h"
+#endif
+#include "art_svp_vpath.h"
+#include "art_svp_vpath_stroke.h"
+
+#define EPSILON 1e-6
+#define EPSILON_2 1e-12
+
+#define yes_OPTIMIZE_INNER
+
+/* Render an arc segment starting at (xc + x0, yc + y0) to (xc + x1,
+ yc + y1), centered at (xc, yc), and with given radius. Both x0^2 +
+ y0^2 and x1^2 + y1^2 should be equal to radius^2.
+
+ A positive value of radius means curve to the left, negative means
+ curve to the right.
+*/
+static void
+art_svp_vpath_stroke_arc (ArtVpath **p_vpath, int *pn, int *pn_max,
+ double xc, double yc,
+ double x0, double y0,
+ double x1, double y1,
+ double radius,
+ double flatness)
+{
+ double theta;
+ double th_0, th_1;
+ int n_pts;
+ int i;
+ double aradius;
+
+ aradius = fabs (radius);
+ theta = 2 * M_SQRT2 * sqrt (flatness / aradius);
+ th_0 = atan2 (y0, x0);
+ th_1 = atan2 (y1, x1);
+ if (radius > 0)
+ {
+ /* curve to the left */
+ if (th_0 < th_1) th_0 += M_PI * 2;
+ n_pts = ceil ((th_0 - th_1) / theta);
+ }
+ else
+ {
+ /* curve to the right */
+ if (th_1 < th_0) th_1 += M_PI * 2;
+ n_pts = ceil ((th_1 - th_0) / theta);
+ }
+#ifdef VERBOSE
+ printf ("start %f %f; th_0 = %f, th_1 = %f, r = %f, theta = %f\n", x0, y0, th_0, th_1, radius, theta);
+#endif
+ art_vpath_add_point (p_vpath, pn, pn_max,
+ ART_LINETO, xc + x0, yc + y0);
+ for (i = 1; i < n_pts; i++)
+ {
+ theta = th_0 + (th_1 - th_0) * i / n_pts;
+ art_vpath_add_point (p_vpath, pn, pn_max,
+ ART_LINETO, xc + cos (theta) * aradius,
+ yc + sin (theta) * aradius);
+#ifdef VERBOSE
+ printf ("mid %f %f\n", cos (theta) * radius, sin (theta) * radius);
+#endif
+ }
+ art_vpath_add_point (p_vpath, pn, pn_max,
+ ART_LINETO, xc + x1, yc + y1);
+#ifdef VERBOSE
+ printf ("end %f %f\n", x1, y1);
+#endif
+}
+
+/* Assume that forw and rev are at point i0. Bring them to i1,
+ joining with the vector i1 - i2.
+
+ This used to be true, but isn't now that the stroke_raw code is
+ filtering out (near)zero length vectors: {It so happens that all
+ invocations of this function maintain the precondition i1 = i0 + 1,
+ so we could decrease the number of arguments by one. We haven't
+ done that here, though.}
+
+ forw is to the line's right and rev is to its left.
+
+ Precondition: no zero-length vectors, otherwise a divide by
+ zero will happen. */
+static void
+render_seg (ArtVpath **p_forw, int *pn_forw, int *pn_forw_max,
+ ArtVpath **p_rev, int *pn_rev, int *pn_rev_max,
+ ArtVpath *vpath, int i0, int i1, int i2,
+ ArtPathStrokeJoinType join,
+ double line_width, double miter_limit, double flatness)
+{
+ double dx0, dy0;
+ double dx1, dy1;
+ double dlx0, dly0;
+ double dlx1, dly1;
+ double dmx, dmy;
+ double dmr2;
+ double scale;
+ double cross;
+
+#ifdef VERBOSE
+ printf ("join style = %d\n", join);
+#endif
+
+ /* The vectors of the lines from i0 to i1 and i1 to i2. */
+ dx0 = vpath[i1].x - vpath[i0].x;
+ dy0 = vpath[i1].y - vpath[i0].y;
+
+ dx1 = vpath[i2].x - vpath[i1].x;
+ dy1 = vpath[i2].y - vpath[i1].y;
+
+ /* Set dl[xy]0 to the vector from i0 to i1, rotated counterclockwise
+ 90 degrees, and scaled to the length of line_width. */
+ scale = line_width / sqrt (dx0 * dx0 + dy0 * dy0);
+ dlx0 = dy0 * scale;
+ dly0 = -dx0 * scale;
+
+ /* Set dl[xy]1 to the vector from i1 to i2, rotated counterclockwise
+ 90 degrees, and scaled to the length of line_width. */
+ scale = line_width / sqrt (dx1 * dx1 + dy1 * dy1);
+ dlx1 = dy1 * scale;
+ dly1 = -dx1 * scale;
+
+#ifdef VERBOSE
+ printf ("%% render_seg: (%g, %g) - (%g, %g) - (%g, %g)\n",
+ vpath[i0].x, vpath[i0].y,
+ vpath[i1].x, vpath[i1].y,
+ vpath[i2].x, vpath[i2].y);
+
+ printf ("%% render_seg: d[xy]0 = (%g, %g), dl[xy]0 = (%g, %g)\n",
+ dx0, dy0, dlx0, dly0);
+
+ printf ("%% render_seg: d[xy]1 = (%g, %g), dl[xy]1 = (%g, %g)\n",
+ dx1, dy1, dlx1, dly1);
+#endif
+
+ /* now, forw's last point is expected to be colinear along d[xy]0
+ to point i0 - dl[xy]0, and rev with i0 + dl[xy]0. */
+
+ /* positive for positive area (i.e. left turn) */
+ cross = dx1 * dy0 - dx0 * dy1;
+
+ dmx = (dlx0 + dlx1) * 0.5;
+ dmy = (dly0 + dly1) * 0.5;
+ dmr2 = dmx * dmx + dmy * dmy;
+
+ if (join == ART_PATH_STROKE_JOIN_MITER &&
+ dmr2 * miter_limit * miter_limit < line_width * line_width)
+ join = ART_PATH_STROKE_JOIN_BEVEL;
+
+ /* the case when dmr2 is zero or very small bothers me
+ (i.e. near a 180 degree angle) */
+ scale = line_width * line_width / dmr2;
+ dmx *= scale;
+ dmy *= scale;
+
+ if (cross * cross < EPSILON_2 && dx0 * dx1 + dy0 * dy1 >= 0)
+ {
+ /* going straight */
+#ifdef VERBOSE
+ printf ("%% render_seg: straight\n");
+#endif
+ art_vpath_add_point (p_forw, pn_forw, pn_forw_max,
+ ART_LINETO, vpath[i1].x - dlx0, vpath[i1].y - dly0);
+ art_vpath_add_point (p_rev, pn_rev, pn_rev_max,
+ ART_LINETO, vpath[i1].x + dlx0, vpath[i1].y + dly0);
+ }
+ else if (cross > 0)
+ {
+ /* left turn, forw is outside and rev is inside */
+
+#ifdef VERBOSE
+ printf ("%% render_seg: left\n");
+#endif
+ if (
+#ifdef NO_OPTIMIZE_INNER
+ 0 &&
+#endif
+ /* check that i1 + dm[xy] is inside i0-i1 rectangle */
+ (dx0 + dmx) * dx0 + (dy0 + dmy) * dy0 > 0 &&
+ /* and that i1 + dm[xy] is inside i1-i2 rectangle */
+ ((dx1 - dmx) * dx1 + (dy1 - dmy) * dy1 > 0)
+#ifdef PEDANTIC_INNER
+ &&
+ /* check that i1 + dl[xy]1 is inside i0-i1 rectangle */
+ (dx0 + dlx1) * dx0 + (dy0 + dly1) * dy0 > 0 &&
+ /* and that i1 + dl[xy]0 is inside i1-i2 rectangle */
+ ((dx1 - dlx0) * dx1 + (dy1 - dly0) * dy1 > 0)
+#endif
+ )
+ {
+ /* can safely add single intersection point */
+ art_vpath_add_point (p_rev, pn_rev, pn_rev_max,
+ ART_LINETO, vpath[i1].x + dmx, vpath[i1].y + dmy);
+ }
+ else
+ {
+ /* need to loop-de-loop the inside */
+ art_vpath_add_point (p_rev, pn_rev, pn_rev_max,
+ ART_LINETO, vpath[i1].x + dlx0, vpath[i1].y + dly0);
+ art_vpath_add_point (p_rev, pn_rev, pn_rev_max,
+ ART_LINETO, vpath[i1].x, vpath[i1].y);
+ art_vpath_add_point (p_rev, pn_rev, pn_rev_max,
+ ART_LINETO, vpath[i1].x + dlx1, vpath[i1].y + dly1);
+ }
+
+ if (join == ART_PATH_STROKE_JOIN_BEVEL)
+ {
+ /* bevel */
+ art_vpath_add_point (p_forw, pn_forw, pn_forw_max,
+ ART_LINETO, vpath[i1].x - dlx0, vpath[i1].y - dly0);
+ art_vpath_add_point (p_forw, pn_forw, pn_forw_max,
+ ART_LINETO, vpath[i1].x - dlx1, vpath[i1].y - dly1);
+ }
+ else if (join == ART_PATH_STROKE_JOIN_MITER)
+ {
+ art_vpath_add_point (p_forw, pn_forw, pn_forw_max,
+ ART_LINETO, vpath[i1].x - dmx, vpath[i1].y - dmy);
+ }
+ else if (join == ART_PATH_STROKE_JOIN_ROUND)
+ art_svp_vpath_stroke_arc (p_forw, pn_forw, pn_forw_max,
+ vpath[i1].x, vpath[i1].y,
+ -dlx0, -dly0,
+ -dlx1, -dly1,
+ line_width,
+ flatness);
+ }
+ else
+ {
+ /* right turn, rev is outside and forw is inside */
+#ifdef VERBOSE
+ printf ("%% render_seg: right\n");
+#endif
+
+ if (
+#ifdef NO_OPTIMIZE_INNER
+ 0 &&
+#endif
+ /* check that i1 - dm[xy] is inside i0-i1 rectangle */
+ (dx0 - dmx) * dx0 + (dy0 - dmy) * dy0 > 0 &&
+ /* and that i1 - dm[xy] is inside i1-i2 rectangle */
+ ((dx1 + dmx) * dx1 + (dy1 + dmy) * dy1 > 0)
+#ifdef PEDANTIC_INNER
+ &&
+ /* check that i1 - dl[xy]1 is inside i0-i1 rectangle */
+ (dx0 - dlx1) * dx0 + (dy0 - dly1) * dy0 > 0 &&
+ /* and that i1 - dl[xy]0 is inside i1-i2 rectangle */
+ ((dx1 + dlx0) * dx1 + (dy1 + dly0) * dy1 > 0)
+#endif
+ )
+ {
+ /* can safely add single intersection point */
+ art_vpath_add_point (p_forw, pn_forw, pn_forw_max,
+ ART_LINETO, vpath[i1].x - dmx, vpath[i1].y - dmy);
+ }
+ else
+ {
+ /* need to loop-de-loop the inside */
+ art_vpath_add_point (p_forw, pn_forw, pn_forw_max,
+ ART_LINETO, vpath[i1].x - dlx0, vpath[i1].y - dly0);
+ art_vpath_add_point (p_forw, pn_forw, pn_forw_max,
+ ART_LINETO, vpath[i1].x, vpath[i1].y);
+ art_vpath_add_point (p_forw, pn_forw, pn_forw_max,
+ ART_LINETO, vpath[i1].x - dlx1, vpath[i1].y - dly1);
+ }
+
+ if (join == ART_PATH_STROKE_JOIN_BEVEL)
+ {
+ /* bevel */
+ art_vpath_add_point (p_rev, pn_rev, pn_rev_max,
+ ART_LINETO, vpath[i1].x + dlx0, vpath[i1].y + dly0);
+ art_vpath_add_point (p_rev, pn_rev, pn_rev_max,
+ ART_LINETO, vpath[i1].x + dlx1, vpath[i1].y + dly1);
+ }
+ else if (join == ART_PATH_STROKE_JOIN_MITER)
+ {
+ art_vpath_add_point (p_rev, pn_rev, pn_rev_max,
+ ART_LINETO, vpath[i1].x + dmx, vpath[i1].y + dmy);
+ }
+ else if (join == ART_PATH_STROKE_JOIN_ROUND)
+ art_svp_vpath_stroke_arc (p_rev, pn_rev, pn_rev_max,
+ vpath[i1].x, vpath[i1].y,
+ dlx0, dly0,
+ dlx1, dly1,
+ -line_width,
+ flatness);
+
+ }
+}
+
+/* caps i1, under the assumption of a vector from i0 */
+static void
+render_cap (ArtVpath **p_result, int *pn_result, int *pn_result_max,
+ ArtVpath *vpath, int i0, int i1,
+ ArtPathStrokeCapType cap, double line_width, double flatness)
+{
+ double dx0, dy0;
+ double dlx0, dly0;
+ double scale;
+ int n_pts;
+ int i;
+
+ dx0 = vpath[i1].x - vpath[i0].x;
+ dy0 = vpath[i1].y - vpath[i0].y;
+
+ /* Set dl[xy]0 to the vector from i0 to i1, rotated counterclockwise
+ 90 degrees, and scaled to the length of line_width. */
+ scale = line_width / sqrt (dx0 * dx0 + dy0 * dy0);
+ dlx0 = dy0 * scale;
+ dly0 = -dx0 * scale;
+
+#ifdef VERBOSE
+ printf ("cap style = %d\n", cap);
+#endif
+
+ switch (cap)
+ {
+ case ART_PATH_STROKE_CAP_BUTT:
+ art_vpath_add_point (p_result, pn_result, pn_result_max,
+ ART_LINETO, vpath[i1].x - dlx0, vpath[i1].y - dly0);
+ art_vpath_add_point (p_result, pn_result, pn_result_max,
+ ART_LINETO, vpath[i1].x + dlx0, vpath[i1].y + dly0);
+ break;
+ case ART_PATH_STROKE_CAP_ROUND:
+ n_pts = ceil (M_PI / (2.0 * M_SQRT2 * sqrt (flatness / line_width)));
+ art_vpath_add_point (p_result, pn_result, pn_result_max,
+ ART_LINETO, vpath[i1].x - dlx0, vpath[i1].y - dly0);
+ for (i = 1; i < n_pts; i++)
+ {
+ double theta, c_th, s_th;
+
+ theta = M_PI * i / n_pts;
+ c_th = cos (theta);
+ s_th = sin (theta);
+ art_vpath_add_point (p_result, pn_result, pn_result_max,
+ ART_LINETO,
+ vpath[i1].x - dlx0 * c_th - dly0 * s_th,
+ vpath[i1].y - dly0 * c_th + dlx0 * s_th);
+ }
+ art_vpath_add_point (p_result, pn_result, pn_result_max,
+ ART_LINETO, vpath[i1].x + dlx0, vpath[i1].y + dly0);
+ break;
+ case ART_PATH_STROKE_CAP_SQUARE:
+ art_vpath_add_point (p_result, pn_result, pn_result_max,
+ ART_LINETO,
+ vpath[i1].x - dlx0 - dly0,
+ vpath[i1].y - dly0 + dlx0);
+ art_vpath_add_point (p_result, pn_result, pn_result_max,
+ ART_LINETO,
+ vpath[i1].x + dlx0 - dly0,
+ vpath[i1].y + dly0 + dlx0);
+ break;
+ }
+}
+
+/**
+ * art_svp_from_vpath_raw: Stroke a vector path, raw version
+ * @vpath: #ArtVPath to stroke.
+ * @join: Join style.
+ * @cap: Cap style.
+ * @line_width: Width of stroke.
+ * @miter_limit: Miter limit.
+ * @flatness: Flatness.
+ *
+ * Exactly the same as art_svp_vpath_stroke(), except that the resulting
+ * stroke outline may self-intersect and have regions of winding number
+ * greater than 1.
+ *
+ * Return value: Resulting raw stroked outline in svp format.
+ **/
+ArtVpath *
+art_svp_vpath_stroke_raw (ArtVpath *vpath,
+ ArtPathStrokeJoinType join,
+ ArtPathStrokeCapType cap,
+ double line_width,
+ double miter_limit,
+ double flatness)
+{
+ int begin_idx, end_idx;
+ int i;
+ ArtVpath *forw, *rev;
+ int n_forw, n_rev;
+ int n_forw_max, n_rev_max;
+ ArtVpath *result;
+ int n_result, n_result_max;
+ double half_lw = 0.5 * line_width;
+ int closed;
+ int last, this, next, second;
+ double dx, dy;
+
+ n_forw_max = 16;
+ forw = art_new (ArtVpath, n_forw_max);
+
+ n_rev_max = 16;
+ rev = art_new (ArtVpath, n_rev_max);
+
+ n_result = 0;
+ n_result_max = 16;
+ result = art_new (ArtVpath, n_result_max);
+
+ for (begin_idx = 0; vpath[begin_idx].code != ART_END; begin_idx = end_idx)
+ {
+ n_forw = 0;
+ n_rev = 0;
+
+ closed = (vpath[begin_idx].code == ART_MOVETO);
+
+ /* we don't know what the first point joins with until we get to the
+ last point and see if it's closed. So we start with the second
+ line in the path.
+
+ Note: this is not strictly true (we now know it's closed from
+ the opening pathcode), but why fix code that isn't broken?
+ */
+
+ this = begin_idx;
+ /* skip over identical points at the beginning of the subpath */
+ for (i = this + 1; vpath[i].code == ART_LINETO; i++)
+ {
+ dx = vpath[i].x - vpath[this].x;
+ dy = vpath[i].y - vpath[this].y;
+ if (dx * dx + dy * dy > EPSILON_2)
+ break;
+ }
+ next = i;
+ second = next;
+
+ /* invariant: this doesn't coincide with next */
+ while (vpath[next].code == ART_LINETO)
+ {
+ last = this;
+ this = next;
+ /* skip over identical points after the beginning of the subpath */
+ for (i = this + 1; vpath[i].code == ART_LINETO; i++)
+ {
+ dx = vpath[i].x - vpath[this].x;
+ dy = vpath[i].y - vpath[this].y;
+ if (dx * dx + dy * dy > EPSILON_2)
+ break;
+ }
+ next = i;
+ if (vpath[next].code != ART_LINETO)
+ {
+ /* reached end of path */
+ /* make "closed" detection conform to PostScript
+ semantics (i.e. explicit closepath code rather than
+ just the fact that end of the path is the beginning) */
+ if (closed &&
+ vpath[this].x == vpath[begin_idx].x &&
+ vpath[this].y == vpath[begin_idx].y)
+ {
+ int j;
+
+ /* path is closed, render join to beginning */
+ render_seg (&forw, &n_forw, &n_forw_max,
+ &rev, &n_rev, &n_rev_max,
+ vpath, last, this, second,
+ join, half_lw, miter_limit, flatness);
+
+#ifdef VERBOSE
+ printf ("%% forw %d, rev %d\n", n_forw, n_rev);
+#endif
+ /* do forward path */
+ art_vpath_add_point (&result, &n_result, &n_result_max,
+ ART_MOVETO, forw[n_forw - 1].x,
+ forw[n_forw - 1].y);
+ for (j = 0; j < n_forw; j++)
+ art_vpath_add_point (&result, &n_result, &n_result_max,
+ ART_LINETO, forw[j].x,
+ forw[j].y);
+
+ /* do reverse path, reversed */
+ art_vpath_add_point (&result, &n_result, &n_result_max,
+ ART_MOVETO, rev[0].x,
+ rev[0].y);
+ for (j = n_rev - 1; j >= 0; j--)
+ art_vpath_add_point (&result, &n_result, &n_result_max,
+ ART_LINETO, rev[j].x,
+ rev[j].y);
+ }
+ else
+ {
+ /* path is open */
+ int j;
+
+ /* add to forw rather than result to ensure that
+ forw has at least one point. */
+ render_cap (&forw, &n_forw, &n_forw_max,
+ vpath, last, this,
+ cap, half_lw, flatness);
+ art_vpath_add_point (&result, &n_result, &n_result_max,
+ ART_MOVETO, forw[0].x,
+ forw[0].y);
+ for (j = 1; j < n_forw; j++)
+ art_vpath_add_point (&result, &n_result, &n_result_max,
+ ART_LINETO, forw[j].x,
+ forw[j].y);
+ for (j = n_rev - 1; j >= 0; j--)
+ art_vpath_add_point (&result, &n_result, &n_result_max,
+ ART_LINETO, rev[j].x,
+ rev[j].y);
+ render_cap (&result, &n_result, &n_result_max,
+ vpath, second, begin_idx,
+ cap, half_lw, flatness);
+ art_vpath_add_point (&result, &n_result, &n_result_max,
+ ART_LINETO, forw[0].x,
+ forw[0].y);
+ }
+ }
+ else
+ render_seg (&forw, &n_forw, &n_forw_max,
+ &rev, &n_rev, &n_rev_max,
+ vpath, last, this, next,
+ join, half_lw, miter_limit, flatness);
+ }
+ end_idx = next;
+ }
+
+ art_free (forw);
+ art_free (rev);
+#ifdef VERBOSE
+ printf ("%% n_result = %d\n", n_result);
+#endif
+ art_vpath_add_point (&result, &n_result, &n_result_max, ART_END, 0, 0);
+ return result;
+}
+
+#define noVERBOSE
+
+#ifdef VERBOSE
+
+#define XOFF 50
+#define YOFF 700
+
+static void
+print_ps_vpath (ArtVpath *vpath)
+{
+ int i;
+
+ for (i = 0; vpath[i].code != ART_END; i++)
+ {
+ switch (vpath[i].code)
+ {
+ case ART_MOVETO:
+ printf ("%g %g moveto\n", XOFF + vpath[i].x, YOFF - vpath[i].y);
+ break;
+ case ART_LINETO:
+ printf ("%g %g lineto\n", XOFF + vpath[i].x, YOFF - vpath[i].y);
+ break;
+ default:
+ break;
+ }
+ }
+ printf ("stroke showpage\n");
+}
+
+static void
+print_ps_svp (ArtSVP *vpath)
+{
+ int i, j;
+
+ printf ("%% begin\n");
+ for (i = 0; i < vpath->n_segs; i++)
+ {
+ printf ("%g setgray\n", vpath->segs[i].dir ? 0.7 : 0);
+ for (j = 0; j < vpath->segs[i].n_points; j++)
+ {
+ printf ("%g %g %s\n",
+ XOFF + vpath->segs[i].points[j].x,
+ YOFF - vpath->segs[i].points[j].y,
+ j ? "lineto" : "moveto");
+ }
+ printf ("stroke\n");
+ }
+
+ printf ("showpage\n");
+}
+#endif
+
+/* Render a vector path into a stroked outline.
+
+ Status of this routine:
+
+ Basic correctness: Only miter and bevel line joins are implemented,
+ and only butt line caps. Otherwise, seems to be fine.
+
+ Numerical stability: We cheat (adding random perturbation). Thus,
+ it seems very likely that no numerical stability problems will be
+ seen in practice.
+
+ Speed: Should be pretty good.
+
+ Precision: The perturbation fuzzes the coordinates slightly,
+ but not enough to be visible. */
+/**
+ * art_svp_vpath_stroke: Stroke a vector path.
+ * @vpath: #ArtVPath to stroke.
+ * @join: Join style.
+ * @cap: Cap style.
+ * @line_width: Width of stroke.
+ * @miter_limit: Miter limit.
+ * @flatness: Flatness.
+ *
+ * Computes an svp representing the stroked outline of @vpath. The
+ * width of the stroked line is @line_width.
+ *
+ * Lines are joined according to the @join rule. Possible values are
+ * ART_PATH_STROKE_JOIN_MITER (for mitered joins),
+ * ART_PATH_STROKE_JOIN_ROUND (for round joins), and
+ * ART_PATH_STROKE_JOIN_BEVEL (for bevelled joins). The mitered join
+ * is converted to a bevelled join if the miter would extend to a
+ * distance of more than @miter_limit * @line_width from the actual
+ * join point.
+ *
+ * If there are open subpaths, the ends of these subpaths are capped
+ * according to the @cap rule. Possible values are
+ * ART_PATH_STROKE_CAP_BUTT (squared cap, extends exactly to end
+ * point), ART_PATH_STROKE_CAP_ROUND (rounded half-circle centered at
+ * the end point), and ART_PATH_STROKE_CAP_SQUARE (squared cap,
+ * extending half @line_width past the end point).
+ *
+ * The @flatness parameter controls the accuracy of the rendering. It
+ * is most important for determining the number of points to use to
+ * approximate circular arcs for round lines and joins. In general, the
+ * resulting vector path will be within @flatness pixels of the "ideal"
+ * path containing actual circular arcs. I reserve the right to use
+ * the @flatness parameter to convert bevelled joins to miters for very
+ * small turn angles, as this would reduce the number of points in the
+ * resulting outline path.
+ *
+ * The resulting path is "clean" with respect to self-intersections, i.e.
+ * the winding number is 0 or 1 at each point.
+ *
+ * Return value: Resulting stroked outline in svp format.
+ **/
+ArtSVP *
+art_svp_vpath_stroke (ArtVpath *vpath,
+ ArtPathStrokeJoinType join,
+ ArtPathStrokeCapType cap,
+ double line_width,
+ double miter_limit,
+ double flatness)
+{
+#ifdef ART_USE_NEW_INTERSECTOR
+ ArtVpath *vpath_stroke;
+ ArtSVP *svp, *svp2;
+ ArtSvpWriter *swr;
+
+ vpath_stroke = art_svp_vpath_stroke_raw (vpath, join, cap,
+ line_width, miter_limit, flatness);
+#ifdef VERBOSE
+ print_ps_vpath (vpath_stroke);
+#endif
+ svp = art_svp_from_vpath (vpath_stroke);
+#ifdef VERBOSE
+ print_ps_svp (svp);
+#endif
+ art_free (vpath_stroke);
+
+ swr = art_svp_writer_rewind_new (ART_WIND_RULE_NONZERO);
+ art_svp_intersector (svp, swr);
+
+ svp2 = art_svp_writer_rewind_reap (swr);
+#ifdef VERBOSE
+ print_ps_svp (svp2);
+#endif
+ art_svp_free (svp);
+ return svp2;
+#else
+ ArtVpath *vpath_stroke, *vpath2;
+ ArtSVP *svp, *svp2, *svp3;
+
+ vpath_stroke = art_svp_vpath_stroke_raw (vpath, join, cap,
+ line_width, miter_limit, flatness);
+#ifdef VERBOSE
+ print_ps_vpath (vpath_stroke);
+#endif
+ vpath2 = art_vpath_perturb (vpath_stroke);
+#ifdef VERBOSE
+ print_ps_vpath (vpath2);
+#endif
+ art_free (vpath_stroke);
+ svp = art_svp_from_vpath (vpath2);
+#ifdef VERBOSE
+ print_ps_svp (svp);
+#endif
+ art_free (vpath2);
+ svp2 = art_svp_uncross (svp);
+#ifdef VERBOSE
+ print_ps_svp (svp2);
+#endif
+ art_svp_free (svp);
+ svp3 = art_svp_rewind_uncrossed (svp2, ART_WIND_RULE_NONZERO);
+#ifdef VERBOSE
+ print_ps_svp (svp3);
+#endif
+ art_svp_free (svp2);
+
+ return svp3;
+#endif
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_SVP_VPATH_STROKE_H__
+#define __ART_SVP_VPATH_STROKE_H__
+
+/* Sort vector paths into sorted vector paths. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef enum {
+ ART_PATH_STROKE_JOIN_MITER,
+ ART_PATH_STROKE_JOIN_ROUND,
+ ART_PATH_STROKE_JOIN_BEVEL
+} ArtPathStrokeJoinType;
+
+typedef enum {
+ ART_PATH_STROKE_CAP_BUTT,
+ ART_PATH_STROKE_CAP_ROUND,
+ ART_PATH_STROKE_CAP_SQUARE
+} ArtPathStrokeCapType;
+
+ArtSVP *
+art_svp_vpath_stroke (ArtVpath *vpath,
+ ArtPathStrokeJoinType join,
+ ArtPathStrokeCapType cap,
+ double line_width,
+ double miter_limit,
+ double flatness);
+
+/* This version may have winding numbers exceeding 1. */
+ArtVpath *
+art_svp_vpath_stroke_raw (ArtVpath *vpath,
+ ArtPathStrokeJoinType join,
+ ArtPathStrokeCapType cap,
+ double line_width,
+ double miter_limit,
+ double flatness);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_SVP_VPATH_STROKE_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998-2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Primitive intersection and winding number operations on sorted
+ vector paths.
+
+ These routines are internal to libart, used to construct operations
+ like intersection, union, and difference. */
+
+
+#include <stdio.h> /* for printf of debugging info */
+#include <string.h> /* for memcpy */
+#include <math.h>
+#include "art_misc.h"
+
+#include "art_rect.h"
+#include "art_svp.h"
+#include "art_svp_wind.h"
+
+#define noVERBOSE
+
+#define PT_EQ(p1,p2) ((p1).x == (p2).x && (p1).y == (p2).y)
+
+#define PT_CLOSE(p1,p2) (fabs ((p1).x - (p2).x) < 1e-6 && fabs ((p1).y - (p2).y) < 1e-6)
+
+/* return nonzero and set *p to the intersection point if the lines
+ z0-z1 and z2-z3 intersect each other. */
+static int
+intersect_lines (ArtPoint z0, ArtPoint z1, ArtPoint z2, ArtPoint z3,
+ ArtPoint *p)
+{
+ double a01, b01, c01;
+ double a23, b23, c23;
+ double d0, d1, d2, d3;
+ double det;
+
+ /* if the vectors share an endpoint, they don't intersect */
+ if (PT_EQ (z0, z2) || PT_EQ (z0, z3) || PT_EQ (z1, z2) || PT_EQ (z1, z3))
+ return 0;
+
+#if 0
+ if (PT_CLOSE (z0, z2) || PT_CLOSE (z0, z3) || PT_CLOSE (z1, z2) || PT_CLOSE (z1, z3))
+ return 0;
+#endif
+
+ /* find line equations ax + by + c = 0 */
+ a01 = z0.y - z1.y;
+ b01 = z1.x - z0.x;
+ c01 = -(z0.x * a01 + z0.y * b01);
+ /* = -((z0.y - z1.y) * z0.x + (z1.x - z0.x) * z0.y)
+ = (z1.x * z0.y - z1.y * z0.x) */
+
+ d2 = a01 * z2.x + b01 * z2.y + c01;
+ d3 = a01 * z3.x + b01 * z3.y + c01;
+ if ((d2 > 0) == (d3 > 0))
+ return 0;
+
+ a23 = z2.y - z3.y;
+ b23 = z3.x - z2.x;
+ c23 = -(z2.x * a23 + z2.y * b23);
+
+ d0 = a23 * z0.x + b23 * z0.y + c23;
+ d1 = a23 * z1.x + b23 * z1.y + c23;
+ if ((d0 > 0) == (d1 > 0))
+ return 0;
+
+ /* now we definitely know that the lines intersect */
+ /* solve the two linear equations ax + by + c = 0 */
+ det = 1.0 / (a01 * b23 - a23 * b01);
+ p->x = det * (c23 * b01 - c01 * b23);
+ p->y = det * (c01 * a23 - c23 * a01);
+
+ return 1;
+}
+
+#define EPSILON 1e-6
+
+static double
+trap_epsilon (double v)
+{
+ const double epsilon = EPSILON;
+
+ if (v < epsilon && v > -epsilon) return 0;
+ else return v;
+}
+
+/* Determine the order of line segments z0-z1 and z2-z3.
+ Return +1 if z2-z3 lies entirely to the right of z0-z1,
+ -1 if entirely to the left,
+ or 0 if overlap.
+
+ The case analysis in this function is quite ugly. The fact that it's
+ almost 200 lines long is ridiculous.
+
+ Ok, so here's the plan to cut it down:
+
+ First, do a bounding line comparison on the x coordinates. This is pretty
+ much the common case, and should go quickly. It also takes care of the
+ case where both lines are horizontal.
+
+ Then, do d0 and d1 computation, but only if a23 is nonzero.
+
+ Finally, do d2 and d3 computation, but only if a01 is nonzero.
+
+ Fall through to returning 0 (this will happen when both lines are
+ horizontal and they overlap).
+ */
+static int
+x_order (ArtPoint z0, ArtPoint z1, ArtPoint z2, ArtPoint z3)
+{
+ double a01, b01, c01;
+ double a23, b23, c23;
+ double d0, d1, d2, d3;
+
+ if (z0.y == z1.y)
+ {
+ if (z2.y == z3.y)
+ {
+ double x01min, x01max;
+ double x23min, x23max;
+
+ if (z0.x > z1.x)
+ {
+ x01min = z1.x;
+ x01max = z0.x;
+ }
+ else
+ {
+ x01min = z0.x;
+ x01max = z1.x;
+ }
+
+ if (z2.x > z3.x)
+ {
+ x23min = z3.x;
+ x23max = z2.x;
+ }
+ else
+ {
+ x23min = z2.x;
+ x23max = z3.x;
+ }
+
+ if (x23min >= x01max) return 1;
+ else if (x01min >= x23max) return -1;
+ else return 0;
+ }
+ else
+ {
+ /* z0-z1 is horizontal, z2-z3 isn't */
+ a23 = z2.y - z3.y;
+ b23 = z3.x - z2.x;
+ c23 = -(z2.x * a23 + z2.y * b23);
+
+ if (z3.y < z2.y)
+ {
+ a23 = -a23;
+ b23 = -b23;
+ c23 = -c23;
+ }
+
+ d0 = trap_epsilon (a23 * z0.x + b23 * z0.y + c23);
+ d1 = trap_epsilon (a23 * z1.x + b23 * z1.y + c23);
+
+ if (d0 > 0)
+ {
+ if (d1 >= 0) return 1;
+ else return 0;
+ }
+ else if (d0 == 0)
+ {
+ if (d1 > 0) return 1;
+ else if (d1 < 0) return -1;
+ else printf ("case 1 degenerate\n");
+ return 0;
+ }
+ else /* d0 < 0 */
+ {
+ if (d1 <= 0) return -1;
+ else return 0;
+ }
+ }
+ }
+ else if (z2.y == z3.y)
+ {
+ /* z2-z3 is horizontal, z0-z1 isn't */
+ a01 = z0.y - z1.y;
+ b01 = z1.x - z0.x;
+ c01 = -(z0.x * a01 + z0.y * b01);
+ /* = -((z0.y - z1.y) * z0.x + (z1.x - z0.x) * z0.y)
+ = (z1.x * z0.y - z1.y * z0.x) */
+
+ if (z1.y < z0.y)
+ {
+ a01 = -a01;
+ b01 = -b01;
+ c01 = -c01;
+ }
+
+ d2 = trap_epsilon (a01 * z2.x + b01 * z2.y + c01);
+ d3 = trap_epsilon (a01 * z3.x + b01 * z3.y + c01);
+
+ if (d2 > 0)
+ {
+ if (d3 >= 0) return -1;
+ else return 0;
+ }
+ else if (d2 == 0)
+ {
+ if (d3 > 0) return -1;
+ else if (d3 < 0) return 1;
+ else printf ("case 2 degenerate\n");
+ return 0;
+ }
+ else /* d2 < 0 */
+ {
+ if (d3 <= 0) return 1;
+ else return 0;
+ }
+ }
+
+ /* find line equations ax + by + c = 0 */
+ a01 = z0.y - z1.y;
+ b01 = z1.x - z0.x;
+ c01 = -(z0.x * a01 + z0.y * b01);
+ /* = -((z0.y - z1.y) * z0.x + (z1.x - z0.x) * z0.y)
+ = -(z1.x * z0.y - z1.y * z0.x) */
+
+ if (a01 > 0)
+ {
+ a01 = -a01;
+ b01 = -b01;
+ c01 = -c01;
+ }
+ /* so now, (a01, b01) points to the left, thus a01 * x + b01 * y + c01
+ is negative if the point lies to the right of the line */
+
+ d2 = trap_epsilon (a01 * z2.x + b01 * z2.y + c01);
+ d3 = trap_epsilon (a01 * z3.x + b01 * z3.y + c01);
+ if (d2 > 0)
+ {
+ if (d3 >= 0) return -1;
+ }
+ else if (d2 == 0)
+ {
+ if (d3 > 0) return -1;
+ else if (d3 < 0) return 1;
+ else
+ fprintf (stderr, "colinear!\n");
+ }
+ else /* d2 < 0 */
+ {
+ if (d3 <= 0) return 1;
+ }
+
+ a23 = z2.y - z3.y;
+ b23 = z3.x - z2.x;
+ c23 = -(z2.x * a23 + z2.y * b23);
+
+ if (a23 > 0)
+ {
+ a23 = -a23;
+ b23 = -b23;
+ c23 = -c23;
+ }
+ d0 = trap_epsilon (a23 * z0.x + b23 * z0.y + c23);
+ d1 = trap_epsilon (a23 * z1.x + b23 * z1.y + c23);
+ if (d0 > 0)
+ {
+ if (d1 >= 0) return 1;
+ }
+ else if (d0 == 0)
+ {
+ if (d1 > 0) return 1;
+ else if (d1 < 0) return -1;
+ else
+ fprintf (stderr, "colinear!\n");
+ }
+ else /* d0 < 0 */
+ {
+ if (d1 <= 0) return -1;
+ }
+
+ return 0;
+}
+
+/* similar to x_order, but to determine whether point z0 + epsilon lies to
+ the left of the line z2-z3 or to the right */
+static int
+x_order_2 (ArtPoint z0, ArtPoint z1, ArtPoint z2, ArtPoint z3)
+{
+ double a23, b23, c23;
+ double d0, d1;
+
+ a23 = z2.y - z3.y;
+ b23 = z3.x - z2.x;
+ c23 = -(z2.x * a23 + z2.y * b23);
+
+ if (a23 > 0)
+ {
+ a23 = -a23;
+ b23 = -b23;
+ c23 = -c23;
+ }
+
+ d0 = a23 * z0.x + b23 * z0.y + c23;
+
+ if (d0 > EPSILON)
+ return -1;
+ else if (d0 < -EPSILON)
+ return 1;
+
+ d1 = a23 * z1.x + b23 * z1.y + c23;
+ if (d1 > EPSILON)
+ return -1;
+ else if (d1 < -EPSILON)
+ return 1;
+
+ if (z0.x <= z2.x && z1.x <= z2.x && z0.x <= z3.x && z1.x <= z3.x)
+ return -1;
+ if (z0.x >= z2.x && z1.x >= z2.x && z0.x >= z3.x && z1.x >= z3.x)
+ return 1;
+
+ fprintf (stderr, "x_order_2: colinear!\n");
+ return 0;
+}
+
+#ifdef DEAD_CODE
+/* Traverse the vector path, keeping it in x-sorted order.
+
+ This routine doesn't actually do anything - it's just here for
+ explanatory purposes. */
+void
+traverse (ArtSVP *vp)
+{
+ int *active_segs;
+ int n_active_segs;
+ int *cursor;
+ int seg_idx;
+ double y;
+ int tmp1, tmp2;
+ int asi;
+ int i, j;
+
+ active_segs = art_new (int, vp->n_segs);
+ cursor = art_new (int, vp->n_segs);
+
+ n_active_segs = 0;
+ seg_idx = 0;
+ y = vp->segs[0].points[0].y;
+ while (seg_idx < vp->n_segs || n_active_segs > 0)
+ {
+ printf ("y = %g\n", y);
+ /* delete segments ending at y from active list */
+ for (i = 0; i < n_active_segs; i++)
+ {
+ asi = active_segs[i];
+ if (vp->segs[asi].n_points - 1 == cursor[asi] &&
+ vp->segs[asi].points[cursor[asi]].y == y)
+ {
+ printf ("deleting %d\n", asi);
+ n_active_segs--;
+ for (j = i; j < n_active_segs; j++)
+ active_segs[j] = active_segs[j + 1];
+ i--;
+ }
+ }
+
+ /* insert new segments into the active list */
+ while (seg_idx < vp->n_segs && y == vp->segs[seg_idx].points[0].y)
+ {
+ cursor[seg_idx] = 0;
+ printf ("inserting %d\n", seg_idx);
+ for (i = 0; i < n_active_segs; i++)
+ {
+ asi = active_segs[i];
+ if (x_order (vp->segs[asi].points[cursor[asi]],
+ vp->segs[asi].points[cursor[asi] + 1],
+ vp->segs[seg_idx].points[0],
+ vp->segs[seg_idx].points[1]) == -1)
+ break;
+ }
+ tmp1 = seg_idx;
+ for (j = i; j < n_active_segs; j++)
+ {
+ tmp2 = active_segs[j];
+ active_segs[j] = tmp1;
+ tmp1 = tmp2;
+ }
+ active_segs[n_active_segs] = tmp1;
+ n_active_segs++;
+ seg_idx++;
+ }
+
+ /* all active segs cross the y scanline (considering segs to be
+ closed on top and open on bottom) */
+ for (i = 0; i < n_active_segs; i++)
+ {
+ asi = active_segs[i];
+ printf ("%d (%g, %g) - (%g, %g) %s\n", asi,
+ vp->segs[asi].points[cursor[asi]].x,
+ vp->segs[asi].points[cursor[asi]].y,
+ vp->segs[asi].points[cursor[asi] + 1].x,
+ vp->segs[asi].points[cursor[asi] + 1].y,
+ vp->segs[asi].dir ? "v" : "^");
+ }
+
+ /* advance y to the next event */
+ if (n_active_segs == 0)
+ {
+ if (seg_idx < vp->n_segs)
+ y = vp->segs[seg_idx].points[0].y;
+ /* else we're done */
+ }
+ else
+ {
+ asi = active_segs[0];
+ y = vp->segs[asi].points[cursor[asi] + 1].y;
+ for (i = 1; i < n_active_segs; i++)
+ {
+ asi = active_segs[i];
+ if (y > vp->segs[asi].points[cursor[asi] + 1].y)
+ y = vp->segs[asi].points[cursor[asi] + 1].y;
+ }
+ if (seg_idx < vp->n_segs && y > vp->segs[seg_idx].points[0].y)
+ y = vp->segs[seg_idx].points[0].y;
+ }
+
+ /* advance cursors to reach new y */
+ for (i = 0; i < n_active_segs; i++)
+ {
+ asi = active_segs[i];
+ while (cursor[asi] < vp->segs[asi].n_points - 1 &&
+ y >= vp->segs[asi].points[cursor[asi] + 1].y)
+ cursor[asi]++;
+ }
+ printf ("\n");
+ }
+ art_free (cursor);
+ art_free (active_segs);
+}
+#endif
+
+/* I believe that the loop will always break with i=1.
+
+ I think I'll want to change this from a simple sorted list to a
+ modified stack. ips[*][0] will get its own data structure, and
+ ips[*] will in general only be allocated if there is an intersection.
+ Finally, the segment can be traced through the initial point
+ (formerly ips[*][0]), backwards through the stack, and finally
+ to cursor + 1.
+
+ This change should cut down on allocation bandwidth, and also
+ eliminate the iteration through n_ipl below.
+
+*/
+static void
+insert_ip (int seg_i, int *n_ips, int *n_ips_max, ArtPoint **ips, ArtPoint ip)
+{
+ int i;
+ ArtPoint tmp1, tmp2;
+ int n_ipl;
+ ArtPoint *ipl;
+
+ n_ipl = n_ips[seg_i]++;
+ if (n_ipl == n_ips_max[seg_i])
+ art_expand (ips[seg_i], ArtPoint, n_ips_max[seg_i]);
+ ipl = ips[seg_i];
+ for (i = 1; i < n_ipl; i++)
+ if (ipl[i].y > ip.y)
+ break;
+ tmp1 = ip;
+ for (; i <= n_ipl; i++)
+ {
+ tmp2 = ipl[i];
+ ipl[i] = tmp1;
+ tmp1 = tmp2;
+ }
+}
+
+/* test active segment (i - 1) against i for intersection, if
+ so, add intersection point to both ips lists. */
+static void
+intersect_neighbors (int i, int *active_segs,
+ int *n_ips, int *n_ips_max, ArtPoint **ips,
+ int *cursor, ArtSVP *vp)
+{
+ ArtPoint z0, z1, z2, z3;
+ int asi01, asi23;
+ ArtPoint ip;
+
+ asi01 = active_segs[i - 1];
+
+ z0 = ips[asi01][0];
+ if (n_ips[asi01] == 1)
+ z1 = vp->segs[asi01].points[cursor[asi01] + 1];
+ else
+ z1 = ips[asi01][1];
+
+ asi23 = active_segs[i];
+
+ z2 = ips[asi23][0];
+ if (n_ips[asi23] == 1)
+ z3 = vp->segs[asi23].points[cursor[asi23] + 1];
+ else
+ z3 = ips[asi23][1];
+
+ if (intersect_lines (z0, z1, z2, z3, &ip))
+ {
+#ifdef VERBOSE
+ printf ("new intersection point: (%g, %g)\n", ip.x, ip.y);
+#endif
+ insert_ip (asi01, n_ips, n_ips_max, ips, ip);
+ insert_ip (asi23, n_ips, n_ips_max, ips, ip);
+ }
+}
+
+/* Add a new point to a segment in the svp.
+
+ Here, we also check to make sure that the segments satisfy nocross.
+ However, this is only valuable for debugging, and could possibly be
+ removed.
+*/
+static void
+svp_add_point (ArtSVP *svp, int *n_points_max,
+ ArtPoint p, int *seg_map, int *active_segs, int n_active_segs,
+ int i)
+{
+ int asi, asi_left, asi_right;
+ int n_points, n_points_left, n_points_right;
+ ArtSVPSeg *seg;
+
+ asi = seg_map[active_segs[i]];
+ seg = &svp->segs[asi];
+ n_points = seg->n_points;
+ /* find out whether neighboring segments share a point */
+ if (i > 0)
+ {
+ asi_left = seg_map[active_segs[i - 1]];
+ n_points_left = svp->segs[asi_left].n_points;
+ if (n_points_left > 1 &&
+ PT_EQ (svp->segs[asi_left].points[n_points_left - 2],
+ svp->segs[asi].points[n_points - 1]))
+ {
+ /* ok, new vector shares a top point with segment to the left -
+ now, check that it satisfies ordering invariant */
+ if (x_order (svp->segs[asi_left].points[n_points_left - 2],
+ svp->segs[asi_left].points[n_points_left - 1],
+ svp->segs[asi].points[n_points - 1],
+ p) < 1)
+
+ {
+#ifdef VERBOSE
+ printf ("svp_add_point: cross on left!\n");
+#endif
+ }
+ }
+ }
+
+ if (i + 1 < n_active_segs)
+ {
+ asi_right = seg_map[active_segs[i + 1]];
+ n_points_right = svp->segs[asi_right].n_points;
+ if (n_points_right > 1 &&
+ PT_EQ (svp->segs[asi_right].points[n_points_right - 2],
+ svp->segs[asi].points[n_points - 1]))
+ {
+ /* ok, new vector shares a top point with segment to the right -
+ now, check that it satisfies ordering invariant */
+ if (x_order (svp->segs[asi_right].points[n_points_right - 2],
+ svp->segs[asi_right].points[n_points_right - 1],
+ svp->segs[asi].points[n_points - 1],
+ p) > -1)
+ {
+#ifdef VERBOSE
+ printf ("svp_add_point: cross on right!\n");
+#endif
+ }
+ }
+ }
+ if (n_points_max[asi] == n_points)
+ art_expand (seg->points, ArtPoint, n_points_max[asi]);
+ seg->points[n_points] = p;
+ if (p.x < seg->bbox.x0)
+ seg->bbox.x0 = p.x;
+ else if (p.x > seg->bbox.x1)
+ seg->bbox.x1 = p.x;
+ seg->bbox.y1 = p.y;
+ seg->n_points++;
+}
+
+#if 0
+/* find where the segment (currently at i) is supposed to go, and return
+ the target index - if equal to i, then there is no crossing problem.
+
+ "Where it is supposed to go" is defined as following:
+
+ Delete element i, re-insert at position target (bumping everything
+ target and greater to the right).
+ */
+static int
+find_crossing (int i, int *active_segs, int n_active_segs,
+ int *cursor, ArtPoint **ips, int *n_ips, ArtSVP *vp)
+{
+ int asi, asi_left, asi_right;
+ ArtPoint p0, p1;
+ ArtPoint p0l, p1l;
+ ArtPoint p0r, p1r;
+ int target;
+
+ asi = active_segs[i];
+ p0 = ips[asi][0];
+ if (n_ips[asi] == 1)
+ p1 = vp->segs[asi].points[cursor[asi] + 1];
+ else
+ p1 = ips[asi][1];
+
+ for (target = i; target > 0; target--)
+ {
+ asi_left = active_segs[target - 1];
+ p0l = ips[asi_left][0];
+ if (n_ips[asi_left] == 1)
+ p1l = vp->segs[asi_left].points[cursor[asi_left] + 1];
+ else
+ p1l = ips[asi_left][1];
+ if (!PT_EQ (p0, p0l))
+ break;
+
+#ifdef VERBOSE
+ printf ("point matches on left (%g, %g) - (%g, %g) x (%g, %g) - (%g, %g)!\n",
+ p0l.x, p0l.y, p1l.x, p1l.y, p0.x, p0.y, p1.x, p1.y);
+#endif
+ if (x_order (p0l, p1l, p0, p1) == 1)
+ break;
+
+#ifdef VERBOSE
+ printf ("scanning to the left (i=%d, target=%d)\n", i, target);
+#endif
+ }
+
+ if (target < i) return target;
+
+ for (; target < n_active_segs - 1; target++)
+ {
+ asi_right = active_segs[target + 1];
+ p0r = ips[asi_right][0];
+ if (n_ips[asi_right] == 1)
+ p1r = vp->segs[asi_right].points[cursor[asi_right] + 1];
+ else
+ p1r = ips[asi_right][1];
+ if (!PT_EQ (p0, p0r))
+ break;
+
+#ifdef VERBOSE
+ printf ("point matches on left (%g, %g) - (%g, %g) x (%g, %g) - (%g, %g)!\n",
+ p0.x, p0.y, p1.x, p1.y, p0r.x, p0r.y, p1r.x, p1r.y);
+#endif
+ if (x_order (p0r, p1r, p0, p1) == 1)
+ break;
+
+#ifdef VERBOSE
+ printf ("scanning to the right (i=%d, target=%d)\n", i, target);
+#endif
+ }
+
+ return target;
+}
+#endif
+
+/* This routine handles the case where the segment changes its position
+ in the active segment list. Generally, this will happen when the
+ segment (defined by i and cursor) shares a top point with a neighbor,
+ but breaks the ordering invariant.
+
+ Essentially, this routine sorts the lines [start..end), all of which
+ share a top point. This is implemented as your basic insertion sort.
+
+ This routine takes care of intersecting the appropriate neighbors,
+ as well.
+
+ A first argument of -1 immediately returns, which helps reduce special
+ casing in the main unwind routine.
+*/
+static void
+fix_crossing (int start, int end, int *active_segs, int n_active_segs,
+ int *cursor, ArtPoint **ips, int *n_ips, int *n_ips_max,
+ ArtSVP *vp, int *seg_map,
+ ArtSVP **p_new_vp, int *pn_segs_max,
+ int **pn_points_max)
+{
+ int i, j;
+ int target;
+ int asi, asj;
+ ArtPoint p0i, p1i;
+ ArtPoint p0j, p1j;
+ int swap = 0;
+#ifdef VERBOSE
+ int k;
+#endif
+ ArtPoint *pts;
+
+#ifdef VERBOSE
+ printf ("fix_crossing: [%d..%d)", start, end);
+ for (k = 0; k < n_active_segs; k++)
+ printf (" %d", active_segs[k]);
+ printf ("\n");
+#endif
+
+ if (start == -1)
+ return;
+
+ for (i = start + 1; i < end; i++)
+ {
+
+ asi = active_segs[i];
+ if (cursor[asi] < vp->segs[asi].n_points - 1) {
+ p0i = ips[asi][0];
+ if (n_ips[asi] == 1)
+ p1i = vp->segs[asi].points[cursor[asi] + 1];
+ else
+ p1i = ips[asi][1];
+
+ for (j = i - 1; j >= start; j--)
+ {
+ asj = active_segs[j];
+ if (cursor[asj] < vp->segs[asj].n_points - 1)
+ {
+ p0j = ips[asj][0];
+ if (n_ips[asj] == 1)
+ p1j = vp->segs[asj].points[cursor[asj] + 1];
+ else
+ p1j = ips[asj][1];
+
+ /* we _hope_ p0i = p0j */
+ if (x_order_2 (p0j, p1j, p0i, p1i) == -1)
+ break;
+ }
+ }
+
+ target = j + 1;
+ /* target is where active_seg[i] _should_ be in active_segs */
+
+ if (target != i)
+ {
+ swap = 1;
+
+#ifdef VERBOSE
+ printf ("fix_crossing: at %i should be %i\n", i, target);
+#endif
+
+ /* let's close off all relevant segments */
+ for (j = i; j >= target; j--)
+ {
+ asi = active_segs[j];
+ /* First conjunct: this isn't the last point in the original
+ segment.
+
+ Second conjunct: this isn't the first point in the new
+ segment (i.e. already broken).
+ */
+ if (cursor[asi] < vp->segs[asi].n_points - 1 &&
+ (*p_new_vp)->segs[seg_map[asi]].n_points != 1)
+ {
+ int seg_num;
+ /* so break here */
+#ifdef VERBOSE
+ printf ("closing off %d\n", j);
+#endif
+
+ pts = art_new (ArtPoint, 16);
+ pts[0] = ips[asi][0];
+ seg_num = art_svp_add_segment (p_new_vp, pn_segs_max,
+ pn_points_max,
+ 1, vp->segs[asi].dir,
+ pts,
+ NULL);
+ (*pn_points_max)[seg_num] = 16;
+ seg_map[asi] = seg_num;
+ }
+ }
+
+ /* now fix the ordering in active_segs */
+ asi = active_segs[i];
+ for (j = i; j > target; j--)
+ active_segs[j] = active_segs[j - 1];
+ active_segs[j] = asi;
+ }
+ }
+ }
+ if (swap && start > 0)
+ {
+ int as_start;
+
+ as_start = active_segs[start];
+ if (cursor[as_start] < vp->segs[as_start].n_points)
+ {
+#ifdef VERBOSE
+ printf ("checking intersection of %d, %d\n", start - 1, start);
+#endif
+ intersect_neighbors (start, active_segs,
+ n_ips, n_ips_max, ips,
+ cursor, vp);
+ }
+ }
+
+ if (swap && end < n_active_segs)
+ {
+ int as_end;
+
+ as_end = active_segs[end - 1];
+ if (cursor[as_end] < vp->segs[as_end].n_points)
+ {
+#ifdef VERBOSE
+ printf ("checking intersection of %d, %d\n", end - 1, end);
+#endif
+ intersect_neighbors (end, active_segs,
+ n_ips, n_ips_max, ips,
+ cursor, vp);
+ }
+ }
+ if (swap)
+ {
+#ifdef VERBOSE
+ printf ("fix_crossing return: [%d..%d)", start, end);
+ for (k = 0; k < n_active_segs; k++)
+ printf (" %d", active_segs[k]);
+ printf ("\n");
+#endif
+ }
+}
+
+/* Return a new sorted vector that covers the same area as the
+ argument, but which satisfies the nocross invariant.
+
+ Basically, this routine works by finding the intersection points,
+ and cutting the segments at those points.
+
+ Status of this routine:
+
+ Basic correctness: Seems ok.
+
+ Numerical stability: known problems in the case of points falling
+ on lines, and colinear lines. For actual use, randomly perturbing
+ the vertices is currently recommended.
+
+ Speed: pretty good, although a more efficient priority queue, as
+ well as bbox culling of potential intersections, are two
+ optimizations that could help.
+
+ Precision: pretty good, although the numerical stability problems
+ make this routine unsuitable for precise calculations of
+ differences.
+
+*/
+
+/* Here is a more detailed description of the algorithm. It follows
+ roughly the structure of traverse (above), but is obviously quite
+ a bit more complex.
+
+ Here are a few important data structures:
+
+ A new sorted vector path (new_svp).
+
+ For each (active) segment in the original, a list of intersection
+ points.
+
+ Of course, the original being traversed.
+
+ The following invariants hold (in addition to the invariants
+ of the traverse procedure).
+
+ The new sorted vector path lies entirely above the y scan line.
+
+ The new sorted vector path keeps the nocross invariant.
+
+ For each active segment, the y scan line crosses the line from the
+ first to the second of the intersection points (where the second
+ point is cursor + 1 if there is only one intersection point).
+
+ The list of intersection points + the (cursor + 1) point is kept
+ in nondecreasing y order.
+
+ Of the active segments, none of the lines from first to second
+ intersection point cross the 1st ip..2nd ip line of the left or
+ right neighbor. (However, such a line may cross further
+ intersection points of the neighbors, or segments past the
+ immediate neighbors).
+
+ Of the active segments, all lines from 1st ip..2nd ip are in
+ strictly increasing x_order (this is very similar to the invariant
+ of the traverse procedure, but is explicitly stated here in terms
+ of ips). (this basically says that nocross holds on the active
+ segments)
+
+ The combination of the new sorted vector path, the path through all
+ the intersection points to cursor + 1, and [cursor + 1, n_points)
+ covers the same area as the argument.
+
+ Another important data structure is mapping from original segment
+ number to new segment number.
+
+ The algorithm is perhaps best understood as advancing the cursors
+ while maintaining these invariants. Here's roughly how it's done.
+
+ When deleting segments from the active list, those segments are added
+ to the new sorted vector path. In addition, the neighbors may intersect
+ each other, so they are intersection tested (see below).
+
+ When inserting new segments, they are intersection tested against
+ their neighbors. The top point of the segment becomes the first
+ intersection point.
+
+ Advancing the cursor is just a bit different from the traverse
+ routine, as the cursor may advance through the intersection points
+ as well. Only when there is a single intersection point in the list
+ does the cursor advance in the original segment. In either case,
+ the new vector is intersection tested against both neighbors. It
+ also causes the vector over which the cursor is advancing to be
+ added to the new svp.
+
+ Two steps need further clarification:
+
+ Intersection testing: the 1st ip..2nd ip lines of the neighbors
+ are tested to see if they cross (using intersect_lines). If so,
+ then the intersection point is added to the ip list of both
+ segments, maintaining the invariant that the list of intersection
+ points is nondecreasing in y).
+
+ Adding vector to new svp: if the new vector shares a top x
+ coordinate with another vector, then it is checked to see whether
+ it is in order. If not, then both segments are "broken," and then
+ restarted. Note: in the case when both segments are in the same
+ order, they may simply be swapped without breaking.
+
+ For the time being, I'm going to put some of these operations into
+ subroutines. If it turns out to be a performance problem, I could
+ try to reorganize the traverse procedure so that each is only
+ called once, and inline them. But if it's not a performance
+ problem, I'll just keep it this way, because it will probably help
+ to make the code clearer, and I believe this code could use all the
+ clarity it can get. */
+/**
+ * art_svp_uncross: Resolve self-intersections of an svp.
+ * @vp: The original svp.
+ *
+ * Finds all the intersections within @vp, and constructs a new svp
+ * with new points added at these intersections.
+ *
+ * This routine needs to be redone from scratch with numerical robustness
+ * in mind. I'm working on it.
+ *
+ * Return value: The new svp.
+ **/
+ArtSVP *
+art_svp_uncross (ArtSVP *vp)
+{
+ int *active_segs;
+ int n_active_segs;
+ int *cursor;
+ int seg_idx;
+ double y;
+ int tmp1, tmp2;
+ int asi;
+ int i, j;
+ /* new data structures */
+ /* intersection points; invariant: *ips[i] is only allocated if
+ i is active */
+ int *n_ips, *n_ips_max;
+ ArtPoint **ips;
+ /* new sorted vector path */
+ int n_segs_max, seg_num;
+ ArtSVP *new_vp;
+ int *n_points_max;
+ /* mapping from argument to new segment numbers - again, only valid
+ if active */
+ int *seg_map;
+ double y_curs;
+ ArtPoint p_curs;
+ int first_share;
+ double share_x;
+ ArtPoint *pts;
+
+ n_segs_max = 16;
+ new_vp = (ArtSVP *)art_alloc (sizeof(ArtSVP) +
+ (n_segs_max - 1) * sizeof(ArtSVPSeg));
+ new_vp->n_segs = 0;
+
+ if (vp->n_segs == 0)
+ return new_vp;
+
+ active_segs = art_new (int, vp->n_segs);
+ cursor = art_new (int, vp->n_segs);
+
+ seg_map = art_new (int, vp->n_segs);
+ n_ips = art_new (int, vp->n_segs);
+ n_ips_max = art_new (int, vp->n_segs);
+ ips = art_new (ArtPoint *, vp->n_segs);
+
+ n_points_max = art_new (int, n_segs_max);
+
+ n_active_segs = 0;
+ seg_idx = 0;
+ y = vp->segs[0].points[0].y;
+ while (seg_idx < vp->n_segs || n_active_segs > 0)
+ {
+#ifdef VERBOSE
+ printf ("y = %g\n", y);
+#endif
+
+ /* maybe move deletions to end of loop (to avoid so much special
+ casing on the end of a segment)? */
+
+ /* delete segments ending at y from active list */
+ for (i = 0; i < n_active_segs; i++)
+ {
+ asi = active_segs[i];
+ if (vp->segs[asi].n_points - 1 == cursor[asi] &&
+ vp->segs[asi].points[cursor[asi]].y == y)
+ {
+ do
+ {
+#ifdef VERBOSE
+ printf ("deleting %d\n", asi);
+#endif
+ art_free (ips[asi]);
+ n_active_segs--;
+ for (j = i; j < n_active_segs; j++)
+ active_segs[j] = active_segs[j + 1];
+ if (i < n_active_segs)
+ asi = active_segs[i];
+ else
+ break;
+ }
+ while (vp->segs[asi].n_points - 1 == cursor[asi] &&
+ vp->segs[asi].points[cursor[asi]].y == y);
+
+ /* test intersection of neighbors */
+ if (i > 0 && i < n_active_segs)
+ intersect_neighbors (i, active_segs,
+ n_ips, n_ips_max, ips,
+ cursor, vp);
+
+ i--;
+ }
+ }
+
+ /* insert new segments into the active list */
+ while (seg_idx < vp->n_segs && y == vp->segs[seg_idx].points[0].y)
+ {
+#ifdef VERBOSE
+ printf ("inserting %d\n", seg_idx);
+#endif
+ cursor[seg_idx] = 0;
+ for (i = 0; i < n_active_segs; i++)
+ {
+ asi = active_segs[i];
+ if (x_order_2 (vp->segs[seg_idx].points[0],
+ vp->segs[seg_idx].points[1],
+ vp->segs[asi].points[cursor[asi]],
+ vp->segs[asi].points[cursor[asi] + 1]) == -1)
+ break;
+ }
+
+ /* Create and initialize the intersection points data structure */
+ n_ips[seg_idx] = 1;
+ n_ips_max[seg_idx] = 2;
+ ips[seg_idx] = art_new (ArtPoint, n_ips_max[seg_idx]);
+ ips[seg_idx][0] = vp->segs[seg_idx].points[0];
+
+ /* Start a new segment in the new vector path */
+ pts = art_new (ArtPoint, 16);
+ pts[0] = vp->segs[seg_idx].points[0];
+ seg_num = art_svp_add_segment (&new_vp, &n_segs_max,
+ &n_points_max,
+ 1, vp->segs[seg_idx].dir,
+ pts,
+ NULL);
+ n_points_max[seg_num] = 16;
+ seg_map[seg_idx] = seg_num;
+
+ tmp1 = seg_idx;
+ for (j = i; j < n_active_segs; j++)
+ {
+ tmp2 = active_segs[j];
+ active_segs[j] = tmp1;
+ tmp1 = tmp2;
+ }
+ active_segs[n_active_segs] = tmp1;
+ n_active_segs++;
+
+ if (i > 0)
+ intersect_neighbors (i, active_segs,
+ n_ips, n_ips_max, ips,
+ cursor, vp);
+
+ if (i + 1 < n_active_segs)
+ intersect_neighbors (i + 1, active_segs,
+ n_ips, n_ips_max, ips,
+ cursor, vp);
+
+ seg_idx++;
+ }
+
+ /* all active segs cross the y scanline (considering segs to be
+ closed on top and open on bottom) */
+#ifdef VERBOSE
+ for (i = 0; i < n_active_segs; i++)
+ {
+ asi = active_segs[i];
+ printf ("%d ", asi);
+ for (j = 0; j < n_ips[asi]; j++)
+ printf ("(%g, %g) - ",
+ ips[asi][j].x,
+ ips[asi][j].y);
+ printf ("(%g, %g) %s\n",
+ vp->segs[asi].points[cursor[asi] + 1].x,
+ vp->segs[asi].points[cursor[asi] + 1].y,
+ vp->segs[asi].dir ? "v" : "^");
+ }
+#endif
+
+ /* advance y to the next event
+ Note: this is quadratic. We'd probably get decent constant
+ factor speed improvement by caching the y_curs values. */
+ if (n_active_segs == 0)
+ {
+ if (seg_idx < vp->n_segs)
+ y = vp->segs[seg_idx].points[0].y;
+ /* else we're done */
+ }
+ else
+ {
+ asi = active_segs[0];
+ if (n_ips[asi] == 1)
+ y = vp->segs[asi].points[cursor[asi] + 1].y;
+ else
+ y = ips[asi][1].y;
+ for (i = 1; i < n_active_segs; i++)
+ {
+ asi = active_segs[i];
+ if (n_ips[asi] == 1)
+ y_curs = vp->segs[asi].points[cursor[asi] + 1].y;
+ else
+ y_curs = ips[asi][1].y;
+ if (y > y_curs)
+ y = y_curs;
+ }
+ if (seg_idx < vp->n_segs && y > vp->segs[seg_idx].points[0].y)
+ y = vp->segs[seg_idx].points[0].y;
+ }
+
+ first_share = -1;
+ share_x = 0; /* to avoid gcc warning, although share_x is never
+ used when first_share is -1 */
+ /* advance cursors to reach new y */
+ for (i = 0; i < n_active_segs; i++)
+ {
+ asi = active_segs[i];
+ if (n_ips[asi] == 1)
+ p_curs = vp->segs[asi].points[cursor[asi] + 1];
+ else
+ p_curs = ips[asi][1];
+ if (p_curs.y == y)
+ {
+ svp_add_point (new_vp, n_points_max,
+ p_curs, seg_map, active_segs, n_active_segs, i);
+
+ n_ips[asi]--;
+ for (j = 0; j < n_ips[asi]; j++)
+ ips[asi][j] = ips[asi][j + 1];
+
+ if (n_ips[asi] == 0)
+ {
+ ips[asi][0] = p_curs;
+ n_ips[asi] = 1;
+ cursor[asi]++;
+ }
+
+ if (first_share < 0 || p_curs.x != share_x)
+ {
+ /* this is where crossings are detected, and if
+ found, the active segments switched around. */
+
+ fix_crossing (first_share, i,
+ active_segs, n_active_segs,
+ cursor, ips, n_ips, n_ips_max, vp, seg_map,
+ &new_vp,
+ &n_segs_max, &n_points_max);
+
+ first_share = i;
+ share_x = p_curs.x;
+ }
+
+ if (cursor[asi] < vp->segs[asi].n_points - 1)
+ {
+
+ if (i > 0)
+ intersect_neighbors (i, active_segs,
+ n_ips, n_ips_max, ips,
+ cursor, vp);
+
+ if (i + 1 < n_active_segs)
+ intersect_neighbors (i + 1, active_segs,
+ n_ips, n_ips_max, ips,
+ cursor, vp);
+ }
+ }
+ else
+ {
+ /* not on a cursor point */
+ fix_crossing (first_share, i,
+ active_segs, n_active_segs,
+ cursor, ips, n_ips, n_ips_max, vp, seg_map,
+ &new_vp,
+ &n_segs_max, &n_points_max);
+ first_share = -1;
+ }
+ }
+
+ /* fix crossing on last shared group */
+ fix_crossing (first_share, i,
+ active_segs, n_active_segs,
+ cursor, ips, n_ips, n_ips_max, vp, seg_map,
+ &new_vp,
+ &n_segs_max, &n_points_max);
+
+#ifdef VERBOSE
+ printf ("\n");
+#endif
+ }
+
+ /* not necessary to sort, new segments only get added at y, which
+ increases monotonically */
+#if 0
+ qsort (&new_vp->segs, new_vp->n_segs, sizeof (svp_seg), svp_seg_compare);
+ {
+ int k;
+ for (k = 0; k < new_vp->n_segs - 1; k++)
+ {
+ printf ("(%g, %g) - (%g, %g) %s (%g, %g) - (%g, %g)\n",
+ new_vp->segs[k].points[0].x,
+ new_vp->segs[k].points[0].y,
+ new_vp->segs[k].points[1].x,
+ new_vp->segs[k].points[1].y,
+ svp_seg_compare (&new_vp->segs[k], &new_vp->segs[k + 1]) > 1 ? ">": "<",
+ new_vp->segs[k + 1].points[0].x,
+ new_vp->segs[k + 1].points[0].y,
+ new_vp->segs[k + 1].points[1].x,
+ new_vp->segs[k + 1].points[1].y);
+ }
+ }
+#endif
+
+ art_free (n_points_max);
+ art_free (seg_map);
+ art_free (n_ips_max);
+ art_free (n_ips);
+ art_free (ips);
+ art_free (cursor);
+ art_free (active_segs);
+
+ return new_vp;
+}
+
+#define noVERBOSE
+
+/* Rewind a svp satisfying the nocross invariant.
+
+ The winding number of a segment is defined as the winding number of
+ the points to the left while travelling in the direction of the
+ segment. Therefore it preincrements and postdecrements as a scan
+ line is traversed from left to right.
+
+ Status of this routine:
+
+ Basic correctness: Was ok in gfonted. However, this code does not
+ yet compute bboxes for the resulting svp segs.
+
+ Numerical stability: known problems in the case of horizontal
+ segments in polygons with any complexity. For actual use, randomly
+ perturbing the vertices is recommended.
+
+ Speed: good.
+
+ Precision: good, except that no attempt is made to remove "hair".
+ Doing random perturbation just makes matters worse.
+
+*/
+/**
+ * art_svp_rewind_uncrossed: Rewind an svp satisfying the nocross invariant.
+ * @vp: The original svp.
+ * @rule: The winding rule.
+ *
+ * Creates a new svp with winding number of 0 or 1 everywhere. The @rule
+ * argument specifies a rule for how winding numbers in the original
+ * @vp map to the winding numbers in the result.
+ *
+ * With @rule == ART_WIND_RULE_NONZERO, the resulting svp has a
+ * winding number of 1 where @vp has a nonzero winding number.
+ *
+ * With @rule == ART_WIND_RULE_INTERSECT, the resulting svp has a
+ * winding number of 1 where @vp has a winding number greater than
+ * 1. It is useful for computing intersections.
+ *
+ * With @rule == ART_WIND_RULE_ODDEVEN, the resulting svp has a
+ * winding number of 1 where @vp has an odd winding number. It is
+ * useful for implementing the even-odd winding rule of the
+ * PostScript imaging model.
+ *
+ * With @rule == ART_WIND_RULE_POSITIVE, the resulting svp has a
+ * winding number of 1 where @vp has a positive winding number. It is
+ * useful for implementing asymmetric difference.
+ *
+ * This routine needs to be redone from scratch with numerical robustness
+ * in mind. I'm working on it.
+ *
+ * Return value: The new svp.
+ **/
+ArtSVP *
+art_svp_rewind_uncrossed (ArtSVP *vp, ArtWindRule rule)
+{
+ int *active_segs;
+ int n_active_segs;
+ int *cursor;
+ int seg_idx;
+ double y;
+ int tmp1, tmp2;
+ int asi;
+ int i, j;
+
+ ArtSVP *new_vp;
+ int n_segs_max;
+ int *winding;
+ int left_wind;
+ int wind;
+ int keep, invert;
+
+#ifdef VERBOSE
+ print_svp (vp);
+#endif
+ n_segs_max = 16;
+ new_vp = (ArtSVP *)art_alloc (sizeof(ArtSVP) +
+ (n_segs_max - 1) * sizeof(ArtSVPSeg));
+ new_vp->n_segs = 0;
+
+ if (vp->n_segs == 0)
+ return new_vp;
+
+ winding = art_new (int, vp->n_segs);
+
+ active_segs = art_new (int, vp->n_segs);
+ cursor = art_new (int, vp->n_segs);
+
+ n_active_segs = 0;
+ seg_idx = 0;
+ y = vp->segs[0].points[0].y;
+ while (seg_idx < vp->n_segs || n_active_segs > 0)
+ {
+#ifdef VERBOSE
+ printf ("y = %g\n", y);
+#endif
+ /* delete segments ending at y from active list */
+ for (i = 0; i < n_active_segs; i++)
+ {
+ asi = active_segs[i];
+ if (vp->segs[asi].n_points - 1 == cursor[asi] &&
+ vp->segs[asi].points[cursor[asi]].y == y)
+ {
+#ifdef VERBOSE
+ printf ("deleting %d\n", asi);
+#endif
+ n_active_segs--;
+ for (j = i; j < n_active_segs; j++)
+ active_segs[j] = active_segs[j + 1];
+ i--;
+ }
+ }
+
+ /* insert new segments into the active list */
+ while (seg_idx < vp->n_segs && y == vp->segs[seg_idx].points[0].y)
+ {
+#ifdef VERBOSE
+ printf ("inserting %d\n", seg_idx);
+#endif
+ cursor[seg_idx] = 0;
+ for (i = 0; i < n_active_segs; i++)
+ {
+ asi = active_segs[i];
+ if (x_order_2 (vp->segs[seg_idx].points[0],
+ vp->segs[seg_idx].points[1],
+ vp->segs[asi].points[cursor[asi]],
+ vp->segs[asi].points[cursor[asi] + 1]) == -1)
+ break;
+ }
+
+ /* Determine winding number for this segment */
+ if (i == 0)
+ left_wind = 0;
+ else if (vp->segs[active_segs[i - 1]].dir)
+ left_wind = winding[active_segs[i - 1]];
+ else
+ left_wind = winding[active_segs[i - 1]] - 1;
+
+ if (vp->segs[seg_idx].dir)
+ wind = left_wind + 1;
+ else
+ wind = left_wind;
+
+ winding[seg_idx] = wind;
+
+ switch (rule)
+ {
+ case ART_WIND_RULE_NONZERO:
+ keep = (wind == 1 || wind == 0);
+ invert = (wind == 0);
+ break;
+ case ART_WIND_RULE_INTERSECT:
+ keep = (wind == 2);
+ invert = 0;
+ break;
+ case ART_WIND_RULE_ODDEVEN:
+ keep = 1;
+ invert = !(wind & 1);
+ break;
+ case ART_WIND_RULE_POSITIVE:
+ keep = (wind == 1);
+ invert = 0;
+ break;
+ default:
+ keep = 0;
+ invert = 0;
+ break;
+ }
+
+ if (keep)
+ {
+ ArtPoint *points, *new_points;
+ int n_points;
+ int new_dir;
+
+#ifdef VERBOSE
+ printf ("keeping segment %d\n", seg_idx);
+#endif
+ n_points = vp->segs[seg_idx].n_points;
+ points = vp->segs[seg_idx].points;
+ new_points = art_new (ArtPoint, n_points);
+ memcpy (new_points, points, n_points * sizeof (ArtPoint));
+ new_dir = vp->segs[seg_idx].dir ^ invert;
+ art_svp_add_segment (&new_vp, &n_segs_max,
+ NULL,
+ n_points, new_dir, new_points,
+ &vp->segs[seg_idx].bbox);
+ }
+
+ tmp1 = seg_idx;
+ for (j = i; j < n_active_segs; j++)
+ {
+ tmp2 = active_segs[j];
+ active_segs[j] = tmp1;
+ tmp1 = tmp2;
+ }
+ active_segs[n_active_segs] = tmp1;
+ n_active_segs++;
+ seg_idx++;
+ }
+
+#ifdef VERBOSE
+ /* all active segs cross the y scanline (considering segs to be
+ closed on top and open on bottom) */
+ for (i = 0; i < n_active_segs; i++)
+ {
+ asi = active_segs[i];
+ printf ("%d:%d (%g, %g) - (%g, %g) %s %d\n", asi,
+ cursor[asi],
+ vp->segs[asi].points[cursor[asi]].x,
+ vp->segs[asi].points[cursor[asi]].y,
+ vp->segs[asi].points[cursor[asi] + 1].x,
+ vp->segs[asi].points[cursor[asi] + 1].y,
+ vp->segs[asi].dir ? "v" : "^",
+ winding[asi]);
+ }
+#endif
+
+ /* advance y to the next event */
+ if (n_active_segs == 0)
+ {
+ if (seg_idx < vp->n_segs)
+ y = vp->segs[seg_idx].points[0].y;
+ /* else we're done */
+ }
+ else
+ {
+ asi = active_segs[0];
+ y = vp->segs[asi].points[cursor[asi] + 1].y;
+ for (i = 1; i < n_active_segs; i++)
+ {
+ asi = active_segs[i];
+ if (y > vp->segs[asi].points[cursor[asi] + 1].y)
+ y = vp->segs[asi].points[cursor[asi] + 1].y;
+ }
+ if (seg_idx < vp->n_segs && y > vp->segs[seg_idx].points[0].y)
+ y = vp->segs[seg_idx].points[0].y;
+ }
+
+ /* advance cursors to reach new y */
+ for (i = 0; i < n_active_segs; i++)
+ {
+ asi = active_segs[i];
+ while (cursor[asi] < vp->segs[asi].n_points - 1 &&
+ y >= vp->segs[asi].points[cursor[asi] + 1].y)
+ cursor[asi]++;
+ }
+#ifdef VERBOSE
+ printf ("\n");
+#endif
+ }
+ art_free (cursor);
+ art_free (active_segs);
+ art_free (winding);
+
+ return new_vp;
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_SVP_WIND_H__
+#define __ART_SVP_WIND_H__
+
+/* Primitive intersection and winding number operations on sorted
+ vector paths. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifndef ART_WIND_RULE_DEFINED
+#define ART_WIND_RULE_DEFINED
+typedef enum {
+ ART_WIND_RULE_NONZERO,
+ ART_WIND_RULE_INTERSECT,
+ ART_WIND_RULE_ODDEVEN,
+ ART_WIND_RULE_POSITIVE
+} ArtWindRule;
+#endif
+
+ArtSVP *
+art_svp_uncross (ArtSVP *vp);
+
+ArtSVP *
+art_svp_rewind_uncrossed (ArtSVP *vp, ArtWindRule rule);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_SVP_WIND_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include "art_misc.h"
+#include "art_uta.h"
+
+/**
+ * art_uta_new: Allocate a new uta.
+ * @x0: Left coordinate of uta.
+ * @y0: Top coordinate of uta.
+ * @x1: Right coordinate of uta.
+ * @y1: Bottom coordinate of uta.
+ *
+ * Allocates a new microtile array. The arguments are in units of
+ * tiles, not pixels.
+ *
+ * Returns: the newly allocated #ArtUta.
+ **/
+ArtUta *
+art_uta_new (int x0, int y0, int x1, int y1)
+{
+ ArtUta *uta;
+
+ uta = art_new (ArtUta, 1);
+ uta->x0 = x0;
+ uta->y0 = y0;
+ uta->width = x1 - x0;
+ uta->height = y1 - y0;
+
+ uta->utiles = art_new (ArtUtaBbox, uta->width * uta->height);
+
+ memset (uta->utiles, 0, uta->width * uta->height * sizeof(ArtUtaBbox));
+ return uta;
+ }
+
+/**
+ * art_uta_new_coords: Allocate a new uta, based on pixel coordinates.
+ * @x0: Left coordinate of uta.
+ * @y0: Top coordinate of uta.
+ * @x1: Right coordinate of uta.
+ * @y1: Bottom coordinate of uta.
+ *
+ * Allocates a new microtile array. The arguments are in pixels
+ *
+ * Returns: the newly allocated #ArtUta.
+ **/
+ArtUta *
+art_uta_new_coords (int x0, int y0, int x1, int y1)
+{
+ return art_uta_new (x0 >> ART_UTILE_SHIFT, y0 >> ART_UTILE_SHIFT,
+ 1 + (x1 >> ART_UTILE_SHIFT),
+ 1 + (y1 >> ART_UTILE_SHIFT));
+}
+
+/**
+ * art_uta_free: Free a uta.
+ * @uta: The uta to free.
+ *
+ * Frees the microtile array structure, including the actual microtile
+ * data.
+ **/
+void
+art_uta_free (ArtUta *uta)
+{
+ art_free (uta->utiles);
+ art_free (uta);
+}
+
+/* User to Aardvark! */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_UTA_H__
+#define __ART_UTA_H__
+
+/* Basic data structures and constructors for microtile arrays */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef art_u32 ArtUtaBbox;
+typedef struct _ArtUta ArtUta;
+
+#define ART_UTA_BBOX_CONS(x0, y0, x1, y1) (((x0) << 24) | ((y0) << 16) | \
+ ((x1) << 8) | (y1))
+
+#define ART_UTA_BBOX_X0(ub) ((ub) >> 24)
+#define ART_UTA_BBOX_Y0(ub) (((ub) >> 16) & 0xff)
+#define ART_UTA_BBOX_X1(ub) (((ub) >> 8) & 0xff)
+#define ART_UTA_BBOX_Y1(ub) ((ub) & 0xff)
+
+#define ART_UTILE_SHIFT 5
+#define ART_UTILE_SIZE (1 << ART_UTILE_SHIFT)
+
+/* Coordinates are shifted right by ART_UTILE_SHIFT wrt the real
+ coordinates. */
+struct _ArtUta {
+ int x0;
+ int y0;
+ int width;
+ int height;
+ ArtUtaBbox *utiles;
+};
+
+ArtUta *
+art_uta_new (int x0, int y0, int x1, int y1);
+
+ArtUta *
+art_uta_new_coords (int x0, int y0, int x1, int y1);
+
+void
+art_uta_free (ArtUta *uta);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_UTA_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998-2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include "art_misc.h"
+#include "art_uta.h"
+#include "art_uta_ops.h"
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+/**
+ * art_uta_union: Compute union of two uta's.
+ * @uta1: One uta.
+ * @uta2: The other uta.
+ *
+ * Computes the union of @uta1 and @uta2. The union is approximate,
+ * but coverage is guaranteed over all pixels included in either of
+ * the arguments, ie more pixels may be covered than the "exact"
+ * union.
+ *
+ * Note: this routine is used in the Gnome Canvas to accumulate the
+ * region that needs to be repainted. However, since it copies over
+ * the entire uta (which might be largish) even when the update may be
+ * small, it can be a performance bottleneck. There are two approaches
+ * to this problem, both of which are probably worthwhile. First, the
+ * generated uta's should always be limited to the visible window,
+ * thus guaranteeing that uta's never become large. Second, there
+ * should be a new, destructive union operation that only touches a
+ * small part of the uta when the update is small.
+ *
+ * Return value: The new union uta.
+ **/
+ArtUta *
+art_uta_union (ArtUta *uta1, ArtUta *uta2)
+{
+ ArtUta *uta;
+ int x0, y0, x1, y1;
+ int x, y;
+ int ix, ix1, ix2;
+ ArtUtaBbox bb, bb1, bb2;
+
+ x0 = MIN(uta1->x0, uta2->x0);
+ y0 = MIN(uta1->y0, uta2->y0);
+ x1 = MAX(uta1->x0 + uta1->width, uta2->x0 + uta2->width);
+ y1 = MAX(uta1->y0 + uta1->height, uta2->y0 + uta2->height);
+ uta = art_uta_new (x0, y0, x1, y1);
+
+ /* could move the first two if/else statements out of the loop */
+ ix = 0;
+ for (y = y0; y < y1; y++)
+ {
+ ix1 = (y - uta1->y0) * uta1->width + x0 - uta1->x0;
+ ix2 = (y - uta2->y0) * uta2->width + x0 - uta2->x0;
+ for (x = x0; x < x1; x++)
+ {
+ if (x < uta1->x0 || y < uta1->y0 ||
+ x >= uta1->x0 + uta1->width || y >= uta1->y0 + uta1->height)
+ bb1 = 0;
+ else
+ bb1 = uta1->utiles[ix1];
+
+ if (x < uta2->x0 || y < uta2->y0 ||
+ x >= uta2->x0 + uta2->width || y >= uta2->y0 + uta2->height)
+ bb2 = 0;
+ else
+ bb2 = uta2->utiles[ix2];
+
+ if (bb1 == 0)
+ bb = bb2;
+ else if (bb2 == 0)
+ bb = bb1;
+ else
+ bb = ART_UTA_BBOX_CONS(MIN(ART_UTA_BBOX_X0(bb1),
+ ART_UTA_BBOX_X0(bb2)),
+ MIN(ART_UTA_BBOX_Y0(bb1),
+ ART_UTA_BBOX_Y0(bb2)),
+ MAX(ART_UTA_BBOX_X1(bb1),
+ ART_UTA_BBOX_X1(bb2)),
+ MAX(ART_UTA_BBOX_Y1(bb1),
+ ART_UTA_BBOX_Y1(bb2)));
+ uta->utiles[ix] = bb;
+ ix++;
+ ix1++;
+ ix2++;
+ }
+ }
+ return uta;
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_UTA_OPS_H__
+#define __ART_UTA_OPS_H__
+
+/* Basic operations on microtile arrays */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+ArtUta *
+art_uta_union (ArtUta *uta1, ArtUta *uta2);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_UTA_OPS_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "art_misc.h"
+#include "art_uta.h"
+#include "art_rect.h"
+#include "art_uta_rect.h"
+
+/**
+ * art_uta_from_irect: Generate uta covering a rectangle.
+ * @bbox: The source rectangle.
+ *
+ * Generates a uta exactly covering @bbox. Please do not call this
+ * function with a @bbox with zero height or width.
+ *
+ * Return value: the new uta.
+ **/
+ArtUta *
+art_uta_from_irect (ArtIRect *bbox)
+{
+ ArtUta *uta;
+ ArtUtaBbox *utiles;
+ ArtUtaBbox bb;
+ int width, height;
+ int x, y;
+ int xf0, yf0, xf1, yf1;
+ int ix;
+
+ uta = art_new (ArtUta, 1);
+ uta->x0 = bbox->x0 >> ART_UTILE_SHIFT;
+ uta->y0 = bbox->y0 >> ART_UTILE_SHIFT;
+ width = ((bbox->x1 + ART_UTILE_SIZE - 1) >> ART_UTILE_SHIFT) - uta->x0;
+ height = ((bbox->y1 + ART_UTILE_SIZE - 1) >> ART_UTILE_SHIFT) - uta->y0;
+ utiles = art_new (ArtUtaBbox, width * height);
+
+ uta->width = width;
+ uta->height = height;
+ uta->utiles = utiles;
+
+ xf0 = bbox->x0 & (ART_UTILE_SIZE - 1);
+ yf0 = bbox->y0 & (ART_UTILE_SIZE - 1);
+ xf1 = ((bbox->x1 - 1) & (ART_UTILE_SIZE - 1)) + 1;
+ yf1 = ((bbox->y1 - 1) & (ART_UTILE_SIZE - 1)) + 1;
+ if (height == 1)
+ {
+ if (width == 1)
+ utiles[0] = ART_UTA_BBOX_CONS (xf0, yf0, xf1, yf1);
+ else
+ {
+ utiles[0] = ART_UTA_BBOX_CONS (xf0, yf0, ART_UTILE_SIZE, yf1);
+ bb = ART_UTA_BBOX_CONS (0, yf0, ART_UTILE_SIZE, yf1);
+ for (x = 1; x < width - 1; x++)
+ utiles[x] = bb;
+ utiles[x] = ART_UTA_BBOX_CONS (0, yf0, xf1, yf1);
+ }
+ }
+ else
+ {
+ if (width == 1)
+ {
+ utiles[0] = ART_UTA_BBOX_CONS (xf0, yf0, xf1, ART_UTILE_SIZE);
+ bb = ART_UTA_BBOX_CONS (xf0, 0, xf1, ART_UTILE_SIZE);
+ for (y = 1; y < height - 1; y++)
+ utiles[y] = bb;
+ utiles[y] = ART_UTA_BBOX_CONS (xf0, 0, xf1, yf1);
+ }
+ else
+ {
+ utiles[0] =
+ ART_UTA_BBOX_CONS (xf0, yf0, ART_UTILE_SIZE, ART_UTILE_SIZE);
+ bb = ART_UTA_BBOX_CONS (0, yf0, ART_UTILE_SIZE, ART_UTILE_SIZE);
+ for (x = 1; x < width - 1; x++)
+ utiles[x] = bb;
+ utiles[x] = ART_UTA_BBOX_CONS (0, yf0, xf1, ART_UTILE_SIZE);
+ ix = width;
+ for (y = 1; y < height - 1; y++)
+ {
+ utiles[ix++] =
+ ART_UTA_BBOX_CONS (xf0, 0, ART_UTILE_SIZE, ART_UTILE_SIZE);
+ bb = ART_UTA_BBOX_CONS (0, 0, ART_UTILE_SIZE, ART_UTILE_SIZE);
+ for (x = 1; x < width - 1; x++)
+ utiles[ix++] = bb;
+ utiles[ix++] = ART_UTA_BBOX_CONS (0, 0, xf1, ART_UTILE_SIZE);
+ }
+ utiles[ix++] = ART_UTA_BBOX_CONS (xf0, 0, ART_UTILE_SIZE, yf1);
+ bb = ART_UTA_BBOX_CONS (0, 0, ART_UTILE_SIZE, yf1);
+ for (x = 1; x < width - 1; x++)
+ utiles[ix++] = bb;
+ utiles[ix++] = ART_UTA_BBOX_CONS (0, 0, xf1, yf1);
+ }
+ }
+ return uta;
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_UTA_RECT_H__
+#define __ART_UTA_RECT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+ArtUta *
+art_uta_from_irect (ArtIRect *bbox);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_UTA_RECT_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998-2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* LGPL Copyright 1998 Raph Levien <raph@acm.org> */
+
+#include "art_misc.h"
+#include "art_vpath.h"
+#include "art_uta.h"
+#include "art_uta_vpath.h"
+#include "art_svp.h"
+#include "art_uta_svp.h"
+#include "art_vpath_svp.h"
+
+/**
+ * art_uta_from_svp: Generate uta covering an svp.
+ * @svp: The source svp.
+ *
+ * Generates a uta covering @svp. The resulting uta is of course
+ * approximate, ie it may cover more pixels than covered by @svp.
+ *
+ * Note: I will want to replace this with a more direct
+ * implementation. But this gets the api in place.
+ *
+ * Return value: the new uta.
+ **/
+ArtUta *
+art_uta_from_svp (const ArtSVP *svp)
+{
+ ArtVpath *vpath;
+ ArtUta *uta;
+
+ vpath = art_vpath_from_svp (svp);
+ uta = art_uta_from_vpath (vpath);
+ art_free (vpath);
+ return uta;
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_UTA_SVP_H__
+#define __ART_UTA_SVP_H__
+
+/* Basic data structures and constructors for microtile arrays */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+ArtUta *
+art_uta_from_svp (const ArtSVP *svp);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_UTA_SVP_H__ */
+
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998-2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* LGPL Copyright 1998 Raph Levien <raph@acm.org> */
+
+#include <math.h>
+
+#include "art_misc.h"
+#include "art_vpath.h"
+#include "art_uta.h"
+#include "art_uta_vpath.h"
+
+#ifndef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif /* MAX */
+
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif /* MIN */
+
+/**
+ * art_uta_add_line: Add a line to the uta.
+ * @uta: The uta to modify.
+ * @x0: X coordinate of line start point.
+ * @y0: Y coordinate of line start point.
+ * @x1: X coordinate of line end point.
+ * @y1: Y coordinate of line end point.
+ * @rbuf: Buffer containing first difference of winding number.
+ * @rbuf_rowstride: Rowstride of @rbuf.
+ *
+ * Add the line (@x0, @y0) - (@x1, @y1) to @uta, and also update the
+ * winding number buffer used for rendering the interior. @rbuf
+ * contains the first partial difference (in the X direction) of the
+ * winding number, measured in grid cells. Thus, each time that a line
+ * crosses a horizontal uta grid line, an entry of @rbuf is
+ * incremented if @y1 > @y0, decremented otherwise.
+ *
+ * Note that edge handling is fairly delicate. Please rtfs for
+ * details.
+ **/
+void
+art_uta_add_line (ArtUta *uta, double x0, double y0, double x1, double y1,
+ int *rbuf, int rbuf_rowstride)
+{
+ int xmin, ymin;
+ double xmax, ymax;
+ int xmaxf, ymaxf;
+ int xmaxc, ymaxc;
+ int xt0, yt0;
+ int xt1, yt1;
+ int xf0, yf0;
+ int xf1, yf1;
+ int ix, ix1;
+ ArtUtaBbox bb;
+
+ xmin = floor (MIN(x0, x1));
+ xmax = MAX(x0, x1);
+ xmaxf = floor (xmax);
+ xmaxc = ceil (xmax);
+ ymin = floor (MIN(y0, y1));
+ ymax = MAX(y0, y1);
+ ymaxf = floor (ymax);
+ ymaxc = ceil (ymax);
+ xt0 = (xmin >> ART_UTILE_SHIFT) - uta->x0;
+ yt0 = (ymin >> ART_UTILE_SHIFT) - uta->y0;
+ xt1 = (xmaxf >> ART_UTILE_SHIFT) - uta->x0;
+ yt1 = (ymaxf >> ART_UTILE_SHIFT) - uta->y0;
+ if (xt0 == xt1 && yt0 == yt1)
+ {
+ /* entirely inside a microtile, this is easy! */
+ xf0 = xmin & (ART_UTILE_SIZE - 1);
+ yf0 = ymin & (ART_UTILE_SIZE - 1);
+ xf1 = (xmaxf & (ART_UTILE_SIZE - 1)) + xmaxc - xmaxf;
+ yf1 = (ymaxf & (ART_UTILE_SIZE - 1)) + ymaxc - ymaxf;
+
+ ix = yt0 * uta->width + xt0;
+ bb = uta->utiles[ix];
+ if (bb == 0)
+ bb = ART_UTA_BBOX_CONS(xf0, yf0, xf1, yf1);
+ else
+ bb = ART_UTA_BBOX_CONS(MIN(ART_UTA_BBOX_X0(bb), xf0),
+ MIN(ART_UTA_BBOX_Y0(bb), yf0),
+ MAX(ART_UTA_BBOX_X1(bb), xf1),
+ MAX(ART_UTA_BBOX_Y1(bb), yf1));
+ uta->utiles[ix] = bb;
+ }
+ else
+ {
+ double dx, dy;
+ int sx, sy;
+
+ dx = x1 - x0;
+ dy = y1 - y0;
+ sx = dx > 0 ? 1 : dx < 0 ? -1 : 0;
+ sy = dy > 0 ? 1 : dy < 0 ? -1 : 0;
+ if (ymin == ymaxf)
+ {
+ /* special case horizontal (dx/dy slope would be infinite) */
+ xf0 = xmin & (ART_UTILE_SIZE - 1);
+ yf0 = ymin & (ART_UTILE_SIZE - 1);
+ xf1 = (xmaxf & (ART_UTILE_SIZE - 1)) + xmaxc - xmaxf;
+ yf1 = (ymaxf & (ART_UTILE_SIZE - 1)) + ymaxc - ymaxf;
+
+ ix = yt0 * uta->width + xt0;
+ ix1 = yt0 * uta->width + xt1;
+ while (ix != ix1)
+ {
+ bb = uta->utiles[ix];
+ if (bb == 0)
+ bb = ART_UTA_BBOX_CONS(xf0, yf0, ART_UTILE_SIZE, yf1);
+ else
+ bb = ART_UTA_BBOX_CONS(MIN(ART_UTA_BBOX_X0(bb), xf0),
+ MIN(ART_UTA_BBOX_Y0(bb), yf0),
+ ART_UTILE_SIZE,
+ MAX(ART_UTA_BBOX_Y1(bb), yf1));
+ uta->utiles[ix] = bb;
+ xf0 = 0;
+ ix++;
+ }
+ bb = uta->utiles[ix];
+ if (bb == 0)
+ bb = ART_UTA_BBOX_CONS(0, yf0, xf1, yf1);
+ else
+ bb = ART_UTA_BBOX_CONS(0,
+ MIN(ART_UTA_BBOX_Y0(bb), yf0),
+ MAX(ART_UTA_BBOX_X1(bb), xf1),
+ MAX(ART_UTA_BBOX_Y1(bb), yf1));
+ uta->utiles[ix] = bb;
+ }
+ else
+ {
+ /* Do a Bresenham-style traversal of the line */
+ double dx_dy;
+ double x, y;
+ double xn, yn;
+
+ /* normalize coordinates to uta origin */
+ x0 -= uta->x0 << ART_UTILE_SHIFT;
+ y0 -= uta->y0 << ART_UTILE_SHIFT;
+ x1 -= uta->x0 << ART_UTILE_SHIFT;
+ y1 -= uta->y0 << ART_UTILE_SHIFT;
+ if (dy < 0)
+ {
+ double tmp;
+
+ tmp = x0;
+ x0 = x1;
+ x1 = tmp;
+
+ tmp = y0;
+ y0 = y1;
+ y1 = tmp;
+
+ dx = -dx;
+ sx = -sx;
+ dy = -dy;
+ /* we leave sy alone, because it would always be 1,
+ and we need it for the rbuf stuff. */
+ }
+ xt0 = ((int)floor (x0) >> ART_UTILE_SHIFT);
+ xt1 = ((int)floor (x1) >> ART_UTILE_SHIFT);
+ /* now [xy]0 is above [xy]1 */
+
+ ix = yt0 * uta->width + xt0;
+ ix1 = yt1 * uta->width + xt1;
+#ifdef VERBOSE
+ printf ("%% ix = %d,%d; ix1 = %d,%d\n", xt0, yt0, xt1, yt1);
+#endif
+
+ dx_dy = dx / dy;
+ x = x0;
+ y = y0;
+ while (ix != ix1)
+ {
+ int dix;
+
+ /* figure out whether next crossing is horizontal or vertical */
+#ifdef VERBOSE
+ printf ("%% %d,%d\n", xt0, yt0);
+#endif
+ yn = (yt0 + 1) << ART_UTILE_SHIFT;
+ xn = x0 + dx_dy * (yn - y0);
+ if (xt0 != (int)floor (xn) >> ART_UTILE_SHIFT)
+ {
+ /* horizontal crossing */
+ xt0 += sx;
+ dix = sx;
+ if (dx > 0)
+ {
+ xn = xt0 << ART_UTILE_SHIFT;
+ yn = y0 + (xn - x0) / dx_dy;
+
+ xf0 = (int)floor (x) & (ART_UTILE_SIZE - 1);
+ xf1 = ART_UTILE_SIZE;
+ }
+ else
+ {
+ xn = (xt0 + 1) << ART_UTILE_SHIFT;
+ yn = y0 + (xn - x0) / dx_dy;
+
+ xf0 = 0;
+ xmaxc = (int)ceil (x);
+ xf1 = xmaxc - ((xt0 + 1) << ART_UTILE_SHIFT);
+ }
+ ymaxf = (int)floor (yn);
+ ymaxc = (int)ceil (yn);
+ yf1 = (ymaxf & (ART_UTILE_SIZE - 1)) + ymaxc - ymaxf;
+ }
+ else
+ {
+ /* vertical crossing */
+ dix = uta->width;
+ xf0 = (int)floor (MIN(x, xn)) & (ART_UTILE_SIZE - 1);
+ xmax = MAX(x, xn);
+ xmaxc = (int)ceil (xmax);
+ xf1 = xmaxc - (xt0 << ART_UTILE_SHIFT);
+ yf1 = ART_UTILE_SIZE;
+
+ if (rbuf != NULL)
+ rbuf[yt0 * rbuf_rowstride + xt0] += sy;
+
+ yt0++;
+ }
+ yf0 = (int)floor (y) & (ART_UTILE_SIZE - 1);
+ bb = uta->utiles[ix];
+ if (bb == 0)
+ bb = ART_UTA_BBOX_CONS(xf0, yf0, xf1, yf1);
+ else
+ bb = ART_UTA_BBOX_CONS(MIN(ART_UTA_BBOX_X0(bb), xf0),
+ MIN(ART_UTA_BBOX_Y0(bb), yf0),
+ MAX(ART_UTA_BBOX_X1(bb), xf1),
+ MAX(ART_UTA_BBOX_Y1(bb), yf1));
+ uta->utiles[ix] = bb;
+
+ x = xn;
+ y = yn;
+ ix += dix;
+ }
+ xmax = MAX(x, x1);
+ xmaxc = ceil (xmax);
+ ymaxc = ceil (y1);
+ xf0 = (int)floor (MIN(x1, x)) & (ART_UTILE_SIZE - 1);
+ yf0 = (int)floor (y) & (ART_UTILE_SIZE - 1);
+ xf1 = xmaxc - (xt0 << ART_UTILE_SHIFT);
+ yf1 = ymaxc - (yt0 << ART_UTILE_SHIFT);
+ bb = uta->utiles[ix];
+ if (bb == 0)
+ bb = ART_UTA_BBOX_CONS(xf0, yf0, xf1, yf1);
+ else
+ bb = ART_UTA_BBOX_CONS(MIN(ART_UTA_BBOX_X0(bb), xf0),
+ MIN(ART_UTA_BBOX_Y0(bb), yf0),
+ MAX(ART_UTA_BBOX_X1(bb), xf1),
+ MAX(ART_UTA_BBOX_Y1(bb), yf1));
+ uta->utiles[ix] = bb;
+ }
+ }
+}
+
+/**
+ * art_uta_from_vpath: Generate uta covering a vpath.
+ * @vec: The source vpath.
+ *
+ * Generates a uta covering @vec. The resulting uta is of course
+ * approximate, ie it may cover more pixels than covered by @vec.
+ *
+ * Return value: the new uta.
+ **/
+ArtUta *
+art_uta_from_vpath (const ArtVpath *vec)
+{
+ ArtUta *uta;
+ ArtIRect bbox;
+ int *rbuf;
+ int i;
+ double x, y;
+ int sum;
+ int xt, yt;
+ ArtUtaBbox *utiles;
+ ArtUtaBbox bb;
+ int width;
+ int height;
+ int ix;
+
+ art_vpath_bbox_irect (vec, &bbox);
+
+ uta = art_uta_new_coords (bbox.x0, bbox.y0, bbox.x1, bbox.y1);
+
+ width = uta->width;
+ height = uta->height;
+ utiles = uta->utiles;
+
+ rbuf = art_new (int, width * height);
+ for (i = 0; i < width * height; i++)
+ rbuf[i] = 0;
+
+ x = 0;
+ y = 0;
+ for (i = 0; vec[i].code != ART_END; i++)
+ {
+ switch (vec[i].code)
+ {
+ case ART_MOVETO:
+ x = vec[i].x;
+ y = vec[i].y;
+ break;
+ case ART_LINETO:
+ art_uta_add_line (uta, vec[i].x, vec[i].y, x, y, rbuf, width);
+ x = vec[i].x;
+ y = vec[i].y;
+ break;
+ default:
+ /* this shouldn't happen */
+ break;
+ }
+ }
+
+ /* now add in the filling from rbuf */
+ ix = 0;
+ for (yt = 0; yt < height; yt++)
+ {
+ sum = 0;
+ for (xt = 0; xt < width; xt++)
+ {
+ sum += rbuf[ix];
+ /* Nonzero winding rule - others are possible, but hardly
+ worth it. */
+ if (sum != 0)
+ {
+ bb = utiles[ix];
+ bb &= 0xffff0000;
+ bb |= (ART_UTILE_SIZE << 8) | ART_UTILE_SIZE;
+ utiles[ix] = bb;
+ if (xt != width - 1)
+ {
+ bb = utiles[ix + 1];
+ bb &= 0xffff00;
+ bb |= ART_UTILE_SIZE;
+ utiles[ix + 1] = bb;
+ }
+ if (yt != height - 1)
+ {
+ bb = utiles[ix + width];
+ bb &= 0xff0000ff;
+ bb |= ART_UTILE_SIZE << 8;
+ utiles[ix + width] = bb;
+ if (xt != width - 1)
+ {
+ utiles[ix + width + 1] &= 0xffff;
+ }
+ }
+ }
+ ix++;
+ }
+ }
+
+ art_free (rbuf);
+
+ return uta;
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_UTA_VPATH_H__
+#define __ART_UTA_VPATH_H__
+
+/* Basic data structures and constructors for microtile arrays */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+ArtUta *
+art_uta_from_vpath (const ArtVpath *vec);
+
+/* This is a private function: */
+void
+art_uta_add_line (ArtUta *uta, double x0, double y0, double x1, double y1,
+ int *rbuf, int rbuf_rowstride);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_UTA_VPATH_H__ */
+
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998-2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Basic constructors and operations for vector paths */
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "art_misc.h"
+
+#include "art_rect.h"
+#include "art_vpath.h"
+
+/**
+ * art_vpath_add_point: Add point to vpath.
+ * @p_vpath: Where the pointer to the #ArtVpath structure is stored.
+ * @pn_points: Pointer to the number of points in *@p_vpath.
+ * @pn_points_max: Pointer to the number of points allocated.
+ * @code: The pathcode for the new point.
+ * @x: The X coordinate of the new point.
+ * @y: The Y coordinate of the new point.
+ *
+ * Adds a new point to *@p_vpath, reallocating and updating *@p_vpath
+ * and *@pn_points_max as necessary. *@pn_points is incremented.
+ *
+ * This routine always adds the point after all points already in the
+ * vpath. Thus, it should be called in the order the points are
+ * desired.
+ **/
+void
+art_vpath_add_point (ArtVpath **p_vpath, int *pn_points, int *pn_points_max,
+ ArtPathcode code, double x, double y)
+{
+ int i;
+
+ i = (*pn_points)++;
+ if (i == *pn_points_max)
+ art_expand (*p_vpath, ArtVpath, *pn_points_max);
+ (*p_vpath)[i].code = code;
+ (*p_vpath)[i].x = x;
+ (*p_vpath)[i].y = y;
+}
+
+/* number of steps should really depend on radius. */
+#define CIRCLE_STEPS 128
+
+/**
+ * art_vpath_new_circle: Create a new circle.
+ * @x: X coordinate of center.
+ * @y: Y coordinate of center.
+ * @r: radius.
+ *
+ * Creates a new polygon closely approximating a circle with center
+ * (@x, @y) and radius @r. Currently, the number of points used in the
+ * approximation is fixed, but that will probably change.
+ *
+ * Return value: The newly created #ArtVpath.
+ **/
+ArtVpath *
+art_vpath_new_circle (double x, double y, double r)
+{
+ int i;
+ ArtVpath *vec;
+ double theta;
+
+ vec = art_new (ArtVpath, CIRCLE_STEPS + 2);
+
+ for (i = 0; i < CIRCLE_STEPS + 1; i++)
+ {
+ vec[i].code = i ? ART_LINETO : ART_MOVETO;
+ theta = (i & (CIRCLE_STEPS - 1)) * (M_PI * 2.0 / CIRCLE_STEPS);
+ vec[i].x = x + r * cos (theta);
+ vec[i].y = y - r * sin (theta);
+ }
+ vec[i].code = ART_END;
+
+ return vec;
+}
+
+/**
+ * art_vpath_affine_transform: Affine transform a vpath.
+ * @src: Source vpath to transform.
+ * @matrix: Affine transform.
+ *
+ * Computes the affine transform of the vpath, using @matrix as the
+ * transform. @matrix is stored in the same format as PostScript, ie.
+ * x' = @matrix[0] * x + @matrix[2] * y + @matrix[4]
+ * y' = @matrix[1] * x + @matrix[3] * y + @matrix[5]
+ *
+ * Return value: the newly allocated vpath resulting from the transform.
+**/
+ArtVpath *
+art_vpath_affine_transform (const ArtVpath *src, const double matrix[6])
+{
+ int i;
+ int size;
+ ArtVpath *new;
+ double x, y;
+
+ for (i = 0; src[i].code != ART_END; i++);
+ size = i;
+
+ new = art_new (ArtVpath, size + 1);
+
+ for (i = 0; i < size; i++)
+ {
+ new[i].code = src[i].code;
+ x = src[i].x;
+ y = src[i].y;
+ new[i].x = matrix[0] * x + matrix[2] * y + matrix[4];
+ new[i].y = matrix[1] * x + matrix[3] * y + matrix[5];
+ }
+ new[i].code = ART_END;
+
+ return new;
+}
+
+/**
+ * art_vpath_bbox_drect: Determine bounding box of vpath.
+ * @vec: Source vpath.
+ * @drect: Where to store bounding box.
+ *
+ * Determines bounding box of @vec, and stores it in @drect.
+ **/
+void
+art_vpath_bbox_drect (const ArtVpath *vec, ArtDRect *drect)
+{
+ int i;
+ double x0, y0, x1, y1;
+
+ if (vec[0].code == ART_END)
+ {
+ x0 = y0 = x1 = y1 = 0;
+ }
+ else
+ {
+ x0 = x1 = vec[0].x;
+ y0 = y1 = vec[0].y;
+ for (i = 1; vec[i].code != ART_END; i++)
+ {
+ if (vec[i].x < x0) x0 = vec[i].x;
+ if (vec[i].x > x1) x1 = vec[i].x;
+ if (vec[i].y < y0) y0 = vec[i].y;
+ if (vec[i].y > y1) y1 = vec[i].y;
+ }
+ }
+ drect->x0 = x0;
+ drect->y0 = y0;
+ drect->x1 = x1;
+ drect->y1 = y1;
+}
+
+/**
+ * art_vpath_bbox_irect: Determine integer bounding box of vpath.
+ * @vec: Source vpath.
+ * idrect: Where to store bounding box.
+ *
+ * Determines integer bounding box of @vec, and stores it in @irect.
+ **/
+void
+art_vpath_bbox_irect (const ArtVpath *vec, ArtIRect *irect)
+{
+ ArtDRect drect;
+
+ art_vpath_bbox_drect (vec, &drect);
+ art_drect_to_irect (irect, &drect);
+}
+
+#define PERTURBATION 2e-3
+
+/**
+ * art_vpath_perturb: Perturb each point in vpath by small random amount.
+ * @src: Source vpath.
+ *
+ * Perturbs each of the points by a small random amount. This is
+ * helpful for cheating in cases when algorithms haven't attained
+ * numerical stability yet.
+ *
+ * Return value: Newly allocated vpath containing perturbed @src.
+ **/
+ArtVpath *
+art_vpath_perturb (ArtVpath *src)
+{
+ int i;
+ int size;
+ ArtVpath *new;
+ double x, y;
+ double x_start, y_start;
+ int open;
+
+ for (i = 0; src[i].code != ART_END; i++);
+ size = i;
+
+ new = art_new (ArtVpath, size + 1);
+
+ x_start = 0;
+ y_start = 0;
+ open = 0;
+ for (i = 0; i < size; i++)
+ {
+ new[i].code = src[i].code;
+ x = src[i].x + (PERTURBATION * rand ()) / RAND_MAX - PERTURBATION * 0.5;
+ y = src[i].y + (PERTURBATION * rand ()) / RAND_MAX - PERTURBATION * 0.5;
+ if (src[i].code == ART_MOVETO)
+ {
+ x_start = x;
+ y_start = y;
+ open = 0;
+ }
+ else if (src[i].code == ART_MOVETO_OPEN)
+ open = 1;
+ if (!open && (i + 1 == size || src[i + 1].code != ART_LINETO))
+ {
+ x = x_start;
+ y = y_start;
+ }
+ new[i].x = x;
+ new[i].y = y;
+ }
+ new[i].code = ART_END;
+
+ return new;
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_VPATH_H__
+#define __ART_VPATH_H__
+
+#ifdef LIBART_COMPILATION
+#include "art_rect.h"
+#include "art_pathcode.h"
+#else
+#include <art_rect.h>
+#include <art_pathcode.h>
+#endif
+
+/* Basic data structures and constructors for simple vector paths */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct _ArtVpath ArtVpath;
+
+/* CURVETO is not allowed! */
+struct _ArtVpath {
+ ArtPathcode code;
+ double x;
+ double y;
+};
+
+/* Some of the functions need to go into their own modules */
+
+void
+art_vpath_add_point (ArtVpath **p_vpath, int *pn_points, int *pn_points_max,
+ ArtPathcode code, double x, double y);
+
+ArtVpath *
+art_vpath_new_circle (double x, double y, double r);
+
+ArtVpath *
+art_vpath_affine_transform (const ArtVpath *src, const double matrix[6]);
+
+void
+art_vpath_bbox_drect (const ArtVpath *vec, ArtDRect *drect);
+
+void
+art_vpath_bbox_irect (const ArtVpath *vec, ArtIRect *irect);
+
+ArtVpath *
+art_vpath_perturb (ArtVpath *src);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_VPATH_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Basic constructors and operations for bezier paths */
+
+#include <math.h>
+
+#include "art_misc.h"
+
+#include "art_bpath.h"
+#include "art_vpath.h"
+#include "art_vpath_bpath.h"
+
+/* p must be allocated 2^level points. */
+
+/* level must be >= 1 */
+ArtPoint *
+art_bezier_to_vec (double x0, double y0,
+ double x1, double y1,
+ double x2, double y2,
+ double x3, double y3,
+ ArtPoint *p,
+ int level)
+{
+ double x_m, y_m;
+
+#ifdef VERBOSE
+ printf ("bezier_to_vec: %g,%g %g,%g %g,%g %g,%g %d\n",
+ x0, y0, x1, y1, x2, y2, x3, y3, level);
+#endif
+ if (level == 1) {
+ x_m = (x0 + 3 * (x1 + x2) + x3) * 0.125;
+ y_m = (y0 + 3 * (y1 + y2) + y3) * 0.125;
+ p->x = x_m;
+ p->y = y_m;
+ p++;
+ p->x = x3;
+ p->y = y3;
+ p++;
+#ifdef VERBOSE
+ printf ("-> (%g, %g) -> (%g, %g)\n", x_m, y_m, x3, y3);
+#endif
+ } else {
+ double xa1, ya1;
+ double xa2, ya2;
+ double xb1, yb1;
+ double xb2, yb2;
+
+ xa1 = (x0 + x1) * 0.5;
+ ya1 = (y0 + y1) * 0.5;
+ xa2 = (x0 + 2 * x1 + x2) * 0.25;
+ ya2 = (y0 + 2 * y1 + y2) * 0.25;
+ xb1 = (x1 + 2 * x2 + x3) * 0.25;
+ yb1 = (y1 + 2 * y2 + y3) * 0.25;
+ xb2 = (x2 + x3) * 0.5;
+ yb2 = (y2 + y3) * 0.5;
+ x_m = (xa2 + xb1) * 0.5;
+ y_m = (ya2 + yb1) * 0.5;
+#ifdef VERBOSE
+ printf ("%g,%g %g,%g %g,%g %g,%g\n", xa1, ya1, xa2, ya2,
+ xb1, yb1, xb2, yb2);
+#endif
+ p = art_bezier_to_vec (x0, y0, xa1, ya1, xa2, ya2, x_m, y_m, p, level - 1);
+ p = art_bezier_to_vec (x_m, y_m, xb1, yb1, xb2, yb2, x3, y3, p, level - 1);
+ }
+ return p;
+}
+
+#define RENDER_LEVEL 4
+#define RENDER_SIZE (1 << (RENDER_LEVEL))
+
+/**
+ * art_vpath_render_bez: Render a bezier segment into the vpath.
+ * @p_vpath: Where the pointer to the #ArtVpath structure is stored.
+ * @pn_points: Pointer to the number of points in *@p_vpath.
+ * @pn_points_max: Pointer to the number of points allocated.
+ * @x0: X coordinate of starting bezier point.
+ * @y0: Y coordinate of starting bezier point.
+ * @x1: X coordinate of first bezier control point.
+ * @y1: Y coordinate of first bezier control point.
+ * @x2: X coordinate of second bezier control point.
+ * @y2: Y coordinate of second bezier control point.
+ * @x3: X coordinate of ending bezier point.
+ * @y3: Y coordinate of ending bezier point.
+ * @flatness: Flatness control.
+ *
+ * Renders a bezier segment into the vector path, reallocating and
+ * updating *@p_vpath and *@pn_vpath_max as necessary. *@pn_vpath is
+ * incremented by the number of vector points added.
+ *
+ * This step includes (@x0, @y0) but not (@x3, @y3).
+ *
+ * The @flatness argument guides the amount of subdivision. The Adobe
+ * PostScript reference manual defines flatness as the maximum
+ * deviation between the any point on the vpath approximation and the
+ * corresponding point on the "true" curve, and we follow this
+ * definition here. A value of 0.25 should ensure high quality for aa
+ * rendering.
+**/
+static void
+art_vpath_render_bez (ArtVpath **p_vpath, int *pn, int *pn_max,
+ double x0, double y0,
+ double x1, double y1,
+ double x2, double y2,
+ double x3, double y3,
+ double flatness)
+{
+ double x3_0, y3_0;
+ double z3_0_dot;
+ double z1_dot, z2_dot;
+ double z1_perp, z2_perp;
+ double max_perp_sq;
+
+ double x_m, y_m;
+ double xa1, ya1;
+ double xa2, ya2;
+ double xb1, yb1;
+ double xb2, yb2;
+
+ /* It's possible to optimize this routine a fair amount.
+
+ First, once the _dot conditions are met, they will also be met in
+ all further subdivisions. So we might recurse to a different
+ routine that only checks the _perp conditions.
+
+ Second, the distance _should_ decrease according to fairly
+ predictable rules (a factor of 4 with each subdivision). So it might
+ be possible to note that the distance is within a factor of 4 of
+ acceptable, and subdivide once. But proving this might be hard.
+
+ Third, at the last subdivision, x_m and y_m can be computed more
+ expeditiously (as in the routine above).
+
+ Finally, if we were able to subdivide by, say 2 or 3, this would
+ allow considerably finer-grain control, i.e. fewer points for the
+ same flatness tolerance. This would speed things up downstream.
+
+ In any case, this routine is unlikely to be the bottleneck. It's
+ just that I have this undying quest for more speed...
+
+ */
+
+ x3_0 = x3 - x0;
+ y3_0 = y3 - y0;
+
+ /* z3_0_dot is dist z0-z3 squared */
+ z3_0_dot = x3_0 * x3_0 + y3_0 * y3_0;
+
+ /* todo: this test is far from satisfactory. */
+ if (z3_0_dot < 0.001)
+ goto nosubdivide;
+
+ /* we can avoid subdivision if:
+
+ z1 has distance no more than flatness from the z0-z3 line
+
+ z1 is no more z0'ward than flatness past z0-z3
+
+ z1 is more z0'ward than z3'ward on the line traversing z0-z3
+
+ and correspondingly for z2 */
+
+ /* perp is distance from line, multiplied by dist z0-z3 */
+ max_perp_sq = flatness * flatness * z3_0_dot;
+
+ z1_perp = (y1 - y0) * x3_0 - (x1 - x0) * y3_0;
+ if (z1_perp * z1_perp > max_perp_sq)
+ goto subdivide;
+
+ z2_perp = (y3 - y2) * x3_0 - (x3 - x2) * y3_0;
+ if (z2_perp * z2_perp > max_perp_sq)
+ goto subdivide;
+
+ z1_dot = (x1 - x0) * x3_0 + (y1 - y0) * y3_0;
+ if (z1_dot < 0 && z1_dot * z1_dot > max_perp_sq)
+ goto subdivide;
+
+ z2_dot = (x3 - x2) * x3_0 + (y3 - y2) * y3_0;
+ if (z2_dot < 0 && z2_dot * z2_dot > max_perp_sq)
+ goto subdivide;
+
+ if (z1_dot + z1_dot > z3_0_dot)
+ goto subdivide;
+
+ if (z2_dot + z2_dot > z3_0_dot)
+ goto subdivide;
+
+ nosubdivide:
+ /* don't subdivide */
+ art_vpath_add_point (p_vpath, pn, pn_max,
+ ART_LINETO, x3, y3);
+ return;
+
+ subdivide:
+
+ xa1 = (x0 + x1) * 0.5;
+ ya1 = (y0 + y1) * 0.5;
+ xa2 = (x0 + 2 * x1 + x2) * 0.25;
+ ya2 = (y0 + 2 * y1 + y2) * 0.25;
+ xb1 = (x1 + 2 * x2 + x3) * 0.25;
+ yb1 = (y1 + 2 * y2 + y3) * 0.25;
+ xb2 = (x2 + x3) * 0.5;
+ yb2 = (y2 + y3) * 0.5;
+ x_m = (xa2 + xb1) * 0.5;
+ y_m = (ya2 + yb1) * 0.5;
+#ifdef VERBOSE
+ printf ("%g,%g %g,%g %g,%g %g,%g\n", xa1, ya1, xa2, ya2,
+ xb1, yb1, xb2, yb2);
+#endif
+ art_vpath_render_bez (p_vpath, pn, pn_max,
+ x0, y0, xa1, ya1, xa2, ya2, x_m, y_m, flatness);
+ art_vpath_render_bez (p_vpath, pn, pn_max,
+ x_m, y_m, xb1, yb1, xb2, yb2, x3, y3, flatness);
+}
+
+/**
+ * art_bez_path_to_vec: Create vpath from bezier path.
+ * @bez: Bezier path.
+ * @flatness: Flatness control.
+ *
+ * Creates a vector path closely approximating the bezier path defined by
+ * @bez. The @flatness argument controls the amount of subdivision. In
+ * general, the resulting vpath deviates by at most @flatness pixels
+ * from the "ideal" path described by @bez.
+ *
+ * Return value: Newly allocated vpath.
+ **/
+ArtVpath *
+art_bez_path_to_vec (const ArtBpath *bez, double flatness)
+{
+ ArtVpath *vec;
+ int vec_n, vec_n_max;
+ int bez_index;
+ double x, y;
+
+ vec_n = 0;
+ vec_n_max = RENDER_SIZE;
+ vec = art_new (ArtVpath, vec_n_max);
+
+ /* Initialization is unnecessary because of the precondition that the
+ bezier path does not begin with LINETO or CURVETO, but is here
+ to make the code warning-free. */
+ x = 0;
+ y = 0;
+
+ bez_index = 0;
+ do
+ {
+#ifdef VERBOSE
+ printf ("%s %g %g\n",
+ bez[bez_index].code == ART_CURVETO ? "curveto" :
+ bez[bez_index].code == ART_LINETO ? "lineto" :
+ bez[bez_index].code == ART_MOVETO ? "moveto" :
+ bez[bez_index].code == ART_MOVETO_OPEN ? "moveto-open" :
+ "end", bez[bez_index].x3, bez[bez_index].y3);
+#endif
+ /* make sure space for at least one more code */
+ if (vec_n >= vec_n_max)
+ art_expand (vec, ArtVpath, vec_n_max);
+ switch (bez[bez_index].code)
+ {
+ case ART_MOVETO_OPEN:
+ case ART_MOVETO:
+ case ART_LINETO:
+ x = bez[bez_index].x3;
+ y = bez[bez_index].y3;
+ vec[vec_n].code = bez[bez_index].code;
+ vec[vec_n].x = x;
+ vec[vec_n].y = y;
+ vec_n++;
+ break;
+ case ART_END:
+ vec[vec_n].code = bez[bez_index].code;
+ vec[vec_n].x = 0;
+ vec[vec_n].y = 0;
+ vec_n++;
+ break;
+ case ART_CURVETO:
+#ifdef VERBOSE
+ printf ("%g,%g %g,%g %g,%g %g,%g\n", x, y,
+ bez[bez_index].x1, bez[bez_index].y1,
+ bez[bez_index].x2, bez[bez_index].y2,
+ bez[bez_index].x3, bez[bez_index].y3);
+#endif
+ art_vpath_render_bez (&vec, &vec_n, &vec_n_max,
+ x, y,
+ bez[bez_index].x1, bez[bez_index].y1,
+ bez[bez_index].x2, bez[bez_index].y2,
+ bez[bez_index].x3, bez[bez_index].y3,
+ flatness);
+ x = bez[bez_index].x3;
+ y = bez[bez_index].y3;
+ break;
+ }
+ }
+ while (bez[bez_index++].code != ART_END);
+ return vec;
+}
+
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_VPATH_BPATH_H__
+#define __ART_VPATH_BPATH_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+ArtPoint *art_bezier_to_vec (double x0, double y0,
+ double x1, double y1,
+ double x2, double y2,
+ double x3, double y3,
+ ArtPoint *p,
+ int level);
+
+ArtVpath *art_bez_path_to_vec (const ArtBpath *bez, double flatness);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_VPATH_BPATH_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1999-2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Apply a dash style to a vector path. */
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "art_misc.h"
+
+#include "art_vpath.h"
+#include "art_vpath_dash.h"
+
+
+/* Return the length of the largest subpath within vpath */
+static int
+art_vpath_dash_max_subpath (const ArtVpath *vpath)
+{
+ int max_subpath;
+ int i;
+ int start;
+
+ max_subpath = 0;
+ start = 0;
+ for (i = 0; vpath[i].code != ART_END; i++)
+ {
+ if (vpath[i].code == ART_MOVETO || vpath[i].code == ART_MOVETO_OPEN)
+ {
+ if (i - start > max_subpath)
+ max_subpath = i - start;
+ start = i;
+ }
+ }
+ if (i - start > max_subpath)
+ max_subpath = i - start;
+
+ return max_subpath;
+}
+
+/**
+ * art_vpath_dash: Add dash style to vpath.
+ * @vpath: Original vpath.
+ * @dash: Dash style.
+ *
+ * Creates a new vpath that is the result of applying dash style @dash
+ * to @vpath.
+ *
+ * This implementation has two known flaws:
+ *
+ * First, it adds a spurious break at the beginning of the vpath. The
+ * only way I see to resolve this flaw is to run the state forward one
+ * dash break at the beginning, and fix up by looping back to the
+ * first dash break at the end. This is doable but of course adds some
+ * complexity.
+ *
+ * Second, it does not suppress output points that are within epsilon
+ * of each other.
+ *
+ * Return value: Newly created vpath.
+ **/
+ArtVpath *
+art_vpath_dash (const ArtVpath *vpath, const ArtVpathDash *dash)
+{
+ int max_subpath;
+ double *dists;
+ ArtVpath *result;
+ int n_result, n_result_max;
+ int start, end;
+ int i;
+ double total_dist;
+
+ /* state while traversing dasharray - offset is offset of current dash
+ value, toggle is 0 for "off" and 1 for "on", and phase is the distance
+ in, >= 0, < dash->dash[offset]. */
+ int offset, toggle;
+ double phase;
+
+ /* initial values */
+ int offset_init, toggle_init;
+ double phase_init;
+
+ max_subpath = art_vpath_dash_max_subpath (vpath);
+ dists = art_new (double, max_subpath);
+
+ n_result = 0;
+ n_result_max = 16;
+ result = art_new (ArtVpath, n_result_max);
+
+ /* determine initial values of dash state */
+ toggle_init = 1;
+ offset_init = 0;
+ phase_init = dash->offset;
+ while (phase_init >= dash->dash[offset_init])
+ {
+ toggle_init = !toggle_init;
+ phase_init -= dash->dash[offset_init];
+ offset_init++;
+ if (offset_init == dash->n_dash)
+ offset_init = 0;
+ }
+
+ for (start = 0; vpath[start].code != ART_END; start = end)
+ {
+ for (end = start + 1; vpath[end].code == ART_LINETO; end++);
+ /* subpath is [start..end) */
+ total_dist = 0;
+ for (i = start; i < end - 1; i++)
+ {
+ double dx, dy;
+
+ dx = vpath[i + 1].x - vpath[i].x;
+ dy = vpath[i + 1].y - vpath[i].y;
+ dists[i - start] = sqrt (dx * dx + dy * dy);
+ total_dist += dists[i - start];
+ }
+ if (total_dist <= dash->dash[offset_init] - phase_init)
+ {
+ /* subpath fits entirely within first dash */
+ if (toggle_init)
+ {
+ for (i = start; i < end; i++)
+ art_vpath_add_point (&result, &n_result, &n_result_max,
+ vpath[i].code, vpath[i].x, vpath[i].y);
+ }
+ }
+ else
+ {
+ /* subpath is composed of at least one dash - thus all
+ generated pieces are open */
+ double dist;
+
+ phase = phase_init;
+ offset = offset_init;
+ toggle = toggle_init;
+ dist = 0;
+ i = start;
+ if (toggle)
+ art_vpath_add_point (&result, &n_result, &n_result_max,
+ ART_MOVETO_OPEN, vpath[i].x, vpath[i].y);
+ while (i != end - 1)
+ {
+ if (dists[i - start] - dist > dash->dash[offset] - phase)
+ {
+ /* dash boundary is next */
+ double a;
+ double x, y;
+
+ dist += dash->dash[offset] - phase;
+ a = dist / dists[i - start];
+ x = vpath[i].x + a * (vpath[i + 1].x - vpath[i].x);
+ y = vpath[i].y + a * (vpath[i + 1].y - vpath[i].y);
+ art_vpath_add_point (&result, &n_result, &n_result_max,
+ toggle ? ART_LINETO : ART_MOVETO_OPEN,
+ x, y);
+ /* advance to next dash */
+ toggle = !toggle;
+ phase = 0;
+ offset++;
+ if (offset == dash->n_dash)
+ offset = 0;
+ }
+ else
+ {
+ /* end of line in vpath is next */
+ phase += dists[i - start] - dist;
+ i++;
+ dist = 0;
+ if (toggle)
+ art_vpath_add_point (&result, &n_result, &n_result_max,
+ ART_LINETO, vpath[i].x, vpath[i].y);
+ }
+ }
+ }
+ }
+
+ art_vpath_add_point (&result, &n_result, &n_result_max,
+ ART_END, 0, 0);
+
+ art_free (dists);
+
+ return result;
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1999 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_VPATH_DASH_H__
+#define __ART_VPATH_DASH_H__
+
+/* Apply a dash style to a vector path. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct _ArtVpathDash ArtVpathDash;
+
+struct _ArtVpathDash {
+ double offset;
+ int n_dash;
+ double *dash;
+};
+
+ArtVpath *
+art_vpath_dash (const ArtVpath *vpath, const ArtVpathDash *dash);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_VPATH_DASH_H__ */
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998-2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* "Unsort" a sorted vector path into an ordinary vector path. */
+
+#include <stdio.h> /* for printf - debugging */
+#include "art_misc.h"
+
+#include "art_vpath.h"
+#include "art_svp.h"
+#include "art_vpath_svp.h"
+
+typedef struct _ArtVpathSVPEnd ArtVpathSVPEnd;
+
+struct _ArtVpathSVPEnd {
+ int seg_num;
+ int which; /* 0 = top, 1 = bottom */
+ double x, y;
+};
+
+#define EPSILON 1e-6
+
+static int
+art_vpath_svp_point_compare (double x1, double y1, double x2, double y2)
+{
+ if (y1 - EPSILON > y2) return 1;
+ if (y1 + EPSILON < y2) return -1;
+ if (x1 - EPSILON > x2) return 1;
+ if (x1 + EPSILON < x2) return -1;
+ return 0;
+}
+
+static int
+art_vpath_svp_compare (const void *s1, const void *s2)
+{
+ const ArtVpathSVPEnd *e1 = s1;
+ const ArtVpathSVPEnd *e2 = s2;
+
+ return art_vpath_svp_point_compare (e1->x, e1->y, e2->x, e2->y);
+}
+
+/* Convert from sorted vector path representation into regular
+ vector path representation.
+
+ Status of this routine:
+
+ Basic correctness: Only works with closed paths.
+
+ Numerical stability: Not known to work when more than two segments
+ meet at a point.
+
+ Speed: Should be pretty good.
+
+ Precision: Does not degrade precision.
+
+*/
+/**
+ * art_vpath_from_svp: Convert from svp to vpath form.
+ * @svp: Original #ArtSVP.
+ *
+ * Converts the sorted vector path @svp into standard vpath form.
+ *
+ * Return value: the newly allocated vpath.
+ **/
+ArtVpath *
+art_vpath_from_svp (const ArtSVP *svp)
+{
+ int n_segs = svp->n_segs;
+ ArtVpathSVPEnd *ends;
+ ArtVpath *new;
+ int *visited;
+ int n_new, n_new_max;
+ int i, k;
+ int j = 0; /* Quiet compiler */
+ int seg_num;
+ int first;
+ double last_x, last_y;
+ int n_points;
+ int pt_num;
+
+ last_x = 0; /* to eliminate "uninitialized" warning */
+ last_y = 0;
+
+ ends = art_new (ArtVpathSVPEnd, n_segs * 2);
+ for (i = 0; i < svp->n_segs; i++)
+ {
+ int lastpt;
+
+ ends[i * 2].seg_num = i;
+ ends[i * 2].which = 0;
+ ends[i * 2].x = svp->segs[i].points[0].x;
+ ends[i * 2].y = svp->segs[i].points[0].y;
+
+ lastpt = svp->segs[i].n_points - 1;
+ ends[i * 2 + 1].seg_num = i;
+ ends[i * 2 + 1].which = 1;
+ ends[i * 2 + 1].x = svp->segs[i].points[lastpt].x;
+ ends[i * 2 + 1].y = svp->segs[i].points[lastpt].y;
+ }
+ qsort (ends, n_segs * 2, sizeof (ArtVpathSVPEnd), art_vpath_svp_compare);
+
+ n_new = 0;
+ n_new_max = 16; /* I suppose we _could_ estimate this from traversing
+ the svp, so we don't have to reallocate */
+ new = art_new (ArtVpath, n_new_max);
+
+ visited = art_new (int, n_segs);
+ for (i = 0; i < n_segs; i++)
+ visited[i] = 0;
+
+ first = 1;
+ for (i = 0; i < n_segs; i++)
+ {
+ if (!first)
+ {
+ /* search for the continuation of the existing subpath */
+ /* This could be a binary search (which is why we sorted, above) */
+ for (j = 0; j < n_segs * 2; j++)
+ {
+ if (!visited[ends[j].seg_num] &&
+ art_vpath_svp_point_compare (last_x, last_y,
+ ends[j].x, ends[j].y) == 0)
+ break;
+ }
+ if (j == n_segs * 2)
+ first = 1;
+ }
+ if (first)
+ {
+ /* start a new subpath */
+ for (j = 0; j < n_segs * 2; j++)
+ if (!visited[ends[j].seg_num])
+ break;
+ }
+ if (j == n_segs * 2)
+ {
+ printf ("failure\n");
+ }
+ seg_num = ends[j].seg_num;
+ n_points = svp->segs[seg_num].n_points;
+ for (k = 0; k < n_points; k++)
+ {
+ pt_num = svp->segs[seg_num].dir ? k : n_points - (1 + k);
+ if (k == 0)
+ {
+ if (first)
+ {
+ art_vpath_add_point (&new, &n_new, &n_new_max,
+ ART_MOVETO,
+ svp->segs[seg_num].points[pt_num].x,
+ svp->segs[seg_num].points[pt_num].y);
+ }
+ }
+ else
+ {
+ art_vpath_add_point (&new, &n_new, &n_new_max,
+ ART_LINETO,
+ svp->segs[seg_num].points[pt_num].x,
+ svp->segs[seg_num].points[pt_num].y);
+ if (k == n_points - 1)
+ {
+ last_x = svp->segs[seg_num].points[pt_num].x;
+ last_y = svp->segs[seg_num].points[pt_num].y;
+ /* to make more robust, check for meeting first_[xy],
+ set first if so */
+ }
+ }
+ first = 0;
+ }
+ visited[seg_num] = 1;
+ }
+
+ art_vpath_add_point (&new, &n_new, &n_new_max,
+ ART_END, 0, 0);
+ art_free (visited);
+ art_free (ends);
+ return new;
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ART_VPATH_SVP_H__
+#define __ART_VPATH_SVP_H__
+
+/* "Unsort" a sorted vector path into an ordinary vector path. */
+
+#ifdef LIBART_COMPILATION
+#include "art_rect.h"
+#include "art_point.h"
+#else
+#include <art_rect.h>
+#include <art_point.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+ArtVpath *art_vpath_from_svp (const ArtSVP *svp);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_VPATH_SVP_H__ */
--- /dev/null
+#include <stdio.h>
+#include "config.h"
+#include <stdlib.h>
+
+/**
+ * A little utility function to generate header info.
+ *
+ * Yes, it would be possible to do this using more "native" autoconf
+ * features, but I personally find this approach to be cleaner.
+ *
+ * The output of this program is generally written to art_config.h,
+ * which is installed in libart's include dir.
+ **/
+
+static void
+die (char *why)
+{
+ fprintf (stderr, "gen_art_config: %s\n", why);
+ exit (1);
+}
+
+int
+main (int argc, char **argv)
+{
+ printf ("/* Automatically generated by gen_art_config.c */\n"
+ "\n"
+ "#define ART_SIZEOF_CHAR %d\n"
+ "#define ART_SIZEOF_SHORT %d\n"
+ "#define ART_SIZEOF_INT %d\n"
+ "#define ART_SIZEOF_LONG %d\n"
+ "\n",
+ (int)sizeof(char), (int)sizeof(short), (int)sizeof(int), (int)sizeof(long));
+
+ if (sizeof(char) == 1)
+ printf ("typedef unsigned char art_u8;\n");
+ else
+ die ("sizeof(char) != 1");
+
+ if (sizeof(short) == 2)
+ printf ("typedef unsigned short art_u16;\n");
+ else
+ die ("sizeof(short) != 2");
+
+ if (sizeof(int) == 4)
+ printf ("typedef unsigned int art_u32;\n");
+ else if (sizeof(long) == 4)
+ printf ("typedef unsigned long art_u32;\n");
+ else
+ die ("sizeof(int) != 4 and sizeof(long) != 4");
+
+ return 0;
+}
--- /dev/null
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
--- /dev/null
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libart
+Description: LGPL version of the libart library
+Version: @VERSION@
+Libs: -L${libdir} -lart_lgpl_2
+Cflags: -I${includedir}/libart-2.0
--- /dev/null
+#!/bin/sh
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+exec_prefix_set=no
+
+usage="\
+Usage: libart-config [--prefix[=DIR]] [--exec-prefix[=DIR]] [--version] [--libs] [--cflags]"
+
+if test $# -eq 0; then
+ echo "${usage}" 1>&2
+ exit 1
+fi
+
+while test $# -gt 0; do
+ case "$1" in
+ -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ case $1 in
+ --prefix=*)
+ prefix=$optarg
+ if test $exec_prefix_set = no ; then
+ exec_prefix=$optarg
+ fi
+ ;;
+ --prefix)
+ echo $prefix
+ ;;
+ --exec-prefix=*)
+ exec_prefix=$optarg
+ exec_prefix_set=yes
+ ;;
+ --exec-prefix)
+ echo $exec_prefix
+ ;;
+ --version)
+ echo @LIBART_VERSION@
+ ;;
+ --cflags)
+ includes=-I@includedir@/libart-2.0
+ echo $includes
+ ;;
+ --libs)
+ libdirs=-L@libdir@
+ echo $libdirs -lart_lgpl_2 -lm
+ ;;
+ *)
+ echo "${usage}" 1>&2
+ exit 1
+ ;;
+ esac
+ shift
+done
+
--- /dev/null
+#include "libart-features.h"
+
+/* General initialization hooks */
+const unsigned int libart_major_version=LIBART_MAJOR_VERSION,
+ libart_minor_version=LIBART_MINOR_VERSION,
+ libart_micro_version=LIBART_MICRO_VERSION;
+
+const char *libart_version = LIBART_VERSION;
+
+void
+libart_preinit(void *app, void *modinfo)
+{
+}
+
+void
+libart_postinit(void *app, void *modinfo)
+{
+}
--- /dev/null
+#ifndef LIBART_FEATURES_H
+#define LIBART_FEATURES_H 1
+
+#define LIBART_MAJOR_VERSION (2)
+#define LIBART_MINOR_VERSION (3)
+#define LIBART_MICRO_VERSION (7)
+#define LIBART_VERSION "2.3.7"
+
+extern const unsigned int libart_major_version, libart_minor_version, libart_micro_version;
+extern const char *libart_version;
+
+void libart_preinit(void *app, void *modinfo);
+void libart_postinit(void *app, void *modinfo);
+#endif
--- /dev/null
+#ifndef LIBART_FEATURES_H
+#define LIBART_FEATURES_H 1
+
+#define LIBART_MAJOR_VERSION (@LIBART_MAJOR_VERSION@)
+#define LIBART_MINOR_VERSION (@LIBART_MINOR_VERSION@)
+#define LIBART_MICRO_VERSION (@LIBART_MICRO_VERSION@)
+#define LIBART_VERSION "@LIBART_VERSION@"
+
+extern const unsigned int libart_major_version, libart_minor_version, libart_micro_version;
+extern const char *libart_version;
+
+void libart_preinit(void *app, void *modinfo);
+void libart_postinit(void *app, void *modinfo);
+#endif
--- /dev/null
+#ifndef LIBART_H
+#define LIBART_H 1
+
+#include <art_affine.h>
+#include <art_alphagamma.h>
+#include <art_bpath.h>
+#include <art_filterlevel.h>
+#include <art_gray_svp.h>
+#include <art_misc.h>
+#include <art_pathcode.h>
+#include <art_pixbuf.h>
+#include <art_point.h>
+#include <art_rect.h>
+#include <art_rect_svp.h>
+#include <art_rect_uta.h>
+#include <art_rgb.h>
+#include <art_rgb_affine.h>
+#include <art_rgb_bitmap_affine.h>
+#include <art_rgb_pixbuf_affine.h>
+#include <art_rgb_rgba_affine.h>
+#include <art_rgb_svp.h>
+#include <art_svp.h>
+#include <art_svp_ops.h>
+#include <art_svp_point.h>
+#include <art_svp_render_aa.h>
+#include <art_svp_vpath.h>
+#include <art_svp_vpath_stroke.h>
+#include <art_svp_wind.h>
+#include <art_uta.h>
+#include <art_uta_ops.h>
+#include <art_uta_rect.h>
+#include <art_uta_svp.h>
+#include <art_uta_vpath.h>
+#include <art_vpath.h>
+#include <art_vpath_bpath.h>
+#include <art_vpath_dash.h>
+#include <art_vpath_svp.h>
+
+#endif
--- /dev/null
+# libart_lgpl_2.la - a libtool library file
+# Generated by ltmain.sh - GNU libtool 1.4 (1.920 2001/04/24 23:26:18)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname=''
+
+# Names of this library.
+library_names=''
+
+# The name of the static archive.
+old_library='libart_lgpl_2.a'
+
+# Libraries that this one depends upon.
+dependency_libs=' -lm'
+
+# Version information for libart_lgpl_2.
+current=5
+age=3
+revision=7
+
+# Is this an already installed library?
+installed=no
+
+# Files to dlopen/dlpreopen
+dlopen=''
+dlpreopen=''
+
+# Directory that this library needs to be installed in:
+libdir='/usr/local/rrdtool-1.0.33/lib'
--- /dev/null
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+case "$1" in
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]"
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing - GNU libit 0.0"
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+ aclocal)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acinclude.m4' or \`configure.in'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`configure.in'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acconfig.h' or \`configure.in'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' configure.in`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case "$f" in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
+ ;;
+
+ automake)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ bison|yacc)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f y.tab.h ]; then
+ echo >y.tab.h
+ fi
+ if [ ! -f y.tab.c ]; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex|flex)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f lex.yy.c ]; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ makeinfo)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+ fi
+ touch $file
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+ system. You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequirements for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
--- /dev/null
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id$
+
+errstatus=0
+
+for file
+do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d
+ do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp"
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ fi
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998, 1999 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include "art_misc.h"
+#include "art_vpath.h"
+#include "art_svp.h"
+#include "art_svp_vpath.h"
+#include "art_gray_svp.h"
+#include "art_rgb_svp.h"
+#include "art_svp_vpath_stroke.h"
+#include "art_svp_ops.h"
+#include "art_affine.h"
+#include "art_rgb_affine.h"
+#include "art_rgb_bitmap_affine.h"
+#include "art_rgb_rgba_affine.h"
+#include "art_alphagamma.h"
+#include "art_svp_point.h"
+#include "art_vpath_dash.h"
+#include "art_render.h"
+#include "art_render_gradient.h"
+#include "art_render_svp.h"
+#include "art_svp_intersect.h"
+
+#ifdef DEAD_CODE
+static void
+test_affine (void) {
+ double src[6];
+ double dst[6];
+ double src2[6];
+ char str[128];
+ int i;
+ ArtPoint ps, pd, ptmp;
+
+ for (i = 0; i < 6; i++)
+ {
+ src[i] = (rand () * 2.0 / RAND_MAX) - 1.0;
+ src2[i] = (rand () * 2.0 / RAND_MAX) - 1.0;
+ }
+#if 0
+ src[0] = 0.9999999;
+ src[1] = -0.000001;
+ src[2] = 0.000001;
+ src[3] = 0.9999999;
+ src[4] = 0;
+ src[5] = 0;
+#if 1
+ src[0] = 0.98480775;
+ src[1] = -0.17364818;
+ src[2] = 0.17364818;
+ src[3] = 0.98480775;
+#endif
+
+ src2[0] = 0.98480775;
+ src2[1] = -0.17364818;
+ src2[2] = 0.17364818;
+ src2[3] = 0.98480775;
+#endif
+
+
+ ps.x = rand() * 100.0 / RAND_MAX;
+ ps.y = rand() * 100.0 / RAND_MAX;
+
+ art_affine_point (&pd, &ps, src);
+ art_affine_invert (dst, src);
+ art_affine_point (&ptmp, &pd, dst);
+ art_affine_to_string (str, src);
+ printf ("src = %s\n", str);
+ art_affine_to_string (str, dst);
+ printf ("dst = %s\n", str);
+ printf ("point (%g, %g) -> (%g, %g) -> (%g, %g)\n",
+ ps.x, ps.y, pd.x, pd.y, ptmp.x, ptmp.y);
+
+ art_affine_point (&ptmp, &ps, src);
+ art_affine_point (&pd, &ptmp, src2);
+ art_affine_to_string (str, src2);
+ printf ("src2 = %s\n", str);
+ printf ("point (%g, %g) -> (%g, %g) -> (%g, %g)\n",
+ ps.x, ps.y, ptmp.x, ptmp.y, pd.x, pd.y);
+ art_affine_multiply (dst, src, src2);
+ art_affine_to_string (str, dst);
+ printf ("dst = %s\n", str);
+ art_affine_point (&pd, &ps, dst);
+ printf ("point (%g, %g) -> (%g, %g)\n",
+ ps.x, ps.y, pd.x, pd.y);
+
+}
+#endif
+
+static ArtVpath *
+randstar (int n)
+{
+ ArtVpath *vec;
+ int i;
+ double r, th;
+
+ vec = art_new (ArtVpath, n + 2);
+ for (i = 0; i < n; i++)
+ {
+ vec[i].code = i ? ART_LINETO : ART_MOVETO;
+ r = rand () * (250.0 / RAND_MAX);
+#if 0
+ r = r + 0.9 * (250 - r);
+#endif
+ th = i * 2 * M_PI / n;
+ vec[i].x = 250 + r * cos (th);
+ vec[i].y = 250 - r * sin (th);
+ }
+ vec[i].code = ART_LINETO;
+ vec[i].x = vec[0].x;
+ vec[i].y = vec[0].y;
+ i++;
+ vec[i].code = ART_END;
+ vec[i].x = 0;
+ vec[i].y = 0;
+ return vec;
+}
+
+#define TILE_SIZE 512
+#define NUM_ITERS 1
+#define COLOR
+
+#ifdef COLOR
+#define BYTES_PP 3
+#else
+#define BYTES_PP 1
+#endif
+
+#ifndef nDEAD_CODE
+static void
+print_svp (ArtSVP *vp)
+{
+ int i, j;
+
+ for (i = 0; i < vp->n_segs; i++)
+ {
+ printf ("segment %d, dir = %s (%f, %f) - (%f, %f)\n",
+ i, vp->segs[i].dir ? "down" : "up",
+ vp->segs[i].bbox.x0,
+ vp->segs[i].bbox.y0,
+ vp->segs[i].bbox.x1,
+ vp->segs[i].bbox.y1);
+ for (j = 0; j < vp->segs[i].n_points; j++)
+ printf (" (%g, %g)\n",
+ vp->segs[i].points[j].x,
+ vp->segs[i].points[j].y);
+ }
+}
+#endif
+
+static void
+print_vpath (ArtVpath *vpath)
+{
+ int i;
+
+ for (i = 0; vpath[i].code != ART_END; i++)
+ printf ("%g %g %s\n",
+ vpath[i].x, vpath[i].y,
+ vpath[i].code == ART_MOVETO_OPEN ? "moveto %open" :
+ vpath[i].code == ART_MOVETO ? "moveto" :
+ vpath[i].code == ART_LINETO ? "lineto" :
+ "?");
+
+ printf ("stroke\n");
+}
+
+static void
+make_testpat (void)
+{
+ ArtVpath *vpath, *vpath2, *vpath3;
+ ArtSVP *svp, *svp2;
+ ArtSVP *svp3;
+ art_u8 buf[512 * 512 * BYTES_PP];
+ int i, j;
+ int iter;
+ art_u8 colorimg[256][256][3];
+ art_u8 rgbaimg[256][256][4];
+ art_u8 bitimg[16][2];
+ int x, y;
+ double affine[6];
+ double affine2[6];
+ double affine3[6];
+ ArtAlphaGamma *alphagamma;
+ double dash_data[] = { 20 };
+ ArtVpathDash dash;
+
+ dash.offset = 0;
+ dash.n_dash = 1;
+ dash.dash = dash_data;
+
+#ifdef TEST_AFFINE
+ test_affine ();
+ exit (0);
+#endif
+
+ vpath = randstar (50);
+ svp = art_svp_from_vpath (vpath);
+ art_free (vpath);
+
+ vpath2 = randstar (50);
+#if 1
+ vpath3 = art_vpath_dash (vpath2, &dash);
+ art_free (vpath2);
+ svp2 = art_svp_vpath_stroke (vpath3,
+ ART_PATH_STROKE_JOIN_MITER,
+ ART_PATH_STROKE_CAP_BUTT,
+ 15,
+ 4,
+ 0.5);
+ art_free (vpath3);
+#else
+ svp2 = art_svp_from_vpath (vpath2);
+#endif
+
+#if 1
+ svp3 = art_svp_intersect (svp, svp2);
+#else
+ svp3 = svp2;
+#endif
+
+#if 0
+ print_svp (svp);
+#endif
+
+ for (y = 0; y < 256; y++)
+ for (x = 0; x < 256; x++)
+ {
+ colorimg[y][x][0] = (x + y) >> 1;
+ colorimg[y][x][1] = (x + (255 - y)) >> 1;
+ colorimg[y][x][2] = ((255 - x) + y) >> 1;
+
+ rgbaimg[y][x][0] = (x + y) >> 1;
+ rgbaimg[y][x][1] = (x + (255 - y)) >> 1;
+ rgbaimg[y][x][2] = ((255 - x) + y) >> 1;
+ rgbaimg[y][x][3] = y;
+ }
+
+ for (y = 0; y < 16; y++)
+ for (x = 0; x < 2; x++)
+ bitimg[y][x] = (x << 4) | y;
+
+ affine[0] = 0.5;
+ affine[1] = .2;
+ affine[2] = -.2;
+ affine[3] = 0.5;
+ affine[4] = 64;
+ affine[5] = 64;
+
+ affine2[0] = 1;
+ affine2[1] = -.2;
+ affine2[2] = .2;
+ affine2[3] = 1;
+ affine2[4] = 128;
+ affine2[5] = 128;
+
+ affine3[0] = 5;
+ affine3[1] = -.2;
+ affine3[2] = .2;
+ affine3[3] = 5;
+ affine3[4] = 384;
+ affine3[5] = 32;
+
+#if 0
+ alphagamma = art_alphagamma_new (1.8);
+#else
+ alphagamma = NULL;
+#endif
+
+#ifdef COLOR
+ printf ("P6\n512 512\n255\n");
+#else
+ printf ("P5\n512 512\n255\n");
+#endif
+ for (iter = 0; iter < NUM_ITERS; iter++)
+ for (j = 0; j < 512; j += TILE_SIZE)
+ for (i = 0; i < 512; i += TILE_SIZE)
+ {
+#ifdef COLOR
+ art_rgb_svp_aa (svp, i, j, i + TILE_SIZE, j + TILE_SIZE,
+ 0xffe0a0, 0x100040,
+ buf + (j * 512 + i) * BYTES_PP, 512 * BYTES_PP,
+ alphagamma);
+ art_rgb_svp_alpha (svp2, i, j, i + TILE_SIZE, j + TILE_SIZE,
+ 0xff000080,
+ buf + (j * 512 + i) * BYTES_PP, 512 * BYTES_PP,
+ alphagamma);
+ art_rgb_svp_alpha (svp3, i, j, i + TILE_SIZE, j + TILE_SIZE,
+ 0x00ff0080,
+ buf + (j * 512 + i) * BYTES_PP, 512 * BYTES_PP,
+ alphagamma);
+ art_rgb_affine (buf + (j * 512 + i) * BYTES_PP,
+ i, j, i + TILE_SIZE, j + TILE_SIZE, 512 * BYTES_PP,
+ (art_u8 *)colorimg, 256, 256, 256 * 3,
+ affine,
+ ART_FILTER_NEAREST, alphagamma);
+ art_rgb_rgba_affine (buf + (j * 512 + i) * BYTES_PP,
+ i, j, i + TILE_SIZE, j + TILE_SIZE,
+ 512 * BYTES_PP,
+ (art_u8 *)rgbaimg, 256, 256, 256 * 4,
+ affine2,
+ ART_FILTER_NEAREST, alphagamma);
+ art_rgb_bitmap_affine (buf + (j * 512 + i) * BYTES_PP,
+ i, j, i + TILE_SIZE, j + TILE_SIZE,
+ 512 * BYTES_PP,
+ (art_u8 *)bitimg, 16, 16, 2,
+ 0xffff00ff,
+ affine3,
+ ART_FILTER_NEAREST, alphagamma);
+#else
+ art_gray_svp_aa (svp, i, j, i + TILE_SIZE, j + TILE_SIZE,
+ buf + (j * 512 + i) * BYTES_PP, 512 * BYTES_PP);
+#endif
+ }
+
+ art_svp_free (svp2);
+ art_svp_free (svp3);
+ art_svp_free (svp);
+
+#if 1
+ fwrite (buf, 1, 512 * 512 * BYTES_PP, stdout);
+#endif
+}
+
+static void
+test_dist (void)
+{
+ ArtVpath *vpath;
+ ArtSVP *svp;
+ art_u8 buf[512 * 512 * BYTES_PP];
+ int x, y;
+ int ix;
+ double dist;
+ int wind;
+
+ vpath = randstar (20);
+#ifdef NO_STROKE
+ svp = art_svp_from_vpath (vpath);
+#else
+ svp = art_svp_vpath_stroke (vpath,
+ ART_PATH_STROKE_JOIN_MITER,
+ ART_PATH_STROKE_CAP_BUTT,
+ 15,
+ 4,
+ 0.5);
+#endif
+
+ art_rgb_svp_aa (svp, 0, 0, 512, 512,
+ 0xffe0a0, 0x100040,
+ buf, 512 * BYTES_PP,
+ NULL);
+
+ ix = 0;
+ for (y = 0; y < 512; y++)
+ {
+ for (x = 0; x < 512; x++)
+ {
+ wind = art_svp_point_wind (svp, x, y);
+ buf[ix] = 204 - wind * 51;
+ dist = art_svp_point_dist (svp, x, y);
+ if (((x | y) & 0x3f) == 0)
+ {
+ fprintf (stderr, "%d,%d: %f\n", x, y, dist);
+ }
+ buf[ix + 1] = 255 - dist;
+ ix += 3;
+ }
+ }
+
+ printf ("P6\n512 512\n255\n");
+ fwrite (buf, 1, 512 * 512 * BYTES_PP, stdout);
+
+}
+
+static void
+test_dash (void)
+{
+ ArtVpath *vpath, *vpath2;
+ double dash_data[] = { 10, 4, 1, 4};
+ ArtVpathDash dash;
+
+ dash.offset = 0;
+ dash.n_dash = 3;
+ dash.dash = dash_data;
+
+ vpath = randstar (50);
+ vpath2 = art_vpath_dash (vpath, &dash);
+ printf ("%%!\n");
+ print_vpath (vpath2);
+ printf ("showpage\n");
+ art_free (vpath);
+ art_free (vpath2);
+}
+
+static void
+test_render_gradient (art_u8 *buf)
+{
+ ArtGradientLinear gradient;
+ ArtGradientStop stops[3] = {
+ { 0.0, { 0x7fff, 0x0000, 0x0000, 0x7fff }},
+ { 0.5, { 0x0000, 0x0000, 0x0000, 0x1000 }},
+ { 1.0, { 0x0000, 0x7fff, 0x0000, 0x7fff }}
+ };
+ ArtVpath *vpath;
+ ArtSVP *svp;
+ ArtRender *render;
+
+ gradient.a = 0.003;
+ gradient.b = -0.0015;
+ gradient.c = 0.1;
+ gradient.spread = ART_GRADIENT_PAD;
+ gradient.n_stops = sizeof(stops) / sizeof(stops[0]);
+ gradient.stops = stops;
+
+ vpath = randstar (50);
+ svp = art_svp_from_vpath (vpath);
+
+ render = art_render_new (0, 0, 512, 512, buf, 512 * 3, 3, 8, ART_ALPHA_NONE,
+ NULL);
+ art_render_svp (render, svp);
+ art_render_gradient_linear (render, &gradient, ART_FILTER_NEAREST);
+ art_render_invoke (render);
+
+}
+
+static void
+test_render_rad_gradient (art_u8 *buf)
+{
+ ArtGradientRadial gradient;
+ ArtGradientStop stops[3] = {
+ { 0.0, { 0xffff, 0x0000, 0x0000, 0xffff }},
+ { 0.5, { 0xe000, 0xe000, 0x0000, 0xe000 }},
+ { 1.0, { 0x0000, 0x0000, 0x0000, 0x0000 }}
+ };
+ ArtVpath *vpath;
+ ArtSVP *svp;
+ ArtRender *render;
+
+ gradient.affine[0] = 3.0 / 512;
+ gradient.affine[1] = 0;
+ gradient.affine[2] = 0;
+ gradient.affine[3] = 3.0 / 512;
+ gradient.affine[4] = -1.5;
+ gradient.affine[5] = -1.5;
+ gradient.fx = 0.9;
+ gradient.fy = 0.1;
+
+ gradient.n_stops = sizeof(stops) / sizeof(stops[0]);
+ gradient.stops = stops;
+
+ vpath = randstar (50);
+ svp = art_svp_from_vpath (vpath);
+
+ render = art_render_new (0, 0, 512, 512, buf, 512 * 3, 3, 8, ART_ALPHA_NONE,
+ NULL);
+ art_render_svp (render, svp);
+ art_render_gradient_radial (render, &gradient, ART_FILTER_NEAREST);
+ art_render_invoke (render);
+
+}
+
+static void
+test_gradient (void)
+{
+ ArtVpath *vpath;
+ ArtSVP *svp;
+ art_u8 buf[512 * 512 * 3];
+ ArtRender *render;
+ ArtPixMaxDepth color[3] = {0x0000, 0x0000, 0x8000 };
+ int i;
+ const int n_iter = 1;
+
+ vpath = randstar (50);
+ svp = art_svp_from_vpath (vpath);
+
+ for (i = 0; i < n_iter; i++)
+ {
+#define USE_RENDER
+#ifdef USE_RENDER
+ render = art_render_new (0, 0, 512, 512, buf, 512 * 3, 3, 8, ART_ALPHA_NONE,
+ NULL);
+ art_render_clear_rgb (render, 0xfff0c0);
+ art_render_svp (render, svp);
+ art_render_image_solid (render, color);
+ art_render_invoke (render);
+#else
+ art_rgb_svp_aa (svp, 0, 0, 512, 512, 0xfff0c0, 0x000080,
+ buf, 512 * 3, NULL);
+#endif
+ }
+
+#if 1
+ test_render_gradient (buf);
+#endif
+ test_render_rad_gradient (buf);
+
+ printf ("P6\n512 512\n255\n");
+ fwrite (buf, 1, 512 * 512 * 3, stdout);
+}
+
+static void
+output_svp_ppm (const ArtSVP *svp)
+{
+ art_u8 buf[512 * 512 * 3];
+ art_rgb_svp_aa (svp, 0, 0, 512, 512, 0xfff0c0, 0x000080,
+ buf, 512 * 3, NULL);
+ printf ("P6\n512 512\n255\n");
+ fwrite (buf, 1, 512 * 512 * 3, stdout);
+}
+
+static void
+test_intersect (void)
+{
+ ArtVpath vpath[] = {
+
+#if 0
+ /* two triangles */
+ { ART_MOVETO, 100, 100 },
+ { ART_LINETO, 300, 400 },
+ { ART_LINETO, 400, 200 },
+ { ART_LINETO, 100, 100 },
+ { ART_MOVETO, 110, 110 },
+ { ART_LINETO, 310, 410 },
+ { ART_LINETO, 410, 210 },
+ { ART_LINETO, 110, 110 },
+#endif
+
+#if 0
+ /* a bowtie */
+ { ART_MOVETO, 100, 100 },
+ { ART_LINETO, 400, 400 },
+ { ART_LINETO, 400, 100 },
+ { ART_LINETO, 100, 400 },
+ { ART_LINETO, 100, 100 },
+#endif
+
+#if 1
+ /* a square */
+ { ART_MOVETO, 100, 100 },
+ { ART_LINETO, 100, 400 },
+ { ART_LINETO, 400, 400 },
+ { ART_LINETO, 400, 100 },
+ { ART_LINETO, 100, 100 },
+#endif
+
+#if 1
+ /* another square */
+#define XOFF 10
+#define YOFF 10
+ { ART_MOVETO, 100 + XOFF, 100 + YOFF },
+ { ART_LINETO, 100 + XOFF, 400 + YOFF },
+ { ART_LINETO, 400 + XOFF, 400 + YOFF },
+ { ART_LINETO, 400 + XOFF, 100 + YOFF },
+ { ART_LINETO, 100 + XOFF, 100 + YOFF },
+#endif
+
+ { ART_END, 0, 0}
+ };
+ ArtSVP *svp, *svp2;
+ ArtSvpWriter *swr;
+
+ svp = art_svp_from_vpath (vpath);
+
+#define RUN_INTERSECT
+#ifdef RUN_INTERSECT
+ swr = art_svp_writer_rewind_new (ART_WIND_RULE_ODDEVEN);
+ art_svp_intersector (svp, swr);
+
+ svp2 = art_svp_writer_rewind_reap (swr);
+#endif
+
+#if 0
+ output_svp_ppm (svp2);
+#else
+ print_svp (svp2);
+#endif
+
+ art_svp_free (svp);
+
+#ifdef RUN_INTERSECT
+ art_svp_free (svp2);
+#endif
+}
+
+static void
+usage (void)
+{
+ fprintf (stderr, "usage: testart <test>\n"
+" where <test> is one of:\n"
+" testpat -- make random star + gradients test pattern\n"
+" gradient -- test pattern for rendered gradients\n"
+" dash -- dash test (output is valid PostScript)\n"
+" dist -- distance test\n"
+" intersect -- softball test for intersector\n");
+ exit (1);
+}
+
+int
+main (int argc, char **argv)
+{
+ if (argc < 2)
+ usage ();
+
+ if (!strcmp (argv[1], "testpat"))
+ make_testpat ();
+ else if (!strcmp (argv[1], "gradient"))
+ test_gradient ();
+ else if (!strcmp (argv[1], "dist"))
+ test_dist ();
+ else if (!strcmp (argv[1], "dash"))
+ test_dash ();
+ else if (!strcmp (argv[1], "intersect"))
+ test_intersect ();
+ else
+ usage ();
+ return 0;
+}
--- /dev/null
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "art_misc.h"
+#include "art_uta.h"
+#include "art_vpath.h"
+#include "art_uta_vpath.h"
+#include "art_rect.h"
+#include "art_rect_uta.h"
+#include "art_uta_rect.h"
+
+#define TEST_UTA
+#define noTEST_UTA_SPEED
+
+#define XOFF 50
+#define YOFF 700
+
+static void
+print_uta_ps (ArtUta *uta)
+{
+ int x, y;
+ int x0, y0, x1, y1;
+ int width = uta->width;
+ ArtUtaBbox ub;
+
+ for (y = 0; y < uta->height; y++)
+ for (x = 0; x < width; x++)
+ {
+ ub = uta->utiles[y * width + x];
+ if (ub != 0)
+ {
+ x0 = (uta->x0 + x) * ART_UTILE_SIZE + ART_UTA_BBOX_X0(ub);
+ x1 = (uta->x0 + x) * ART_UTILE_SIZE + ART_UTA_BBOX_X1(ub);
+ y0 = (uta->y0 + y) * ART_UTILE_SIZE + ART_UTA_BBOX_Y0(ub);
+ y1 = (uta->y0 + y) * ART_UTILE_SIZE + ART_UTA_BBOX_Y1(ub);
+ printf ("%% tile %d, %d: %d %d %d %d\n",
+ x, y,
+ ART_UTA_BBOX_X0(ub),
+ ART_UTA_BBOX_Y0(ub),
+ ART_UTA_BBOX_X1(ub),
+ ART_UTA_BBOX_Y1(ub));
+ printf ("%d %d moveto %d %d lineto %d %d lineto %d %d lineto closepath fill\n",
+ XOFF + x0, YOFF - y0, XOFF + x1, YOFF - y0,
+ XOFF + x1, YOFF - y1, XOFF + x0, YOFF - y1);
+ }
+ }
+}
+
+static void
+print_rbuf_ps (int *rbuf, int width, int height)
+{
+ int x, y;
+
+ for (y = 0; y < height; y++)
+ for (x = 0; x < width; x++)
+ if (1 && rbuf[y * width + x] != 0)
+ printf ("%d %d moveto (%d) show\n", x * ART_UTILE_SIZE, y * ART_UTILE_SIZE,
+ rbuf[y * width + x]);
+}
+
+#if 0
+void
+randline (ArtUta *uta, int *rbuf, int rbuf_rowstride)
+{
+ double x0, y0, x1, y1;
+
+ x0 = rand () * (500.0 / RAND_MAX);
+ y0 = rand () * (500.0 / RAND_MAX);
+ x1 = rand () * (500.0 / RAND_MAX);
+ y1 = rand () * (500.0 / RAND_MAX);
+
+ printf ("%g %g moveto %g %g lineto stroke\n", x0, y0, x1, y1);
+ art_uta_add_line (uta, x0, y0, x1, y1, rbuf, rbuf_rowstride);
+}
+#endif
+
+static void
+print_ps_vpath (ArtVpath *vpath)
+{
+ int i;
+
+ for (i = 0; vpath[i].code != ART_END; i++)
+ {
+ switch (vpath[i].code)
+ {
+ case ART_MOVETO:
+ printf ("%g %g moveto\n", XOFF + vpath[i].x, YOFF - vpath[i].y);
+ break;
+ case ART_LINETO:
+ printf ("%g %g lineto\n", XOFF + vpath[i].x, YOFF - vpath[i].y);
+ break;
+ default:
+ break;
+ }
+ }
+ printf ("stroke\n");
+}
+
+static ArtVpath *
+randstar (int n)
+{
+ ArtVpath *vec;
+ int i;
+ double r, th;
+
+ vec = art_new (ArtVpath, n + 2);
+ for (i = 0; i < n; i++)
+ {
+ vec[i].code = i ? ART_LINETO : ART_MOVETO;
+ r = rand () * (250.0 / RAND_MAX);
+ th = i * 2 * M_PI / n;
+ vec[i].x = 250 + r * cos (th);
+ vec[i].y = 250 - r * sin (th);
+ }
+ vec[i].code = ART_LINETO;
+ vec[i].x = vec[0].x;
+ vec[i].y = vec[0].y;
+ i++;
+ vec[i].code = ART_END;
+ vec[i].x = 0;
+ vec[i].y = 0;
+ return vec;
+}
+
+int
+main (int argc, char **argv)
+{
+ ArtUta *uta;
+ int i;
+ int *rbuf;
+ ArtVpath *vec;
+ ArtIRect *rects;
+ int n_rects;
+
+ if (argc == 2)
+ srand (atoi (argv[1]));
+
+#ifdef TEST_UTA
+ printf ("%%!PS-Adobe\n");
+ printf ("/Helvetica findfont 12 scalefont setfont\n");
+ printf ("0.5 setlinewidth\n");
+
+ printf ("0.5 setgray\n");
+ for (i = 0; i < 500; i += ART_UTILE_SIZE)
+ {
+ printf ("%d %d moveto %d %d lineto stroke\n",
+ XOFF, YOFF - i, XOFF + 500, YOFF - i);
+ printf ("%d %d moveto %d %d lineto stroke\n",
+ XOFF + i, YOFF, XOFF + i, YOFF - 500);
+ }
+
+ printf ("/a {\n");
+
+#if 1
+ vec = randstar (50);
+ print_ps_vpath (vec);
+ uta = art_uta_from_vpath (vec);
+#ifdef TEST_UTA_RECT
+ {
+ ArtIRect bbox = {5, 5, 450, 450};
+ uta = art_uta_from_irect (&bbox);
+ }
+#endif
+ rbuf = 0;
+#else
+ uta = art_uta_new_coords (0, 0, 500, 500);
+
+ rbuf = malloc (sizeof(int) * (500 >> ART_UTILE_SHIFT) * (500 >> ART_UTILE_SHIFT));
+ for (i = 0; i < 10; i++)
+ randline (uta, rbuf, 500 >> ART_UTILE_SHIFT);
+#endif
+
+ printf ("} def 1 0.5 0.5 setrgbcolor\n");
+
+ print_uta_ps (uta);
+
+ printf ("0 0 0.5 setrgbcolor\n");
+
+ if (rbuf)
+ print_rbuf_ps (rbuf, 500 >> ART_UTILE_SHIFT, 500 >> ART_UTILE_SHIFT);
+
+ printf ("0 setgray a\n");
+
+ rects = art_rect_list_from_uta (uta, 256, 64, &n_rects);
+
+ printf ("%% %d rectangles:\n0 0 1 setrgbcolor\n", n_rects);
+
+ for (i = 0; i < n_rects; i++)
+ printf ("%d %d moveto %d %d lineto %d %d lineto %d %d lineto closepath stroke\n",
+ XOFF + rects[i].x0, YOFF - rects[i].y0,
+ XOFF + rects[i].x1, YOFF - rects[i].y0,
+ XOFF + rects[i].x1, YOFF - rects[i].y1,
+ XOFF + rects[i].x0, YOFF - rects[i].y1);
+
+ printf ("showpage\n");
+#endif
+
+#ifdef TEST_UTA_SPEED
+ for (i = 0; i < 1000; i++)
+ {
+ vec = randstar (50);
+ uta = art_uta_from_vpath (vec);
+ art_free (vec);
+ art_uta_free (uta);
+ }
+#endif
+
+ return 0;
+}
--- /dev/null
+cd libpng-1.2.0/
+rm -rf contrib/ projects/ scripts/ configure
+
+---- create Makefile.am
--- /dev/null
+
+Libpng 1.2.0 - September 1, 2001
+
+This is a public release of libpng, intended for use in production codes.
+
+Changes since the last public release (1.0.12):
+
+ Enabled PNG_MNG_FEATURES_SUPPORTED and enabled PNG_ASSEMBLER_CODE_SUPPORTED
+ by default.
+ Added runtime selection of MMX features.
+ Added png_set_strip_error_numbers function and related macros.
+ Enabled user memory function by default.
+ Increased png_mng_features flag from png_byte to png_uint_32.
+ Bumped shared-library (so-number) and dll-number to 3.
+ Updated makefile.ibmc, makefile.gcmmx
+ Added some typecasts to eliminate gcc 3.0 warnings. Changed prototypes
+ of png_write_oFFS width and height from png_uint_32 to png_int_32.
+ Updated example.c
+ Revised prototypes for png_debug_malloc and png_debug_free in pngtest.c
+ Revised pnggccrd.c to conditionally compile some thread-unsafe code only
+ when PNG_THREAD_UNSAFE_OK is defined.
+ Added tests to prevent pngwutil.c from writing a bKGD or tRNS chunk with
+ value exceeding 2^bit_depth-1
+ Removed restriction that do_invert_mono only operate on 1-bit opaque files
+ Replaced calls to fprintf(stderr,...) with png_warning() or png_debug()
+ in pnggccrd.c
+ Fixed contrib/gregbook/rpng-x.c, rpng2-x.c to avoid crash with XFreeGC().
+
+Send comments/corrections/commendations to
+png-implement@ccrc.wustl.edu or to randeg@alum.rpi.edu
+
+Glenn R-P
--- /dev/null
+
+CHANGES - changes for libpng
+
+version 0.2
+ added reader into png.h
+ fixed small problems in stub file
+version 0.3
+ added pull reader
+ split up pngwrite.c to several files
+ added pnglib.txt
+ added example.c
+ cleaned up writer, adding a few new tranformations
+ fixed some bugs in writer
+ interfaced with zlib 0.5
+ added K&R support
+ added check for 64 KB blocks for 16 bit machines
+version 0.4
+ cleaned up code and commented code
+ simplified time handling into png_time
+ created png_color_16 and png_color_8 to handle color needs
+ cleaned up color type defines
+ fixed various bugs
+ made various names more consistant
+ interfaced with zlib 0.71
+ cleaned up zTXt reader and writer (using zlib's Reset functions)
+ split transformations into pngrtran.c and pngwtran.c
+version 0.5
+ interfaced with zlib 0.8
+ fixed many reading and writing bugs
+ saved using 3 spaces instead of tabs
+version 0.6
+ added png_large_malloc() and png_large_free()
+ added png_size_t
+ cleaned up some compiler warnings
+ added png_start_read_image()
+version 0.7
+ cleaned up lots of bugs
+ finished dithering and other stuff
+ added test program
+ changed name from pnglib to libpng
+version 0.71 [June, 1995]
+ changed pngtest.png for zlib 0.93
+ fixed error in libpng.txt and example.c
+version 0.8
+ cleaned up some bugs
+ added png_set_filler()
+ split up pngstub.c into pngmem.c, pngio.c, and pngerror.c
+ added #define's to remove unwanted code
+ moved png_info_init() to png.c
+ added old_size into png_realloc()
+ added functions to manually set filtering and compression info
+ changed compression parameters based on image type
+ optimized filter selection code
+ added version info
+ changed external functions passing floats to doubles (k&r problems?)
+ put all the configurable stuff in pngconf.h
+ enabled png_set_shift to work with paletted images on read
+ added png_read_update_info() - updates info structure with
+ transformations
+version 0.81 [August, 1995]
+ incorporated Tim Wegner's medium model code (thanks, Tim)
+version 0.82 [September, 1995]
+ [unspecified changes]
+version 0.85 [December, 1995]
+ added more medium model code (almost everything's a far)
+ added i/o, error, and memory callback functions
+ fixed some bugs (16 bit, 4 bit interlaced, etc.)
+ added first run progressive reader (barely tested)
+version 0.86 [January, 1996]
+ fixed bugs
+ improved documentation
+version 0.87 [January, 1996]
+ fixed medium model bugs
+ fixed other bugs introduced in 0.85 and 0.86
+ added some minor documentation
+version 0.88 [January, 1996]
+ fixed progressive bugs
+ replaced tabs with spaces
+ cleaned up documentation
+ added callbacks for read/write and warning/error functions
+version 0.89 [July, 1996]
+ added new initialization API to make libpng work better with shared libs
+ we now have png_create_read_struct(), png_create_write_struct(),
+ png_create_info_struct(), png_destroy_read_struct(), and
+ png_destroy_write_struct() instead of the separate calls to
+ malloc and png_read_init(), png_info_init(), and png_write_init()
+ changed warning/error callback functions to fix bug - this means you
+ should use the new initialization API if you were using the old
+ png_set_message_fn() calls, and that the old API no longer exists
+ so that people are aware that they need to change their code
+ changed filter selection API to allow selection of multiple filters
+ since it didn't work in previous versions of libpng anyways
+ optimized filter selection code
+ fixed png_set_background() to allow using an arbitrary RGB color for
+ paletted images
+ fixed gamma and background correction for paletted images, so
+ png_correct_palette is not needed unless you are correcting an
+ external palette (you will need to #define PNG_CORRECT_PALETTE_SUPPORTED
+ in pngconf.h) - if nobody uses this, it may disappear in the future.
+ fixed bug with Borland 64K memory allocation (Alexander Lehmann)
+ fixed bug in interlace handling (Smarasderagd, I think)
+ added more error checking for writing and image to reduce invalid files
+ separated read and write functions so that they won't both be linked
+ into a binary when only reading or writing functionality is used
+ new pngtest image also has interlacing and zTXt
+ updated documentation to reflect new API
+version 0.90 [January, 1997]
+ made CRC errors/warnings on critical and ancillary chunks configurable
+ libpng will use the zlib CRC routines by (compile-time) default
+ changed DOS small/medium model memory support - needs zlib 1.04 (Tim Wegner)
+ added external C++ wrapper statements to png.h (Gilles Dauphin)
+ allow PNG file to be read when some or all of file signature has already
+ been read from the beginning of the stream. ****This affects the size
+ of info_struct and invalidates all programs that use a shared libpng****
+ fixed png_filler() declarations
+ fixed? background color conversions
+ fixed order of error function pointers to match documentation
+ current chunk name is now available in png_struct to reduce the number
+ of nearly identical error messages (will simplify multi-lingual
+ support when available)
+ try to get ready for unknown-chunk callback functions:
+ - previously read critical chunks are flagged, so the chunk handling
+ routines can determine if the chunk is in the right place
+ - all chunk handling routines have the same prototypes, so we will
+ be able to handle all chunks via a callback mechanism
+ try to fix Linux "setjmp" buffer size problems
+ removed png_large_malloc, png_large_free, and png_realloc functions.
+version 0.95 [March, 1997]
+ fixed bug in pngwutil.c allocating "up_row" twice and "avg_row" never
+ fixed bug in PNG file signature compares when start != 0
+ changed parameter type of png_set_filler(...filler...) from png_byte
+ to png_uint_32
+ added test for MACOS to ensure that both math.h and fp.h are not #included
+ added macros for libpng to be compiled as a Windows DLL (Andreas Kupries)
+ added "packswap" transformation, which changes the endianness of
+ packed-pixel bytes (Kevin Bracey)
+ added "strip_alpha" transformation, which removes the alpha channel of
+ input images without using it (not neccesarily a good idea)
+ added "swap_alpha" transformation, which puts the alpha channel in front
+ of the color bytes instead of after
+ removed all implicit variable tests which assume NULL == 0 (I think)
+ changed several variables to "png_size_t" to show 16/32-bit limitations
+ added new pCAL chunk read/write support
+ added experimental filter selection weighting (Greg Roelofs)
+ removed old png_set_rgbx() and png_set_xrgb() functions that have been
+ obsolete for about 2 years now (use png_set_filler() instead)
+ added macros to read 16- and 32-bit ints directly from buffer, to be
+ used only on those systems that support it (namely PowerPC and 680x0)
+ With some testing, this may become the default for MACOS/PPC systems.
+ only calculate CRC on data if we are going to use it
+ added macros for zTXt compression type PNG_zTXt_COMPRESSION_???
+ added macros for simple libpng debugging output selectable at compile time
+ removed PNG_READ_END_MODE in progressive reader (Smarasderagd)
+ more description of info_struct in libpng.txt and png.h
+ more instructions in example.c
+ more chunk types tested in pngtest.c
+ renamed pngrcb.c to pngset.c, and all png_read_<chunk> functions to be
+ png_set_<chunk>. We now have corresponding png_get_<chunk>
+ functions in pngget.c to get infomation in info_ptr. This isolates
+ the application from the internal organization of png_info_struct
+ (good for shared library implementations).
+version 0.96 [May, 1997]
+ fixed serious bug with < 8bpp images introduced in 0.95
+ fixed 256-color transparency bug (Greg Roelofs)
+ fixed up documentation (Greg Roelofs, Laszlo Nyul)
+ fixed "error" in pngconf.h for Linux setjmp() behaviour
+ fixed DOS medium model support (Tim Wegner)
+ fixed png_check_keyword() for case with error in static string text
+ added read of CRC after IEND chunk for embedded PNGs (Laszlo Nyul)
+ added typecasts to quiet compiler errors
+ added more debugging info
+version 0.97 [January, 1998]
+ removed PNG_USE_OWN_CRC capability
+ relocated png_set_crc_action from pngrutil.c to pngrtran.c
+ fixed typecasts of "new_key", etc. (Andreas Dilger)
+ added RFC 1152 [sic] date support
+ fixed bug in gamma handling of 4-bit grayscale
+ added 2-bit grayscale gamma handling (Glenn R-P)
+ added more typecasts. 65536L becomes (png_uint_32)65536L, etc. (Glenn R-P)
+ minor corrections in libpng.txt
+ added simple sRGB support (Glenn R-P)
+ easier conditional compiling, e.g. define PNG_READ/WRITE_NOT_FULLY_SUPPORTED;
+ all configurable options can be selected from command-line instead
+ of having to edit pngconf.h (Glenn R-P)
+ fixed memory leak in pngwrite.c (free info_ptr->text) (Glenn R-P)
+ added more conditions for png_do_background, to avoid changing
+ black pixels to background when a background is supplied and
+ no pixels are transparent
+ repaired PNG_NO_STDIO behaviour
+ tested NODIV support and made it default behaviour (Greg Roelofs)
+ added "-m" option and PNGTEST_DEBUG_MEMORY to pngtest (John Bowler)
+ regularized version numbering scheme and bumped shared-library major
+ version number to 2 to avoid problems with libpng 0.89 apps (Greg Roelofs)
+version 0.98 [January, 1998]
+ cleaned up some typos in libpng.txt and in code documentation
+ fixed memory leaks in pCAL chunk processing (Glenn R-P and John Bowler)
+ cosmetic change "display_gamma" to "screen_gamma" in pngrtran.c
+ changed recommendation about file_gamma for PC images to .51 from .45,
+ in example.c and libpng.txt, added comments to distinguish between
+ screen_gamma, viewing_gamma, and display_gamma.
+ changed all references to RFC1152 to read RFC1123 and changed the
+ PNG_TIME_RFC1152_SUPPORTED macro to PNG_TIME_RFC1123_SUPPORTED
+ added png_invert_alpha capability (Glenn R-P -- suggestion by Jon Vincent)
+ changed srgb_intent from png_byte to int to avoid compiler bugs
+version 0.99 [January 30, 1998]
+ free info_ptr->text instead of end_info_ptr->text in pngread.c (John Bowler)
+ fixed a longstanding "packswap" bug in pngtrans.c
+ fixed some inconsistencies in pngconf.h that prevented compiling with
+ PNG_READ_GAMMA_SUPPORTED and PNG_READ_hIST_SUPPORTED undefined
+ fixed some typos and made other minor rearrangement of libpng.txt (Andreas)
+ changed recommendation about file_gamma for PC images to .50 from .51 in
+ example.c and libpng.txt, and changed file_gamma for sRGB images to .45
+ added a number of functions to access information from the png structure
+ png_get_image_height(), etc. (Glenn R-P, suggestion by Brad Pettit)
+ added TARGET_MACOS similar to zlib-1.0.8
+ define PNG_ALWAYS_EXTERN when __MWERKS__ && WIN32 are defined
+ added type casting to all png_malloc() function calls
+version 0.99a [January 31, 1998]
+ Added type casts and parentheses to all returns that return a value.(Tim W.)
+version 0.99b [February 4, 1998]
+ Added type cast png_uint_32 on malloc function calls where needed.
+ Changed type of num_hist from png_uint_32 to int (same as num_palette).
+ Added checks for rowbytes overflow, in case png_size_t is less than 32 bits.
+ Renamed makefile.elf to makefile.lnx.
+version 0.99c [February 7, 1998]
+ More type casting. Removed erroneous overflow test in pngmem.c.
+ Added png_buffered_memcpy() and png_buffered_memset(), apply them to rowbytes.
+ Added UNIX manual pages libpng.3 (incorporating libpng.txt) and png.5.
+version 0.99d [February 11, 1998]
+ Renamed "far_to_near()" "png_far_to_near()"
+ Revised libpng.3
+ Version 99c "buffered" operations didn't work as intended. Replaced them
+ with png_memcpy_check() and png_memset_check().
+ Added many "if (png_ptr == NULL) return" to quell compiler warnings about
+ unused png_ptr, mostly in pngget.c and pngset.c.
+ Check for overlength tRNS chunk present when indexed-color PLTE is read.
+ Cleaned up spelling errors in libpng.3/libpng.txt
+ Corrected a problem with png_get_tRNS() which returned undefined trans array
+version 0.99e [February 28, 1998]
+ Corrected png_get_tRNS() again.
+ Add parentheses for easier reading of pngget.c, fixed "||" should be "&&".
+ Touched up example.c to make more of it compileable, although the entire
+ file still can't be compiled (Willem van Schaik)
+ Fixed a bug in png_do_shift() (Bryan Tsai)
+ Added a space in png.h prototype for png_write_chunk_start()
+ Replaced pngtest.png with one created with zlib 1.1.1
+ Changed pngtest to report PASS even when file size is different (Jean-loup G.)
+ Corrected some logic errors in png_do_invert_alpha() (Chris Patterson)
+version 0.99f [March 5, 1998]
+ Corrected a bug in pngpread() introduced in version 99c (Kevin Bracey)
+ Moved makefiles into a "scripts" directory, and added INSTALL instruction file
+ Added makefile.os2 and pngos2.def (A. Zabolotny) and makefile.s2x (W. Sebok)
+ Added pointers to "note on libpng versions" in makefile.lnx and README
+ Added row callback feature when reading and writing nonprogressive rows
+ and added a test of this feature in pngtest.c
+ Added user transform callbacks, with test of the feature in pngtest.c
+version 0.99g [March 6, 1998, morning]
+ Minor changes to pngtest.c to suppress compiler warnings.
+ Removed "beta" language from documentation.
+version 0.99h [March 6, 1998, evening]
+ Minor changes to previous minor changes to pngtest.c
+ Changed PNG_READ_NOT_FULLY_SUPPORTED to PNG_READ_TRANSFORMS_NOT_SUPPORTED
+ and added PNG_PROGRESSIVE_READ_NOT_SUPPORTED macro
+ Added user transform capability
+version 1.00 [March 7, 1998]
+ Changed several typedefs in pngrutil.c
+ Added makefile.wat (Pawel Mrochen), updated makefile.tc3 (Willem van Schaik)
+ replaced "while(1)" with "for(;;)"
+ added PNGARG() to prototypes in pngtest.c and removed some prototypes
+ updated some of the makefiles (Tom Lane)
+ changed some typedefs (s_start, etc.) in pngrutil.c
+ fixed dimensions of "short_months" array in pngwrite.c
+ Replaced ansi2knr.c with the one from jpeg-v6
+version 1.0.0 [March 8, 1998]
+ Changed name from 1.00 to 1.0.0 (Adam Costello)
+ Added smakefile.ppc (with SCOPTIONS.ppc) for Amiga PPC (Andreas Kleinert)
+version 1.0.0a [March 9, 1998]
+ Fixed three bugs in pngrtran.c to make gamma+background handling consistent
+ (Greg Roelofs)
+ Changed format of the PNG_LIBPNG_VER integer to xyyzz instead of xyz
+ for major, minor, and bugfix releases. This is 10001. (Adam Costello,
+ Tom Lane)
+ Make months range from 1-12 in png_convert_to_rfc1123
+version 1.0.0b [March 13, 1998]
+ Quieted compiler complaints about two empty "for" loops in pngrutil.c
+ Minor changes to makefile.s2x
+ Removed #ifdef/#endif around a png_free() in pngread.c
+version 1.0.1 [March 14, 1998]
+ Changed makefile.s2x to reduce security risk of using a relative pathname
+ Fixed some typos in the documentation (Greg).
+ Fixed a problem with value of "channels" returned by png_read_update_info()
+version 1.0.1a [April 21, 1998]
+ Optimized Paeth calculations by replacing abs() function calls with intrinsics
+ plus other loop optimizations. Improves avg decoding speed by about 20%.
+ Commented out i386istic "align" compiler flags in makefile.lnx.
+ Reduced the default warning level in some makefiles, to make them consistent.
+ Removed references to IJG and JPEG in the ansi2knr.c copyright statement.
+ Fixed a bug in png_do_strip_filler with XXRRGGBB => RRGGBB transformation.
+ Added grayscale and 16-bit capability to png_do_read_filler().
+ Fixed a bug in pngset.c, introduced in version 0.99c, that sets rowbytes
+ too large when writing an image with bit_depth < 8 (Bob Dellaca).
+ Corrected some bugs in the experimental weighted filtering heuristics.
+ Moved a misplaced pngrutil code block that truncates tRNS if it has more
+ than num_palette entries -- test was done before num_palette was defined.
+ Fixed a png_convert_to_rfc1123() bug that converts day 31 to 0 (Steve Eddins).
+ Changed compiler flags in makefile.wat for better optimization (Pawel Mrochen).
+version 1.0.1b [May 2, 1998]
+ Relocated png_do_gray_to_rgb() within png_do_read_transformations() (Greg).
+ Relocated the png_composite macros from pngrtran.c to png.h (Greg).
+ Added makefile.sco (contributed by Mike Hopkirk).
+ Fixed two bugs (missing definitions of "istop") introduced in libpng-1.0.1a.
+ Fixed a bug in pngrtran.c that would set channels=5 under some circumstances.
+ More work on the Paeth-filtering, achieving imperceptible speedup (A Kleinert).
+ More work on loop optimization which may help when compiled with C++ compilers.
+ Added warnings when people try to use transforms they've defined out.
+ Collapsed 4 "i" and "c" loops into single "i" loops in pngrtran and pngwtran.
+ Revised paragraph about png_set_expand() in libpng.txt and libpng.3 (Greg)
+version 1.0.1c [May 11, 1998]
+ Fixed a bug in pngrtran.c (introduced in libpng-1.0.1a) where the masks for
+ filler bytes should have been 0xff instead of 0xf.
+ Added max_pixel_depth=32 in pngrutil.c when using FILLER with palette images.
+ Moved PNG_WRITE_WEIGHTED_FILTER_SUPPORTED and PNG_WRITE_FLUSH_SUPPORTED
+ out of the PNG_WRITE_TRANSFORMS_NOT_SUPPORTED block of pngconf.h
+ Added "PNG_NO_WRITE_TRANSFORMS" etc., as alternatives for *_NOT_SUPPORTED,
+ for consistency, in pngconf.h
+ Added individual "ifndef PNG_NO_[CAPABILITY]" in pngconf.h to make it easier
+ to remove unwanted capabilities via the compile line
+ Made some corrections to grammar (which, it's) in documentation (Greg).
+ Corrected example.c, use of row_pointers in png_write_image().
+version 1.0.1d [May 24, 1998]
+ Corrected several statements that used side effects illegally in pngrutil.c
+ and pngtrans.c, that were introduced in version 1.0.1b
+ Revised png_read_rows() to avoid repeated if-testing for NULL (A Kleinert)
+ More corrections to example.c, use of row_pointers in png_write_image()
+ and png_read_rows().
+ Added pngdll.mak and pngdef.pas to scripts directory, contributed by
+ Bob Dellaca, to make a png32bd.dll with Borland C++ 4.5
+ Fixed error in example.c with png_set_text: num_text is 3, not 2 (Guido V.)
+ Changed several loops from count-down to count-up, for consistency.
+version 1.0.1e [June 6, 1998]
+ Revised libpng.txt and libpng.3 description of png_set_read|write_fn(), and
+ added warnings when people try to set png_read_fn and png_write_fn in
+ the same structure.
+ Added a test such that png_do_gamma will be done when num_trans==0
+ for truecolor images that have defined a background. This corrects an
+ error that was introduced in libpng-0.90 that can cause gamma processing
+ to be skipped.
+ Added tests in png.h to include "trans" and "trans_values" in structures
+ when PNG_READ_BACKGROUND_SUPPORTED or PNG_READ_EXPAND_SUPPORTED is defined.
+ Add png_free(png_ptr->time_buffer) in png_destroy_read_struct()
+ Moved png_convert_to_rfc_1123() from pngwrite.c to png.c
+ Added capability for user-provided malloc_fn() and free_fn() functions,
+ and revised pngtest.c to demonstrate their use, replacing the
+ PNGTEST_DEBUG_MEM feature.
+ Added makefile.w32, for Microsoft C++ 4.0 and later (Tim Wegner).
+version 1.0.2 [June 14, 1998]
+ Fixed two bugs in makefile.bor .
+version 1.0.2a [December 30, 1998]
+ Replaced and extended code that was removed from png_set_filler() in 1.0.1a.
+ Fixed a bug in png_do_filler() that made it fail to write filler bytes in
+ the left-most pixel of each row (Kevin Bracey).
+ Changed "static pngcharp tIME_string" to "static char tIME_string[30]"
+ in pngtest.c (Duncan Simpson).
+ Fixed a bug in pngtest.c that caused pngtest to try to write a tIME chunk
+ even when no tIME chunk was present in the source file.
+ Fixed a problem in pngrutil.c: gray_to_rgb didn't always work with 16-bit.
+ Fixed a problem in png_read_push_finish_row(), which would not skip some
+ passes that it should skip, for images that are less than 3 pixels high.
+ Interchanged the order of calls to png_do_swap() and png_do_shift()
+ in pngwtran.c (John Cromer).
+ Added #ifdef PNG_DEBUG/#endif surrounding use of PNG_DEBUG in png.h .
+ Changed "bad adaptive filter type" from error to warning in pngrutil.c .
+ Fixed a documentation error about default filtering with 8-bit indexed-color.
+ Separated the PNG_NO_STDIO macro into PNG_NO_STDIO and PNG_NO_CONSOLE_IO
+ (L. Peter Deutsch).
+ Added png_set_rgb_to_gray() and png_get_rgb_to_gray_status() functions.
+ Added png_get_copyright() and png_get_header_version() functions.
+ Revised comments on png_set_progressive_read_fn() in libpng.txt and example.c
+ Added information about debugging in libpng.txt and libpng.3 .
+ Changed "ln -sf" to "ln -s -f" in makefile.s2x, makefile.lnx, and makefile.sco.
+ Removed lines after Dynamic Dependencies" in makefile.aco .
+ Revised makefile.dec to make a shared library (Jeremie Petit).
+ Removed trailing blanks from all files.
+version 1.0.2a [January 6, 1999]
+ Removed misplaced #endif and #ifdef PNG_NO_EXTERN near the end of png.h
+ Added "if" tests to silence complaints about unused png_ptr in png.h and png.c
+ Changed "check_if_png" function in example.c to return true (nonzero) if PNG.
+ Changed libpng.txt to demonstrate png_sig_cmp() instead of png_check_sig()
+ which is obsolete.
+version 1.0.3 [January 14, 1999]
+ Added makefile.hux, for Hewlett Packard HPUX 10.20 and 11.00 (Jim Rice)
+ Added a statement of Y2K compliance in png.h, libpng.3, and Y2KINFO.
+version 1.0.3a [August 12, 1999]
+ Added check for PNG_READ_INTERLACE_SUPPORTED in pngread.c; issue a warning
+ if an attempt is made to read an interlaced image when it's not supported.
+ Added check if png_ptr->trans is defined before freeing it in pngread.c
+ Modified the Y2K statement to include versions back to version 0.71
+ Fixed a bug in the check for valid IHDR bit_depth/color_types in pngrutil.c
+ Modified makefile.wat (added -zp8 flag, ".symbolic", changed some comments)
+ Replaced leading blanks with tab characters in makefile.hux
+ Changed "dworkin.wustl.edu" to "ccrc.wustl.edu" in various documents.
+ Changed (float)red and (float)green to (double)red, (double)green
+ in png_set_rgb_to_gray() to avoid "promotion" problems in AIX.
+ Fixed a bug in pngconf.h that omitted <stdio.h> when PNG_DEBUG==0 (K Bracey).
+ Reformatted libpng.3 and libpngpf.3 with proper fonts (script by J. vanZandt).
+ Updated documentation to refer to the PNG-1.2 specification.
+ Removed ansi2knr.c and left pointers to the latest source for ansi2knr.c
+ in makefile.knr, INSTALL, and README (L. Peter Deutsch)
+ Fixed bugs in calculation of the length of rowbytes when adding alpha
+ channels to 16-bit images, in pngrtran.c (Chris Nokleberg)
+ Added function png_set_user_transform_info() to store user_transform_ptr,
+ user_depth, and user_channels into the png_struct, and a function
+ png_get_user_transform_ptr() to retrieve the pointer (Chris Nokleberg)
+ Added function png_set_empty_plte_permitted() to make libpng useable
+ in MNG applications.
+ Corrected the typedef for png_free_ptr in png.h (Jesse Jones).
+ Correct gamma with srgb is 45455 instead of 45000 in pngrutil.c, to be
+ consistent with PNG-1.2, and allow variance of 500 before complaining.
+ Added assembler code contributed by Intel in file pngvcrd.c and modified
+ makefile.w32 to use it (Nirav Chhatrapati, INTEL Corporation, Gilles Vollant)
+ Changed "ln -s -f" to "ln -f -s" in the makefiles to make Solaris happy.
+ Added some aliases for png_set_expand() in pngrtran.c, namely
+ png_set_expand_PLTE(), png_set_expand_depth(), and png_set_expand_tRNS()
+ (Greg Roelofs, in "PNG: The Definitive Guide").
+ Added makefile.beo for BEOS on X86, contributed by Sander Stok.
+version 1.0.3b [August 26, 1999]
+ Replaced 2147483647L several places with PNG_MAX_UINT macro, defined in png.h
+ Changed leading blanks to tabs in all makefiles.
+ Define PNG_USE_PNGVCRD in makefile.w32, to get MMX assembler code.
+ Made alternate versions of png_set_expand() in pngrtran.c, namely
+ png_set_gray_1_2_4_to_8, png_set_palette_to_rgb, and png_set_tRNS_to_alpha
+ (Greg Roelofs, in "PNG: The Definitive Guide"). Deleted the 1.0.3a aliases.
+ Relocated start of 'extern "C"' block in png.h so it doesn't include pngconf.h
+ Revised calculation of num_blocks in pngmem.c to avoid a potentially
+ negative shift distance, whose results are undefined in the C language.
+ Added a check in pngset.c to prevent writing multiple tIME chunks.
+ Added a check in pngwrite.c to detect invalid small window_bits sizes.
+version 1.0.3d [September 4, 1999]
+ Fixed type casting of igamma in pngrutil.c
+ Added new png_expand functions to scripts/pngdef.pas and pngos2.def
+ Added a demo read_user_transform_fn that examines the row filters in pngtest.c
+version 1.0.4 [September 24, 1999]
+ Define PNG_ALWAYS_EXTERN in pngconf.h if __STDC__ is defined
+ Delete #define PNG_INTERNAL and include "png.h" from pngasmrd.h
+ Made several minor corrections to pngtest.c
+ Renamed the makefiles with longer but more user friendly extensions.
+ Copied the PNG copyright and license to a separate LICENSE file.
+ Revised documentation, png.h, and example.c to remove reference to
+ "viewing_gamma" which no longer appears in the PNG specification.
+ Revised pngvcrd.c to use MMX code for interlacing only on the final pass.
+ Updated pngvcrd.c to use the faster C filter algorithms from libpng-1.0.1a
+ Split makefile.win32vc into two versions, makefile.vcawin32 (uses MMX
+ assembler code) and makefile.vcwin32 (doesn't).
+ Added a CPU timing report to pngtest.c (enabled by defining PNGTEST_TIMING)
+ Added a copy of pngnow.png to the distribution.
+version 1.0.4a [September 25, 1999]
+ Increase max_pixel_depth in pngrutil.c if a user transform needs it.
+ Changed several division operations to right-shifts in pngvcrd.c
+version 1.0.4b [September 30, 1999]
+ Added parentheses in line 3732 of pngvcrd.c
+ Added a comment in makefile.linux warning about buggy -O3 in pgcc 2.95.1
+version 1.0.4c [October 1, 1999]
+ Added a "png_check_version" function in png.c and pngtest.c that will generate
+ a helpful compiler error if an old png.h is found in the search path.
+ Changed type of png_user_transform_depth|channels from int to png_byte.
+version 1.0.4d [October 6, 1999]
+ Changed 0.45 to 0.45455 in png_set_sRGB()
+ Removed unused PLTE entries from pngnow.png
+ Re-enabled some parts of pngvcrd.c (png_combine_row) that work properly.
+version 1.0.4e [October 10, 1999]
+ Fixed sign error in pngvcrd.c (Greg Roelofs)
+ Replaced some instances of memcpy with simple assignments in pngvcrd (GR-P)
+version 1.0.4f [October 15, 1999]
+ Surrounded example.c code with #if 0 .. #endif to prevent people from
+ inadvertently trying to compile it.
+ Changed png_get_header_version() from a function to a macro in png.h
+ Added type casting mostly in pngrtran.c and pngwtran.c
+ Removed some pointless "ptr = NULL" in pngmem.c
+ Added a "contrib" directory containing the source code from Greg's book.
+version 1.0.5 [October 15, 1999]
+ Minor editing of the INSTALL and README files.
+version 1.0.5a [October 23, 1999]
+ Added contrib/pngsuite and contrib/pngminus (Willem van Schaik)
+ Fixed a typo in the png_set_sRGB() function call in example.c (Jan Nijtmans)
+ Further optimization and bugfix of pngvcrd.c
+ Revised pngset.c so that it does not allocate or free memory in the user's
+ text_ptr structure. Instead, it makes its own copy.
+ Created separate write_end_info_struct in pngtest.c for a more severe test.
+ Added code in pngwrite.c to free info_ptr->text[i].key to stop a memory leak.
+version 1.0.5b [November 23, 1999]
+ Moved PNG_FLAG_HAVE_CHUNK_HEADER, PNG_FLAG_BACKGROUND_IS_GRAY and
+ PNG_FLAG_WROTE_tIME from flags to mode.
+ Added png_write_info_before_PLTE() function.
+ Fixed some typecasting in contrib/gregbook/*.c
+ Updated scripts/makevms.com and added makevms.com to contrib/gregbook
+ and contrib/pngminus (Martin Zinser)
+version 1.0.5c [November 26, 1999]
+ Moved png_get_header_version from png.h to png.c, to accomodate ansi2knr.
+ Removed all global arrays (according to PNG_NO_GLOBAL_ARRAYS macro), to
+ accomodate making DLL's: Moved usr_png_ver from global variable to function
+ png_get_header_ver() in png.c. Moved png_sig to png_sig_bytes in png.c and
+ eliminated use of png_sig in pngwutil.c. Moved the various png_CHNK arrays
+ into pngtypes.h. Eliminated use of global png_pass arrays. Declared the
+ png_CHNK and png_pass arrays to be "const". Made the global arrays
+ available to applications (although none are used in libpng itself) when
+ PNG_NO_GLOBAL_ARRAYS is not defined or when PNG_GLOBAL_ARRAYS is defined.
+ Removed some extraneous "-I" from contrib/pngminus/makefile.std
+ Changed the PNG_sRGB_INTENT macros in png.h to be consistent with PNG-1.2.
+ Change PNG_SRGB_INTENT to PNG_sRGB_INTENT in libpng.txt and libpng.3
+version 1.0.5d [November 29, 1999]
+ Add type cast (png_const_charp) two places in png.c
+ Eliminated pngtypes.h; use macros instead to declare PNG_CHNK arrays.
+ Renamed "PNG_GLOBAL_ARRAYS" to "PNG_USE_GLOBAL_ARRAYS" and made available
+ to applications a macro "PNG_USE_LOCAL_ARRAYS".
+ #ifdef out all the new declarations when PNG_USE_GLOBAL_ARRAYS is defined.
+ Added PNG_EXPORT_VAR macro to accommodate making DLL's.
+version 1.0.5e [November 30, 1999]
+ Added iCCP, iTXt, and sPLT support; added "lang" member to the png_text
+ structure; refactored the inflate/deflate support to make adding new chunks
+ with trailing compressed parts easier in the future, and added new functions
+ png_free_iCCP, png_free_pCAL, png_free_sPLT, png_free_text, png_get_iCCP,
+ png_get_spalettes, png_set_iCCP, png_set_spalettes (Eric S. Raymond).
+ NOTE: Applications that write text chunks MUST define png_text->lang
+ before calling png_set_text(). It must be set to NULL if you want to
+ write tEXt or zTXt chunks. If you want your application to be able to
+ run with older versions of libpng, use
+
+ #ifdef PNG_iTXt_SUPPORTED
+ png_text[i].lang = NULL;
+ #endif
+
+ Changed png_get_oFFs() and png_set_oFFs() to use signed rather than unsigned
+ offsets (Eric S. Raymond).
+ Combined PNG_READ_cHNK_SUPPORTED and PNG_WRITE_cHNK_SUPPORTED macros into
+ PNG_cHNK_SUPPORTED and combined the three types of PNG_text_SUPPORTED
+ macros, leaving the separate macros also available.
+ Removed comments on #endifs at the end of many short, non-nested #if-blocks.
+version 1.0.5f [December 6, 1999]
+ Changed makefile.solaris to issue a warning about potential problems when
+ the ucb "ld" is in the path ahead of the ccs "ld".
+ Removed "- [date]" from the "synopsis" line in libpng.3 and libpngpf.3.
+ Added sCAL chunk support (Eric S. Raymond).
+version 1.0.5g [December 7, 1999]
+ Fixed "png_free_spallettes" typo in png.h
+ Added code to handle new chunks in pngpread.c
+ Moved PNG_CHNK string macro definitions outside of PNG_NO_EXTERN block
+ Added "translated_key" to png_text structure and png_write_iTXt().
+ Added code in pngwrite.c to work around a newly discovered zlib bug.
+version 1.0.5h [December 10, 1999]
+ NOTE: regarding the note for version 1.0.5e, the following must also
+ be included in your code:
+ png_text[i].translated_key = NULL;
+ Unknown chunk handling is now supported.
+ Option to eliminate all floating point support was added. Some new
+ fixed-point functions such as png_set_gAMA_fixed() were added.
+ Expanded tabs and removed trailing blanks in source files.
+version 1.0.5i [December 13, 1999]
+ Added some type casts to silence compiler warnings.
+ Renamed "png_free_spalette" to "png_free_spalettes" for consistency.
+ Removed leading blanks from a #define in pngvcrd.c
+ Added some parameters to the new png_set_keep_unknown_chunks() function.
+ Added a test for up->location != 0 in the first instance of writing
+ unknown chunks in pngwrite.c
+ Changed "num" to "i" in png_free_spalettes() and png_free_unknowns() to
+ prevent recursion.
+ Added png_free_hIST() function.
+ Various patches to fix bugs in the sCAL and integer cHRM processing,
+ and to add some convenience macros for use with sCAL.
+version 1.0.5j [December 21, 1999]
+ Changed "unit" parameter of png_write_sCAL from png_byte to int, to work
+ around buggy compilers.
+ Added new type "png_fixed_point" for integers that hold float*100000 values
+ Restored backward compatibility of tEXt/zTXt chunk processing:
+ Restored the first four members of png_text to the same order as v.1.0.5d.
+ Added members "lang_key" and "itxt_length" to png_text struct. Set
+ text_length=0 when "text" contains iTXt data. Use the "compression"
+ member to distinguish among tEXt/zTXt/iTXt types. Added
+ PNG_ITXT_COMPRESSION_NONE (1) and PNG_ITXT_COMPRESSION_zTXt(2) macros.
+ The "Note" above, about backward incompatibility of libpng-1.0.5e, no
+ longer applies.
+ Fixed png_read|write_iTXt() to read|write parameters in the right order,
+ and to write the iTXt chunk after IDAT if it appears in the end_ptr.
+ Added pnggccrd.c, version of pngvcrd.c Intel assembler for gcc (Greg Roelofs)
+ Reversed the order of trying to write floating-point and fixed-point gAMA.
+version 1.0.5k [December 27, 1999]
+ Added many parentheses, e.g., "if (a && b & c)" becomes "if (a && (b & c))"
+ Added png_handle_as_unknown() function (Glenn)
+ Added png_free_chunk_list() function and chunk_list and num_chunk_list members
+ of png_ptr.
+ Eliminated erroneous warnings about multiple sPLT chunks and sPLT-after-PLTE.
+ Fixed a libpng-1.0.5h bug in pngrutil.c that was issuing erroneous warnings
+ about ignoring incorrect gAMA with sRGB (gAMA was in fact not ignored)
+ Added png_free_tRNS(); png_set_tRNS() now malloc's its own trans array (ESR).
+ Define png_get_int_32 when oFFs chunk is supported as well as when pCAL is.
+ Changed type of proflen from png_int_32 to png_uint_32 in png_get_iCCP().
+version 1.0.5l [January 1, 2000]
+ Added functions png_set_read_user_chunk_fn() and png_get_user_chunk_ptr()
+ for setting a callback function to handle unknown chunks and for
+ retrieving the associated user pointer (Glenn).
+version 1.0.5m [January 7, 2000]
+ Added high-level functions png_read_png(), png_write_png(), png_free_pixels().
+version 1.0.5n [January 9, 2000]
+ Added png_free_PLTE() function, and modified png_set_PLTE() to malloc its
+ own memory for info_ptr->palette. This makes it safe for the calling
+ application to free its copy of the palette any time after it calls
+ png_set_PLTE().
+version 1.0.5o [January 20, 2000]
+ Cosmetic changes only (removed some trailing blanks and TABs)
+version 1.0.5p [January 31, 2000]
+ Renamed pngdll.mak to makefile.bd32
+ Cosmetic changes in pngtest.c
+version 1.0.5q [February 5, 2000]
+ Relocated the makefile.solaris warning about PATH problems.
+ Fixed pngvcrd.c bug by pushing/popping registers in mmxsupport (Bruce Oberg)
+ Revised makefile.gcmmx
+ Added PNG_SETJMP_SUPPORTED, PNG_SETJMP_NOT_SUPPORTED, and PNG_ABORT() macros
+version 1.0.5r [February 7, 2000]
+ Removed superfluous prototype for png_get_itxt from png.h
+ Fixed a bug in pngrtran.c that improperly expanded the background color.
+ Return *num_text=0 from png_get_text() when appropriate, and fix documentation
+ of png_get_text() in libpng.txt/libpng.3.
+version 1.0.5s [February 18, 2000]
+ Added "png_jmp_env()" macro to pngconf.h, to help people migrate to the
+ new error handler that's planned for the next libpng release, and changed
+ example.c, pngtest.c, and contrib programs to use this macro.
+ Revised some of the DLL-export macros in pngconf.h (Greg Roelofs)
+ Fixed a bug in png_read_png() that caused it to fail to expand some images
+ that it should have expanded.
+ Fixed some mistakes in the unused and undocumented INCH_CONVERSIONS functions
+ in pngget.c
+ Changed the allocation of palette, history, and trans arrays back to
+ the version 1.0.5 method (linking instead of copying) which restores
+ backward compatibility with version 1.0.5. Added some remarks about
+ that in example.c. Added "free_me" member to info_ptr and png_ptr
+ and added png_free_data() function.
+ Updated makefile.linux and makefile.gccmmx to make directories conditionally.
+ Made cosmetic changes to pngasmrd.h
+ Added png_set_rows() and png_get_rows(), for use with png_read|write_png().
+ Modified png_read_png() to allocate info_ptr->row_pointers only if it
+ hasn't already been allocated.
+version 1.0.5t [March 4, 2000]
+ Changed png_jmp_env() migration aiding macro to png_jmpbuf().
+ Fixed "interlace" typo (should be "interlaced") in contrib/gregbook/read2-x.c
+ Fixed bug with use of PNG_BEFORE_IHDR bit in png_ptr->mode, introduced when
+ PNG_FLAG_HAVE_CHUNK_HEADER was moved into png_ptr->mode in version 1.0.5b
+ Files in contrib/gregbook were revised to use png_jmpbuf() and to select
+ a 24-bit visual if one is available, and to allow abbreviated options.
+ Files in contrib/pngminus were revised to use the png_jmpbuf() macro.
+ Removed spaces in makefile.linux and makefile.gcmmx, introduced in 1.0.5s
+version 1.0.5u [March 5, 2000]
+ Simplified the code that detects old png.h in png.c and pngtest.c
+ Renamed png_spalette (_p, _pp) to png_sPLT_t (_tp, _tpp)
+ Increased precision of rgb_to_gray calculations from 8 to 15 bits and
+ added png_set_rgb_to_gray_fixed() function.
+ Added makefile.bc32 (32-bit Borland C++, C mode)
+version 1.0.5v [March 11, 2000]
+ Added some parentheses to the png_jmpbuf macro definition.
+ Updated references to the zlib home page, which has moved to freesoftware.com.
+ Corrected bugs in documentation regarding png_read_row() and png_write_row().
+ Updated documentation of png_rgb_to_gray calculations in libpng.3/libpng.txt.
+ Renamed makefile.borland,turboc3 back to makefile.bor,tc3 as in version 1.0.3,
+ revised borland makefiles; added makefile.ibmvac3 and makefile.gcc (Cosmin)
+version 1.0.6 [March 20, 2000]
+ Minor revisions of makefile.bor, libpng.txt, and gregbook/rpng2-win.c
+ Added makefile.sggcc (SGI IRIX with gcc)
+version 1.0.6d [April 7, 2000]
+ Changed sprintf() to strcpy() in png_write_sCAL_s() to work without STDIO
+ Added data_length parameter to png_decompress_chunk() function
+ Revised documentation to remove reference to abandoned png_free_chnk functions
+ Fixed an error in png_rgb_to_gray_fixed()
+ Revised example.c, usage of png_destroy_write_struct().
+ Renamed makefile.ibmvac3 to makefile.ibmc, added libpng.icc IBM project file
+ Added a check for info_ptr->free_me&PNG_FREE_TEXT when freeing text in png.c
+ Simplify png_sig_bytes() function to remove use of non-ISO-C strdup().
+version 1.0.6e [April 9, 2000]
+ Added png_data_freer() function.
+ In the code that checks for over-length tRNS chunks, added check of
+ info_ptr->num_trans as well as png_ptr->num_trans (Matthias Benckmann)
+ Minor revisions of libpng.txt/libpng.3.
+ Check for existing data and free it if the free_me flag is set, in png_set_*()
+ and png_handle_*().
+ Only define PNG_WEIGHTED_FILTERS_SUPPORTED when PNG_FLOATING_POINT_SUPPORTED
+ is defined.
+ Changed several instances of PNG_NO_CONSOLE_ID to PNG_NO_STDIO in pngrutil.c
+ and mentioned the purposes of the two macros in libpng.txt/libpng.3.
+version 1.0.6f [April 14, 2000]
+ Revised png_set_iCCP() and png_set_rows() to avoid prematurely freeing data.
+ Add checks in png_set_text() for NULL members of the input text structure.
+ Revised libpng.txt/libpng.3.
+ Removed superfluous prototype for png_set_itxt from png.h
+ Removed "else" from pngread.c, after png_error(), and changed "0" to "length".
+ Changed several png_errors about malformed ancillary chunks to png_warnings.
+version 1.0.6g [April 24, 2000]
+ Added png_pass-* arrays to pnggccrd.c when PNG_USE_LOCAL_ARRAYS is defined.
+ Relocated paragraph about png_set_background() in libpng.3/libpng.txt
+ and other revisions (Matthias Benckmann)
+ Relocated info_ptr->free_me, png_ptr->free_me, and other info_ptr and
+ png_ptr members to restore binary compatibility with libpng-1.0.5
+ (breaks compatibility with libpng-1.0.6).
+version 1.0.6h [April 24, 2000]
+ Changed shared library so-number pattern from 2.x.y.z to xy.z (this builds
+ libpng.so.10 & libpng.so.10.6h instead of libpng.so.2 & libpng.so.2.1.0.6h)
+ This is a temporary change for test purposes.
+version 1.0.6i [May 2, 2000]
+ Rearranged some members at the end of png_info and png_struct, to put
+ unknown_chunks_num and free_me within the original size of the png_structs
+ and free_me, png_read_user_fn, and png_free_fn within the original png_info,
+ because some old applications allocate the structs directly instead of
+ using png_create_*().
+ Added documentation of user memory functions in libpng.txt/libpng.3
+ Modified png_read_png so that it will use user_allocated row_pointers
+ if present, unless free_me directs that it be freed, and added description
+ of the use of png_set_rows() and png_get_rows() in libpng.txt/libpng.3.
+ Added PNG_LEGACY_SUPPORTED macro, and #ifdef out all new (since version
+ 1.00) members of png_struct and png_info, to regain binary compatibility
+ when you define this macro. Capabilities lost in this event
+ are user transforms (new in version 1.0.0),the user transform pointer
+ (new in version 1.0.2), rgb_to_gray (new in 1.0.5), iCCP, sCAL, sPLT,
+ the high-level interface, and unknown chunks support (all new in 1.0.6).
+ This was necessary because of old applications that allocate the structs
+ directly as authors were instructed to do in libpng-0.88 and earlier,
+ instead of using png_create_*().
+ Added modes PNG_CREATED_READ_STRUCT and PNG_CREATED_WRITE_STRUCT which
+ can be used to detect codes that directly allocate the structs, and
+ code to check these modes in png_read_init() and png_write_init() and
+ generate a libpng error if the modes aren't set and PNG_LEGACY_SUPPORTED
+ was not defined.
+ Added makefile.intel and updated makefile.watcom (Pawel Mrochen)
+version 1.0.6j [May 3, 2000]
+ Overloaded png_read_init() and png_write_init() with macros that convert
+ calls to png_read_init_2() or png_write_init_2() that check the version
+ and structure sizes.
+version 1.0.7beta11 [May 7, 2000]
+ Removed the new PNG_CREATED_READ_STRUCT and PNG_CREATED_WRITE_STRUCT modes
+ which are no longer used.
+ Eliminated the three new members of png_text when PNG_NO_iTXt_SUPPORTED
+ or PNG_LEGACY_SUPPORTED is defined.
+ Made PNG_NO_ITXT_SUPPORTED the default setting, to avoid memory overrun
+ when old applications fill the info_ptr->text structure directly.
+ Added PNGAPI macro, and added it to the definitions of all exported functions.
+ Relocated version macro definitions ahead of the includes of zlib.h and
+ pngconf.h in png.h.
+version 1.0.7beta12 [May 12, 2000]
+ Revised pngset.c to avoid a problem with expanding the png_debug macro.
+ Deleted some extraneous defines from pngconf.h
+ Made PNG_NO_CONSOLE_IO the default condition when PNG_BUILD_DLL is defined.
+ Use MSC _RPTn debugging instead of fprintf if _MSC_VER is defined.
+ Added png_access_version_number() function.
+ Check for mask&PNG_FREE_CHNK (for TEXT, SCAL, PCAL) in png_free_data().
+ Expanded libpng.3/libpng.txt information about png_data_freer().
+version 1.0.7beta14 [May 17, 2000] (beta13 was not published)
+ Changed pnggccrd.c and pngvcrd.c to handle bad adaptive filter types as
+ warnings instead of errors, as pngrutil.c does.
+ Set the PNG_INFO_IDAT valid flag in png_set_rows() so png_write_png()
+ will actually write IDATs.
+ Made the default PNG_USE_LOCAL_ARRAYS depend on PNG_DLL instead of WIN32.
+ Make png_free_data() ignore its final parameter except when freeing data
+ that can have multiple instances (text, sPLT, unknowns).
+ Fixed a new bug in png_set_rows().
+ Removed info_ptr->valid tests from png_free_data(), as in version 1.0.5.
+ Added png_set_invalid() function.
+ Fixed incorrect illustrations of png_destroy_write_struct() in example.c.
+version 1.0.7beta15 [May 30, 2000]
+ Revised the deliberately erroneous Linux setjmp code in pngconf.h to produce
+ fewer error messages.
+ Rearranged checks for Z_OK to check the most likely path first in pngpread.c
+ and pngwutil.c.
+ Added checks in pngtest.c for png_create_*() returning NULL, and mentioned
+ in libpng.txt/libpng.3 the need for applications to check this.
+ Changed names of png_default_*() functions in pngtest to pngtest_*().
+ Changed return type of png_get_x|y_offset_*() from png_uint_32 to png_int_32.
+ Fixed some bugs in the unused PNG_INCH_CONVERSIONS functions in pngget.c
+ Set each pointer to NULL after freeing it in png_free_data().
+ Worked around a problem in pngconf.h; AIX's strings.h defines an "index"
+ macro that conflicts with libpng's png_color_16.index. (Dimitri Papadapoulos)
+ Added "msvc" directory with MSVC++ project files (Simon-Pierre Cadieux).
+version 1.0.7beta16 [June 4, 2000]
+ Revised the workaround of AIX string.h "index" bug.
+ Added a check for overlength PLTE chunk in pngrutil.c.
+ Added PNG_NO_POINTER_INDEXING macro to use array-indexing instead of pointer
+ indexing in pngrutil.c and pngwutil.c to accommodate a buggy compiler.
+ Added a warning in png_decompress_chunk() when it runs out of data, e.g.
+ when it tries to read an erroneous PhotoShop iCCP chunk.
+ Added PNG_USE_DLL macro.
+ Revised the copyright/disclaimer/license notice.
+ Added contrib/msvctest directory
+version 1.0.7rc1 [June 9, 2000]
+ Corrected the definition of PNG_TRANSFORM_INVERT_ALPHA (0x0400 not 0x0200)
+ Added contrib/visupng directory (Willem van Schaik)
+version 1.0.7beta18 [June 23, 2000]
+ Revised PNGAPI definition, and pngvcrd.c to work with __GCC__
+ and do not redefine PNGAPI if it is passed in via a compiler directive.
+ Revised visupng/PngFile.c to remove returns from within the Try block.
+ Removed leading underscores from "_PNG_H" and "_PNG_SAVE_BSD_SOURCE" macros.
+ Updated contrib/visupng/cexcept.h to version 1.0.0.
+ Fixed bugs in pngwrite.c and pngwutil.c that prevented writing iCCP chunks.
+version 1.0.7rc2 [June 28, 2000]
+ Updated license to include disclaimers required by UCITA.
+ Fixed "DJBPP" typo in pnggccrd.c introduced in beta18.
+version 1.0.7 [July 1, 2000]
+ Revised the definition of "trans_values" in libpng.3/libpng.txt
+version 1.0.8beta1 [July 8, 2000]
+ Added png_free(png_ptr, key) two places in pngpread.c to stop memory leaks.
+ Changed PNG_NO_STDIO to PNG_NO_CONSOLE_IO, several places in pngrutil.c and
+ pngwutil.c.
+ Changed PNG_EXPORT_VAR to use PNG_IMPEXP, in pngconf.h.
+ Removed unused "#include <assert.h>" from png.c
+ Added WindowsCE support.
+ Revised pnggccrd.c to work with gcc-2.95.2 and in the Cygwin environment.
+version 1.0.8beta2 [July 10, 2000]
+ Added project files to the wince directory and made further revisions
+ of pngtest.c, pngrio.c, and pngwio.c in support of WindowsCE.
+version 1.0.8beta3 [July 11, 2000]
+ Only set the PNG_FLAG_FREE_TRNS or PNG_FREE_TRNS flag in png_handle_tRNS()
+ for indexed-color input files to avoid potential double-freeing trans array
+ under some unusual conditions; problem was introduced in version 1.0.6f.
+ Further revisions to pngtest.c and files in the wince subdirectory.
+version 1.0.8beta4 [July 14, 2000]
+ Added the files pngbar.png and pngbar.jpg to the distribution.
+ Added makefile.cygwin, and cygwin support in pngconf.h
+ Added PNG_NO_ZALLOC_ZERO macro (makes png_zalloc skip zeroing memory)
+version 1.0.8rc1 [July 16, 2000]
+ Revised png_debug() macros and statements to eliminate compiler warnings.
+version 1.0.8 [July 24, 2000]
+ Added png_flush() in pngwrite.c, after png_write_IEND().
+ Updated makefile.hpux to build a shared library.
+version 1.0.9beta1 [November 10, 2000]
+ Fixed typo in scripts/makefile.hpux
+ Updated makevms.com in scripts and contrib/* and contrib/* (Martin Zinser)
+ Fixed seqence-point bug in contrib/pngminus/png2pnm (Martin Zinser)
+ Changed "cdrom.com" in documentation to "libpng.org"
+ Revised pnggccrd.c to get it all working, and updated makefile.gcmmx (Greg).
+ Changed type of "params" from voidp to png_voidp in png_read|write_png().
+ Make sure PNGAPI and PNG_IMPEXP are defined in pngconf.h.
+ Revised the 3 instances of WRITEFILE in pngtest.c.
+ Relocated "msvc" and "wince" project subdirectories into "dll" subdirectory.
+ Updated png.rc in dll/msvc project
+ Revised makefile.dec to define and use LIBPATH and INCPATH
+ Increased size of global png_libpng_ver[] array from 12 to 18 chars.
+ Made global png_libpng_ver[], png_sig[] and png_pass_*[] arrays const.
+ Removed duplicate png_crc_finish() from png_handle_bKGD() function.
+ Added a warning when application calls png_read_update_info() multiple times.
+ Revised makefile.cygwin
+ Fixed bugs in iCCP support in pngrutil.c and pngwutil.c.
+ Replaced png_set_empty_plte_permitted() with png_permit_mng_features().
+version 1.0.9beta2 [November 19, 2000]
+ Renamed the "dll" subdirectory "projects".
+ Added borland project files to "projects" subdirectory.
+ Set VS_FF_PRERELEASE and VS_FF_PATCHED flags in msvc/png.rc when appropriate.
+ Add error message in png_set_compression_buffer_size() when malloc fails.
+version 1.0.9beta3 [November 23, 2000]
+ Revised PNG_LIBPNG_BUILD_TYPE macro in png.h, used in the msvc project.
+ Removed the png_flush() in pngwrite.c that crashes some applications
+ that don't set png_output_flush_fn.
+ Added makefile.macosx and makefile.aix to scripts directory.
+version 1.0.9beta4 [December 1, 2000]
+ Change png_chunk_warning to png_warning in png_check_keyword().
+ Increased the first part of msg buffer from 16 to 18 in png_chunk_error().
+version 1.0.9beta5 [December 15, 2000]
+ Added support for filter method 64 (for PNG datastreams embedded in MNG).
+version 1.0.9beta6 [December 18, 2000]
+ Revised png_set_filter() to accept filter method 64 when appropriate.
+ Added new PNG_HAVE_PNG_SIGNATURE bit to png_ptr->mode and use it to
+ help prevent applications from using MNG features in PNG datastreams.
+ Added png_permit_mng_features() function.
+ Revised libpng.3/libpng.txt. Changed "filter type" to "filter method".
+version 1.0.9rc1 [December 23, 2000]
+ Revised test for PNG_HAVE_PNG_SIGNATURE in pngrutil.c
+ Fixed error handling of unknown compression type in png_decompress_chunk().
+ In pngconf.h, define __cdecl when _MSC_VER is defined.
+version 1.0.9beta7 [December 28, 2000]
+ Changed PNG_TEXT_COMPRESSION_zTXt to PNG_COMPRESSION_TYPE_BASE several places.
+ Revised memory management in png_set_hIST and png_handle_hIST in a backward
+ compatible manner. PLTE and tRNS were revised similarly.
+ Revised the iCCP chunk reader to ignore trailing garbage.
+version 1.0.9beta8 [January 12, 2001]
+ Moved pngasmrd.h into pngconf.h.
+ Improved handling of out-of-spec garbage iCCP chunks generated by PhotoShop.
+version 1.0.9beta9 [January 15, 2001]
+ Added png_set_invalid, png_permit_mng_features, and png_mmx_supported to
+ wince and msvc project module definition files.
+ Minor revision of makefile.cygwin.
+ Fixed bug with progressive reading of narrow interlaced images in pngpread.c
+version 1.0.9beta10 [January 16, 2001]
+ Do not typedef png_FILE_p in pngconf.h when PNG_NO_STDIO is defined.
+ Fixed "png_mmx_supported" typo in project definition files.
+version 1.0.9beta11 [January 19, 2001]
+ Updated makefile.sgi to make shared library.
+ Removed png_mmx_support() function and disabled PNG_MNG_FEATURES_SUPPORTED
+ by default, for the benefit of DLL forward compatibility. These will
+ be re-enabled in version 1.2.0.
+version 1.0.9rc2 [January 22, 2001]
+ Revised cygwin support.
+version 1.0.9 [January 31, 2001]
+ Added check of cygwin's ALL_STATIC in pngconf.h
+ Added "-nommx" parameter to contrib/gregbook/rpng2-win and rpng2-x demos.
+version 1.0.10beta1 [March 14, 2001]
+ Revised makefile.dec, makefile.sgi, and makefile.sggcc; added makefile.hpgcc.
+ Reformatted libpng.3 to eliminate bad line breaks.
+ Added checks for _mmx_supported in the read_filter_row function of pnggccrd.c
+ Added prototype for png_mmx_support() near the top of pnggccrd.c
+ Moved some error checking from png_handle_IHDR to png_set_IHDR.
+ Added PNG_NO_READ_SUPPORTED and PNG_NO_WRITE_SUPPORTED macros.
+ Revised png_mmx_support() function in pnggccrd.c
+ Restored version 1.0.8 PNG_WRITE_EMPTY_PLTE_SUPPORTED behavior in pngwutil.c
+ Fixed memory leak in contrib/visupng/PngFile.c
+ Fixed bugs in png_combine_row() in pnggccrd.c and pngvcrd.c (C version)
+ Added warnings when retrieving or setting gamma=0.
+ Increased the first part of msg buffer from 16 to 18 in png_chunk_warning().
+version 1.0.10rc1 [March 23, 2001]
+ Changed all instances of memcpy, strcpy, and strlen to png_memcpy, png_strcpy,
+ and png_strlen.
+ Revised png_mmx_supported() function in pnggccrd.c to return proper value.
+ Fixed bug in progressive reading (pngpread.c) with small images (height < 8).
+version 1.0.10 [March 30, 2001]
+ Deleted extraneous space (introduced in 1.0.9) from line 42 of makefile.cygwin
+ Added beos project files (Chris Herborth)
+version 1.0.11beta1 [April 3, 2001]
+ Added type casts on several png_malloc() calls (Dimitri Papadapoulos).
+ Removed a no-longer needed AIX work-around from pngconf.h
+ Changed several "//" single-line comments to C-style in pnggccrd.c
+version 1.0.11beta2 [April 11, 2001]
+ Removed PNGAPI from several functions whose prototypes did not have PNGAPI.
+ Updated scripts/pngos2.def
+version 1.0.11beta3 [April 14, 2001]
+ Added checking the results of many instances of png_malloc() for NULL
+version 1.0.11beta4 [April 20, 2001]
+ Undid the changes from version 1.0.11beta3. Added a check for NULL return
+ from user's malloc_fn().
+ Removed some useless type casts of the NULL pointer.
+ Added makefile.netbsd
+version 1.0.11 [April 27, 2001]
+ Revised makefile.netbsd
+version 1.0.12beta1 [May 14, 2001]
+ Test for Windows platform in pngconf.h when including malloc.h (Emmanuel Blot)
+ Updated makefile.cygwin and handling of Cygwin's ALL_STATIC in pngconf.h
+ Added some never-to-be-executed code in pnggccrd.c to quiet compiler warnings.
+ Eliminated the png_error about apps using png_read|write_init(). Instead,
+ libpng will reallocate the png_struct and info_struct if they are too small.
+ This retains future binary compatibility for old applications written for
+ libpng-0.88 and earlier.
+version 1.2.0beta1 [May 6, 2001]
+ Bumped DLLNUM to 2.
+ Re-enabled PNG_MNG_FEATURES_SUPPORTED and enabled PNG_ASSEMBLER_CODE_SUPPORTED
+ by default.
+ Added runtime selection of MMX features.
+ Added png_set_strip_error_numbers function and related macros.
+version 1.2.0beta2 [May 7, 2001]
+ Finished merging 1.2.0beta1 with version 1.0.11
+ Added a check for attempts to read or write PLTE in grayscale PNG datastreams.
+version 1.2.0beta3 [May 17, 2001]
+ Enabled user memory function by default.
+ Modified png_create_struct so it passes user mem_ptr to user memory allocator.
+ Increased png_mng_features flag from png_byte to png_uint_32.
+ Bumped shared-library (so-number) and dll-number to 3.
+version 1.2.0beta4 [June 23, 2001]
+ Check for missing profile length field in iCCP chunk and free chunk_data
+ in case of truncated iCCP chunk.
+ Bumped shared-library number to 3 in makefile.sgi and makefile.sggcc
+ Bumped dll-number from 2 to 3 in makefile.cygwin
+ Revised contrib/gregbook/rpng*-x.c to avoid a memory leak and to exit cleanly
+ if user attempts to run it on an 8-bit display.
+ Updated contrib/gregbook
+ Use png_malloc instead of png_zalloc to allocate palette in pngset.c
+ Updated makefile.ibmc
+ Added some typecasts to eliminate gcc 3.0 warnings. Changed prototypes
+ of png_write_oFFS width and height from png_uint_32 to png_int_32.
+ Updated example.c
+ Revised prototypes for png_debug_malloc and png_debug_free in pngtest.c
+version 1.2.0beta5 [August 8, 2001]
+ Revised contrib/gregbook
+ Revised makefile.gcmmx
+ Revised pnggccrd.c to conditionally compile some thread-unsafe code only
+ when PNG_THREAD_UNSAFE_OK is defined.
+ Added tests to prevent pngwutil.c from writing a bKGD or tRNS chunk with
+ value exceeding 2^bit_depth-1
+ Revised makefile.sgi and makefile.sggcc
+ Replaced calls to fprintf(stderr,...) with png_warning() in pnggccrd.c
+ Removed restriction that do_invert_mono only operate on 1-bit opaque files
+version 1.2.0 [September 1, 2001]
+ Changed a png_warning() to png_debug() in pnggccrd.c
+ Fixed contrib/gregbook/rpng-x.c, rpng2-x.c to avoid crash with XFreeGC().
+
+Send comments/corrections/commendations to
+png-implement@ccrc.wustl.edu or to randeg@alum.rpi.edu
+
+Glenn R-P
--- /dev/null
+
+Installing libpng version 1.2.0 - September 1, 2001
+
+Before installing libpng, you must first install zlib. zlib
+can usually be found wherever you got libpng. zlib can be
+placed in another directory, at the same level as libpng.
+Note that your system might already have a preinstalled
+zlib, but you will still need to have access to the
+zlib.h and zconf.h include files that correspond to the
+version of zlib that's installed.
+
+You can rename the directories that you downloaded (they
+might be called "libpng-1.2.0" or "lpng109" and "zlib-1.1.3"
+or "zlib113") so that you have directories called "zlib" and "libpng".
+
+Your directory structure should look like this:
+
+ .. (the parent directory)
+ libpng (this directory)
+ INSTALL (this file)
+ README
+ *.h
+ *.c
+ contrib
+ gregbook
+ msvctest
+ pngminus
+ pngsuite
+ visupng
+ projects
+ beos
+ borland
+ msvc
+ netware.txt
+ wince.txt
+ scripts
+ makefile.*
+ pngtest.png
+ etc.
+ zlib
+ README
+ *.h
+ *.c
+ contrib
+ etc.
+
+If the line endings in the files look funny, you may wish to get the other
+distribution of libpng. It is available in both tar.gz (UNIX style line
+endings) and zip (DOS style line endings) formats.
+
+If you are building libpng with MSVC, you can enter the libpng\msvc directory
+and follow the instructions in msvc\README.txt.
+
+You can build libpng for WindowsCE by entering the downloading and installing
+the libpng\wince directory as instructed in the projects\wince.txt file, and
+then following the instructions in the README* files. Similarly, you can
+build libpng for Netware as instructed in projects\netware.txt.
+
+Else enter the zlib directory and follow the instructions in zlib/README,
+then come back here and choose the appropriate makefile.sys in the scripts
+directory.
+
+The files that are presently available in the scripts directory
+include
+
+ makefile.std => Generic UNIX makefile (cc, creates static libpng.a)
+ makefile.linux => Linux/ELF makefile (gcc, creates libpng.so.2.1.2.0)
+ makefile.gcmmx => Linux/ELF makefile (gcc, creates libpng.so.2.1.2.0,
+ uses assembler code tuned for Intel MMX platform)
+ makefile.gcc => Generic makefile (gcc, creates static libpng.a)
+ makefile.knr => Archaic UNIX Makefile that converts files with
+ ansi2knr (Requires ansi2knr.c from
+ ftp://ftp.cs.wisc.edu/ghost)
+ makefile.aix => AIX makefile
+ makefile.cygwin => Cygwin/gcc makefile
+ makefile.dec => DEC Alpha UNIX makefile
+ makefile.hpgcc => HPUX makefile using gcc
+ makefile.hpux => HPUX (10.20 and 11.00) makefile
+ makefile.ibmc => IBM C/C++ version 3.x for Win32 and OS/2 (static)
+ makefile.intel => Intel C/C++ version 4.0 and later
+ libpng.icc => Project file for IBM VisualAge/C++ version 4.0 or later
+ makefile.macosx => MACOS X Makefile
+ makefile.netbsd => NetBSD/cc makefile, uses PNGGCCRD
+ makefile.sgi => Silicon Graphics IRIX makefile (cc, creates static lib)
+ makefile.sggcc => Silicon Graphics (gcc, creates libpng.so.2.1.2.0)
+ makefile.sunos => Sun makefile
+ makefile.solaris => Solaris 2.X makefile (gcc, creates libpng.so.2.1.2.0)
+ makefile.sco => For SCO OSr5 ELF and Unixware 7 with Native cc
+ makefile.mips => MIPS makefile
+ makefile.acorn => Acorn makefile
+ makefile.amiga => Amiga makefile
+ smakefile.ppc => AMIGA smakefile for SAS C V6.58/7.00 PPC compiler
+ (Requires SCOPTIONS, copied from scripts/SCOPTIONS.ppc)
+ makefile.atari => Atari makefile
+ makefile.beos => BEOS makefile for X86
+ makefile.bor => Borland makefile (uses bcc)
+ makefile.bc32 => 32-bit Borland C++ (all modules compiled in C mode)
+ makefile.bd32 => To make a png32bd.dll with Borland C++ 4.5
+ makefile.tc3 => Turbo C 3.0 makefile
+ makefile.dj2 => DJGPP 2 makefile
+ makefile.msc => Microsoft C makefile
+ makefile.vcawin32 => makefile for Microsoft Visual C++ 5.0 and later (uses
+ assembler code tuned for Intel MMX platform)
+ makefile.vcwin32 => makefile for Microsoft Visual C++ 4.0 and later (does
+ not use assembler code)
+ makefile.os2 => OS/2 Makefile (gcc and emx, requires pngos2.def)
+ pngos2.def => OS/2 module definition file used by makefile.os2
+ makefile.watcom => Watcom 10a+ Makefile, 32-bit flat memory model
+ makevms.com => VMS build script
+ descrip.mms => VMS makefile for MMS or MMK
+ pngdef.pas => Defines for a png32bd.dll with Borland C++ 4.5
+ SCOPTIONS.ppc => Used with smakefile.ppc
+
+Copy the file (or files) that you need from the
+scripts directory into this directory, for example
+
+ MSDOS example: copy scripts\makefile.msc makefile
+ UNIX example: cp scripts/makefile.std makefile
+
+Read the makefile to see if you need to change any source or
+target directories to match your preferences.
+
+Then read pngconf.h to see if you want to make any configuration
+changes.
+
+Then just run "make test" which will create the libpng library in
+this directory and run a quick test that reads the "pngtest.png"
+file and writes a "pngout.png" file that should be identical to it.
+Look for "9782 zero samples" in the output of the test. For more
+confidence, you can run another test by typing "pngtest pngnow.png"
+and looking for "289 zero samples" in the output. Also, you can
+run "pngtest -m *.png" in the "contrib/pngsuite" directory and compare
+your output with the result shown in contrib/pngsuite/README.
+
+Most of the makefiles will allow you to run "make install" to
+put the library in its final resting place (if you want to
+do that, run "make install" in the zlib directory first if necessary).
+
+Further information can be found in the README and libpng.txt
+files, in the individual makefiles, in png.h, in the README files in
+subdirectories of the LIB directory, and the manual pages libpng.3 and png.5.
--- /dev/null
+
+Known bugs in libpng-1.2.0
+
+1. April 22, 2001: pnggccrd.c has been reported to crash on NetBSD when
+ reading interlaced PNG files, when assembler code is enabled.
+
+ STATUS: Under investigation.
+
--- /dev/null
+
+This copy of the libpng notices is provided for your convenience. In case of
+any discrepancy between this copy and the notices in the file png.h that is
+included in the libpng distribution, the latter shall prevail.
+
+COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
+
+If you modify libpng you may insert additional notices immediately following
+this sentence.
+
+libpng versions 1.0.7, July 1, 2000, through 1.2.0, September 1, 2001, are
+Copyright (c) 2000 Glenn Randers-Pehrson
+and are distributed according to the same disclaimer and license as libpng-1.0.6
+with the following individuals added to the list of Contributing Authors
+
+ Simon-Pierre Cadieux
+ Eric S. Raymond
+ Gilles Vollant
+
+and with the following additions to the disclaimer:
+
+ There is no warranty against interference with your enjoyment of the
+ library or against infringement. There is no warranty that our
+ efforts or the library will fulfill any of your particular purposes
+ or needs. This library is provided with all faults, and the entire
+ risk of satisfactory quality, performance, accuracy, and effort is with
+ the user.
+
+libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are
+Copyright (c) 1998, 1999 Glenn Randers-Pehrson, and are
+distributed according to the same disclaimer and license as libpng-0.96,
+with the following individuals added to the list of Contributing Authors:
+
+ Tom Lane
+ Glenn Randers-Pehrson
+ Willem van Schaik
+
+libpng versions 0.89, June 1996, through 0.96, May 1997, are
+Copyright (c) 1996, 1997 Andreas Dilger
+Distributed according to the same disclaimer and license as libpng-0.88,
+with the following individuals added to the list of Contributing Authors:
+
+ John Bowler
+ Kevin Bracey
+ Sam Bushell
+ Magnus Holmgren
+ Greg Roelofs
+ Tom Tanner
+
+libpng versions 0.5, May 1995, through 0.88, January 1996, are
+Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+
+For the purposes of this copyright and license, "Contributing Authors"
+is defined as the following set of individuals:
+
+ Andreas Dilger
+ Dave Martindale
+ Guy Eric Schalnat
+ Paul Schmidt
+ Tim Wegner
+
+The PNG Reference Library is supplied "AS IS". The Contributing Authors
+and Group 42, Inc. disclaim all warranties, expressed or implied,
+including, without limitation, the warranties of merchantability and of
+fitness for any purpose. The Contributing Authors and Group 42, Inc.
+assume no liability for direct, indirect, incidental, special, exemplary,
+or consequential damages, which may result from the use of the PNG
+Reference Library, even if advised of the possibility of such damage.
+
+Permission is hereby granted to use, copy, modify, and distribute this
+source code, or portions hereof, for any purpose, without fee, subject
+to the following restrictions:
+
+1. The origin of this source code must not be misrepresented.
+
+2. Altered versions must be plainly marked as such and must not
+ be misrepresented as being the original source.
+
+3. This Copyright notice may not be removed or altered from any
+ source or altered source distribution.
+
+The Contributing Authors and Group 42, Inc. specifically permit, without
+fee, and encourage the use of this source code as a component to
+supporting the PNG file format in commercial products. If you use this
+source code in a product, acknowledgment is not required but would be
+appreciated.
+
+
+A "png_get_copyright" function is available, for convenient use in "about"
+boxes and the like:
+
+ printf("%s",png_get_copyright(NULL));
+
+Also, the PNG logo (in PNG format, of course) is supplied in the
+files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31).
+
+Libpng is OSI Certified Open Source Software. OSI Certified Open Source is a
+certification mark of the Open Source Initiative.
+
+Glenn Randers-Pehrson
+randeg@alum.rpi.edu
+September 1, 2001
--- /dev/null
+# Makefile.in generated automatically by automake 1.5 from Makefile.am.
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+SHELL = /bin/sh
+
+srcdir = .
+top_srcdir = ../..
+
+prefix = /usr/local/rrdtool-1.1.0
+exec_prefix = ${prefix}
+
+bindir = ${exec_prefix}/bin
+sbindir = ${exec_prefix}/sbin
+libexecdir = ${exec_prefix}/libexec
+datadir = ${prefix}/share
+sysconfdir = ${prefix}/etc
+sharedstatedir = ${prefix}/com
+localstatedir = ${prefix}/var
+libdir = ${exec_prefix}/lib
+infodir = ${prefix}/info
+mandir = ${prefix}/man
+includedir = ${prefix}/include
+oldincludedir = /usr/include
+pkgdatadir = $(datadir)/rrdtool
+pkglibdir = $(libdir)/rrdtool
+pkgincludedir = $(includedir)/rrdtool
+top_builddir = ../..
+
+ACLOCAL = ${SHELL} /home/oetiker/data/projects/cvs-checkout/rrdtool/program/config/missing --run aclocal
+AUTOCONF = ${SHELL} /home/oetiker/data/projects/cvs-checkout/rrdtool/program/config/missing --run autoconf
+AUTOMAKE = ${SHELL} /home/oetiker/data/projects/cvs-checkout/rrdtool/program/config/missing --run automake
+AUTOHEADER = ${SHELL} /home/oetiker/data/projects/cvs-checkout/rrdtool/program/config/missing --run autoheader
+
+INSTALL = /usr/sepp/bin/ginstall -c
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = s,x,x,
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias =
+host_triplet = sparc-sun-solaris2.8
+AMTAR = ${SHELL} /home/oetiker/data/projects/cvs-checkout/rrdtool/program/config/missing --run tar
+ART_LIB_DIR = libraries/libart_lgpl-2.3.7
+AS = @AS@
+AWK = gawk
+CC = gcc
+CGI_LIB_DIR = libraries/cgilib-0.4
+COMP_PERL = perl_piped perl_shared
+CPP = gcc -E
+DEPDIR = .deps
+DLLTOOL = @DLLTOOL@
+ECHO = /usr/ucb/echo
+EXEEXT =
+FREETYPE_LIB_DIR = libraries/freetype-2.0.5
+INSTALL_STRIP_PROGRAM = ${SHELL} $(install_sh) -c -s
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LN_S = ln -s
+NROFF = /usr/sepp/bin/gnroff
+OBJDUMP = @OBJDUMP@
+OBJEXT = o
+PACKAGE = rrdtool
+PERL = /usr/bin/perl
+PERLFLAGS =
+PERL_MAKE_OPTIONS =
+PNG_LIB_DIR = libraries/libpng-1.2.0
+RANLIB = ranlib
+SO_EXT = so
+STRIP = strip
+TCL_LD_SEARCH_FLAGS =
+TCL_PACKAGE_PATH =
+TCL_PREFIX =
+TCL_SHLIB_CFLAGS =
+TCL_SHLIB_LD =
+TCL_SHLIB_SUFFIX =
+TROFF = /usr/sepp/bin/groff
+VERSION = 1.1.0
+ZLIB_CFLAGS = -g -O2 -Wall -pedantic -Wshadow -Wpointer-arith -Wcast-align -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline -fPIC
+am__include = include
+am__quote =
+install_sh = /home/oetiker/data/projects/cvs-checkout/rrdtool/program/config/install-sh
+
+ZLIB_LIB_DIR = libraries/zlib-1.1.3
+
+INCLUDES = -I$(top_srcdir)/$(ZLIB_LIB_DIR)
+
+EXTRA_DIST = ANNOUNCE CHANGES INSTALL KNOWNBUG README README.rrdtool \
+ TODO Y2KINFO example.c libpng.3 \
+ libpng.txt libpngpf.3 png.5 png.dsp png.dsw
+
+
+noinst_LTLIBRARIES = librrd_png.la
+
+librrd_png_la_SOURCES = \
+ png.c \
+ pngerror.c \
+ pngget.c \
+ pngmem.c \
+ pngpread.c \
+ pngread.c \
+ pngrio.c \
+ pngrtran.c \
+ pngrutil.c \
+ pngset.c \
+ pngtrans.c \
+ pngwio.c \
+ pngwrite.c \
+ pngwtran.c \
+ pngwutil.c \
+ png.h pngconf.h
+
+subdir = libraries/libpng-1.2.0
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config/config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+
+librrd_png_la_LDFLAGS =
+librrd_png_la_LIBADD =
+am_librrd_png_la_OBJECTS = png.lo pngerror.lo pngget.lo pngmem.lo \
+ pngpread.lo pngread.lo pngrio.lo pngrtran.lo pngrutil.lo \
+ pngset.lo pngtrans.lo pngwio.lo pngwrite.lo pngwtran.lo \
+ pngwutil.lo
+librrd_png_la_OBJECTS = $(am_librrd_png_la_OBJECTS)
+
+DEFS = -DHAVE_CONFIG_H
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/config
+CPPFLAGS =
+LDFLAGS =
+LIBS = -lm
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+DEP_FILES = $(DEPDIR)/png.Plo $(DEPDIR)/pngerror.Plo \
+ $(DEPDIR)/pngget.Plo $(DEPDIR)/pngmem.Plo \
+ $(DEPDIR)/pngpread.Plo $(DEPDIR)/pngread.Plo \
+ $(DEPDIR)/pngrio.Plo $(DEPDIR)/pngrtran.Plo \
+ $(DEPDIR)/pngrutil.Plo $(DEPDIR)/pngset.Plo \
+ $(DEPDIR)/pngtrans.Plo $(DEPDIR)/pngwio.Plo \
+ $(DEPDIR)/pngwrite.Plo $(DEPDIR)/pngwtran.Plo \
+ $(DEPDIR)/pngwutil.Plo
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) \
+ $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+CFLAGS = -g -O2 -Wall -pedantic -Wshadow -Wpointer-arith -Wcast-align -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline -fPIC
+DIST_SOURCES = $(librrd_png_la_SOURCES)
+DIST_COMMON = README INSTALL Makefile.am Makefile.in TODO
+SOURCES = $(librrd_png_la_SOURCES)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4)
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign libraries/libpng-1.2.0/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) && \
+ CONFIG_HEADERS= CONFIG_LINKS= \
+ CONFIG_FILES=$(subdir)/$@ $(SHELL) ./config.status
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+librrd_png.la: $(librrd_png_la_OBJECTS) $(librrd_png_la_DEPENDENCIES)
+ $(LINK) $(librrd_png_la_LDFLAGS) $(librrd_png_la_OBJECTS) $(librrd_png_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+ -rm -f *.tab.c
+
+include $(DEPDIR)/png.Plo
+include $(DEPDIR)/pngerror.Plo
+include $(DEPDIR)/pngget.Plo
+include $(DEPDIR)/pngmem.Plo
+include $(DEPDIR)/pngpread.Plo
+include $(DEPDIR)/pngread.Plo
+include $(DEPDIR)/pngrio.Plo
+include $(DEPDIR)/pngrtran.Plo
+include $(DEPDIR)/pngrutil.Plo
+include $(DEPDIR)/pngset.Plo
+include $(DEPDIR)/pngtrans.Plo
+include $(DEPDIR)/pngwio.Plo
+include $(DEPDIR)/pngwrite.Plo
+include $(DEPDIR)/pngwtran.Plo
+include $(DEPDIR)/pngwutil.Plo
+
+distclean-depend:
+ -rm -rf $(DEPDIR)
+
+.c.o:
+ source='$<' object='$@' libtool=no \
+ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' \
+ $(CCDEPMODE) $(depcomp) \
+ $(COMPILE) -c `test -f $< || echo '$(srcdir)/'`$<
+
+.c.obj:
+ source='$<' object='$@' libtool=no \
+ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' \
+ $(CCDEPMODE) $(depcomp) \
+ $(COMPILE) -c `cygpath -w $<`
+
+.c.lo:
+ source='$<' object='$@' libtool=yes \
+ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' \
+ $(CCDEPMODE) $(depcomp) \
+ $(LTCOMPILE) -c -o $@ `test -f $< || echo '$(srcdir)/'`$<
+CCDEPMODE = depmode=gcc
+uninstall-info-am:
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || etags $(ETAGS_ARGS) $$tags $$unique $(LISP)
+
+GTAGS:
+ here=`CDPATH=: && cd $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH
+
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ../..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ if test -f $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ $(mkinstalldirs) "$(distdir)/$$dir"; \
+ fi; \
+ if test -d $$d/$$file; then \
+ cp -pR $$d/$$file $(distdir) \
+ || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+
+installdirs:
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES) stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-compile distclean-depend \
+ distclean-generic distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+uninstall-am: uninstall-info-am
+
+.PHONY: GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES distclean \
+ distclean-compile distclean-depend distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am info \
+ info-am install install-am install-data install-data-am \
+ install-exec install-exec-am install-info install-info-am \
+ install-man install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool tags uninstall uninstall-am \
+ uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+## Process this file with automake to produce Makefile.in
+
+ZLIB_LIB_DIR = @ZLIB_LIB_DIR@
+
+INCLUDES = -I$(top_srcdir)/$(ZLIB_LIB_DIR)
+
+EXTRA_DIST= ANNOUNCE CHANGES INSTALL KNOWNBUG README README.rrdtool \
+ TODO Y2KINFO example.c libpng.3 \
+ libpng.txt libpngpf.3 png.5 png.dsp png.dsw
+
+noinst_LTLIBRARIES = librrd_png.la
+
+librrd_png_la_SOURCES = \
+ png.c \
+ pngerror.c \
+ pngget.c \
+ pngmem.c \
+ pngpread.c \
+ pngread.c \
+ pngrio.c \
+ pngrtran.c \
+ pngrutil.c \
+ pngset.c \
+ pngtrans.c \
+ pngwio.c \
+ pngwrite.c \
+ pngwtran.c \
+ pngwutil.c \
+ png.h pngconf.h
--- /dev/null
+# Makefile.in generated automatically by automake 1.5 from Makefile.am.
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = @program_transform_name@
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+AMTAR = @AMTAR@
+ART_LIB_DIR = @ART_LIB_DIR@
+AS = @AS@
+AWK = @AWK@
+CC = @CC@
+CGI_LIB_DIR = @CGI_LIB_DIR@
+COMP_PERL = @COMP_PERL@
+CPP = @CPP@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+ECHO = @ECHO@
+EXEEXT = @EXEEXT@
+FREETYPE_LIB_DIR = @FREETYPE_LIB_DIR@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+NROFF = @NROFF@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PERL = @PERL@
+PERLFLAGS = @PERLFLAGS@
+PERL_MAKE_OPTIONS = @PERL_MAKE_OPTIONS@
+PNG_LIB_DIR = @PNG_LIB_DIR@
+RANLIB = @RANLIB@
+SO_EXT = @SO_EXT@
+STRIP = @STRIP@
+TCL_LD_SEARCH_FLAGS = @TCL_LD_SEARCH_FLAGS@
+TCL_PACKAGE_PATH = @TCL_PACKAGE_PATH@
+TCL_PREFIX = @TCL_PREFIX@
+TCL_SHLIB_CFLAGS = @TCL_SHLIB_CFLAGS@
+TCL_SHLIB_LD = @TCL_SHLIB_LD@
+TCL_SHLIB_SUFFIX = @TCL_SHLIB_SUFFIX@
+TROFF = @TROFF@
+VERSION = @VERSION@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+am__include = @am__include@
+am__quote = @am__quote@
+install_sh = @install_sh@
+
+ZLIB_LIB_DIR = @ZLIB_LIB_DIR@
+
+INCLUDES = -I$(top_srcdir)/$(ZLIB_LIB_DIR)
+
+EXTRA_DIST = ANNOUNCE CHANGES INSTALL KNOWNBUG README README.rrdtool \
+ TODO Y2KINFO example.c libpng.3 \
+ libpng.txt libpngpf.3 png.5 png.dsp png.dsw
+
+
+noinst_LTLIBRARIES = librrd_png.la
+
+librrd_png_la_SOURCES = \
+ png.c \
+ pngerror.c \
+ pngget.c \
+ pngmem.c \
+ pngpread.c \
+ pngread.c \
+ pngrio.c \
+ pngrtran.c \
+ pngrutil.c \
+ pngset.c \
+ pngtrans.c \
+ pngwio.c \
+ pngwrite.c \
+ pngwtran.c \
+ pngwutil.c \
+ png.h pngconf.h
+
+subdir = libraries/libpng-1.2.0
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config/config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+
+librrd_png_la_LDFLAGS =
+librrd_png_la_LIBADD =
+am_librrd_png_la_OBJECTS = png.lo pngerror.lo pngget.lo pngmem.lo \
+ pngpread.lo pngread.lo pngrio.lo pngrtran.lo pngrutil.lo \
+ pngset.lo pngtrans.lo pngwio.lo pngwrite.lo pngwtran.lo \
+ pngwutil.lo
+librrd_png_la_OBJECTS = $(am_librrd_png_la_OBJECTS)
+
+DEFS = @DEFS@
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/config
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+@AMDEP_TRUE@DEP_FILES = $(DEPDIR)/png.Plo $(DEPDIR)/pngerror.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/pngget.Plo $(DEPDIR)/pngmem.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/pngpread.Plo $(DEPDIR)/pngread.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/pngrio.Plo $(DEPDIR)/pngrtran.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/pngrutil.Plo $(DEPDIR)/pngset.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/pngtrans.Plo $(DEPDIR)/pngwio.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/pngwrite.Plo $(DEPDIR)/pngwtran.Plo \
+@AMDEP_TRUE@ $(DEPDIR)/pngwutil.Plo
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) \
+ $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+DIST_SOURCES = $(librrd_png_la_SOURCES)
+DIST_COMMON = README INSTALL Makefile.am Makefile.in TODO
+SOURCES = $(librrd_png_la_SOURCES)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4)
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign libraries/libpng-1.2.0/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) && \
+ CONFIG_HEADERS= CONFIG_LINKS= \
+ CONFIG_FILES=$(subdir)/$@ $(SHELL) ./config.status
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+librrd_png.la: $(librrd_png_la_OBJECTS) $(librrd_png_la_DEPENDENCIES)
+ $(LINK) $(librrd_png_la_LDFLAGS) $(librrd_png_la_OBJECTS) $(librrd_png_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/png.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pngerror.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pngget.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pngmem.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pngpread.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pngread.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pngrio.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pngrtran.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pngrutil.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pngset.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pngtrans.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pngwio.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pngwrite.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pngwtran.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pngwutil.Plo@am__quote@
+
+distclean-depend:
+ -rm -rf $(DEPDIR)
+
+.c.o:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(COMPILE) -c `test -f $< || echo '$(srcdir)/'`$<
+
+.c.obj:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(COMPILE) -c `cygpath -w $<`
+
+.c.lo:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(LTCOMPILE) -c -o $@ `test -f $< || echo '$(srcdir)/'`$<
+CCDEPMODE = @CCDEPMODE@
+uninstall-info-am:
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || etags $(ETAGS_ARGS) $$tags $$unique $(LISP)
+
+GTAGS:
+ here=`CDPATH=: && cd $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH
+
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ../..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+ @for file in $(DISTFILES); do \
+ if test -f $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ $(mkinstalldirs) "$(distdir)/$$dir"; \
+ fi; \
+ if test -d $$d/$$file; then \
+ cp -pR $$d/$$file $(distdir) \
+ || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+
+installdirs:
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES) stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-compile distclean-depend \
+ distclean-generic distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+uninstall-am: uninstall-info-am
+
+.PHONY: GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES distclean \
+ distclean-compile distclean-depend distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am info \
+ info-am install install-am install-data install-data-am \
+ install-exec install-exec-am install-info install-info-am \
+ install-man install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool tags uninstall uninstall-am \
+ uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+README for libpng 1.2.0 - September 1, 2001 (shared library 2.1)
+See the note about version numbers near the top of png.h
+
+See INSTALL for instructions on how to install libpng.
+
+Libpng comes in two distribution formats. Get libpng-*.tar.gz if you
+want UNIX-style line endings in the text files, or lpng*.zip if you want
+DOS-style line endings.
+
+Version 0.89 was the first official release of libpng. Don't let the
+fact that it's the first release fool you. The libpng library has been in
+extensive use and testing since mid-1995. By late 1997 it had
+finally gotten to the stage where there hadn't been significant
+changes to the API in some time, and people have a bad feeling about
+libraries with versions < 1.0. Version 1.0.0 was released in
+March 1998.
+
+****
+Note that some of the changes to the png_info structure render this
+version of the library binary incompatible with libpng-0.89 or
+earlier versions if you are using a shared library. The type of the
+"filler" parameter for png_set_filler() has changed from png_byte to
+png_uint_32, which will affect shared-library applications that use
+this function.
+
+To avoid problems with changes to the internals of png_info_struct,
+new APIs have been made available in 0.95 to avoid direct application
+access to info_ptr. These functions are the png_set_<chunk> and
+png_get_<chunk> functions. These functions should be used when
+accessing/storing the info_struct data, rather than manipulating it
+directly, to avoid such problems in the future.
+
+It is important to note that the APIs do not make current programs
+that access the info struct directly incompatible with the new
+library. However, it is strongly suggested that new programs use
+the new APIs (as shown in example.c and pngtest.c), and older programs
+be converted to the new format, to facilitate upgrades in the future.
+****
+
+Additions since 0.90 include the ability to compile libpng as a
+Windows DLL, and new APIs for accessing data in the info struct.
+Experimental functions include the ability to set weighting and cost
+factors for row filter selection, direct reads of integers from buffers
+on big-endian processors that support misaligned data access, faster
+methods of doing alpha composition, and more accurate 16->8 bit color
+conversion.
+
+The additions since 0.89 include the ability to read from a PNG stream
+which has had some (or all) of the signature bytes read by the calling
+application. This also allows the reading of embedded PNG streams that
+do not have the PNG file signature. As well, it is now possible to set
+the library action on the detection of chunk CRC errors. It is possible
+to set different actions based on whether the CRC error occurred in a
+critical or an ancillary chunk.
+
+The changes made to the library, and bugs fixed are based on discussions
+on the PNG implementation mailing list <png-implement@ccrc.wustl.edu>
+and not on material submitted privately to Guy, Andreas, or Glenn. They will
+forward any good suggestions to the list.
+
+For a detailed description on using libpng, read libpng.txt. For
+examples of libpng in a program, see example.c and pngtest.c. For usage
+information and restrictions (what little they are) on libpng, see
+png.h. For a description on using zlib (the compression library used by
+libpng) and zlib's restrictions, see zlib.h
+
+I have included a general makefile, as well as several machine and
+compiler specific ones, but you may have to modify one for your own needs.
+
+You should use zlib 1.0.4 or later to run this, but it MAY work with
+versions as old as zlib 0.95. Even so, there are bugs in older zlib
+versions which can cause the output of invalid compression streams for
+some images. You will definitely need zlib 1.0.4 or later if you are
+taking advantage of the MS-DOS "far" structure allocation for the small
+and medium memory models. You should also note that zlib is a
+compression library that is useful for more things than just PNG files.
+You can use zlib as a drop-in replacement for fread() and fwrite() if
+you are so inclined.
+
+zlib should be available at the same place that libpng is.
+If not, it should be at ftp.uu.net in /graphics/png
+Eventually, it will be at ftp.uu.net in /pub/archiving/zip/zlib
+
+You may also want a copy of the PNG specification. It is available
+as an RFC and a W3C Recommendation. Failing
+these resources you can try ftp.uu.net in the /graphics/png directory.
+
+This code is currently being archived at ftp.uu.net in the
+/graphics/png directory, and on CompuServe, Lib 20 (PNG SUPPORT)
+at GO GRAPHSUP. If you can't find it in any of those places,
+e-mail me, and I'll help you find it.
+
+If you have any code changes, requests, problems, etc., please e-mail
+them to me. Also, I'd appreciate any make files or project files,
+and any modifications you needed to make to get libpng to compile,
+along with a #define variable to tell what compiler/system you are on.
+If you needed to add transformations to libpng, or wish libpng would
+provide the image in a different way, drop me a note (and code, if
+possible), so I can consider supporting the transformation.
+Finally, if you get any warning messages when compiling libpng
+(note: not zlib), and they are easy to fix, I'd appreciate the
+fix. Please mention "libpng" somewhere in the subject line. Thanks.
+
+This release was created and will be supported by myself (of course
+based in a large way on Guy's and Andreas' earlier work), and the PNG group.
+
+randeg@alum.rpi.edu
+png-implement@ccrc.wustl.edu
+
+You can't reach Guy, the original libpng author, at the addresses
+given in previous versions of this document. He and Andreas will read mail
+addressed to the png-implement list, however.
+
+Please do not send general questions about PNG. Send them to
+the address in the specification (png-group@w3.org). At the same
+time, please do not send libpng questions to that address, send them to me
+or to png-implement@ccrc.wustl.edu. I'll
+get them in the end anyway. If you have a question about something
+in the PNG specification that is related to using libpng, send it
+to me. Send me any questions that start with "I was using libpng,
+and ...". If in doubt, send questions to me. I'll bounce them
+to others, if necessary.
+
+Please do not send suggestions on how to change PNG. We have
+been discussing PNG for three years now, and it is official and
+finished. If you have suggestions for libpng, however, I'll
+gladly listen. Even if your suggestion is not used for version
+1.0, it may be used later.
+
+Files in this distribution:
+
+ ANNOUNCE => Announcement of this version, with recent changes
+ CHANGES => Description of changes between libpng versions
+ KNOWNBUG => List of known bugs and deficiencies
+ LICENSE => License to use and redistribute libpng
+ README => This file
+ TODO => Things not implemented in the current library
+ Y2KINFO => Statement of Y2K compliance
+ example.c => Example code for using libpng functions
+ libpng.3 => manual page for libpng (includes libpng.txt)
+ libpng.txt => Description of libpng and its functions
+ libpngpf.3 => manual page for libpng's private functions
+ png.5 => manual page for the PNG format
+ png.c => Basic interface functions common to library
+ png.h => Library function and interface declarations
+ pngconf.h => System specific library configuration
+ pngasmrd.h => Header file for assembler-coded functions
+ pngerror.c => Error/warning message I/O functions
+ pngget.c => Functions for retrieving info from struct
+ pngmem.c => Memory handling functions
+ pngbar.png => PNG logo, 88x31
+ pngnow.png => PNG logo, 98x31
+ pngpread.c => Progressive reading functions
+ pngread.c => Read data/helper high-level functions
+ pngrio.c => Lowest-level data read I/O functions
+ pngrtran.c => Read data transformation functions
+ pngrutil.c => Read data utility functions
+ pngset.c => Functions for storing data into the info_struct
+ pngtest.c => Library test program
+ pngtest.png => Library test sample image
+ pngtrans.c => Common data transformation functions
+ pngwio.c => Lowest-level write I/O functions
+ pngwrite.c => High-level write functions
+ pngwtran.c => Write data transformations
+ pngwutil.c => Write utility functions
+ contrib => Contributions
+ gregbook => source code for PNG reading and writing, from
+ Greg Roelofs' "PNG: The Definitive Guide",
+ O'Reilly, 1999
+ msvctest => Builds and runs pngtest using a MSVC workspace
+ pngminus => Simple pnm2png and png2pnm programs
+ pngsuite => Test images
+ visupng => Contains a MSVC workspace for VisualPng
+ projects => Contains project files and workspaces for building DLL
+ beos => Contains a Beos workspace for building libpng
+ borland => Contains a Borland workspace for building libpng
+ and zlib
+ msvc => Contains a Microsoft Visual C++ (MSVC) workspace
+ for building libpng and zlib
+ netware.txt => Contains instructions for downloading a set of
+ project files for building libpng and zlib on
+ Netware.
+ wince.txt => Contains instructions for downloading a Microsoft
+ Visual C++ (Windows CD Toolkit) workspace for
+ building libpng and zlib on WindowsCE
+ scripts => Directory containing scripts for building libpng:
+ descrip.mms => VMS makefile for MMS or MMK
+ makefile.std => Generic UNIX makefile (cc, creates static libpng.a)
+ makefile.linux => Linux/ELF makefile
+ (gcc, creates libpng.so.2.1.2.0)
+ makefile.gcmmx => Linux/ELF makefile (gcc, creates
+ libpng.so.2.1.2.0, uses assembler code
+ tuned for Intel MMX platform)
+ makefile.gcc => Generic makefile (gcc, creates static libpng.a)
+ makefile.knr => Archaic UNIX Makefile that converts files with
+ ansi2knr (Requires ansi2knr.c from
+ ftp://ftp.cs.wisc.edu/ghost)
+ makefile.aix => AIX makefile
+ makefile.cygwin => Cygwin/gcc makefile
+ makefile.dec => DEC Alpha UNIX makefile
+ makefile.hpgcc => HPUX makefile using gcc
+ makefile.hpux => HPUX (10.20 and 11.00) makefile
+ makefile.ibmc => IBM C/C++ version 3.x for Win32 and OS/2 (static)
+ makefile.intel => Intel C/C++ version 4.0 and later
+ libpng.icc => Project file, IBM VisualAge/C++ 4.0 or later
+ makefile.macosx => MACOS X Makefile
+ makefile.netbsd => NetBSD/cc makefile, uses PNGGCCRD
+ makefile.sgi => Silicon Graphics IRIX (cc, creates static lib)
+ makefile.sggcc => Silicon Graphics (gcc, creates libpng.so.2.1.2.0)
+ makefile.sunos => Sun makefile
+ makefile.solaris => Solaris 2.X makefile
+ (gcc, creates libpng.so.2.1.2.0)
+ makefile.sco => For SCO OSr5 ELF and Unixware 7 with Native cc
+ makefile.mips => MIPS makefile
+ makefile.acorn => Acorn makefile
+ makefile.amiga => Amiga makefile
+ smakefile.ppc => AMIGA smakefile for SAS C V6.58/7.00 PPC
+ compiler (Requires SCOPTIONS, copied from
+ scripts/SCOPTIONS.ppc)
+ makefile.atari => Atari makefile
+ makefile.beos => BEOS makefile for X86
+ makefile.bor => Borland makefile (uses bcc)
+ makefile.bc32 => 32-bit Borland C++ (all modules compiled in C mode)
+ makefile.bd32 => To make a png32bd.dll with Borland C++ 4.5
+ makefile.tc3 => Turbo C 3.0 makefile
+ makefile.dj2 => DJGPP 2 makefile
+ makefile.msc => Microsoft C makefile
+ makefile.vcawin32 => makefile for Microsoft Visual C++ 5.0 and
+ later (uses assembler code tuned for Intel MMX
+ platform)
+ makefile.vcwin32 => makefile for Microsoft Visual C++ 4.0 and
+ later (does not use assembler code)
+ makefile.os2 => OS/2 Makefile (gcc and emx, requires pngos2.def)
+ pngos2.def => OS/2 module definition file used by makefile.os2
+ makefile.watcom => Watcom 10a+ Makefile, 32-bit flat memory model
+ makevms.com => VMS build script
+ pngdef.pas => Defines for a png32bd.dll with Borland C++ 4.5
+ SCOPTIONS.ppc => Used with smakefile.ppc
+
+Good luck, and happy coding.
+
+-Glenn Randers-Pehrson
+ Internet: randeg@alum.rpi.edu
+
+-Andreas Eric Dilger
+ Internet: adilger@enel.ucalgary.ca
+ Web: http://www-mddsp.enel.ucalgary.ca/People/adilger/
+
+-Guy Eric Schalnat
+ (formerly of Group 42, Inc)
+ Internet: gschal@infinet.com
--- /dev/null
+TODO - list of things to do for libpng:
+
+Final bug fixes.
+Improve API by hiding the png_struct and png_info structs.
+Finish work on the no-floating-point version (including gamma compensation)
+Better C++ wrapper/full C++ implementation?
+Fix problem with C++ and EXTERN "C".
+cHRM transformation.
+Improve setjmp/longjmp usage or remove it in favor of returning error codes.
+Add "grayscale->palette" transformation and "palette->grayscale" detection.
+Improved dithering.
+Multi-lingual error and warning message support.
+Complete sRGB transformation (presently it simply uses gamma=0.45455).
+Man pages for function calls.
+Better documentation.
+Better filter selection
+ (counting huffman bits/precompression? filter inertia? filter costs?).
+Histogram creation.
+Text conversion between different code pages (Latin-1 -> Mac and DOS).
+Should we always malloc 2^bit_depth PLTE/tRNS/hIST entries for safety?
+Build gamma tables using fixed point (and do away with floating point entirely).
+Use greater precision when changing to linear gamma for compositing against
+ background and doing rgb-to-gray transformation.
+Investigate pre-incremented loop counters and other loop constructions.
--- /dev/null
+ Y2K compliance in libpng:
+ =========================
+
+ September 1, 2001
+
+ Since the PNG Development group is an ad-hoc body, we can't make
+ an official declaration.
+
+ This is your unofficial assurance that libpng from version 0.71 and
+ upward through 1.2.0 are Y2K compliant. It is my belief that earlier
+ versions were also Y2K compliant.
+
+ Libpng only has three year fields. One is a 2-byte unsigned integer
+ that will hold years up to 65535. The other two hold the date in text
+ format, and will hold years up to 9999.
+
+ The integer is
+ "png_uint_16 year" in png_time_struct.
+
+ The strings are
+ "png_charp time_buffer" in png_struct and
+ "near_time_buffer", which is a local character string in png.c.
+
+ There are seven time-related functions:
+
+ png_convert_to_rfc_1123() in png.c
+ (formerly png_convert_to_rfc_1152() in error)
+ png_convert_from_struct_tm() in pngwrite.c, called in pngwrite.c
+ png_convert_from_time_t() in pngwrite.c
+ png_get_tIME() in pngget.c
+ png_handle_tIME() in pngrutil.c, called in pngread.c
+ png_set_tIME() in pngset.c
+ png_write_tIME() in pngwutil.c, called in pngwrite.c
+
+ All appear to handle dates properly in a Y2K environment. The
+ png_convert_from_time_t() function calls gmtime() to convert from system
+ clock time, which returns (year - 1900), which we properly convert to
+ the full 4-digit year. There is a possibility that applications using
+ libpng are not passing 4-digit years into the png_convert_to_rfc_1123()
+ function, or that they are incorrectly passing only a 2-digit year
+ instead of "year - 1900" into the png_convert_from_struct_tm() function,
+ but this is not under our control. The libpng documentation has always
+ stated that it works with 4-digit years, and the APIs have been
+ documented as such.
+
+ The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned
+ integer to hold the year, and can hold years as large as 65535.
+
+ zlib, upon which libpng depends, is also Y2K compliant. It contains
+ no date-related code.
+
+
+ Glenn Randers-Pehrson
+ libpng maintainer
+ PNG Development Group
--- /dev/null
+
+#if 0 /* in case someone actually tries to compile this */
+
+/* example.c - an example of using libpng */
+
+/* This is an example of how to use libpng to read and write PNG files.
+ * The file libpng.txt is much more verbose then this. If you have not
+ * read it, do so first. This was designed to be a starting point of an
+ * implementation. This is not officially part of libpng, is hereby placed
+ * in the public domain, and therefore does not require a copyright notice.
+ *
+ * This file does not currently compile, because it is missing certain
+ * parts, like allocating memory to hold an image. You will have to
+ * supply these parts to get it to compile. For an example of a minimal
+ * working PNG reader/writer, see pngtest.c, included in this distribution;
+ * see also the programs in the contrib directory.
+ */
+
+#include "png.h"
+
+ /* The png_jmpbuf() macro, used in error handling, became available in
+ * libpng version 1.0.6. If you want to be able to run your code with older
+ * versions of libpng, you must define the macro yourself (but only if it
+ * is not already defined by libpng!).
+ */
+
+#ifndef png_jmpbuf
+# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
+#endif
+
+/* Check to see if a file is a PNG file using png_sig_cmp(). png_sig_cmp()
+ * returns zero if the image is a PNG and nonzero if it isn't a PNG.
+ *
+ * The function check_if_png() shown here, but not used, returns nonzero (true)
+ * if the file can be opened and is a PNG, 0 (false) otherwise.
+ *
+ * If this call is successful, and you are going to keep the file open,
+ * you should call png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); once
+ * you have created the png_ptr, so that libpng knows your application
+ * has read that many bytes from the start of the file. Make sure you
+ * don't call png_set_sig_bytes() with more than 8 bytes read or give it
+ * an incorrect number of bytes read, or you will either have read too
+ * many bytes (your fault), or you are telling libpng to read the wrong
+ * number of magic bytes (also your fault).
+ *
+ * Many applications already read the first 2 or 4 bytes from the start
+ * of the image to determine the file type, so it would be easiest just
+ * to pass the bytes to png_sig_cmp() or even skip that if you know
+ * you have a PNG file, and call png_set_sig_bytes().
+ */
+#define PNG_BYTES_TO_CHECK 4
+int check_if_png(char *file_name, FILE **fp)
+{
+ char buf[PNG_BYTES_TO_CHECK];
+
+ /* Open the prospective PNG file. */
+ if ((*fp = fopen(file_name, "rb")) == NULL)
+ return 0;
+
+ /* Read in some of the signature bytes */
+ if (fread(buf, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK)
+ return 0;
+
+ /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature.
+ Return nonzero (true) if they match */
+
+ return(!png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK));
+}
+
+/* Read a PNG file. You may want to return an error code if the read
+ * fails (depending upon the failure). There are two "prototypes" given
+ * here - one where we are given the filename, and we need to open the
+ * file, and the other where we are given an open file (possibly with
+ * some or all of the magic bytes read - see comments above).
+ */
+#ifdef open_file /* prototype 1 */
+void read_png(char *file_name) /* We need to open the file */
+{
+ png_structp png_ptr;
+ png_infop info_ptr;
+ unsigned int sig_read = 0;
+ png_uint_32 width, height;
+ int bit_depth, color_type, interlace_type;
+ FILE *fp;
+
+ if ((fp = fopen(file_name, "rb")) == NULL)
+ return (ERROR);
+#else no_open_file /* prototype 2 */
+void read_png(FILE *fp, unsigned int sig_read) /* file is already open */
+{
+ png_structp png_ptr;
+ png_infop info_ptr;
+ png_uint_32 width, height;
+ int bit_depth, color_type, interlace_type;
+#endif no_open_file /* only use one prototype! */
+
+ /* Create and initialize the png_struct with the desired error handler
+ * functions. If you want to use the default stderr and longjump method,
+ * you can supply NULL for the last three parameters. We also supply the
+ * the compiler header file version, so that we know if the application
+ * was compiled with a compatible version of the library. REQUIRED
+ */
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
+ png_voidp user_error_ptr, user_error_fn, user_warning_fn);
+
+ if (png_ptr == NULL)
+ {
+ fclose(fp);
+ return (ERROR);
+ }
+
+ /* Allocate/initialize the memory for image information. REQUIRED. */
+ info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL)
+ {
+ fclose(fp);
+ png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
+ return (ERROR);
+ }
+
+ /* Set error handling if you are using the setjmp/longjmp method (this is
+ * the normal method of doing things with libpng). REQUIRED unless you
+ * set up your own error handlers in the png_create_read_struct() earlier.
+ */
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ /* Free all of the memory associated with the png_ptr and info_ptr */
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+ fclose(fp);
+ /* If we get here, we had a problem reading the file */
+ return (ERROR);
+ }
+
+ /* One of the following I/O initialization methods is REQUIRED */
+#ifdef streams /* PNG file I/O method 1 */
+ /* Set up the input control if you are using standard C streams */
+ png_init_io(png_ptr, fp);
+
+#else no_streams /* PNG file I/O method 2 */
+ /* If you are using replacement read functions, instead of calling
+ * png_init_io() here you would call:
+ */
+ png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn);
+ /* where user_io_ptr is a structure you want available to the callbacks */
+#endif no_streams /* Use only one I/O method! */
+
+ /* If we have already read some of the signature */
+ png_set_sig_bytes(png_ptr, sig_read);
+
+#ifdef hilevel
+ /*
+ * If you have enough memory to read in the entire image at once,
+ * and you need to specify only transforms that can be controlled
+ * with one of the PNG_TRANSFORM_* bits (this presently excludes
+ * dithering, filling, setting background, and doing gamma
+ * adjustment), then you can read the entire image (including
+ * pixels) into the info structure with this call:
+ */
+ png_read_png(png_ptr, info_ptr, png_transforms, NULL);
+#else
+ /* OK, you're doing it the hard way, with the lower-level functions */
+
+ /* The call to png_read_info() gives us all of the information from the
+ * PNG file before the first IDAT (image data chunk). REQUIRED
+ */
+ png_read_info(png_ptr, info_ptr);
+
+ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
+ &interlace_type, NULL, NULL);
+
+/**** Set up the data transformations you want. Note that these are all
+ **** optional. Only call them if you want/need them. Many of the
+ **** transformations only work on specific types of images, and many
+ **** are mutually exclusive.
+ ****/
+
+ /* tell libpng to strip 16 bit/color files down to 8 bits/color */
+ png_set_strip_16(png_ptr);
+
+ /* Strip alpha bytes from the input data without combining with the
+ * background (not recommended).
+ */
+ png_set_strip_alpha(png_ptr);
+
+ /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
+ * byte into separate bytes (useful for paletted and grayscale images).
+ */
+ png_set_packing(png_ptr);
+
+ /* Change the order of packed pixels to least significant bit first
+ * (not useful if you are using png_set_packing). */
+ png_set_packswap(png_ptr);
+
+ /* Expand paletted colors into true RGB triplets */
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_palette_rgb(png_ptr);
+
+ /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
+ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
+ png_set_gray_1_2_4_to_8(png_ptr);
+
+ /* Expand paletted or RGB images with transparency to full alpha channels
+ * so the data will be available as RGBA quartets.
+ */
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ png_set_tRNS_to_alpha(png_ptr);
+
+ /* Set the background color to draw transparent and alpha images over.
+ * It is possible to set the red, green, and blue components directly
+ * for paletted images instead of supplying a palette index. Note that
+ * even if the PNG file supplies a background, you are not required to
+ * use it - you should use the (solid) application background if it has one.
+ */
+
+ png_color_16 my_background, *image_background;
+
+ if (png_get_bKGD(png_ptr, info_ptr, &image_background))
+ png_set_background(png_ptr, image_background,
+ PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+ else
+ png_set_background(png_ptr, &my_background,
+ PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
+
+ /* Some suggestions as to how to get a screen gamma value */
+
+ /* Note that screen gamma is the display_exponent, which includes
+ * the CRT_exponent and any correction for viewing conditions */
+ if (/* We have a user-defined screen gamma value */)
+ {
+ screen_gamma = user-defined screen_gamma;
+ }
+ /* This is one way that applications share the same screen gamma value */
+ else if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL)
+ {
+ screen_gamma = atof(gamma_str);
+ }
+ /* If we don't have another value */
+ else
+ {
+ screen_gamma = 2.2; /* A good guess for a PC monitors in a dimly
+ lit room */
+ screen_gamma = 1.7 or 1.0; /* A good guess for Mac systems */
+ }
+
+ /* Tell libpng to handle the gamma conversion for you. The final call
+ * is a good guess for PC generated images, but it should be configurable
+ * by the user at run time by the user. It is strongly suggested that
+ * your application support gamma correction.
+ */
+
+ int intent;
+
+ if (png_get_sRGB(png_ptr, info_ptr, &intent))
+ png_set_gamma(png_ptr, screen_gamma, 0.45455);
+ else
+ {
+ double image_gamma;
+ if (png_get_gAMA(png_ptr, info_ptr, &image_gamma))
+ png_set_gamma(png_ptr, screen_gamma, image_gamma);
+ else
+ png_set_gamma(png_ptr, screen_gamma, 0.45455);
+ }
+
+ /* Dither RGB files down to 8 bit palette or reduce palettes
+ * to the number of colors available on your screen.
+ */
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ int num_palette;
+ png_colorp palette;
+
+ /* This reduces the image to the application supplied palette */
+ if (/* we have our own palette */)
+ {
+ /* An array of colors to which the image should be dithered */
+ png_color std_color_cube[MAX_SCREEN_COLORS];
+
+ png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS,
+ MAX_SCREEN_COLORS, NULL, 0);
+ }
+ /* This reduces the image to the palette supplied in the file */
+ else if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette))
+ {
+ png_uint_16p histogram;
+
+ png_get_hIST(png_ptr, info_ptr, &histogram);
+
+ png_set_dither(png_ptr, palette, num_palette,
+ max_screen_colors, histogram, 0);
+ }
+ }
+
+ /* invert monochrome files to have 0 as white and 1 as black */
+ png_set_invert_mono(png_ptr);
+
+ /* If you want to shift the pixel values from the range [0,255] or
+ * [0,65535] to the original [0,7] or [0,31], or whatever range the
+ * colors were originally in:
+ */
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
+ {
+ png_color_8p sig_bit;
+
+ png_get_sBIT(png_ptr, info_ptr, &sig_bit);
+ png_set_shift(png_ptr, sig_bit);
+ }
+
+ /* flip the RGB pixels to BGR (or RGBA to BGRA) */
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ png_set_bgr(png_ptr);
+
+ /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
+ png_set_swap_alpha(png_ptr);
+
+ /* swap bytes of 16 bit files to least significant byte first */
+ png_set_swap(png_ptr);
+
+ /* Add filler (or alpha) byte (before/after each RGB triplet) */
+ png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
+
+ /* Turn on interlace handling. REQUIRED if you are not using
+ * png_read_image(). To see how to handle interlacing passes,
+ * see the png_read_row() method below:
+ */
+ number_passes = png_set_interlace_handling(png_ptr);
+
+ /* Optional call to gamma correct and add the background to the palette
+ * and update info structure. REQUIRED if you are expecting libpng to
+ * update the palette for you (ie you selected such a transform above).
+ */
+ png_read_update_info(png_ptr, info_ptr);
+
+ /* Allocate the memory to hold the image using the fields of info_ptr. */
+
+ /* The easiest way to read the image: */
+ png_bytep row_pointers[height];
+
+ for (row = 0; row < height; row++)
+ {
+ row_pointers[row] = png_malloc(png_ptr, png_get_rowbytes(png_ptr,
+ info_ptr));
+ }
+
+ /* Now it's time to read the image. One of these methods is REQUIRED */
+#ifdef entire /* Read the entire image in one go */
+ png_read_image(png_ptr, row_pointers);
+
+#else no_entire /* Read the image one or more scanlines at a time */
+ /* The other way to read images - deal with interlacing: */
+
+ for (pass = 0; pass < number_passes; pass++)
+ {
+#ifdef single /* Read the image a single row at a time */
+ for (y = 0; y < height; y++)
+ {
+ png_read_rows(png_ptr, &row_pointers[y], NULL, 1);
+ }
+
+#else no_single /* Read the image several rows at a time */
+ for (y = 0; y < height; y += number_of_rows)
+ {
+#ifdef sparkle /* Read the image using the "sparkle" effect. */
+ png_read_rows(png_ptr, &row_pointers[y], NULL, number_of_rows);
+#else no_sparkle /* Read the image using the "rectangle" effect */
+ png_read_rows(png_ptr, NULL, &row_pointers[y], number_of_rows);
+#endif no_sparkle /* use only one of these two methods */
+ }
+
+ /* if you want to display the image after every pass, do
+ so here */
+#endif no_single /* use only one of these two methods */
+ }
+#endif no_entire /* use only one of these two methods */
+
+ /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
+ png_read_end(png_ptr, info_ptr);
+#endif hilevel
+
+ /* At this point you have read the entire image */
+
+ /* clean up after the read, and free any memory allocated - REQUIRED */
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+
+ /* close the file */
+ fclose(fp);
+
+ /* that's it */
+ return (OK);
+}
+
+/* progressively read a file */
+
+int
+initialize_png_reader(png_structp *png_ptr, png_infop *info_ptr)
+{
+ /* Create and initialize the png_struct with the desired error handler
+ * functions. If you want to use the default stderr and longjump method,
+ * you can supply NULL for the last three parameters. We also check that
+ * the library version is compatible in case we are using dynamically
+ * linked libraries.
+ */
+ *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
+ png_voidp user_error_ptr, user_error_fn, user_warning_fn);
+
+ if (*png_ptr == NULL)
+ {
+ *info_ptr = NULL;
+ return (ERROR);
+ }
+
+ *info_ptr = png_create_info_struct(png_ptr);
+
+ if (*info_ptr == NULL)
+ {
+ png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL);
+ return (ERROR);
+ }
+
+ if (setjmp(png_jmpbuf((*png_ptr))))
+ {
+ png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL);
+ return (ERROR);
+ }
+
+ /* This one's new. You will need to provide all three
+ * function callbacks, even if you aren't using them all.
+ * If you aren't using all functions, you can specify NULL
+ * parameters. Even when all three functions are NULL,
+ * you need to call png_set_progressive_read_fn().
+ * These functions shouldn't be dependent on global or
+ * static variables if you are decoding several images
+ * simultaneously. You should store stream specific data
+ * in a separate struct, given as the second parameter,
+ * and retrieve the pointer from inside the callbacks using
+ * the function png_get_progressive_ptr(png_ptr).
+ */
+ png_set_progressive_read_fn(*png_ptr, (void *)stream_data,
+ info_callback, row_callback, end_callback);
+
+ return (OK);
+}
+
+int
+process_data(png_structp *png_ptr, png_infop *info_ptr,
+ png_bytep buffer, png_uint_32 length)
+{
+ if (setjmp(png_jmpbuf((*png_ptr))))
+ {
+ /* Free the png_ptr and info_ptr memory on error */
+ png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL);
+ return (ERROR);
+ }
+
+ /* This one's new also. Simply give it chunks of data as
+ * they arrive from the data stream (in order, of course).
+ * On Segmented machines, don't give it any more than 64K.
+ * The library seems to run fine with sizes of 4K, although
+ * you can give it much less if necessary (I assume you can
+ * give it chunks of 1 byte, but I haven't tried with less
+ * than 256 bytes yet). When this function returns, you may
+ * want to display any rows that were generated in the row
+ * callback, if you aren't already displaying them there.
+ */
+ png_process_data(*png_ptr, *info_ptr, buffer, length);
+ return (OK);
+}
+
+info_callback(png_structp png_ptr, png_infop info)
+{
+/* do any setup here, including setting any of the transformations
+ * mentioned in the Reading PNG files section. For now, you _must_
+ * call either png_start_read_image() or png_read_update_info()
+ * after all the transformations are set (even if you don't set
+ * any). You may start getting rows before png_process_data()
+ * returns, so this is your last chance to prepare for that.
+ */
+}
+
+row_callback(png_structp png_ptr, png_bytep new_row,
+ png_uint_32 row_num, int pass)
+{
+/* this function is called for every row in the image. If the
+ * image is interlacing, and you turned on the interlace handler,
+ * this function will be called for every row in every pass.
+ * Some of these rows will not be changed from the previous pass.
+ * When the row is not changed, the new_row variable will be NULL.
+ * The rows and passes are called in order, so you don't really
+ * need the row_num and pass, but I'm supplying them because it
+ * may make your life easier.
+ *
+ * For the non-NULL rows of interlaced images, you must call
+ * png_progressive_combine_row() passing in the row and the
+ * old row. You can call this function for NULL rows (it will
+ * just return) and for non-interlaced images (it just does the
+ * png_memcpy for you) if it will make the code easier. Thus, you
+ * can just do this for all cases:
+ */
+
+ png_progressive_combine_row(png_ptr, old_row, new_row);
+
+/* where old_row is what was displayed for previous rows. Note
+ * that the first pass (pass == 0 really) will completely cover
+ * the old row, so the rows do not have to be initialized. After
+ * the first pass (and only for interlaced images), you will have
+ * to pass the current row, and the function will combine the
+ * old row and the new row.
+ */
+}
+
+end_callback(png_structp png_ptr, png_infop info)
+{
+/* this function is called when the whole image has been read,
+ * including any chunks after the image (up to and including
+ * the IEND). You will usually have the same info chunk as you
+ * had in the header, although some data may have been added
+ * to the comments and time fields.
+ *
+ * Most people won't do much here, perhaps setting a flag that
+ * marks the image as finished.
+ */
+}
+
+/* write a png file */
+void write_png(char *file_name /* , ... other image information ... */)
+{
+ FILE *fp;
+ png_structp png_ptr;
+ png_infop info_ptr;
+ png_colorp palette;
+
+ /* open the file */
+ fp = fopen(file_name, "wb");
+ if (fp == NULL)
+ return (ERROR);
+
+ /* Create and initialize the png_struct with the desired error handler
+ * functions. If you want to use the default stderr and longjump method,
+ * you can supply NULL for the last three parameters. We also check that
+ * the library version is compatible with the one used at compile time,
+ * in case we are using dynamically linked libraries. REQUIRED.
+ */
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+ png_voidp user_error_ptr, user_error_fn, user_warning_fn);
+
+ if (png_ptr == NULL)
+ {
+ fclose(fp);
+ return (ERROR);
+ }
+
+ /* Allocate/initialize the image information data. REQUIRED */
+ info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL)
+ {
+ fclose(fp);
+ png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+ return (ERROR);
+ }
+
+ /* Set error handling. REQUIRED if you aren't supplying your own
+ * error handling functions in the png_create_write_struct() call.
+ */
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ /* If we get here, we had a problem reading the file */
+ fclose(fp);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ return (ERROR);
+ }
+
+ /* One of the following I/O initialization functions is REQUIRED */
+#ifdef streams /* I/O initialization method 1 */
+ /* set up the output control if you are using standard C streams */
+ png_init_io(png_ptr, fp);
+#else no_streams /* I/O initialization method 2 */
+ /* If you are using replacement read functions, instead of calling
+ * png_init_io() here you would call */
+ png_set_write_fn(png_ptr, (void *)user_io_ptr, user_write_fn,
+ user_IO_flush_function);
+ /* where user_io_ptr is a structure you want available to the callbacks */
+#endif no_streams /* only use one initialization method */
+
+#ifdef hilevel
+ /* This is the easy way. Use it if you already have all the
+ * image info living info in the structure. You could "|" many
+ * PNG_TRANSFORM flags into the png_transforms integer here.
+ */
+ png_write_png(png_ptr, info_ptr, png_transforms, NULL);
+#else
+ /* This is the hard way */
+
+ /* Set the image information here. Width and height are up to 2^31,
+ * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
+ * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
+ * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
+ * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
+ * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
+ * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
+ */
+ png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_???,
+ PNG_INTERLACE_????, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+ /* set the palette if there is one. REQUIRED for indexed-color images */
+ palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH
+ * sizeof (png_color));
+ /* ... set palette colors ... */
+ png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH);
+ /* You must not free palette here, because png_set_PLTE only makes a link to
+ the palette that you malloced. Wait until you are about to destroy
+ the png structure. */
+
+ /* optional significant bit chunk */
+ /* if we are dealing with a grayscale image then */
+ sig_bit.gray = true_bit_depth;
+ /* otherwise, if we are dealing with a color image then */
+ sig_bit.red = true_red_bit_depth;
+ sig_bit.green = true_green_bit_depth;
+ sig_bit.blue = true_blue_bit_depth;
+ /* if the image has an alpha channel then */
+ sig_bit.alpha = true_alpha_bit_depth;
+ png_set_sBIT(png_ptr, info_ptr, sig_bit);
+
+
+ /* Optional gamma chunk is strongly suggested if you have any guess
+ * as to the correct gamma of the image.
+ */
+ png_set_gAMA(png_ptr, info_ptr, gamma);
+
+ /* Optionally write comments into the image */
+ text_ptr[0].key = "Title";
+ text_ptr[0].text = "Mona Lisa";
+ text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
+ text_ptr[1].key = "Author";
+ text_ptr[1].text = "Leonardo DaVinci";
+ text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
+ text_ptr[2].key = "Description";
+ text_ptr[2].text = "<long text>";
+ text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
+#ifdef PNG_iTXt_SUPPORTED
+ text_ptr[0].lang = NULL;
+ text_ptr[1].lang = NULL;
+ text_ptr[2].lang = NULL;
+#endif
+ png_set_text(png_ptr, info_ptr, text_ptr, 3);
+
+ /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */
+ /* note that if sRGB is present the gAMA and cHRM chunks must be ignored
+ * on read and must be written in accordance with the sRGB profile */
+
+ /* Write the file header information. REQUIRED */
+ png_write_info(png_ptr, info_ptr);
+
+ /* If you want, you can write the info in two steps, in case you need to
+ * write your private chunk ahead of PLTE:
+ *
+ * png_write_info_before_PLTE(write_ptr, write_info_ptr);
+ * write_my_chunk();
+ * png_write_info(png_ptr, info_ptr);
+ *
+ * However, given the level of known- and unknown-chunk support in 1.1.0
+ * and up, this should no longer be necessary.
+ */
+
+ /* Once we write out the header, the compression type on the text
+ * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or
+ * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again
+ * at the end.
+ */
+
+ /* set up the transformations you want. Note that these are
+ * all optional. Only call them if you want them.
+ */
+
+ /* invert monochrome pixels */
+ png_set_invert_mono(png_ptr);
+
+ /* Shift the pixels up to a legal bit depth and fill in
+ * as appropriate to correctly scale the image.
+ */
+ png_set_shift(png_ptr, &sig_bit);
+
+ /* pack pixels into bytes */
+ png_set_packing(png_ptr);
+
+ /* swap location of alpha bytes from ARGB to RGBA */
+ png_set_swap_alpha(png_ptr);
+
+ /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
+ * RGB (4 channels -> 3 channels). The second parameter is not used.
+ */
+ png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
+
+ /* flip BGR pixels to RGB */
+ png_set_bgr(png_ptr);
+
+ /* swap bytes of 16-bit files to most significant byte first */
+ png_set_swap(png_ptr);
+
+ /* swap bits of 1, 2, 4 bit packed pixel formats */
+ png_set_packswap(png_ptr);
+
+ /* turn on interlace handling if you are not using png_write_image() */
+ if (interlacing)
+ number_passes = png_set_interlace_handling(png_ptr);
+ else
+ number_passes = 1;
+
+ /* The easiest way to write the image (you may have a different memory
+ * layout, however, so choose what fits your needs best). You need to
+ * use the first method if you aren't handling interlacing yourself.
+ */
+ png_uint_32 k, height, width;
+ png_byte image[height][width*bytes_per_pixel];
+ png_bytep row_pointers[height];
+ for (k = 0; k < height; k++)
+ row_pointers[k] = image + k*width*bytes_per_pixel;
+
+ /* One of the following output methods is REQUIRED */
+#ifdef entire /* write out the entire image data in one call */
+ png_write_image(png_ptr, row_pointers);
+
+ /* the other way to write the image - deal with interlacing */
+
+#else no_entire /* write out the image data by one or more scanlines */
+ /* The number of passes is either 1 for non-interlaced images,
+ * or 7 for interlaced images.
+ */
+ for (pass = 0; pass < number_passes; pass++)
+ {
+ /* Write a few rows at a time. */
+ png_write_rows(png_ptr, &row_pointers[first_row], number_of_rows);
+
+ /* If you are only writing one row at a time, this works */
+ for (y = 0; y < height; y++)
+ {
+ png_write_rows(png_ptr, &row_pointers[y], 1);
+ }
+ }
+#endif no_entire /* use only one output method */
+
+ /* You can write optional chunks like tEXt, zTXt, and tIME at the end
+ * as well. Shouldn't be necessary in 1.1.0 and up as all the public
+ * chunks are supported and you can use png_set_unknown_chunks() to
+ * register unknown chunks into the info structure to be written out.
+ */
+
+ /* It is REQUIRED to call this to finish writing the rest of the file */
+ png_write_end(png_ptr, info_ptr);
+#endif hilevel
+
+ /* If you png_malloced a palette, free it here (don't free info_ptr->palette,
+ as recommended in versions 1.0.5m and earlier of this example; if
+ libpng mallocs info_ptr->palette, libpng will free it). If you
+ allocated it with malloc() instead of png_malloc(), use free() instead
+ of png_free(). */
+ png_free(png_ptr, palette);
+ palette=NULL;
+
+ /* Similarly, if you png_malloced any data that you passed in with
+ png_set_something(), such as a hist or trans array, free it here,
+ when you can be sure that libpng is through with it. */
+ png_free(png_ptr, trans);
+ trans=NULL;
+
+ /* clean up after the write, and free any memory allocated */
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+ /* close the file */
+ fclose(fp);
+
+ /* that's it */
+ return (OK);
+}
+
+#endif /* if 0 */
--- /dev/null
+.TH LIBPNG 3 "September 1, 2001"
+.SH NAME
+libpng \- Portable Network Graphics (PNG) Reference Library 1.2.0
+.SH SYNOPSIS
+\fI\fB
+
+\fB#include <png.h>\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_access_version_number \fI(void\fP\fB);\fP
+
+\fI\fB
+
+\fBint png_check_sig (png_bytep \fP\fIsig\fP\fB, int \fInum\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_chunk_error (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fIerror\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_chunk_warning (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fImessage\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_convert_from_struct_tm (png_timep \fP\fIptime\fP\fB, struct tm FAR * \fIttime\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_convert_from_time_t (png_timep \fP\fIptime\fP\fB, time_t \fIttime\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_charp png_convert_to_rfc1123 (png_structp \fP\fIpng_ptr\fP\fB, png_timep \fIptime\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_infop png_create_info_struct (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_structp png_create_read_struct (png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fIwarn_fn\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_structp png_create_read_struct_2(png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fP\fIwarn_fn\fP\fB, png_voidp \fP\fImem_ptr\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_free_ptr \fIfree_fn\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_structp png_create_write_struct (png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fIwarn_fn\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_structp png_create_write_struct_2(png_const_charp \fP\fIuser_png_ver\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fP\fIwarn_fn\fP\fB, png_voidp \fP\fImem_ptr\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_free_ptr \fIfree_fn\fP\fB);\fP
+
+\fI\fB
+
+\fBint png_debug(int \fP\fIlevel\fP\fB, png_const_charp \fImessage\fP\fB);\fP
+
+\fI\fB
+
+\fBint png_debug1(int \fP\fIlevel\fP\fB, png_const_charp \fP\fImessage\fP\fB, \fIp1\fP\fB);\fP
+
+\fI\fB
+
+\fBint png_debug2(int \fP\fIlevel\fP\fB, png_const_charp \fP\fImessage\fP\fB, \fP\fIp1\fP\fB, \fIp2\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_destroy_info_struct (png_structp \fP\fIpng_ptr\fP\fB, png_infopp \fIinfo_ptr_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_destroy_read_struct (png_structpp \fP\fIpng_ptr_ptr\fP\fB, png_infopp \fP\fIinfo_ptr_ptr\fP\fB, png_infopp \fIend_info_ptr_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_destroy_write_struct (png_structpp \fP\fIpng_ptr_ptr\fP\fB, png_infopp \fIinfo_ptr_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_error (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fIerror\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_free (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fIptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_free_chunk_list (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_free_default(png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fIptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_free_data (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fInum\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_asm_flags (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_byte png_get_bit_depth (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_bKGD (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_16p \fI*background\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_byte png_get_channels (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_cHRM (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fP\fI*white_x\fP\fB, double \fP\fI*white_y\fP\fB, double \fP\fI*red_x\fP\fB, double \fP\fI*red_y\fP\fB, double \fP\fI*green_x\fP\fB, double \fP\fI*green_y\fP\fB, double \fP\fI*blue_x\fP\fB, double \fI*blue_y\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_cHRM_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*white_x\fP\fB, png_uint_32 \fP\fI*white_y\fP\fB, png_uint_32 \fP\fI*red_x\fP\fB, png_uint_32 \fP\fI*red_y\fP\fB, png_uint_32 \fP\fI*green_x\fP\fB, png_uint_32 \fP\fI*green_y\fP\fB, png_uint_32 \fP\fI*blue_x\fP\fB, png_uint_32 \fI*blue_y\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_byte png_get_color_type (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_byte png_get_compression_type (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_byte png_get_copyright (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_voidp png_get_error_ptr (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_byte png_get_filter_type (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_gAMA (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fI*file_gamma\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_gAMA_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fI*int_file_gamma\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_byte png_get_header_ver (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_byte png_get_header_version (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_hIST (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_16p \fI*hist\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_iCCP (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charpp \fP\fIname\fP\fB, int \fP\fI*compression_type\fP\fB, png_charpp \fP\fIprofile\fP\fB, png_uint_32 \fI*proflen\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*width\fP\fB, png_uint_32 \fP\fI*height\fP\fB, int \fP\fI*bit_depth\fP\fB, int \fP\fI*color_type\fP\fB, int \fP\fI*interlace_type\fP\fB, int \fP\fI*compression_type\fP\fB, int \fI*filter_type\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_image_height (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_image_width (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_byte png_get_interlace_type (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_voidp png_get_io_ptr (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_byte png_get_libpng_ver (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_voidp png_get_mem_ptr(png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_byte png_get_mmx_bitdepth_threshold (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_mmx_flagmask (int \fP\fIflag_select\fP\fB, int \fI*compilerID\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_mmx_rowbytes_threshold (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_oFFs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*offset_x\fP\fB, png_uint_32 \fP\fI*offset_y\fP\fB, int \fI*unit_type\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_pCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fI*purpose\fP\fB, png_int_32 \fP\fI*X0\fP\fB, png_int_32 \fP\fI*X1\fP\fB, int \fP\fI*type\fP\fB, int \fP\fI*nparams\fP\fB, png_charp \fP\fI*units\fP\fB, png_charpp \fI*params\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_pHYs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fI*res_x\fP\fB, png_uint_32 \fP\fI*res_y\fP\fB, int \fI*unit_type\fP\fB);\fP
+
+\fI\fB
+
+\fBfloat png_get_pixel_aspect_ratio (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_pixels_per_meter (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_voidp png_get_progressive_ptr (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_colorp \fP\fI*palette\fP\fB, int \fI*num_palette\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_byte png_get_rgb_to_gray_status (png_structp \fIpng_ptr)
+
+\fBpng_uint_32 png_get_rowbytes (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_bytepp png_get_rows (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_sBIT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_8p \fI*sig_bit\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_bytep png_get_signature (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_sPLT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_spalette_p \fI*splt_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_sRGB (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fI*intent\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_text (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_textp \fP\fI*text_ptr\fP\fB, int \fI*num_text\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_tIME (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_timep \fI*mod_time\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_tRNS (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytep \fP\fI*trans\fP\fB, int \fP\fI*num_trans\fP\fB, png_color_16p \fI*trans_values\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_unknown_chunks (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_unknown_chunkpp \fIunknowns\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_voidp png_get_user_chunk_ptr (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_voidp png_get_user_transform_ptr (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_valid (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIflag\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_int_32 png_get_x_offset_microns (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_int_32 png_get_x_offset_pixels (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_x_pixels_per_meter (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_int_32 png_get_y_offset_microns (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_int_32 png_get_y_offset_pixels (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_y_pixels_per_meter (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_compression_buffer_size (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_init_io (png_structp \fP\fIpng_ptr\fP\fB, FILE \fI*fp\fP\fB);\fP
+
+\fI\fB
+
+\fBDEPRECATED: void png_info_init (png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBDEPRECATED: void png_info_init_2 (png_infopp \fP\fIptr_ptr\fP\fB, png_size_t \fIpng_info_struct_size\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_voidp png_malloc (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIsize\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_voidp png_malloc_default(png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIsize\fP\fB);\fP
+
+\fI\fB
+
+\fBvoidp png_memcpy (png_voidp \fP\fIs1\fP\fB, png_voidp \fP\fIs2\fP\fB, png_size_t \fIsize\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_voidp png_memcpy_check (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIs1\fP\fB, png_voidp \fP\fIs2\fP\fB, png_uint_32 \fIsize\fP\fB);\fP
+
+\fI\fB
+
+\fBvoidp png_memset (png_voidp \fP\fIs1\fP\fB, int \fP\fIvalue\fP\fB, png_size_t \fIsize\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_voidp png_memset_check (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIs1\fP\fB, int \fP\fIvalue\fP\fB, png_uint_32 \fIsize\fP\fB);\fP
+
+\fI\fB
+
+\fBint png_mmx_support \fI(void\fP\fB);\fP
+
+\fI\fB
+
+\fBDEPRECATED: void png_permit_empty_plte (png_structp \fP\fIpng_ptr\fP\fB, int \fIempty_plte_permitted\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_process_data (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytep \fP\fIbuffer\fP\fB, png_size_t \fIbuffer_size\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_progressive_combine_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIold_row\fP\fB, png_bytep \fInew_row\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_read_destroy (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_infop \fIend_info_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_read_end (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_read_image (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fIimage\fP\fB);\fP
+
+\fI\fB
+
+\fBDEPRECATED: void png_read_init (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBDEPRECATED: void png_read_init_2 (png_structpp \fP\fIptr_ptr\fP\fB, png_const_charp \fP\fIuser_png_ver\fP\fB, png_size_t \fP\fIpng_struct_size\fP\fB, png_size_t \fIpng_info_size\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_read_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_read_png (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fItransforms\fP\fB, png_voidp \fIparams\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_read_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIrow\fP\fB, png_bytep \fIdisplay_row\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_read_rows (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fP\fIrow\fP\fB, png_bytepp \fP\fIdisplay_row\fP\fB, png_uint_32 \fInum_rows\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_read_update_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_set_asm_flags (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIasm_flags\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_background (png_structp \fP\fIpng_ptr\fP\fB, png_color_16p \fP\fIbackground_color\fP\fB, int \fP\fIbackground_gamma_code\fP\fB, int \fP\fIneed_expand\fP\fB, double \fIbackground_gamma\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_bgr (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_bKGD (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_16p \fIbackground\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_cHRM (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fP\fIwhite_x\fP\fB, double \fP\fIwhite_y\fP\fB, double \fP\fIred_x\fP\fB, double \fP\fIred_y\fP\fB, double \fP\fIgreen_x\fP\fB, double \fP\fIgreen_y\fP\fB, double \fP\fIblue_x\fP\fB, double \fIblue_y\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_cHRM_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIwhite_x\fP\fB, png_uint_32 \fP\fIwhite_y\fP\fB, png_uint_32 \fP\fIred_x\fP\fB, png_uint_32 \fP\fIred_y\fP\fB, png_uint_32 \fP\fIgreen_x\fP\fB, png_uint_32 \fP\fIgreen_y\fP\fB, png_uint_32 \fP\fIblue_x\fP\fB, png_uint_32 \fIblue_y\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_compression_level (png_structp \fP\fIpng_ptr\fP\fB, int \fIlevel\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_compression_mem_level (png_structp \fP\fIpng_ptr\fP\fB, int \fImem_level\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_compression_method (png_structp \fP\fIpng_ptr\fP\fB, int \fImethod\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_compression_strategy (png_structp \fP\fIpng_ptr\fP\fB, int \fIstrategy\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_compression_window_bits (png_structp \fP\fIpng_ptr\fP\fB, int \fIwindow_bits\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_crc_action (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIcrit_action\fP\fB, int \fIancil_action\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_dither (png_structp \fP\fIpng_ptr\fP\fB, png_colorp \fP\fIpalette\fP\fB, int \fP\fInum_palette\fP\fB, int \fP\fImaximum_colors\fP\fB, png_uint_16p \fP\fIhistogram\fP\fB, int \fIfull_dither\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_error_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIerror_ptr\fP\fB, png_error_ptr \fP\fIerror_fn\fP\fB, png_error_ptr \fIwarning_fn\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_expand (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_filler (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIfiller\fP\fB, int \fIflags\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_filter (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fImethod\fP\fB, int \fIfilters\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_filter_heuristics (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIheuristic_method\fP\fB, int \fP\fInum_weights\fP\fB, png_doublep \fP\fIfilter_weights\fP\fB, png_doublep \fIfilter_costs\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_flush (png_structp \fP\fIpng_ptr\fP\fB, int \fInrows\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_gamma (png_structp \fP\fIpng_ptr\fP\fB, double \fP\fIscreen_gamma\fP\fB, double \fIdefault_file_gamma\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_gAMA (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, double \fIfile_gamma\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_gAMA_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIfile_gamma\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_gray_1_2_4_to_8(png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_gray_to_rgb (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_hIST (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_16p \fIhist\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_iCCP (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fIname\fP\fB, int \fP\fIcompression_type\fP\fB, png_charp \fP\fIprofile\fP\fB, png_uint_32 \fIproflen\fP\fB);\fP
+
+\fI\fB
+
+\fBint png_set_interlace_handling (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_invalid (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fImask\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_invert_alpha (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_invert_mono (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIwidth\fP\fB, png_uint_32 \fP\fIheight\fP\fB, int \fP\fIbit_depth\fP\fB, int \fP\fIcolor_type\fP\fB, int \fP\fIinterlace_type\fP\fB, int \fP\fIcompression_type\fP\fB, int \fIfilter_type\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_keep_unknown_chunks (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIkeep\fP\fB, png_bytep \fP\fIchunk_list\fP\fB, int \fInum_chunks\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_mem_fn(png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fImem_ptr\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_free_ptr \fIfree_fn\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_set_mmx_thresholds (png_structp \fP\fIpng_ptr\fP\fB, png_byte \fP\fImmx_bitdepth_threshold\fP\fB, png_uint_32 \fImmx_rowbytes_threshold\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_oFFs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIoffset_x\fP\fB, png_uint_32 \fP\fIoffset_y\fP\fB, int \fIunit_type\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_packing (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_packswap (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_palette_to_rgb(png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_pCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fIpurpose\fP\fB, png_int_32 \fP\fIX0\fP\fB, png_int_32 \fP\fIX1\fP\fB, int \fP\fItype\fP\fB, int \fP\fInparams\fP\fB, png_charp \fP\fIunits\fP\fB, png_charpp \fIparams\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_pHYs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fP\fIres_x\fP\fB, png_uint_32 \fP\fIres_y\fP\fB, int \fIunit_type\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_progressive_read_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIprogressive_ptr\fP\fB, png_progressive_info_ptr \fP\fIinfo_fn\fP\fB, png_progressive_row_ptr \fP\fIrow_fn\fP\fB, png_progressive_end_ptr \fIend_fn\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_colorp \fP\fIpalette\fP\fB, int \fInum_palette\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_read_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIio_ptr\fP\fB, png_rw_ptr \fIread_data_fn\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_read_status_fn (png_structp \fP\fIpng_ptr\fP\fB, png_read_status_ptr \fIread_row_fn\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_read_user_transform_fn (png_structp \fP\fIpng_ptr\fP\fB, png_user_transform_ptr \fIread_user_transform_fn\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_rgb_to_gray (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIerror_action\fP\fB, double \fP\fIred\fP\fB, double \fIgreen\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_rgb_to_gray_fixed (png_structp \fP\fIpng_ptr\fP\fB, int error_action png_fixed_point \fP\fIred\fP\fB, png_fixed_point \fIgreen\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_rows (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytepp \fIrow_pointers\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_sBIT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_color_8p \fIsig_bit\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_sCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_charp \fP\fIunit\fP\fB, double \fP\fIwidth\fP\fB, double \fIheight\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_shift (png_structp \fP\fIpng_ptr\fP\fB, png_color_8p \fItrue_bits\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_sig_bytes (png_structp \fP\fIpng_ptr\fP\fB, int \fInum_bytes\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_sPLT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_spalette_p \fP\fIsplt_ptr\fP\fB, int \fInum_spalettes\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_sRGB (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fIintent\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_sRGB_gAMA_and_cHRM (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fIintent\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_strip_16 (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_strip_alpha (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_strip_error_numbers (png_structp \fIpng_ptr,
+
+\fBpng_uint_32 \fIstrip_mode\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_swap (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_swap_alpha (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_text (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_textp \fP\fItext_ptr\fP\fB, int \fInum_text\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_tIME (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_timep \fImod_time\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_tRNS (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_bytep \fP\fItrans\fP\fB, int \fP\fInum_trans\fP\fB, png_color_16p \fItrans_values\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_tRNS_to_alpha(png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_set_unknown_chunks (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_unknown_chunkp \fP\fIunknowns\fP\fB, int \fP\fInum\fP\fB, int \fIlocation\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_unknown_chunk_location(png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fIchunk\fP\fB, int \fIlocation\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_read_user_chunk_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIuser_chunk_ptr\fP\fB, png_user_chunk_ptr \fIread_user_chunk_fn\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_user_transform_info (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIuser_transform_ptr\fP\fB, int \fP\fIuser_transform_depth\fP\fB, int \fIuser_transform_channels\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_write_fn (png_structp \fP\fIpng_ptr\fP\fB, png_voidp \fP\fIio_ptr\fP\fB, png_rw_ptr \fP\fIwrite_data_fn\fP\fB, png_flush_ptr \fIoutput_flush_fn\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_write_status_fn (png_structp \fP\fIpng_ptr\fP\fB, png_write_status_ptr \fIwrite_row_fn\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_write_user_transform_fn (png_structp \fP\fIpng_ptr\fP\fB, png_user_transform_ptr \fIwrite_user_transform_fn\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_set_compression_buffer_size(png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIsize\fP\fB);\fP
+
+\fI\fB
+
+\fBint png_sig_cmp (png_bytep \fP\fIsig\fP\fB, png_size_t \fP\fIstart\fP\fB, png_size_t \fInum_to_check\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_start_read_image (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_warning (png_structp \fP\fIpng_ptr\fP\fB, png_const_charp \fImessage\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_chunk (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIchunk_name\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_chunk_data (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_chunk_end (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_chunk_start (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIchunk_name\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_destroy (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_destroy_info (png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_end (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_flush (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_image (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fIimage\fP\fB);\fP
+
+\fI\fB
+
+\fBDEPRECATED: void png_write_init (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBDEPRECATED: void png_write_init_2 (png_structpp \fP\fIptr_ptr\fP\fB, png_const_charp \fP\fIuser_png_ver\fP\fB, png_size_t \fP\fIpng_struct_size\fP\fB, png_size_t \fIpng_info_size\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_info_before_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_png (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, int \fP\fItransforms\fP\fB, png_voidp \fIparams\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIrow\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_rows (png_structp \fP\fIpng_ptr\fP\fB, png_bytepp \fP\fIrow\fP\fB, png_uint_32 \fInum_rows\fP\fB);\fP
+
+\fI\fB
+
+.SH DESCRIPTION
+The
+.I libpng
+library supports encoding, decoding, and various manipulations of
+the Portable Network Graphics (PNG) format image files. It uses the
+.IR zlib(3)
+compression library.
+Following is a copy of the libpng.txt file that accompanies libpng.
+.SH LIBPNG.TXT
+libpng.txt - A description on how to use and modify libpng
+
+ libpng version 1.2.0 - September 1, 2001
+ Updated and distributed by Glenn Randers-Pehrson
+ <randeg@alum.rpi.edu>
+ Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ For conditions of distribution and use, see copyright
+ notice in png.h.
+
+ based on:
+
+ libpng 1.0 beta 6 version 0.96 May 28, 1997
+ Updated and distributed by Andreas Dilger
+ Copyright (c) 1996, 1997 Andreas Dilger
+
+ libpng 1.0 beta 2 - version 0.88 January 26, 1996
+ For conditions of distribution and use, see copyright
+ notice in png.h. Copyright (c) 1995, 1996 Guy Eric
+ Schalnat, Group 42, Inc.
+
+ Updated/rewritten per request in the libpng FAQ
+ Copyright (c) 1995, 1996 Frank J. T. Wojcik
+ December 18, 1995 & January 20, 1996
+
+.SH I. Introduction
+
+This file describes how to use and modify the PNG reference library
+(known as libpng) for your own use. There are five sections to this
+file: introduction, structures, reading, writing, and modification and
+configuration notes for various special platforms. In addition to this
+file, example.c is a good starting point for using the library, as
+it is heavily commented and should include everything most people
+will need. We assume that libpng is already installed; see the
+INSTALL file for instructions on how to install libpng.
+
+Libpng was written as a companion to the PNG specification, as a way
+of reducing the amount of time and effort it takes to support the PNG
+file format in application programs.
+
+The PNG-1.2 specification is available at <http://www.libpng.org/pub/png>
+and at <ftp://ftp.uu.net/graphics/png/documents/>.
+
+The PNG-1.0 specification is available
+as RFC 2083 <ftp://ftp.uu.net/graphics/png/documents/> and as a
+W3C Recommendation <http://www.w3.org/TR/REC.png.html>. Some
+additional chunks are described in the special-purpose public chunks
+documents at <ftp://ftp.uu.net/graphics/png/documents/>.
+
+Other information
+about PNG, and the latest version of libpng, can be found at the PNG home
+page, <http://www.libpng.org/pub/png/>
+and at <ftp://ftp.uu.net/graphics/png/>.
+
+Most users will not have to modify the library significantly; advanced
+users may want to modify it more. All attempts were made to make it as
+complete as possible, while keeping the code easy to understand.
+Currently, this library only supports C. Support for other languages
+is being considered.
+
+Libpng has been designed to handle multiple sessions at one time,
+to be easily modifiable, to be portable to the vast majority of
+machines (ANSI, K&R, 16-, 32-, and 64-bit) available, and to be easy
+to use. The ultimate goal of libpng is to promote the acceptance of
+the PNG file format in whatever way possible. While there is still
+work to be done (see the TODO file), libpng should cover the
+majority of the needs of its users.
+
+Libpng uses zlib for its compression and decompression of PNG files.
+Further information about zlib, and the latest version of zlib, can
+be found at the zlib home page, <http://www.info-zip.org/pub/infozip/zlib/>.
+The zlib compression utility is a general purpose utility that is
+useful for more than PNG files, and can be used without libpng.
+See the documentation delivered with zlib for more details.
+You can usually find the source files for the zlib utility wherever you
+find the libpng source files.
+
+Libpng is thread safe, provided the threads are using different
+instances of the structures. Each thread should have its own
+png_struct and png_info instances, and thus its own image.
+Libpng does not protect itself against two threads using the
+same instance of a structure. Note: thread safety may be defeated
+by use of some of the MMX assembler code in pnggccrd.c, which is only
+compiled when the user defines PNG_THREAD_UNSAFE_OK.
+
+
+.SH II. Structures
+
+There are two main structures that are important to libpng, png_struct
+and png_info. The first, png_struct, is an internal structure that
+will not, for the most part, be used by a user except as the first
+variable passed to every libpng function call.
+
+The png_info structure is designed to provide information about the
+PNG file. At one time, the fields of png_info were intended to be
+directly accessible to the user. However, this tended to cause problems
+with applications using dynamically loaded libraries, and as a result
+a set of interface functions for png_info (the png_get_*() and png_set_*()
+functions) was developed. The fields of png_info are still available for
+older applications, but it is suggested that applications use the new
+interfaces if at all possible.
+
+Applications that do make direct access to the members of png_struct (except
+for png_ptr->jmpbuf) must be recompiled whenever the library is updated,
+and applications that make direct access to the members of png_info must
+be recompiled if they were compiled or loaded with libpng version 1.0.6,
+in which the members were in a different order. In version 1.0.7, the
+members of the png_info structure reverted to the old order, as they were
+in versions 0.97c through 1.0.5. Starting with version 2.0.0, both
+structures are going to be hidden, and the contents of the structures will
+only be accessible through the png_get/png_set functions.
+
+The png.h header file is an invaluable reference for programming with libpng.
+And while I'm on the topic, make sure you include the libpng header file:
+
+#include <png.h>
+
+.SH III. Reading
+
+We'll now walk you through the possible functions to call when reading
+in a PNG file sequentially, briefly explaining the syntax and purpose
+of each one. See example.c and png.h for more detail. While
+progressive reading is covered in the next section, you will still
+need some of the functions discussed in this section to read a PNG
+file.
+
+.SS Setup
+
+You will want to do the I/O initialization(*) before you get into libpng,
+so if it doesn't work, you don't have much to undo. Of course, you
+will also want to insure that you are, in fact, dealing with a PNG
+file. Libpng provides a simple check to see if a file is a PNG file.
+To use it, pass in the first 1 to 8 bytes of the file to the function
+png_sig_cmp(), and it will return 0 if the bytes match the corresponding
+bytes of the PNG signature, or nonzero otherwise. Of course, the more bytes
+you pass in, the greater the accuracy of the prediction.
+
+If you are intending to keep the file pointer open for use in libpng,
+you must ensure you don't read more than 8 bytes from the beginning
+of the file, and you also have to make a call to png_set_sig_bytes_read()
+with the number of bytes you read from the beginning. Libpng will
+then only check the bytes (if any) that your program didn't read.
+
+(*): If you are not using the standard I/O functions, you will need
+to replace them with custom functions. See the discussion under
+Customizing libpng.
+
+
+ FILE *fp = fopen(file_name, "rb");
+ if (!fp)
+ {
+ return (ERROR);
+ }
+ fread(header, 1, number, fp);
+ is_png = !png_sig_cmp(header, 0, number);
+ if (!is_png)
+ {
+ return (NOT_PNG);
+ }
+
+
+Next, png_struct and png_info need to be allocated and initialized. In
+order to ensure that the size of these structures is correct even with a
+dynamically linked libpng, there are functions to initialize and
+allocate the structures. We also pass the library version, optional
+pointers to error handling functions, and a pointer to a data struct for
+use by the error functions, if necessary (the pointer and functions can
+be NULL if the default error handlers are to be used). See the section
+on Changes to Libpng below regarding the old initialization functions.
+The structure allocation functions quietly return NULL if they fail to
+create the structure, so your application should check for that.
+
+ png_structp png_ptr = png_create_read_struct
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn);
+ if (!png_ptr)
+ return (ERROR);
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_read_struct(&png_ptr,
+ (png_infopp)NULL, (png_infopp)NULL);
+ return (ERROR);
+ }
+
+ png_infop end_info = png_create_info_struct(png_ptr);
+ if (!end_info)
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ (png_infopp)NULL);
+ return (ERROR);
+ }
+
+If you want to use your own memory allocation routines,
+define PNG_USER_MEM_SUPPORTED and use
+png_create_read_struct_2() instead of png_create_read_struct():
+
+ png_structp png_ptr = png_create_read_struct_2
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn, (png_voidp)
+ user_mem_ptr, user_malloc_fn, user_free_fn);
+
+The error handling routines passed to png_create_read_struct()
+and the memory alloc/free routines passed to png_create_struct_2()
+are only necessary if you are not using the libpng supplied error
+handling and memory alloc/free functions.
+
+When libpng encounters an error, it expects to longjmp back
+to your routine. Therefore, you will need to call setjmp and pass
+your png_jmpbuf(png_ptr). If you read the file from different
+routines, you will need to update the jmpbuf field every time you enter
+a new routine that will call a png_*() function.
+
+See your documentation of setjmp/longjmp for your compiler for more
+information on setjmp/longjmp. See the discussion on libpng error
+handling in the Customizing Libpng section below for more information
+on the libpng error handling. If an error occurs, and libpng longjmp's
+back to your setjmp, you will want to call png_destroy_read_struct() to
+free any memory.
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ &end_info);
+ fclose(fp);
+ return (ERROR);
+ }
+
+If you would rather avoid the complexity of setjmp/longjmp issues,
+you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case
+errors will result in a call to PNG_ABORT() which defaults to abort().
+
+Now you need to set up the input code. The default for libpng is to
+use the C function fread(). If you use this, you will need to pass a
+valid FILE * in the function png_init_io(). Be sure that the file is
+opened in binary mode. If you wish to handle reading data in another
+way, you need not call the png_init_io() function, but you must then
+implement the libpng I/O methods discussed in the Customizing Libpng
+section below.
+
+ png_init_io(png_ptr, fp);
+
+If you had previously opened the file and read any of the signature from
+the beginning in order to see if this was a PNG file, you need to let
+libpng know that there are some bytes missing from the start of the file.
+
+ png_set_sig_bytes(png_ptr, number);
+
+.SS Setting up callback code
+
+You can set up a callback function to handle any unknown chunks in the
+input stream. You must supply the function
+
+ read_chunk_callback(png_ptr ptr,
+ png_unknown_chunkp chunk);
+ {
+ /* The unknown chunk structure contains your
+ chunk data: */
+ png_byte name[5];
+ png_byte *data;
+ png_size_t size;
+ /* Note that libpng has already taken care of
+ the CRC handling */
+
+ /* put your code here. Return one of the
+ following: */
+
+ return (-n); /* chunk had an error */
+ return (0); /* did not recognize */
+ return (n); /* success */
+ }
+
+(You can give your function another name that you like instead of
+"read_chunk_callback")
+
+To inform libpng about your function, use
+
+ png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr,
+ read_chunk_callback);
+
+This names not only the callback function, but also a user pointer that
+you can retrieve with
+
+ png_get_user_chunk_ptr(png_ptr);
+
+At this point, you can set up a callback function that will be
+called after each row has been read, which you can use to control
+a progress meter or the like. It's demonstrated in pngtest.c.
+You must supply a function
+
+ void read_row_callback(png_ptr ptr, png_uint_32 row,
+ int pass);
+ {
+ /* put your code here */
+ }
+
+(You can give it another name that you like instead of "read_row_callback")
+
+To inform libpng about your function, use
+
+ png_set_read_status_fn(png_ptr, read_row_callback);
+
+.SS Unknown-chunk handling
+
+Now you get to set the way the library processes unknown chunks in the
+input PNG stream. Both known and unknown chunks will be read. Normal
+behavior is that known chunks will be parsed into information in
+various info_ptr members; unknown chunks will be discarded. To change
+this, you can call:
+
+ png_set_keep_unknown_chunks(png_ptr, info_ptr, keep,
+ chunk_list, num_chunks);
+ keep - 0: do not keep
+ 1: keep only if safe-to-copy
+ 2: keep even if unsafe-to-copy
+ chunk_list - list of chunks affected (a byte string,
+ five bytes per chunk, NULL or '\0' if
+ num_chunks is 0)
+ num_chunks - number of chunks affected; if 0, all
+ unknown chunks are affected
+
+Unknown chunks declared in this way will be saved as raw data onto a
+list of png_unknown_chunk structures. If a chunk that is normally
+known to libpng is named in the list, it will be handled as unknown,
+according to the "keep" directive. If a chunk is named in successive
+instances of png_set_keep_unknown_chunks(), the final instance will
+take precedence.
+
+.SS The high-level read interface
+
+At this point there are two ways to proceed; through the high-level
+read interface, or through a sequence of low-level read operations.
+You can use the high-level interface if (a) you are willing to read
+the entire image into memory, and (b) the input transformations
+you want to do are limited to the following set:
+
+ PNG_TRANSFORM_IDENTITY No transformation
+ PNG_TRANSFORM_STRIP_16 Strip 16-bit samples to
+ 8 bits
+ PNG_TRANSFORM_STRIP_ALPHA Discard the alpha channel
+ PNG_TRANSFORM_PACKING Expand 1, 2 and 4-bit
+ samples to bytes
+ PNG_TRANSFORM_PACKSWAP Change order of packed
+ pixels to LSB first
+ PNG_TRANSFORM_EXPAND Perform set_expand()
+ PNG_TRANSFORM_INVERT_MONO Invert monochrome images
+ PNG_TRANSFORM_SHIFT Normalize pixels to the
+ sBIT depth
+ PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA
+ to BGRA
+ PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA
+ to AG
+ PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity
+ to transparency
+ PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples
+
+(This excludes setting a background color, doing gamma transformation,
+dithering, and setting filler.) If this is the case, simply do this:
+
+ png_read_png(png_ptr, info_ptr, png_transforms, NULL)
+
+where png_transforms is an integer containing the logical OR of
+some set of transformation flags. This call is equivalent to png_read_info(),
+followed the set of transformations indicated by the transform mask,
+then png_read_image(), and finally png_read_end().
+
+(The final parameter of this call is not yet used. Someday it might point
+to transformation parameters required by some future input transform.)
+
+After you have called png_read_png(), you can retrieve the image data
+with
+
+ row_pointers = png_get_rows(png_ptr, info_ptr);
+
+where row_pointers is an array of pointers to the pixel data for each row:
+
+ png_bytep row_pointers[height];
+
+If you know your image size and pixel size ahead of time, you can allocate
+row_pointers prior to calling png_read_png() with
+
+ row_pointers = png_malloc(png_ptr,
+ height*sizeof(png_bytep));
+ for (int i=0; i<height, i++)
+ row_pointers[i]=png_malloc(png_ptr,
+ width*pixel_size);
+ png_set_rows(png_ptr, info_ptr, &row_pointers);
+
+Alternatively you could allocate your image in one big block and define
+row_pointers[i] to point into the proper places in your block.
+
+If you use png_set_rows(), the application is responsible for freeing
+row_pointers (and row_pointers[i], if they were separately allocated).
+
+If you don't allocate row_pointers ahead of time, png_read_png() will
+do it, and it'll be free'ed when you call png_destroy_*().
+
+.SS The low-level read interface
+
+If you are going the low-level route, you are now ready to read all
+the file information up to the actual image data. You do this with a
+call to png_read_info().
+
+ png_read_info(png_ptr, info_ptr);
+
+This will process all chunks up to but not including the image data.
+
+.SS Querying the info structure
+
+Functions are used to get the information from the info_ptr once it
+has been read. Note that these fields may not be completely filled
+in until png_read_end() has read the chunk data following the image.
+
+ png_get_IHDR(png_ptr, info_ptr, &width, &height,
+ &bit_depth, &color_type, &interlace_type,
+ &compression_type, &filter_method);
+
+ width - holds the width of the image
+ in pixels (up to 2^31).
+ height - holds the height of the image
+ in pixels (up to 2^31).
+ bit_depth - holds the bit depth of one of the
+ image channels. (valid values are
+ 1, 2, 4, 8, 16 and depend also on
+ the color_type. See also
+ significant bits (sBIT) below).
+ color_type - describes which color/alpha channels
+ are present.
+ PNG_COLOR_TYPE_GRAY
+ (bit depths 1, 2, 4, 8, 16)
+ PNG_COLOR_TYPE_GRAY_ALPHA
+ (bit depths 8, 16)
+ PNG_COLOR_TYPE_PALETTE
+ (bit depths 1, 2, 4, 8)
+ PNG_COLOR_TYPE_RGB
+ (bit_depths 8, 16)
+ PNG_COLOR_TYPE_RGB_ALPHA
+ (bit_depths 8, 16)
+
+ PNG_COLOR_MASK_PALETTE
+ PNG_COLOR_MASK_COLOR
+ PNG_COLOR_MASK_ALPHA
+
+ filter_method - (must be PNG_FILTER_TYPE_BASE
+ for PNG 1.0, and can also be
+ PNG_INTRAPIXEL_DIFFERENCING if
+ the PNG datastream is embedded in
+ a MNG-1.0 datastream)
+ compression_type - (must be PNG_COMPRESSION_TYPE_BASE
+ for PNG 1.0)
+ interlace_type - (PNG_INTERLACE_NONE or
+ PNG_INTERLACE_ADAM7)
+ Any or all of interlace_type, compression_type, of
+ filter_method can be NULL if you are
+ not interested in their values.
+
+ channels = png_get_channels(png_ptr, info_ptr);
+ channels - number of channels of info for the
+ color type (valid values are 1 (GRAY,
+ PALETTE), 2 (GRAY_ALPHA), 3 (RGB),
+ 4 (RGB_ALPHA or RGB + filler byte))
+ rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+ rowbytes - number of bytes needed to hold a row
+
+ signature = png_get_signature(png_ptr, info_ptr);
+ signature - holds the signature read from the
+ file (if any). The data is kept in
+ the same offset it would be if the
+ whole signature were read (i.e. if an
+ application had already read in 4
+ bytes of signature before starting
+ libpng, the remaining 4 bytes would
+ be in signature[4] through signature[7]
+ (see png_set_sig_bytes())).
+
+
+ width = png_get_image_width(png_ptr,
+ info_ptr);
+ height = png_get_image_height(png_ptr,
+ info_ptr);
+ bit_depth = png_get_bit_depth(png_ptr,
+ info_ptr);
+ color_type = png_get_color_type(png_ptr,
+ info_ptr);
+ filter_method = png_get_filter_type(png_ptr,
+ info_ptr);
+ compression_type = png_get_compression_type(png_ptr,
+ info_ptr);
+ interlace_type = png_get_interlace_type(png_ptr,
+ info_ptr);
+
+
+These are also important, but their validity depends on whether the chunk
+has been read. The png_get_valid(png_ptr, info_ptr, PNG_INFO_<chunk>) and
+png_get_<chunk>(png_ptr, info_ptr, ...) functions return non-zero if the
+data has been read, or zero if it is missing. The parameters to the
+png_get_<chunk> are set directly if they are simple data types, or a pointer
+into the info_ptr is returned for any complex types.
+
+ png_get_PLTE(png_ptr, info_ptr, &palette,
+ &num_palette);
+ palette - the palette for the file
+ (array of png_color)
+ num_palette - number of entries in the palette
+
+ png_get_gAMA(png_ptr, info_ptr, &gamma);
+ gamma - the gamma the file is written
+ at (PNG_INFO_gAMA)
+
+ png_get_sRGB(png_ptr, info_ptr, &srgb_intent);
+ srgb_intent - the rendering intent (PNG_INFO_sRGB)
+ The presence of the sRGB chunk
+ means that the pixel data is in the
+ sRGB color space. This chunk also
+ implies specific values of gAMA and
+ cHRM.
+
+ png_get_iCCP(png_ptr, info_ptr, &name,
+ &compression_type, &profile, &proflen);
+ name - The profile name.
+ compression - The compression type; always
+ PNG_COMPRESSION_TYPE_BASE for PNG 1.0.
+ You may give NULL to this argument to
+ ignore it.
+ profile - International Color Consortium color
+ profile data. May contain NULs.
+ proflen - length of profile data in bytes.
+
+ png_get_sBIT(png_ptr, info_ptr, &sig_bit);
+ sig_bit - the number of significant bits for
+ (PNG_INFO_sBIT) each of the gray,
+ red, green, and blue channels,
+ whichever are appropriate for the
+ given color type (png_color_16)
+
+ png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans,
+ &trans_values);
+ trans - array of transparent entries for
+ palette (PNG_INFO_tRNS)
+ trans_values - graylevel or color sample values of
+ the single transparent color for
+ non-paletted images (PNG_INFO_tRNS)
+ num_trans - number of transparent entries
+ (PNG_INFO_tRNS)
+
+ png_get_hIST(png_ptr, info_ptr, &hist);
+ (PNG_INFO_hIST)
+ hist - histogram of palette (array of
+ png_uint_16)
+
+ png_get_tIME(png_ptr, info_ptr, &mod_time);
+ mod_time - time image was last modified
+ (PNG_VALID_tIME)
+
+ png_get_bKGD(png_ptr, info_ptr, &background);
+ background - background color (PNG_VALID_bKGD)
+ valid 16-bit red, green and blue
+ values, regardless of color_type
+
+ num_comments = png_get_text(png_ptr, info_ptr,
+ &text_ptr, &num_text);
+ num_comments - number of comments
+ text_ptr - array of png_text holding image
+ comments
+ text_ptr[i].compression - type of compression used
+ on "text" PNG_TEXT_COMPRESSION_NONE
+ PNG_TEXT_COMPRESSION_zTXt
+ PNG_ITXT_COMPRESSION_NONE
+ PNG_ITXT_COMPRESSION_zTXt
+ text_ptr[i].key - keyword for comment. Must contain
+ 1-79 characters.
+ text_ptr[i].text - text comments for current
+ keyword. Can be empty.
+ text_ptr[i].text_length - length of text string,
+ after decompression, 0 for iTXt
+ text_ptr[i].itxt_length - length of itxt string,
+ after decompression, 0 for tEXt/zTXt
+ text_ptr[i].lang - language of comment (empty
+ string for unknown).
+ text_ptr[i].translated_keyword - keyword in UTF-8
+ (empty string for unknown).
+ num_text - number of comments (same as
+ num_comments; you can put NULL here
+ to avoid the duplication)
+ Note while png_set_text() will accept text, language,
+ and translated keywords that can be NULL pointers, the
+ structure returned by png_get_text will always contain
+ regular zero-terminated C strings. They might be
+ empty strings but they will never be NULL pointers.
+
+ num_spalettes = png_get_sPLT(png_ptr, info_ptr,
+ &palette_ptr);
+ palette_ptr - array of palette structures holding
+ contents of one or more sPLT chunks
+ read.
+ num_spalettes - number of sPLT chunks read.
+
+ png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y,
+ &unit_type);
+ offset_x - positive offset from the left edge
+ of the screen
+ offset_y - positive offset from the top edge
+ of the screen
+ unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER
+
+ png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y,
+ &unit_type);
+ res_x - pixels/unit physical resolution in
+ x direction
+ res_y - pixels/unit physical resolution in
+ x direction
+ unit_type - PNG_RESOLUTION_UNKNOWN,
+ PNG_RESOLUTION_METER
+
+ png_get_sCAL(png_ptr, info_ptr, &unit, &width,
+ &height)
+ unit - physical scale units (an integer)
+ width - width of a pixel in physical scale units
+ height - height of a pixel in physical scale units
+ (width and height are doubles)
+
+ png_get_sCAL_s(png_ptr, info_ptr, &unit, &width,
+ &height)
+ unit - physical scale units (an integer)
+ width - width of a pixel in physical scale units
+ height - height of a pixel in physical scale units
+ (width and height are strings like "2.54")
+
+ num_unknown_chunks = png_get_unknown_chunks(png_ptr,
+ info_ptr, &unknowns)
+ unknowns - array of png_unknown_chunk
+ structures holding unknown chunks
+ unknowns[i].name - name of unknown chunk
+ unknowns[i].data - data of unknown chunk
+ unknowns[i].size - size of unknown chunk's data
+ unknowns[i].location - position of chunk in file
+
+ The value of "i" corresponds to the order in which the
+ chunks were read from the PNG file or inserted with the
+ png_set_unknown_chunks() function.
+
+The data from the pHYs chunk can be retrieved in several convenient
+forms:
+
+ res_x = png_get_x_pixels_per_meter(png_ptr,
+ info_ptr)
+ res_y = png_get_y_pixels_per_meter(png_ptr,
+ info_ptr)
+ res_x_and_y = png_get_pixels_per_meter(png_ptr,
+ info_ptr)
+ res_x = png_get_x_pixels_per_inch(png_ptr,
+ info_ptr)
+ res_y = png_get_y_pixels_per_inch(png_ptr,
+ info_ptr)
+ res_x_and_y = png_get_pixels_per_inch(png_ptr,
+ info_ptr)
+ aspect_ratio = png_get_pixel_aspect_ratio(png_ptr,
+ info_ptr)
+
+ (Each of these returns 0 [signifying "unknown"] if
+ the data is not present or if res_x is 0;
+ res_x_and_y is 0 if res_x != res_y)
+
+The data from the oFFs chunk can be retrieved in several convenient
+forms:
+
+ x_offset = png_get_x_offset_microns(png_ptr, info_ptr);
+ y_offset = png_get_y_offset_microns(png_ptr, info_ptr);
+ x_offset = png_get_x_offset_inches(png_ptr, info_ptr);
+ y_offset = png_get_y_offset_inches(png_ptr, info_ptr);
+
+ (Each of these returns 0 [signifying "unknown" if both
+ x and y are 0] if the data is not present or if the
+ chunk is present but the unit is the pixel)
+
+For more information, see the png_info definition in png.h and the
+PNG specification for chunk contents. Be careful with trusting
+rowbytes, as some of the transformations could increase the space
+needed to hold a row (expand, filler, gray_to_rgb, etc.).
+See png_read_update_info(), below.
+
+A quick word about text_ptr and num_text. PNG stores comments in
+keyword/text pairs, one pair per chunk, with no limit on the number
+of text chunks, and a 2^31 byte limit on their size. While there are
+suggested keywords, there is no requirement to restrict the use to these
+strings. It is strongly suggested that keywords and text be sensible
+to humans (that's the point), so don't use abbreviations. Non-printing
+symbols are not allowed. See the PNG specification for more details.
+There is also no requirement to have text after the keyword.
+
+Keywords should be limited to 79 Latin-1 characters without leading or
+trailing spaces, but non-consecutive spaces are allowed within the
+keyword. It is possible to have the same keyword any number of times.
+The text_ptr is an array of png_text structures, each holding a
+pointer to a language string, a pointer to a keyword and a pointer to
+a text string. The text string, language code, and translated
+keyword may be empty or NULL pointers. The keyword/text
+pairs are put into the array in the order that they are received.
+However, some or all of the text chunks may be after the image, so, to
+make sure you have read all the text chunks, don't mess with these
+until after you read the stuff after the image. This will be
+mentioned again below in the discussion that goes with png_read_end().
+
+.SS Input transformations
+
+After you've read the header information, you can set up the library
+to handle any special transformations of the image data. The various
+ways to transform the data will be described in the order that they
+should occur. This is important, as some of these change the color
+type and/or bit depth of the data, and some others only work on
+certain color types and bit depths. Even though each transformation
+checks to see if it has data that it can do something with, you should
+make sure to only enable a transformation if it will be valid for the
+data. For example, don't swap red and blue on grayscale data.
+
+The colors used for the background and transparency values should be
+supplied in the same format/depth as the current image data. They
+are stored in the same format/depth as the image data in a bKGD or tRNS
+chunk, so this is what libpng expects for this data. The colors are
+transformed to keep in sync with the image data when an application
+calls the png_read_update_info() routine (see below).
+
+Data will be decoded into the supplied row buffers packed into bytes
+unless the library has been told to transform it into another format.
+For example, 4 bit/pixel paletted or grayscale data will be returned
+2 pixels/byte with the leftmost pixel in the high-order bits of the
+byte, unless png_set_packing() is called. 8-bit RGB data will be stored
+in RGB RGB RGB format unless png_set_filler() is called to insert filler
+bytes, either before or after each RGB triplet. 16-bit RGB data will
+be returned RRGGBB RRGGBB, with the most significant byte of the color
+value first, unless png_set_strip_16() is called to transform it to
+regular RGB RGB triplets, or png_set_filler() is called to insert
+filler bytes, either before or after each RRGGBB triplet. Similarly,
+8-bit or 16-bit grayscale data can be modified with png_set_filler()
+or png_set_strip_16().
+
+The following code transforms grayscale images of less than 8 to 8 bits,
+changes paletted images to RGB, and adds a full alpha channel if there is
+transparency information in a tRNS chunk. This is most useful on
+grayscale images with bit depths of 2 or 4 or if there is a multiple-image
+viewing application that wishes to treat all images in the same way.
+
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_palette_to_rgb(png_ptr);
+
+ if (color_type == PNG_COLOR_TYPE_GRAY &&
+ bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr);
+
+ if (png_get_valid(png_ptr, info_ptr,
+ PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr);
+
+These three functions are actually aliases for png_set_expand(), added
+in libpng version 1.0.4, with the function names expanded to improve code
+readability. In some future version they may actually do different
+things.
+
+PNG can have files with 16 bits per channel. If you only can handle
+8 bits per channel, this will strip the pixels down to 8 bit.
+
+ if (bit_depth == 16)
+ png_set_strip_16(png_ptr);
+
+If, for some reason, you don't need the alpha channel on an image,
+and you want to remove it rather than combining it with the background
+(but the image author certainly had in mind that you *would* combine
+it with the background, so that's what you should probably do):
+
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ png_set_strip_alpha(png_ptr);
+
+In PNG files, the alpha channel in an image
+is the level of opacity. If you need the alpha channel in an image to
+be the level of transparency instead of opacity, you can invert the
+alpha channel (or the tRNS chunk data) after it's read, so that 0 is
+fully opaque and 255 (in 8-bit or paletted images) or 65535 (in 16-bit
+images) is fully transparent, with
+
+ png_set_invert_alpha(png_ptr);
+
+PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as
+they can, resulting in, for example, 8 pixels per byte for 1 bit
+files. This code expands to 1 pixel per byte without changing the
+values of the pixels:
+
+ if (bit_depth < 8)
+ png_set_packing(png_ptr);
+
+PNG files have possible bit depths of 1, 2, 4, 8, and 16. All pixels
+stored in a PNG image have been "scaled" or "shifted" up to the next
+higher possible bit depth (e.g. from 5 bits/sample in the range [0,31] to
+8 bits/sample in the range [0, 255]). However, it is also possible to
+convert the PNG pixel data back to the original bit depth of the image.
+This call reduces the pixels back down to the original bit depth:
+
+ png_color_8p sig_bit;
+
+ if (png_get_sBIT(png_ptr, info_ptr, &sig_bit))
+ png_set_shift(png_ptr, sig_bit);
+
+PNG files store 3-color pixels in red, green, blue order. This code
+changes the storage of the pixels to blue, green, red:
+
+ if (color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_bgr(png_ptr);
+
+PNG files store RGB pixels packed into 3 or 6 bytes. This code expands them
+into 4 or 8 bytes for windowing systems that need them in this format:
+
+ if (color_type == PNG_COLOR_TYPE_RGB)
+ png_set_filler(png_ptr, filler, PNG_FILLER_BEFORE);
+
+where "filler" is the 8 or 16-bit number to fill with, and the location is
+either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether
+you want the filler before the RGB or after. This transformation
+does not affect images that already have full alpha channels. To add an
+opaque alpha channel, use filler=0xff or 0xffff and PNG_FILLER_AFTER which
+will generate RGBA pixels.
+
+If you are reading an image with an alpha channel, and you need the
+data as ARGB instead of the normal PNG format RGBA:
+
+ if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_swap_alpha(png_ptr);
+
+For some uses, you may want a grayscale image to be represented as
+RGB. This code will do that conversion:
+
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb(png_ptr);
+
+Conversely, you can convert an RGB or RGBA image to grayscale or grayscale
+with alpha.
+
+ if (color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_rgb_to_gray_fixed(png_ptr, error_action,
+ int red_weight, int green_weight);
+
+ error_action = 1: silently do the conversion
+ error_action = 2: issue a warning if the original
+ image has any pixel where
+ red != green or red != blue
+ error_action = 3: issue an error and abort the
+ conversion if the original
+ image has any pixel where
+ red != green or red != blue
+
+ red_weight: weight of red component times 100000
+ green_weight: weight of green component times 100000
+ If either weight is negative, default
+ weights (21268, 71514) are used.
+
+If you have set error_action = 1 or 2, you can
+later check whether the image really was gray, after processing
+the image rows, with the png_get_rgb_to_gray_status(png_ptr) function.
+It will return a png_byte that is zero if the image was gray or
+1 if there were any non-gray pixels. bKGD and sBIT data
+will be silently converted to grayscale, using the green channel
+data, regardless of the error_action setting.
+
+With red_weight+green_weight<=100000,
+the normalized graylevel is computed:
+
+ int rw = red_weight * 65536;
+ int gw = green_weight * 65536;
+ int bw = 65536 - (rw + gw);
+ gray = (rw*red + gw*green + bw*blue)/65536;
+
+The default values approximate those recommended in the Charles
+Poynton's Color FAQ, <http://www.inforamp.net/~poynton/>
+Copyright (c) 1998-01-04 Charles Poynton poynton@inforamp.net
+
+ Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
+
+Libpng approximates this with
+
+ Y = 0.21268 * R + 0.7151 * G + 0.07217 * B
+
+which can be expressed with integers as
+
+ Y = (6969 * R + 23434 * G + 2365 * B)/32768
+
+The calculation is done in a linear colorspace, if the image gamma
+is known.
+
+If you have a grayscale and you are using png_set_expand_depth() or
+png_set_expand() to change to
+a higher bit-depth, you must either supply the background color as a gray
+value at the original file bit-depth (need_expand = 1) or else supply the
+background color as an RGB triplet at the final, expanded bit depth
+(need_expand = 0). Similarly, if you are reading a paletted image, you
+must either supply the background color as a palette index (need_expand = 1)
+or as an RGB triplet that may or may not be in the palette (need_expand = 0).
+
+ png_color_16 my_background;
+ png_color_16p image_background;
+
+ if (png_get_bKGD(png_ptr, info_ptr, &image_background))
+ png_set_background(png_ptr, image_background,
+ PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+ else
+ png_set_background(png_ptr, &my_background,
+ PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
+
+The png_set_background() function tells libpng to composite images
+with alpha or simple transparency against the supplied background
+color. If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid),
+you may use this color, or supply another color more suitable for
+the current display (e.g., the background color from a web page). You
+need to tell libpng whether the color is in the gamma space of the
+display (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file
+(PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one
+that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't
+know why anyone would use this, but it's here).
+
+To properly display PNG images on any kind of system, the application needs
+to know what the display gamma is. Ideally, the user will know this, and
+the application will allow them to set it. One method of allowing the user
+to set the display gamma separately for each system is to check for a
+SCREEN_GAMMA or DISPLAY_GAMMA environment variable, which will hopefully be
+correctly set.
+
+Note that display_gamma is the overall gamma correction required to produce
+pleasing results, which depends on the lighting conditions in the surrounding
+environment. In a dim or brightly lit room, no compensation other than
+the physical gamma exponent of the monitor is needed, while in a dark room
+a slightly smaller exponent is better.
+
+ double gamma, screen_gamma;
+
+ if (/* We have a user-defined screen
+ gamma value */)
+ {
+ screen_gamma = user_defined_screen_gamma;
+ }
+ /* One way that applications can share the same
+ screen gamma value */
+ else if ((gamma_str = getenv("SCREEN_GAMMA"))
+ != NULL)
+ {
+ screen_gamma = (double)atof(gamma_str);
+ }
+ /* If we don't have another value */
+ else
+ {
+ screen_gamma = 2.2; /* A good guess for a
+ PC monitor in a bright office or a dim room */
+ screen_gamma = 2.0; /* A good guess for a
+ PC monitor in a dark room */
+ screen_gamma = 1.7 or 1.0; /* A good
+ guess for Mac systems */
+ }
+
+The png_set_gamma() function handles gamma transformations of the data.
+Pass both the file gamma and the current screen_gamma. If the file does
+not have a gamma value, you can pass one anyway if you have an idea what
+it is (usually 0.45455 is a good guess for GIF images on PCs). Note
+that file gammas are inverted from screen gammas. See the discussions
+on gamma in the PNG specification for an excellent description of what
+gamma is, and why all applications should support it. It is strongly
+recommended that PNG viewers support gamma correction.
+
+ if (png_get_gAMA(png_ptr, info_ptr, &gamma))
+ png_set_gamma(png_ptr, screen_gamma, gamma);
+ else
+ png_set_gamma(png_ptr, screen_gamma, 0.45455);
+
+If you need to reduce an RGB file to a paletted file, or if a paletted
+file has more entries then will fit on your screen, png_set_dither()
+will do that. Note that this is a simple match dither that merely
+finds the closest color available. This should work fairly well with
+optimized palettes, and fairly badly with linear color cubes. If you
+pass a palette that is larger then maximum_colors, the file will
+reduce the number of colors in the palette so it will fit into
+maximum_colors. If there is a histogram, it will use it to make
+more intelligent choices when reducing the palette. If there is no
+histogram, it may not do as good a job.
+
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ if (png_get_valid(png_ptr, info_ptr,
+ PNG_INFO_PLTE))
+ {
+ png_uint_16p histogram;
+
+ png_get_hIST(png_ptr, info_ptr,
+ &histogram);
+ png_set_dither(png_ptr, palette, num_palette,
+ max_screen_colors, histogram, 1);
+ }
+ else
+ {
+ png_color std_color_cube[MAX_SCREEN_COLORS] =
+ { ... colors ... };
+
+ png_set_dither(png_ptr, std_color_cube,
+ MAX_SCREEN_COLORS, MAX_SCREEN_COLORS,
+ NULL,0);
+ }
+ }
+
+PNG files describe monochrome as black being zero and white being one.
+The following code will reverse this (make black be one and white be
+zero):
+
+ if (bit_depth == 1 && color_type == PNG_COLOR_TYPE_GRAY)
+ png_set_invert_mono(png_ptr);
+
+This function can also be used to invert grayscale and gray-alpha images:
+
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_invert_mono(png_ptr);
+
+PNG files store 16 bit pixels in network byte order (big-endian,
+ie. most significant bits first). This code changes the storage to the
+other way (little-endian, i.e. least significant bits first, the
+way PCs store them):
+
+ if (bit_depth == 16)
+ png_set_swap(png_ptr);
+
+If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you
+need to change the order the pixels are packed into bytes, you can use:
+
+ if (bit_depth < 8)
+ png_set_packswap(png_ptr);
+
+Finally, you can write your own transformation function if none of
+the existing ones meets your needs. This is done by setting a callback
+with
+
+ png_set_read_user_transform_fn(png_ptr,
+ read_transform_fn);
+
+You must supply the function
+
+ void read_transform_fn(png_ptr ptr, row_info_ptr
+ row_info, png_bytep data)
+
+See pngtest.c for a working example. Your function will be called
+after all of the other transformations have been processed.
+
+You can also set up a pointer to a user structure for use by your
+callback function, and you can inform libpng that your transform
+function will change the number of channels or bit depth with the
+function
+
+ png_set_user_transform_info(png_ptr, user_ptr,
+ user_depth, user_channels);
+
+The user's application, not libpng, is responsible for allocating and
+freeing any memory required for the user structure.
+
+You can retrieve the pointer via the function
+png_get_user_transform_ptr(). For example:
+
+ voidp read_user_transform_ptr =
+ png_get_user_transform_ptr(png_ptr);
+
+The last thing to handle is interlacing; this is covered in detail below,
+but you must call the function here if you want libpng to handle expansion
+of the interlaced image.
+
+ number_of_passes = png_set_interlace_handling(png_ptr);
+
+After setting the transformations, libpng can update your png_info
+structure to reflect any transformations you've requested with this
+call. This is most useful to update the info structure's rowbytes
+field so you can use it to allocate your image memory. This function
+will also update your palette with the correct screen_gamma and
+background if these have been given with the calls above.
+
+ png_read_update_info(png_ptr, info_ptr);
+
+After you call png_read_update_info(), you can allocate any
+memory you need to hold the image. The row data is simply
+raw byte data for all forms of images. As the actual allocation
+varies among applications, no example will be given. If you
+are allocating one large chunk, you will need to build an
+array of pointers to each row, as it will be needed for some
+of the functions below.
+
+.SS Reading image data
+
+After you've allocated memory, you can read the image data.
+The simplest way to do this is in one function call. If you are
+allocating enough memory to hold the whole image, you can just
+call png_read_image() and libpng will read in all the image data
+and put it in the memory area supplied. You will need to pass in
+an array of pointers to each row.
+
+This function automatically handles interlacing, so you don't need
+to call png_set_interlace_handling() or call this function multiple
+times, or any of that other stuff necessary with png_read_rows().
+
+ png_read_image(png_ptr, row_pointers);
+
+where row_pointers is:
+
+ png_bytep row_pointers[height];
+
+You can point to void or char or whatever you use for pixels.
+
+If you don't want to read in the whole image at once, you can
+use png_read_rows() instead. If there is no interlacing (check
+interlace_type == PNG_INTERLACE_NONE), this is simple:
+
+ png_read_rows(png_ptr, row_pointers, NULL,
+ number_of_rows);
+
+where row_pointers is the same as in the png_read_image() call.
+
+If you are doing this just one row at a time, you can do this with
+a single row_pointer instead of an array of row_pointers:
+
+ png_bytep row_pointer = row;
+ png_read_row(png_ptr, row_pointer, NULL);
+
+If the file is interlaced (interlace_type != 0 in the IHDR chunk), things
+get somewhat harder. The only current (PNG Specification version 1.2)
+interlacing type for PNG is (interlace_type == PNG_INTERLACE_ADAM7)
+is a somewhat complicated 2D interlace scheme, known as Adam7, that
+breaks down an image into seven smaller images of varying size, based
+on an 8x8 grid.
+
+libpng can fill out those images or it can give them to you "as is".
+If you want them filled out, there are two ways to do that. The one
+mentioned in the PNG specification is to expand each pixel to cover
+those pixels that have not been read yet (the "rectangle" method).
+This results in a blocky image for the first pass, which gradually
+smooths out as more pixels are read. The other method is the "sparkle"
+method, where pixels are drawn only in their final locations, with the
+rest of the image remaining whatever colors they were initialized to
+before the start of the read. The first method usually looks better,
+but tends to be slower, as there are more pixels to put in the rows.
+
+If you don't want libpng to handle the interlacing details, just call
+png_read_rows() seven times to read in all seven images. Each of the
+images is a valid image by itself, or they can all be combined on an
+8x8 grid to form a single image (although if you intend to combine them
+you would be far better off using the libpng interlace handling).
+
+The first pass will return an image 1/8 as wide as the entire image
+(every 8th column starting in column 0) and 1/8 as high as the original
+(every 8th row starting in row 0), the second will be 1/8 as wide
+(starting in column 4) and 1/8 as high (also starting in row 0). The
+third pass will be 1/4 as wide (every 4th pixel starting in column 0) and
+1/8 as high (every 8th row starting in row 4), and the fourth pass will
+be 1/4 as wide and 1/4 as high (every 4th column starting in column 2,
+and every 4th row starting in row 0). The fifth pass will return an
+image 1/2 as wide, and 1/4 as high (starting at column 0 and row 2),
+while the sixth pass will be 1/2 as wide and 1/2 as high as the original
+(starting in column 1 and row 0). The seventh and final pass will be as
+wide as the original, and 1/2 as high, containing all of the odd
+numbered scanlines. Phew!
+
+If you want libpng to expand the images, call this before calling
+png_start_read_image() or png_read_update_info():
+
+ if (interlace_type == PNG_INTERLACE_ADAM7)
+ number_of_passes
+ = png_set_interlace_handling(png_ptr);
+
+This will return the number of passes needed. Currently, this
+is seven, but may change if another interlace type is added.
+This function can be called even if the file is not interlaced,
+where it will return one pass.
+
+If you are not going to display the image after each pass, but are
+going to wait until the entire image is read in, use the sparkle
+effect. This effect is faster and the end result of either method
+is exactly the same. If you are planning on displaying the image
+after each pass, the "rectangle" effect is generally considered the
+better looking one.
+
+If you only want the "sparkle" effect, just call png_read_rows() as
+normal, with the third parameter NULL. Make sure you make pass over
+the image number_of_passes times, and you don't change the data in the
+rows between calls. You can change the locations of the data, just
+not the data. Each pass only writes the pixels appropriate for that
+pass, and assumes the data from previous passes is still valid.
+
+ png_read_rows(png_ptr, row_pointers, NULL,
+ number_of_rows);
+
+If you only want the first effect (the rectangles), do the same as
+before except pass the row buffer in the third parameter, and leave
+the second parameter NULL.
+
+ png_read_rows(png_ptr, NULL, row_pointers,
+ number_of_rows);
+
+.SS Finishing a sequential read
+
+After you are finished reading the image through either the high- or
+low-level interfaces, you can finish reading the file. If you are
+interested in comments or time, which may be stored either before or
+after the image data, you should pass the separate png_info struct if
+you want to keep the comments from before and after the image
+separate. If you are not interested, you can pass NULL.
+
+ png_read_end(png_ptr, end_info);
+
+When you are done, you can free all memory allocated by libpng like this:
+
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ &end_info);
+
+It is also possible to individually free the info_ptr members that
+point to libpng-allocated storage with the following function:
+
+ png_free_data(png_ptr, info_ptr, mask, seq)
+ mask - identifies data to be freed, a mask
+ containing the logical OR of one or
+ more of
+ PNG_FREE_PLTE, PNG_FREE_TRNS,
+ PNG_FREE_HIST, PNG_FREE_ICCP,
+ PNG_FREE_PCAL, PNG_FREE_ROWS,
+ PNG_FREE_SCAL, PNG_FREE_SPLT,
+ PNG_FREE_TEXT, PNG_FREE_UNKN,
+ or simply PNG_FREE_ALL
+ seq - sequence number of item to be freed
+ (-1 for all items)
+
+This function may be safely called when the relevant storage has
+already been freed, or has not yet been allocated, or was allocated
+by the user and not by libpng, and will in those
+cases do nothing. The "seq" parameter is ignored if only one item
+of the selected data type, such as PLTE, is allowed. If "seq" is not
+-1, and multiple items are allowed for the data type identified in
+the mask, such as text or sPLT, only the n'th item in the structure
+is freed, where n is "seq".
+
+The default behavior is only to free data that was allocated internally
+by libpng. This can be changed, so that libpng will not free the data,
+or so that it will free data that was allocated by the user with png_malloc()
+or png_zalloc() and passed in via a png_set_*() function, with
+
+ png_data_freer(png_ptr, info_ptr, freer, mask)
+ mask - which data elements are affected
+ same choices as in png_free_data()
+ freer - one of
+ PNG_DESTROY_WILL_FREE_DATA
+ PNG_SET_WILL_FREE_DATA
+ PNG_USER_WILL_FREE_DATA
+
+This function only affects data that has already been allocated.
+You can call this function after reading the PNG data but before calling
+any png_set_*() functions, to control whether the user or the png_set_*()
+function is responsible for freeing any existing data that might be present,
+and again after the png_set_*() functions to control whether the user
+or png_destroy_*() is supposed to free the data. When the user assumes
+responsibility for libpng-allocated data, the application must use
+png_free() to free it, and when the user transfers responsibility to libpng
+for data that the user has allocated, the user must have used png_malloc()
+or png_zalloc() to allocate it.
+
+If you allocated your row_pointers in a single block, as suggested above in
+the description of the high level read interface, you must not transfer
+responsibility for freeing it to the png_set_rows or png_read_destroy function,
+because they would also try to free the individual row_pointers[i].
+
+If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword
+separately, do not transfer responsibility for freeing text_ptr to libpng,
+because when libpng fills a png_text structure it combines these members with
+the key member, and png_free_data() will free only text_ptr.key. Similarly,
+if you transfer responsibility for free'ing text_ptr from libpng to your
+application, your application must not separately free those members.
+
+The png_free_data() function will turn off the "valid" flag for anything
+it frees. If you need to turn the flag off for a chunk that was freed by your
+application instead of by libpng, you can use
+
+ png_set_invalid(png_ptr, info_ptr, mask);
+ mask - identifies the chunks to be made invalid,
+ containing the logical OR of one or
+ more of
+ PNG_INFO_gAMA, PNG_INFO_sBIT,
+ PNG_INFO_cHRM, PNG_INFO_PLTE,
+ PNG_INFO_tRNS, PNG_INFO_bKGD,
+ PNG_INFO_hIST, PNG_INFO_pHYs,
+ PNG_INFO_oFFs, PNG_INFO_tIME,
+ PNG_INFO_pCAL, PNG_INFO_sRGB,
+ PNG_INFO_iCCP, PNG_INFO_sPLT,
+ PNG_INFO_sCAL, PNG_INFO_IDAT
+
+For a more compact example of reading a PNG image, see the file example.c.
+
+.SS Reading PNG files progressively
+
+The progressive reader is slightly different then the non-progressive
+reader. Instead of calling png_read_info(), png_read_rows(), and
+png_read_end(), you make one call to png_process_data(), which calls
+callbacks when it has the info, a row, or the end of the image. You
+set up these callbacks with png_set_progressive_read_fn(). You don't
+have to worry about the input/output functions of libpng, as you are
+giving the library the data directly in png_process_data(). I will
+assume that you have read the section on reading PNG files above,
+so I will only highlight the differences (although I will show
+all of the code).
+
+png_structp png_ptr;
+png_infop info_ptr;
+
+ /* An example code fragment of how you would
+ initialize the progressive reader in your
+ application. */
+ int
+ initialize_png_reader()
+ {
+ png_ptr = png_create_read_struct
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn);
+ if (!png_ptr)
+ return (ERROR);
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_read_struct(&png_ptr, (png_infopp)NULL,
+ (png_infopp)NULL);
+ return (ERROR);
+ }
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ (png_infopp)NULL);
+ return (ERROR);
+ }
+
+ /* This one's new. You can provide functions
+ to be called when the header info is valid,
+ when each row is completed, and when the image
+ is finished. If you aren't using all functions,
+ you can specify NULL parameters. Even when all
+ three functions are NULL, you need to call
+ png_set_progressive_read_fn(). You can use
+ any struct as the user_ptr (cast to a void pointer
+ for the function call), and retrieve the pointer
+ from inside the callbacks using the function
+
+ png_get_progressive_ptr(png_ptr);
+
+ which will return a void pointer, which you have
+ to cast appropriately.
+ */
+ png_set_progressive_read_fn(png_ptr, (void *)user_ptr,
+ info_callback, row_callback, end_callback);
+
+ return 0;
+ }
+
+ /* A code fragment that you call as you receive blocks
+ of data */
+ int
+ process_data(png_bytep buffer, png_uint_32 length)
+ {
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ (png_infopp)NULL);
+ return (ERROR);
+ }
+
+ /* This one's new also. Simply give it a chunk
+ of data from the file stream (in order, of
+ course). On machines with segmented memory
+ models machines, don't give it any more than
+ 64K. The library seems to run fine with sizes
+ of 4K. Although you can give it much less if
+ necessary (I assume you can give it chunks of
+ 1 byte, I haven't tried less then 256 bytes
+ yet). When this function returns, you may
+ want to display any rows that were generated
+ in the row callback if you don't already do
+ so there.
+ */
+ png_process_data(png_ptr, info_ptr, buffer, length);
+ return 0;
+ }
+
+ /* This function is called (as set by
+ png_set_progressive_read_fn() above) when enough data
+ has been supplied so all of the header has been
+ read.
+ */
+ void
+ info_callback(png_structp png_ptr, png_infop info)
+ {
+ /* Do any setup here, including setting any of
+ the transformations mentioned in the Reading
+ PNG files section. For now, you _must_ call
+ either png_start_read_image() or
+ png_read_update_info() after all the
+ transformations are set (even if you don't set
+ any). You may start getting rows before
+ png_process_data() returns, so this is your
+ last chance to prepare for that.
+ */
+ }
+
+ /* This function is called when each row of image
+ data is complete */
+ void
+ row_callback(png_structp png_ptr, png_bytep new_row,
+ png_uint_32 row_num, int pass)
+ {
+ /* If the image is interlaced, and you turned
+ on the interlace handler, this function will
+ be called for every row in every pass. Some
+ of these rows will not be changed from the
+ previous pass. When the row is not changed,
+ the new_row variable will be NULL. The rows
+ and passes are called in order, so you don't
+ really need the row_num and pass, but I'm
+ supplying them because it may make your life
+ easier.
+
+ For the non-NULL rows of interlaced images,
+ you must call png_progressive_combine_row()
+ passing in the row and the old row. You can
+ call this function for NULL rows (it will just
+ return) and for non-interlaced images (it just
+ does the memcpy for you) if it will make the
+ code easier. Thus, you can just do this for
+ all cases:
+ */
+
+ png_progressive_combine_row(png_ptr, old_row,
+ new_row);
+
+ /* where old_row is what was displayed for
+ previously for the row. Note that the first
+ pass (pass == 0, really) will completely cover
+ the old row, so the rows do not have to be
+ initialized. After the first pass (and only
+ for interlaced images), you will have to pass
+ the current row, and the function will combine
+ the old row and the new row.
+ */
+ }
+
+ void
+ end_callback(png_structp png_ptr, png_infop info)
+ {
+ /* This function is called after the whole image
+ has been read, including any chunks after the
+ image (up to and including the IEND). You
+ will usually have the same info chunk as you
+ had in the header, although some data may have
+ been added to the comments and time fields.
+
+ Most people won't do much here, perhaps setting
+ a flag that marks the image as finished.
+ */
+ }
+
+
+
+.SH IV. Writing
+
+Much of this is very similar to reading. However, everything of
+importance is repeated here, so you won't have to constantly look
+back up in the reading section to understand writing.
+
+.SS Setup
+
+You will want to do the I/O initialization before you get into libpng,
+so if it doesn't work, you don't have anything to undo. If you are not
+using the standard I/O functions, you will need to replace them with
+custom writing functions. See the discussion under Customizing libpng.
+
+ FILE *fp = fopen(file_name, "wb");
+ if (!fp)
+ {
+ return (ERROR);
+ }
+
+Next, png_struct and png_info need to be allocated and initialized.
+As these can be both relatively large, you may not want to store these
+on the stack, unless you have stack space to spare. Of course, you
+will want to check if they return NULL. If you are also reading,
+you won't want to name your read structure and your write structure
+both "png_ptr"; you can call them anything you like, such as
+"read_ptr" and "write_ptr". Look at pngtest.c, for example.
+
+ png_structp png_ptr = png_create_write_struct
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn);
+ if (!png_ptr)
+ return (ERROR);
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_write_struct(&png_ptr,
+ (png_infopp)NULL);
+ return (ERROR);
+ }
+
+If you want to use your own memory allocation routines,
+define PNG_USER_MEM_SUPPORTED and use
+png_create_write_struct_2() instead of png_create_write_struct():
+
+ png_structp png_ptr = png_create_write_struct_2
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn, (png_voidp)
+ user_mem_ptr, user_malloc_fn, user_free_fn);
+
+After you have these structures, you will need to set up the
+error handling. When libpng encounters an error, it expects to
+longjmp() back to your routine. Therefore, you will need to call
+setjmp() and pass the png_jmpbuf(png_ptr). If you
+write the file from different routines, you will need to update
+the png_jmpbuf(png_ptr) every time you enter a new routine that will
+call a png_*() function. See your documentation of setjmp/longjmp
+for your compiler for more information on setjmp/longjmp. See
+the discussion on libpng error handling in the Customizing Libpng
+section below for more information on the libpng error handling.
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ fclose(fp);
+ return (ERROR);
+ }
+ ...
+ return;
+
+If you would rather avoid the complexity of setjmp/longjmp issues,
+you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case
+errors will result in a call to PNG_ABORT() which defaults to abort().
+
+Now you need to set up the output code. The default for libpng is to
+use the C function fwrite(). If you use this, you will need to pass a
+valid FILE * in the function png_init_io(). Be sure that the file is
+opened in binary mode. Again, if you wish to handle writing data in
+another way, see the discussion on libpng I/O handling in the Customizing
+Libpng section below.
+
+ png_init_io(png_ptr, fp);
+
+.SS Write callbacks
+
+At this point, you can set up a callback function that will be
+called after each row has been written, which you can use to control
+a progress meter or the like. It's demonstrated in pngtest.c.
+You must supply a function
+
+ void write_row_callback(png_ptr, png_uint_32 row,
+ int pass);
+ {
+ /* put your code here */
+ }
+
+(You can give it another name that you like instead of "write_row_callback")
+
+To inform libpng about your function, use
+
+ png_set_write_status_fn(png_ptr, write_row_callback);
+
+You now have the option of modifying how the compression library will
+run. The following functions are mainly for testing, but may be useful
+in some cases, like if you need to write PNG files extremely fast and
+are willing to give up some compression, or if you want to get the
+maximum possible compression at the expense of slower writing. If you
+have no special needs in this area, let the library do what it wants by
+not calling this function at all, as it has been tuned to deliver a good
+speed/compression ratio. The second parameter to png_set_filter() is
+the filter method, for which the only valid values are 0 (as of the
+July 1999 PNG specification, version 1.2) or 64 (if you are writing
+a PNG datastream that is to be embedded in a MNG datastream). The third
+parameter is a flag that indicates which filter type(s) are to be tested
+for each scanline. See the PNG specification for details on the specific filter
+types.
+
+
+ /* turn on or off filtering, and/or choose
+ specific filters. You can use either a single
+ PNG_FILTER_VALUE_NAME or the logical OR of one
+ or more PNG_FILTER_NAME masks. */
+ png_set_filter(png_ptr, 0,
+ PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE |
+ PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB |
+ PNG_FILTER_UP | PNG_FILTER_VALUE_UP |
+ PNG_FILTER_AVE | PNG_FILTER_VALUE_AVE |
+ PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH|
+ PNG_ALL_FILTERS);
+
+If an application
+wants to start and stop using particular filters during compression,
+it should start out with all of the filters (to ensure that the previous
+row of pixels will be stored in case it's needed later), and then add
+and remove them after the start of compression.
+
+If you are writing a PNG datastream that is to be embedded in a MNG
+datastream, the second parameter can be either 0 or 64.
+
+The png_set_compression_*() functions interface to the zlib compression
+library, and should mostly be ignored unless you really know what you are
+doing. The only generally useful call is png_set_compression_level()
+which changes how much time zlib spends on trying to compress the image
+data. See the Compression Library (zlib.h and algorithm.txt, distributed
+with zlib) for details on the compression levels.
+
+ /* set the zlib compression level */
+ png_set_compression_level(png_ptr,
+ Z_BEST_COMPRESSION);
+
+ /* set other zlib parameters */
+ png_set_compression_mem_level(png_ptr, 8);
+ png_set_compression_strategy(png_ptr,
+ Z_DEFAULT_STRATEGY);
+ png_set_compression_window_bits(png_ptr, 15);
+ png_set_compression_method(png_ptr, 8);
+ png_set_compression_buffer_size(png_ptr, 8192)
+
+extern PNG_EXPORT(void,png_set_zbuf_size)
+
+.SS Setting the contents of info for output
+
+You now need to fill in the png_info structure with all the data you
+wish to write before the actual image. Note that the only thing you
+are allowed to write after the image is the text chunks and the time
+chunk (as of PNG Specification 1.2, anyway). See png_write_end() and
+the latest PNG specification for more information on that. If you
+wish to write them before the image, fill them in now, and flag that
+data as being valid. If you want to wait until after the data, don't
+fill them until png_write_end(). For all the fields in png_info and
+their data types, see png.h. For explanations of what the fields
+contain, see the PNG specification.
+
+Some of the more important parts of the png_info are:
+
+ png_set_IHDR(png_ptr, info_ptr, width, height,
+ bit_depth, color_type, interlace_type,
+ compression_type, filter_method)
+ width - holds the width of the image
+ in pixels (up to 2^31).
+ height - holds the height of the image
+ in pixels (up to 2^31).
+ bit_depth - holds the bit depth of one of the
+ image channels.
+ (valid values are 1, 2, 4, 8, 16
+ and depend also on the
+ color_type. See also significant
+ bits (sBIT) below).
+ color_type - describes which color/alpha
+ channels are present.
+ PNG_COLOR_TYPE_GRAY
+ (bit depths 1, 2, 4, 8, 16)
+ PNG_COLOR_TYPE_GRAY_ALPHA
+ (bit depths 8, 16)
+ PNG_COLOR_TYPE_PALETTE
+ (bit depths 1, 2, 4, 8)
+ PNG_COLOR_TYPE_RGB
+ (bit_depths 8, 16)
+ PNG_COLOR_TYPE_RGB_ALPHA
+ (bit_depths 8, 16)
+
+ PNG_COLOR_MASK_PALETTE
+ PNG_COLOR_MASK_COLOR
+ PNG_COLOR_MASK_ALPHA
+
+ interlace_type - PNG_INTERLACE_NONE or
+ PNG_INTERLACE_ADAM7
+ compression_type - (must be
+ PNG_COMPRESSION_TYPE_DEFAULT)
+ filter_method - (must be PNG_FILTER_TYPE_DEFAULT
+ or, if you are writing a PNG to
+ be embedded in a MNG datastream,
+ can also be
+ PNG_INTRAPIXEL_DIFFERENCING)
+
+ png_set_PLTE(png_ptr, info_ptr, palette,
+ num_palette);
+ palette - the palette for the file
+ (array of png_color)
+ num_palette - number of entries in the palette
+
+ png_set_gAMA(png_ptr, info_ptr, gamma);
+ gamma - the gamma the image was created
+ at (PNG_INFO_gAMA)
+
+ png_set_sRGB(png_ptr, info_ptr, srgb_intent);
+ srgb_intent - the rendering intent
+ (PNG_INFO_sRGB) The presence of
+ the sRGB chunk means that the pixel
+ data is in the sRGB color space.
+ This chunk also implies specific
+ values of gAMA and cHRM. Rendering
+ intent is the CSS-1 property that
+ has been defined by the International
+ Color Consortium
+ (http://www.color.org).
+ It can be one of
+ PNG_sRGB_INTENT_SATURATION,
+ PNG_sRGB_INTENT_PERCEPTUAL,
+ PNG_sRGB_INTENT_ABSOLUTE, or
+ PNG_sRGB_INTENT_RELATIVE.
+
+
+ png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr,
+ srgb_intent);
+ srgb_intent - the rendering intent
+ (PNG_INFO_sRGB) The presence of the
+ sRGB chunk means that the pixel
+ data is in the sRGB color space.
+ This function also causes gAMA and
+ cHRM chunks with the specific values
+ that are consistent with sRGB to be
+ written.
+
+ png_set_iCCP(png_ptr, info_ptr, name, compression_type,
+ profile, proflen);
+ name - The profile name.
+ compression - The compression type; always
+ PNG_COMPRESSION_TYPE_BASE for PNG 1.0.
+ You may give NULL to this argument to
+ ignore it.
+ profile - International Color Consortium color
+ profile data. May contain NULs.
+ proflen - length of profile data in bytes.
+
+ png_set_sBIT(png_ptr, info_ptr, sig_bit);
+ sig_bit - the number of significant bits for
+ (PNG_INFO_sBIT) each of the gray, red,
+ green, and blue channels, whichever are
+ appropriate for the given color type
+ (png_color_16)
+
+ png_set_tRNS(png_ptr, info_ptr, trans, num_trans,
+ trans_values);
+ trans - array of transparent entries for
+ palette (PNG_INFO_tRNS)
+ trans_values - graylevel or color sample values of
+ the single transparent color for
+ non-paletted images (PNG_INFO_tRNS)
+ num_trans - number of transparent entries
+ (PNG_INFO_tRNS)
+
+ png_set_hIST(png_ptr, info_ptr, hist);
+ (PNG_INFO_hIST)
+ hist - histogram of palette (array of
+ png_uint_16)
+
+ png_set_tIME(png_ptr, info_ptr, mod_time);
+ mod_time - time image was last modified
+ (PNG_VALID_tIME)
+
+ png_set_bKGD(png_ptr, info_ptr, background);
+ background - background color (PNG_VALID_bKGD)
+
+ png_set_text(png_ptr, info_ptr, text_ptr, num_text);
+ text_ptr - array of png_text holding image
+ comments
+ text_ptr[i].compression - type of compression used
+ on "text" PNG_TEXT_COMPRESSION_NONE
+ PNG_TEXT_COMPRESSION_zTXt
+ PNG_ITXT_COMPRESSION_NONE
+ PNG_ITXT_COMPRESSION_zTXt
+ text_ptr[i].key - keyword for comment. Must contain
+ 1-79 characters.
+ text_ptr[i].text - text comments for current
+ keyword. Can be NULL or empty.
+ text_ptr[i].text_length - length of text string,
+ after decompression, 0 for iTXt
+ text_ptr[i].itxt_length - length of itxt string,
+ after decompression, 0 for tEXt/zTXt
+ text_ptr[i].lang - language of comment (NULL or
+ empty for unknown).
+ text_ptr[i].translated_keyword - keyword in UTF-8 (NULL
+ or empty for unknown).
+ num_text - number of comments
+
+ png_set_sPLT(png_ptr, info_ptr, &palette_ptr,
+ num_spalettes);
+ palette_ptr - array of png_sPLT_struct structures
+ to be added to the list of palettes
+ in the info structure.
+ num_spalettes - number of palette structures to be
+ added.
+
+ png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y,
+ unit_type);
+ offset_x - positive offset from the left
+ edge of the screen
+ offset_y - positive offset from the top
+ edge of the screen
+ unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER
+
+ png_set_pHYs(png_ptr, info_ptr, res_x, res_y,
+ unit_type);
+ res_x - pixels/unit physical resolution
+ in x direction
+ res_y - pixels/unit physical resolution
+ in y direction
+ unit_type - PNG_RESOLUTION_UNKNOWN,
+ PNG_RESOLUTION_METER
+
+ png_set_sCAL(png_ptr, info_ptr, unit, width, height)
+ unit - physical scale units (an integer)
+ width - width of a pixel in physical scale units
+ height - height of a pixel in physical scale units
+ (width and height are doubles)
+
+ png_set_sCAL_s(png_ptr, info_ptr, unit, width, height)
+ unit - physical scale units (an integer)
+ width - width of a pixel in physical scale units
+ height - height of a pixel in physical scale units
+ (width and height are strings like "2.54")
+
+ png_set_unknown_chunks(png_ptr, info_ptr, &unknowns,
+ num_unknowns)
+ unknowns - array of png_unknown_chunk
+ structures holding unknown chunks
+ unknowns[i].name - name of unknown chunk
+ unknowns[i].data - data of unknown chunk
+ unknowns[i].size - size of unknown chunk's data
+ unknowns[i].location - position to write chunk in file
+ 0: do not write chunk
+ PNG_HAVE_IHDR: before PLTE
+ PNG_HAVE_PLTE: before IDAT
+ PNG_AFTER_IDAT: after IDAT
+
+The "location" member is set automatically according to
+what part of the output file has already been written.
+You can change its value after calling png_set_unknown_chunks()
+as demonstrated in pngtest.c. Within each of the "locations",
+the chunks are sequenced according to their position in the
+structure (that is, the value of "i", which is the order in which
+the chunk was either read from the input file or defined with
+png_set_unknown_chunks).
+
+A quick word about text and num_text. text is an array of png_text
+structures. num_text is the number of valid structures in the array.
+Each png_text structure holds a language code, a keyword, a text value,
+and a compression type.
+
+The compression types have the same valid numbers as the compression
+types of the image data. Currently, the only valid number is zero.
+However, you can store text either compressed or uncompressed, unlike
+images, which always have to be compressed. So if you don't want the
+text compressed, set the compression type to PNG_TEXT_COMPRESSION_NONE.
+Because tEXt and zTXt chunks don't have a language field, if you
+specify PNG_TEXT_COMPRESSION_NONE or PNG_TEXT_COMPRESSION_zTXt
+any language code or translated keyword will not be written out.
+
+Until text gets around 1000 bytes, it is not worth compressing it.
+After the text has been written out to the file, the compression type
+is set to PNG_TEXT_COMPRESSION_NONE_WR or PNG_TEXT_COMPRESSION_zTXt_WR,
+so that it isn't written out again at the end (in case you are calling
+png_write_end() with the same struct.
+
+The keywords that are given in the PNG Specification are:
+
+ Title Short (one line) title or
+ caption for image
+ Author Name of image's creator
+ Description Description of image (possibly long)
+ Copyright Copyright notice
+ Creation Time Time of original image creation
+ (usually RFC 1123 format, see below)
+ Software Software used to create the image
+ Disclaimer Legal disclaimer
+ Warning Warning of nature of content
+ Source Device used to create the image
+ Comment Miscellaneous comment; conversion
+ from other image format
+
+The keyword-text pairs work like this. Keywords should be short
+simple descriptions of what the comment is about. Some typical
+keywords are found in the PNG specification, as is some recommendations
+on keywords. You can repeat keywords in a file. You can even write
+some text before the image and some after. For example, you may want
+to put a description of the image before the image, but leave the
+disclaimer until after, so viewers working over modem connections
+don't have to wait for the disclaimer to go over the modem before
+they start seeing the image. Finally, keywords should be full
+words, not abbreviations. Keywords and text are in the ISO 8859-1
+(Latin-1) character set (a superset of regular ASCII) and can not
+contain NUL characters, and should not contain control or other
+unprintable characters. To make the comments widely readable, stick
+with basic ASCII, and avoid machine specific character set extensions
+like the IBM-PC character set. The keyword must be present, but
+you can leave off the text string on non-compressed pairs.
+Compressed pairs must have a text string, as only the text string
+is compressed anyway, so the compression would be meaningless.
+
+PNG supports modification time via the png_time structure. Two
+conversion routines are provided, png_convert_from_time_t() for
+time_t and png_convert_from_struct_tm() for struct tm. The
+time_t routine uses gmtime(). You don't have to use either of
+these, but if you wish to fill in the png_time structure directly,
+you should provide the time in universal time (GMT) if possible
+instead of your local time. Note that the year number is the full
+year (e.g. 1998, rather than 98 - PNG is year 2000 compliant!), and
+that months start with 1.
+
+If you want to store the time of the original image creation, you should
+use a plain tEXt chunk with the "Creation Time" keyword. This is
+necessary because the "creation time" of a PNG image is somewhat vague,
+depending on whether you mean the PNG file, the time the image was
+created in a non-PNG format, a still photo from which the image was
+scanned, or possibly the subject matter itself. In order to facilitate
+machine-readable dates, it is recommended that the "Creation Time"
+tEXt chunk use RFC 1123 format dates (e.g. "22 May 1997 18:07:10 GMT"),
+although this isn't a requirement. Unlike the tIME chunk, the
+"Creation Time" tEXt chunk is not expected to be automatically changed
+by the software. To facilitate the use of RFC 1123 dates, a function
+png_convert_to_rfc1123(png_timep) is provided to convert from PNG
+time to an RFC 1123 format string.
+
+.SS Writing unknown chunks
+
+You can use the png_set_unknown_chunks function to queue up chunks
+for writing. You give it a chunk name, raw data, and a size; that's
+all there is to it. The chunks will be written by the next following
+png_write_info_before_PLTE, png_write_info, or png_write_end function.
+Any chunks previously read into the info structure's unknown-chunk
+list will also be written out in a sequence that satisfies the PNG
+specification's ordering rules.
+
+.SS The high-level write interface
+
+At this point there are two ways to proceed; through the high-level
+write interface, or through a sequence of low-level write operations.
+You can use the high-level interface if your image data is present
+in the info structure. All defined output
+transformations are permitted, enabled by the following masks.
+
+ PNG_TRANSFORM_IDENTITY No transformation
+ PNG_TRANSFORM_PACKING Pack 1, 2 and 4-bit samples
+ PNG_TRANSFORM_PACKSWAP Change order of packed
+ pixels to LSB first
+ PNG_TRANSFORM_INVERT_MONO Invert monochrome images
+ PNG_TRANSFORM_SHIFT Normalize pixels to the
+ sBIT depth
+ PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA
+ to BGRA
+ PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA
+ to AG
+ PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity
+ to transparency
+ PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples
+ PNG_TRANSFORM_STRIP_FILLER Strip out filler bytes.
+
+If you have valid image data in the info structure (you can use
+png_set_rows() to put image data in the info structure), simply do this:
+
+ png_write_png(png_ptr, info_ptr, png_transforms, NULL)
+
+where png_transforms is an integer containing the logical OR of some set of
+transformation flags. This call is equivalent to png_write_info(),
+followed the set of transformations indicated by the transform mask,
+then png_write_image(), and finally png_write_end().
+
+(The final parameter of this call is not yet used. Someday it might point
+to transformation parameters required by some future output transform.)
+
+.SS The low-level write interface
+
+If you are going the low-level route instead, you are now ready to
+write all the file information up to the actual image data. You do
+this with a call to png_write_info().
+
+ png_write_info(png_ptr, info_ptr);
+
+Note that there is one transformation you may need to do before
+png_write_info(). In PNG files, the alpha channel in an image is the
+level of opacity. If your data is supplied as a level of
+transparency, you can invert the alpha channel before you write it, so
+that 0 is fully transparent and 255 (in 8-bit or paletted images) or
+65535 (in 16-bit images) is fully opaque, with
+
+ png_set_invert_alpha(png_ptr);
+
+This must appear before png_write_info() instead of later with the
+other transformations because in the case of paletted images the tRNS
+chunk data has to be inverted before the tRNS chunk is written. If
+your image is not a paletted image, the tRNS data (which in such cases
+represents a single color to be rendered as transparent) won't need to
+be changed, and you can safely do this transformation after your
+png_write_info() call.
+
+If you need to write a private chunk that you want to appear before
+the PLTE chunk when PLTE is present, you can write the PNG info in
+two steps, and insert code to write your own chunk between them:
+
+ png_write_info_before_PLTE(png_ptr, info_ptr);
+ png_set_unknown_chunks(png_ptr, info_ptr, ...);
+ png_write_info(png_ptr, info_ptr);
+
+After you've written the file information, you can set up the library
+to handle any special transformations of the image data. The various
+ways to transform the data will be described in the order that they
+should occur. This is important, as some of these change the color
+type and/or bit depth of the data, and some others only work on
+certain color types and bit depths. Even though each transformation
+checks to see if it has data that it can do something with, you should
+make sure to only enable a transformation if it will be valid for the
+data. For example, don't swap red and blue on grayscale data.
+
+PNG files store RGB pixels packed into 3 or 6 bytes. This code tells
+the library to strip input data that has 4 or 8 bytes per pixel down
+to 3 or 6 bytes (or strip 2 or 4-byte grayscale+filler data to 1 or 2
+bytes per pixel).
+
+ png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
+
+where the 0 is unused, and the location is either PNG_FILLER_BEFORE or
+PNG_FILLER_AFTER, depending upon whether the filler byte in the pixel
+is stored XRGB or RGBX.
+
+PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as
+they can, resulting in, for example, 8 pixels per byte for 1 bit files.
+If the data is supplied at 1 pixel per byte, use this code, which will
+correctly pack the pixels into a single byte:
+
+ png_set_packing(png_ptr);
+
+PNG files reduce possible bit depths to 1, 2, 4, 8, and 16. If your
+data is of another bit depth, you can write an sBIT chunk into the
+file so that decoders can recover the original data if desired.
+
+ /* Set the true bit depth of the image data */
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ sig_bit.red = true_bit_depth;
+ sig_bit.green = true_bit_depth;
+ sig_bit.blue = true_bit_depth;
+ }
+ else
+ {
+ sig_bit.gray = true_bit_depth;
+ }
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ sig_bit.alpha = true_bit_depth;
+ }
+
+ png_set_sBIT(png_ptr, info_ptr, &sig_bit);
+
+If the data is stored in the row buffer in a bit depth other than
+one supported by PNG (e.g. 3 bit data in the range 0-7 for a 4-bit PNG),
+this will scale the values to appear to be the correct bit depth as
+is required by PNG.
+
+ png_set_shift(png_ptr, &sig_bit);
+
+PNG files store 16 bit pixels in network byte order (big-endian,
+ie. most significant bits first). This code would be used if they are
+supplied the other way (little-endian, i.e. least significant bits
+first, the way PCs store them):
+
+ if (bit_depth > 8)
+ png_set_swap(png_ptr);
+
+If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you
+need to change the order the pixels are packed into bytes, you can use:
+
+ if (bit_depth < 8)
+ png_set_packswap(png_ptr);
+
+PNG files store 3 color pixels in red, green, blue order. This code
+would be used if they are supplied as blue, green, red:
+
+ png_set_bgr(png_ptr);
+
+PNG files describe monochrome as black being zero and white being
+one. This code would be used if the pixels are supplied with this reversed
+(black being one and white being zero):
+
+ png_set_invert_mono(png_ptr);
+
+Finally, you can write your own transformation function if none of
+the existing ones meets your needs. This is done by setting a callback
+with
+
+ png_set_write_user_transform_fn(png_ptr,
+ write_transform_fn);
+
+You must supply the function
+
+ void write_transform_fn(png_ptr ptr, row_info_ptr
+ row_info, png_bytep data)
+
+See pngtest.c for a working example. Your function will be called
+before any of the other transformations are processed.
+
+You can also set up a pointer to a user structure for use by your
+callback function.
+
+ png_set_user_transform_info(png_ptr, user_ptr, 0, 0);
+
+The user_channels and user_depth parameters of this function are ignored
+when writing; you can set them to zero as shown.
+
+You can retrieve the pointer via the function png_get_user_transform_ptr().
+For example:
+
+ voidp write_user_transform_ptr =
+ png_get_user_transform_ptr(png_ptr);
+
+It is possible to have libpng flush any pending output, either manually,
+or automatically after a certain number of lines have been written. To
+flush the output stream a single time call:
+
+ png_write_flush(png_ptr);
+
+and to have libpng flush the output stream periodically after a certain
+number of scanlines have been written, call:
+
+ png_set_flush(png_ptr, nrows);
+
+Note that the distance between rows is from the last time png_write_flush()
+was called, or the first row of the image if it has never been called.
+So if you write 50 lines, and then png_set_flush 25, it will flush the
+output on the next scanline, and every 25 lines thereafter, unless
+png_write_flush() is called before 25 more lines have been written.
+If nrows is too small (less than about 10 lines for a 640 pixel wide
+RGB image) the image compression may decrease noticeably (although this
+may be acceptable for real-time applications). Infrequent flushing will
+only degrade the compression performance by a few percent over images
+that do not use flushing.
+
+.SS Writing the image data
+
+That's it for the transformations. Now you can write the image data.
+The simplest way to do this is in one function call. If you have the
+whole image in memory, you can just call png_write_image() and libpng
+will write the image. You will need to pass in an array of pointers to
+each row. This function automatically handles interlacing, so you don't
+need to call png_set_interlace_handling() or call this function multiple
+times, or any of that other stuff necessary with png_write_rows().
+
+ png_write_image(png_ptr, row_pointers);
+
+where row_pointers is:
+
+ png_byte *row_pointers[height];
+
+You can point to void or char or whatever you use for pixels.
+
+If you don't want to write the whole image at once, you can
+use png_write_rows() instead. If the file is not interlaced,
+this is simple:
+
+ png_write_rows(png_ptr, row_pointers,
+ number_of_rows);
+
+row_pointers is the same as in the png_write_image() call.
+
+If you are just writing one row at a time, you can do this with
+a single row_pointer instead of an array of row_pointers:
+
+ png_bytep row_pointer = row;
+
+ png_write_row(png_ptr, row_pointer);
+
+When the file is interlaced, things can get a good deal more
+complicated. The only currently (as of the PNG Specification
+version 1.2, dated July 1999) defined interlacing scheme for PNG files
+is the "Adam7" interlace scheme, that breaks down an
+image into seven smaller images of varying size. libpng will build
+these images for you, or you can do them yourself. If you want to
+build them yourself, see the PNG specification for details of which
+pixels to write when.
+
+If you don't want libpng to handle the interlacing details, just
+use png_set_interlace_handling() and call png_write_rows() the
+correct number of times to write all seven sub-images.
+
+If you want libpng to build the sub-images, call this before you start
+writing any rows:
+
+ number_of_passes =
+ png_set_interlace_handling(png_ptr);
+
+This will return the number of passes needed. Currently, this
+is seven, but may change if another interlace type is added.
+
+Then write the complete image number_of_passes times.
+
+ png_write_rows(png_ptr, row_pointers,
+ number_of_rows);
+
+As some of these rows are not used, and thus return immediately,
+you may want to read about interlacing in the PNG specification,
+and only update the rows that are actually used.
+
+.SS Finishing a sequential write
+
+After you are finished writing the image, you should finish writing
+the file. If you are interested in writing comments or time, you should
+pass an appropriately filled png_info pointer. If you are not interested,
+you can pass NULL.
+
+ png_write_end(png_ptr, info_ptr);
+
+When you are done, you can free all memory used by libpng like this:
+
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+It is also possible to individually free the info_ptr members that
+point to libpng-allocated storage with the following function:
+
+ png_free_data(png_ptr, info_ptr, mask, seq)
+ mask - identifies data to be freed, a mask
+ containing the logical OR of one or
+ more of
+ PNG_FREE_PLTE, PNG_FREE_TRNS,
+ PNG_FREE_HIST, PNG_FREE_ICCP,
+ PNG_FREE_PCAL, PNG_FREE_ROWS,
+ PNG_FREE_SCAL, PNG_FREE_SPLT,
+ PNG_FREE_TEXT, PNG_FREE_UNKN,
+ or simply PNG_FREE_ALL
+ seq - sequence number of item to be freed
+ (-1 for all items)
+
+This function may be safely called when the relevant storage has
+already been freed, or has not yet been allocated, or was allocated
+by the user and not by libpng, and will in those
+cases do nothing. The "seq" parameter is ignored if only one item
+of the selected data type, such as PLTE, is allowed. If "seq" is not
+-1, and multiple items are allowed for the data type identified in
+the mask, such as text or sPLT, only the n'th item in the structure
+is freed, where n is "seq".
+
+If you allocated data such as a palette that you passed
+in to libpng with png_set_*, you must not free it until just before the call to
+png_destroy_write_struct().
+
+The default behavior is only to free data that was allocated internally
+by libpng. This can be changed, so that libpng will not free the data,
+or so that it will free data that was allocated by the user with png_malloc()
+or png_zalloc() and passed in via a png_set_*() function, with
+
+ png_data_freer(png_ptr, info_ptr, freer, mask)
+ mask - which data elements are affected
+ same choices as in png_free_data()
+ freer - one of
+ PNG_DESTROY_WILL_FREE_DATA
+ PNG_SET_WILL_FREE_DATA
+ PNG_USER_WILL_FREE_DATA
+
+For example, to transfer responsibility for some data from a read structure
+to a write structure, you could use
+
+ png_data_freer(read_ptr, read_info_ptr,
+ PNG_USER_WILL_FREE_DATA,
+ PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST)
+ png_data_freer(write_ptr, write_info_ptr,
+ PNG_DESTROY_WILL_FREE_DATA,
+ PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST)
+
+thereby briefly reassigning responsibility for freeing to the user but
+immediately afterwards reassigning it once more to the write_destroy
+function. Having done this, it would then be safe to destroy the read
+structure and continue to use the PLTE, tRNS, and hIST data in the write
+structure.
+
+This function only affects data that has already been allocated.
+You can call this function before calling after the png_set_*() functions
+to control whether the user or png_destroy_*() is supposed to free the data.
+When the user assumes responsibility for libpng-allocated data, the
+application must use
+png_free() to free it, and when the user transfers responsibility to libpng
+for data that the user has allocated, the user must have used png_malloc()
+or png_zalloc() to allocate it.
+
+If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword
+separately, do not transfer responsibility for freeing text_ptr to libpng,
+because when libpng fills a png_text structure it combines these members with
+the key member, and png_free_data() will free only text_ptr.key. Similarly,
+if you transfer responsibility for free'ing text_ptr from libpng to your
+application, your application must not separately free those members.
+For a more compact example of writing a PNG image, see the file example.c.
+
+.SH V. Modifying/Customizing libpng:
+
+There are three issues here. The first is changing how libpng does
+standard things like memory allocation, input/output, and error handling.
+The second deals with more complicated things like adding new chunks,
+adding new transformations, and generally changing how libpng works.
+Both of those are compile-time issues; that is, they are generally
+determined at the time the code is written, and there is rarely a need
+to provide the user with a means of changing them. The third is a
+run-time issue: choosing between and/or tuning one or more alternate
+versions of computationally intensive routines; specifically, optimized
+assembly-language (and therefore compiler- and platform-dependent)
+versions.
+
+Memory allocation, input/output, and error handling
+
+All of the memory allocation, input/output, and error handling in libpng
+goes through callbacks that are user-settable. The default routines are
+in pngmem.c, pngrio.c, pngwio.c, and pngerror.c, respectively. To change
+these functions, call the appropriate png_set_*_fn() function.
+
+Memory allocation is done through the functions png_malloc(), png_zalloc(),
+and png_free(). These currently just call the standard C functions. If
+your pointers can't access more then 64K at a time, you will want to set
+MAXSEG_64K in zlib.h. Since it is unlikely that the method of handling
+memory allocation on a platform will change between applications, these
+functions must be modified in the library at compile time. If you prefer
+to use a different method of allocating and freeing data, you can use
+
+ png_set_mem_fn(png_structp png_ptr, png_voidp mem_ptr,
+ png_malloc_ptr malloc_fn, png_free_ptr free_fn)
+
+This function also provides a void pointer that can be retrieved via
+
+ mem_ptr=png_get_mem_ptr(png_ptr);
+
+Your replacement memory functions must have prototypes as follows:
+
+ png_voidp malloc_fn(png_structp png_ptr,
+ png_uint_32 size);
+ void free_fn(png_structp png_ptr, png_voidp ptr);
+
+Your malloc_fn() can return NULL in case of failure. The png_malloc()
+function will call png_error() if it receives a NULL from the system
+memory allocator or from your replacement malloc_fn().
+
+Input/Output in libpng is done through png_read() and png_write(),
+which currently just call fread() and fwrite(). The FILE * is stored in
+png_struct and is initialized via png_init_io(). If you wish to change
+the method of I/O, the library supplies callbacks that you can set
+through the function png_set_read_fn() and png_set_write_fn() at run
+time, instead of calling the png_init_io() function. These functions
+also provide a void pointer that can be retrieved via the function
+png_get_io_ptr(). For example:
+
+ png_set_read_fn(png_structp read_ptr,
+ voidp read_io_ptr, png_rw_ptr read_data_fn)
+
+ png_set_write_fn(png_structp write_ptr,
+ voidp write_io_ptr, png_rw_ptr write_data_fn,
+ png_flush_ptr output_flush_fn);
+
+ voidp read_io_ptr = png_get_io_ptr(read_ptr);
+ voidp write_io_ptr = png_get_io_ptr(write_ptr);
+
+The replacement I/O functions must have prototypes as follows:
+
+ void user_read_data(png_structp png_ptr,
+ png_bytep data, png_uint_32 length);
+ void user_write_data(png_structp png_ptr,
+ png_bytep data, png_uint_32 length);
+ void user_flush_data(png_structp png_ptr);
+
+Supplying NULL for the read, write, or flush functions sets them back
+to using the default C stream functions. It is an error to read from
+a write stream, and vice versa.
+
+Error handling in libpng is done through png_error() and png_warning().
+Errors handled through png_error() are fatal, meaning that png_error()
+should never return to its caller. Currently, this is handled via
+setjmp() and longjmp() (unless you have compiled libpng with
+PNG_SETJMP_NOT_SUPPORTED, in which case it is handled via PNG_ABORT()),
+but you could change this to do things like exit() if you should wish.
+
+On non-fatal errors, png_warning() is called
+to print a warning message, and then control returns to the calling code.
+By default png_error() and png_warning() print a message on stderr via
+fprintf() unless the library is compiled with PNG_NO_CONSOLE_IO defined
+(because you don't want the messages) or PNG_NO_STDIO defined (because
+fprintf() isn't available). If you wish to change the behavior of the error
+functions, you will need to set up your own message callbacks. These
+functions are normally supplied at the time that the png_struct is created.
+It is also possible to redirect errors and warnings to your own replacement
+functions after png_create_*_struct() has been called by calling:
+
+ png_set_error_fn(png_structp png_ptr,
+ png_voidp error_ptr, png_error_ptr error_fn,
+ png_error_ptr warning_fn);
+
+ png_voidp error_ptr = png_get_error_ptr(png_ptr);
+
+If NULL is supplied for either error_fn or warning_fn, then the libpng
+default function will be used, calling fprintf() and/or longjmp() if a
+problem is encountered. The replacement error functions should have
+parameters as follows:
+
+ void user_error_fn(png_structp png_ptr,
+ png_const_charp error_msg);
+ void user_warning_fn(png_structp png_ptr,
+ png_const_charp warning_msg);
+
+The motivation behind using setjmp() and longjmp() is the C++ throw and
+catch exception handling methods. This makes the code much easier to write,
+as there is no need to check every return code of every function call.
+However, there are some uncertainties about the status of local variables
+after a longjmp, so the user may want to be careful about doing anything after
+setjmp returns non-zero besides returning itself. Consult your compiler
+documentation for more details. For an alternative approach, you may wish
+to use the "cexcept" facility (see http://cexcept.sourceforge.net).
+
+.SS Custom chunks
+
+If you need to read or write custom chunks, you may need to get deeper
+into the libpng code. The library now has mechanisms for storing
+and writing chunks of unknown type; you can even declare callbacks
+for custom chunks. Hoewver, this may not be good enough if the
+library code itself needs to know about interactions between your
+chunk and existing `intrinsic' chunks.
+
+If you need to write a new intrinsic chunk, first read the PNG
+specification. Acquire a first level of
+understanding of how it works. Pay particular attention to the
+sections that describe chunk names, and look at how other chunks were
+designed, so you can do things similarly. Second, check out the
+sections of libpng that read and write chunks. Try to find a chunk
+that is similar to yours and use it as a template. More details can
+be found in the comments inside the code. It is best to handle unknown
+chunks in a generic method, via callback functions, instead of by
+modifying libpng functions.
+
+If you wish to write your own transformation for the data, look through
+the part of the code that does the transformations, and check out some of
+the simpler ones to get an idea of how they work. Try to find a similar
+transformation to the one you want to add and copy off of it. More details
+can be found in the comments inside the code itself.
+
+.SS Configuring for 16 bit platforms
+
+You will want to look into zconf.h to tell zlib (and thus libpng) that
+it cannot allocate more then 64K at a time. Even if you can, the memory
+won't be accessible. So limit zlib and libpng to 64K by defining MAXSEG_64K.
+
+.SS Configuring for DOS
+
+For DOS users who only have access to the lower 640K, you will
+have to limit zlib's memory usage via a png_set_compression_mem_level()
+call. See zlib.h or zconf.h in the zlib library for more information.
+
+.SS Configuring for Medium Model
+
+Libpng's support for medium model has been tested on most of the popular
+compilers. Make sure MAXSEG_64K gets defined, USE_FAR_KEYWORD gets
+defined, and FAR gets defined to far in pngconf.h, and you should be
+all set. Everything in the library (except for zlib's structure) is
+expecting far data. You must use the typedefs with the p or pp on
+the end for pointers (or at least look at them and be careful). Make
+note that the rows of data are defined as png_bytepp, which is an
+unsigned char far * far *.
+
+.SS Configuring for gui/windowing platforms:
+
+You will need to write new error and warning functions that use the GUI
+interface, as described previously, and set them to be the error and
+warning functions at the time that png_create_*_struct() is called,
+in order to have them available during the structure initialization.
+They can be changed later via png_set_error_fn(). On some compilers,
+you may also have to change the memory allocators (png_malloc, etc.).
+
+.SS Configuring for compiler xxx:
+
+All includes for libpng are in pngconf.h. If you need to add/change/delete
+an include, this is the place to do it. The includes that are not
+needed outside libpng are protected by the PNG_INTERNAL definition,
+which is only defined for those routines inside libpng itself. The
+files in libpng proper only include png.h, which includes pngconf.h.
+
+.SS Configuring zlib:
+
+There are special functions to configure the compression. Perhaps the
+most useful one changes the compression level, which currently uses
+input compression values in the range 0 - 9. The library normally
+uses the default compression level (Z_DEFAULT_COMPRESSION = 6). Tests
+have shown that for a large majority of images, compression values in
+the range 3-6 compress nearly as well as higher levels, and do so much
+faster. For online applications it may be desirable to have maximum speed
+(Z_BEST_SPEED = 1). With versions of zlib after v0.99, you can also
+specify no compression (Z_NO_COMPRESSION = 0), but this would create
+files larger than just storing the raw bitmap. You can specify the
+compression level by calling:
+
+ png_set_compression_level(png_ptr, level);
+
+Another useful one is to reduce the memory level used by the library.
+The memory level defaults to 8, but it can be lowered if you are
+short on memory (running DOS, for example, where you only have 640K).
+
+ png_set_compression_mem_level(png_ptr, level);
+
+The other functions are for configuring zlib. They are not recommended
+for normal use and may result in writing an invalid PNG file. See
+zlib.h for more information on what these mean.
+
+ png_set_compression_strategy(png_ptr,
+ strategy);
+ png_set_compression_window_bits(png_ptr,
+ window_bits);
+ png_set_compression_method(png_ptr, method);
+ png_set_compression_buffer_size(png_ptr, size);
+
+.SS Controlling row filtering
+
+If you want to control whether libpng uses filtering or not, which
+filters are used, and how it goes about picking row filters, you
+can call one of these functions. The selection and configuration
+of row filters can have a significant impact on the size and
+encoding speed and a somewhat lesser impact on the decoding speed
+of an image. Filtering is enabled by default for RGB and grayscale
+images (with and without alpha), but not for paletted images nor
+for any images with bit depths less than 8 bits/pixel.
+
+The 'method' parameter sets the main filtering method, which is
+currently only '0' in the PNG 1.2 specification. The 'filters'
+parameter sets which filter(s), if any, should be used for each
+scanline. Possible values are PNG_ALL_FILTERS and PNG_NO_FILTERS
+to turn filtering on and off, respectively.
+
+Individual filter types are PNG_FILTER_NONE, PNG_FILTER_SUB,
+PNG_FILTER_UP, PNG_FILTER_AVG, PNG_FILTER_PAETH, which can be bitwise
+ORed together with '|' to specify one or more filters to use.
+These filters are described in more detail in the PNG specification. If
+you intend to change the filter type during the course of writing
+the image, you should start with flags set for all of the filters
+you intend to use so that libpng can initialize its internal
+structures appropriately for all of the filter types.
+
+ filters = PNG_FILTER_NONE | PNG_FILTER_SUB
+ PNG_FILTER_UP | PNG_FILTER_AVE |
+ PNG_FILTER_PAETH | PNG_ALL_FILTERS;
+ or
+ filters = one of PNG_FILTER_VALUE_NONE,
+ PNG_FILTER_VALUE_SUB, PNG_FILTER_VALUE_UP,
+ PNG_FILTER_VALUE_AVE, PNG_FILTER_VALUE_PAETH
+
+ png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE,
+ filters);
+ The second parameter can also be
+ PNG_INTRAPIXEL_DIFFERENCING if you are
+ writing a PNG to be embedded in a MNG
+ datastream. This parameter must be the
+ same as the value of filter_method used
+ in png_set_IHDR().
+
+It is also possible to influence how libpng chooses from among the
+available filters. This is done in two ways - by telling it how
+important it is to keep the same filter for successive rows, and
+by telling it the relative computational costs of the filters.
+
+ double weights[3] = {1.5, 1.3, 1.1},
+ costs[PNG_FILTER_VALUE_LAST] =
+ {1.0, 1.3, 1.3, 1.5, 1.7};
+
+ png_set_filter_selection(png_ptr,
+ PNG_FILTER_SELECTION_WEIGHTED, 3,
+ weights, costs);
+
+The weights are multiplying factors that indicate to libpng that the
+row filter should be the same for successive rows unless another row filter
+is that many times better than the previous filter. In the above example,
+if the previous 3 filters were SUB, SUB, NONE, the SUB filter could have a
+"sum of absolute differences" 1.5 x 1.3 times higher than other filters
+and still be chosen, while the NONE filter could have a sum 1.1 times
+higher than other filters and still be chosen. Unspecified weights are
+taken to be 1.0, and the specified weights should probably be declining
+like those above in order to emphasize recent filters over older filters.
+
+The filter costs specify for each filter type a relative decoding cost
+to be considered when selecting row filters. This means that filters
+with higher costs are less likely to be chosen over filters with lower
+costs, unless their "sum of absolute differences" is that much smaller.
+The costs do not necessarily reflect the exact computational speeds of
+the various filters, since this would unduly influence the final image
+size.
+
+Note that the numbers above were invented purely for this example and
+are given only to help explain the function usage. Little testing has
+been done to find optimum values for either the costs or the weights.
+
+.SS Removing unwanted object code
+
+There are a bunch of #define's in pngconf.h that control what parts of
+libpng are compiled. All the defines end in _SUPPORTED. If you are
+never going to use a capability, you can change the #define to #undef
+before recompiling libpng and save yourself code and data space, or
+you can turn off individual capabilities with defines that begin with
+PNG_NO_.
+
+You can also turn all of the transforms and ancillary chunk capabilities
+off en masse with compiler directives that define
+PNG_NO_READ[or WRITE]_TRANSFORMS, or PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS,
+or all four,
+along with directives to turn on any of the capabilities that you do
+want. The PNG_NO_READ[or WRITE]_TRANSFORMS directives disable
+the extra transformations but still leave the library fully capable of reading
+and writing PNG files with all known public chunks
+Use of the PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS directive
+produces a library that is incapable of reading or writing ancillary chunks.
+If you are not using the progressive reading capability, you can
+turn that off with PNG_NO_PROGRESSIVE_READ (don't confuse
+this with the INTERLACING capability, which you'll still have).
+
+All the reading and writing specific code are in separate files, so the
+linker should only grab the files it needs. However, if you want to
+make sure, or if you are building a stand alone library, all the
+reading files start with pngr and all the writing files start with
+pngw. The files that don't match either (like png.c, pngtrans.c, etc.)
+are used for both reading and writing, and always need to be included.
+The progressive reader is in pngpread.c
+
+If you are creating or distributing a dynamically linked library (a .so
+or DLL file), you should not remove or disable any parts of the library,
+as this will cause applications linked with different versions of the
+library to fail if they call functions not available in your library.
+The size of the library itself should not be an issue, because only
+those sections that are actually used will be loaded into memory.
+
+.SS Requesting debug printout
+
+The macro definition PNG_DEBUG can be used to request debugging
+printout. Set it to an integer value in the range 0 to 3. Higher
+numbers result in increasing amounts of debugging information. The
+information is printed to the "stderr" file, unless another file
+name is specified in the PNG_DEBUG_FILE macro definition.
+
+When PNG_DEBUG > 0, the following functions (macros) become available:
+
+ png_debug(level, message)
+ png_debug1(level, message, p1)
+ png_debug2(level, message, p1, p2)
+
+in which "level" is compared to PNG_DEBUG to decide whether to print
+the message, "message" is the formatted string to be printed,
+and p1 and p2 are parameters that are to be embedded in the string
+according to printf-style formatting directives. For example,
+
+ png_debug1(2, "foo=%d\n", foo);
+
+is expanded to
+
+ if(PNG_DEBUG > 2)
+ fprintf(PNG_DEBUG_FILE, "foo=%d\n", foo);
+
+When PNG_DEBUG is defined but is zero, the macros aren't defined, but you
+can still use PNG_DEBUG to control your own debugging:
+
+ #ifdef PNG_DEBUG
+ fprintf(stderr, ...
+ #endif
+
+When PNG_DEBUG = 1, the macros are defined, but only png_debug statements
+having level = 0 will be printed. There aren't any such statements in
+this version of libpng, but if you insert some they will be printed.
+
+.SH VI. Runtime optimization
+
+A new feature in libpng 1.2.0 is the ability to dynamically switch between
+standard and optimized versions of some routines. Currently these are
+limited to three computationally intensive tasks when reading PNG files:
+decoding row filters, expanding interlacing, and combining interlaced or
+transparent row data with previous row data. Currently the optimized
+versions are available only for x86 (Intel, AMD, etc.) platforms with
+MMX support, though this may change in future versions. (For example,
+the non-MMX assembler optimizations for zlib might become similarly
+runtime-selectable in future releases, in which case libpng could be
+extended to support them. Alternatively, the compile-time choice of
+floating-point versus integer routines for gamma correction might become
+runtime-selectable.)
+
+Because such optimizations tend to be very platform- and compiler-dependent,
+both in how they are written and in how they perform, the new runtime code
+in libpng has been written to allow programs to query, enable, and disable
+either specific optimizations or all such optimizations. For example, to
+enable all possible optimizations (bearing in mind that some "optimizations"
+may actually run more slowly in rare cases):
+
+ #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
+ png_uint_32 mask, flags;
+
+ flags = png_get_asm_flags(png_ptr);
+ mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
+ png_set_asm_flags(png_ptr, flags | mask);
+ #endif
+
+To enable only optimizations relevant to reading PNGs, use PNG_SELECT_READ
+by itself when calling png_get_asm_flagmask(); similarly for optimizing
+only writing. To disable all optimizations:
+
+ #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
+ flags = png_get_asm_flags(png_ptr);
+ mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
+ png_set_asm_flags(png_ptr, flags & ~mask);
+ #endif
+
+To enable or disable only MMX-related features, use png_get_mmx_flagmask()
+in place of png_get_asm_flagmask(). The mmx version takes one additional
+parameter:
+
+ #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
+ int selection = PNG_SELECT_READ | PNG_SELECT_WRITE;
+ int compilerID;
+
+ mask = png_get_mmx_flagmask(selection, &compilerID);
+ #endif
+
+On return, compilerID will indicate which version of the MMX assembler
+optimizations was compiled. Currently two flavors exist: Microsoft
+Visual C++ (compilerID == 1) and GNU C (a.k.a. gcc/gas, compilerID == 2).
+On non-x86 platforms or on systems compiled without MMX optimizations, a
+value of -1 is used.
+
+Note that both png_get_asm_flagmask() and png_get_mmx_flagmask() return
+all valid, settable optimization bits for the version of the library that's
+currently in use. In the case of shared (dynamically linked) libraries,
+this may include optimizations that did not exist at the time the code was
+written and compiled. It is also possible, of course, to enable only known,
+specific optimizations; for example:
+
+ #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
+ flags = PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
+ | PNG_ASM_FLAG_MMX_READ_INTERLACE \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_UP \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ;
+ png_set_asm_flags(png_ptr, flags);
+ #endif
+
+This method would enable only the MMX read-optimizations available at the
+time of libpng 1.2.0's release, regardless of whether a later version of
+the DLL were actually being used. (Also note that these functions did not
+exist in versions older than 1.2.0, so any attempt to run a dynamically
+linked app on such an older version would fail.)
+
+To determine whether the processor supports MMX instructions at all, use
+the png_mmx_support() function:
+
+ #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
+ mmxsupport = png_mmx_support();
+ #endif
+
+It returns -1 if MMX support is not compiled into libpng, 0 if MMX code
+is compiled but MMX is not supported by the processor, or 1 if MMX support
+is fully available. Note that png_mmx_support(), png_get_mmx_flagmask(),
+and png_get_asm_flagmask() all may be called without allocating and ini-
+tializing any PNG structures (for example, as part of a usage screen or
+"about" box).
+
+The following code can be used to prevent an application from using the
+thread_unsafe features, even if libpng was built with PNG_THREAD_UNSAFE_OK
+defined:
+
+#if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) \
+ && defined(PNG_THREAD_UNSAFE_OK)
+ /* Disable thread-unsafe features of pnggccrd */
+ if (png_access_version() >= 10200)
+ {
+ png_uint_32 mmx_disable_mask = 0;
+ png_uint_32 asm_flags;
+
+ mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
+ asm_flags = png_get_asm_flags(png_ptr);
+ png_set_asm_flags(png_ptr, asm_flags & ~mmx_disable_mask);
+ }
+#endif
+
+For more extensive examples of runtime querying, enabling and disabling
+of optimized features, see contrib/gregbook/readpng2.c in the libpng
+source-code distribution.
+
+
+.SH VII. MNG support
+
+The MNG specification (available at http://www.libpng.org/pub/mng) allows
+certain extensions to PNG for PNG images that are embedded in MNG datastreams.
+Libpng can support some of these extensions. To enable them, use the
+png_permit_mng_features() function:
+
+ feature_set = png_permit_mng_features(png_ptr, mask)
+ mask is a png_uint_32 containing the logical OR of the
+ features you want to enable. These include
+ PNG_FLAG_MNG_EMPTY_PLTE
+ PNG_FLAG_MNG_FILTER_64
+ PNG_ALL_MNG_FEATURES
+ feature_set is a png_32_uint that is the logical AND of
+ your mask with the set of MNG features that is
+ supported by the version of libpng that you are using.
+
+It is an error to use this function when reading or writing a standalone
+PNG file with the PNG 8-byte signature. The PNG datastream must be wrapped
+in a MNG datastream. As a minimum, it must have the MNG 8-byte signature
+and the MHDR and MEND chunks. Libpng does not provide support for these
+or any other MNG chunks; your application must provide its own support for
+them. You may wish to consider using libmng (available at
+http://www.libmng.com) instead.
+
+.SH VIII. Changes to Libpng from version 0.88
+
+It should be noted that versions of libpng later than 0.96 are not
+distributed by the original libpng author, Guy Schalnat, nor by
+Andreas Dilger, who had taken over from Guy during 1996 and 1997, and
+distributed versions 0.89 through 0.96, but rather by another member
+of the original PNG Group, Glenn Randers-Pehrson. Guy and Andreas are
+still alive and well, but they have moved on to other things.
+
+The old libpng functions png_read_init(), png_write_init(),
+png_info_init(), png_read_destroy(), and png_write_destroy() have been
+moved to PNG_INTERNAL in version 0.95 to discourage their use. These
+functions will be removed from libpng version 2.0.0.
+
+The preferred method of creating and initializing the libpng structures is
+via the png_create_read_struct(), png_create_write_struct(), and
+png_create_info_struct() because they isolate the size of the structures
+from the application, allow version error checking, and also allow the
+use of custom error handling routines during the initialization, which
+the old functions do not. The functions png_read_destroy() and
+png_write_destroy() do not actually free the memory that libpng
+allocated for these structs, but just reset the data structures, so they
+can be used instead of png_destroy_read_struct() and
+png_destroy_write_struct() if you feel there is too much system overhead
+allocating and freeing the png_struct for each image read.
+
+Setting the error callbacks via png_set_message_fn() before
+png_read_init() as was suggested in libpng-0.88 is no longer supported
+because this caused applications that do not use custom error functions
+to fail if the png_ptr was not initialized to zero. It is still possible
+to set the error callbacks AFTER png_read_init(), or to change them with
+png_set_error_fn(), which is essentially the same function, but with a new
+name to force compilation errors with applications that try to use the old
+method.
+
+Starting with version 1.0.7, you can find out which version of the library
+you are using at run-time:
+
+ png_uint_32 libpng_vn = png_access_version_number();
+
+The number libpng_vn is constructed from the major version, minor
+version with leading zero, and release number with leading zero,
+(e.g., libpng_vn for version 1.0.7 is 10007).
+
+You can also check which version of png.h you used when compiling your
+application:
+
+ png_uint_32 application_vn = PNG_LIBPNG_VER;
+
+.SH IX. Y2K Compliance in libpng
+
+September 1, 2001
+
+Since the PNG Development group is an ad-hoc body, we can't make
+an official declaration.
+
+This is your unofficial assurance that libpng from version 0.71 and
+upward through 1.2.0 are Y2K compliant. It is my belief that earlier
+versions were also Y2K compliant.
+
+Libpng only has three year fields. One is a 2-byte unsigned integer that
+will hold years up to 65535. The other two hold the date in text
+format, and will hold years up to 9999.
+
+The integer is
+ "png_uint_16 year" in png_time_struct.
+
+The strings are
+ "png_charp time_buffer" in png_struct and
+ "near_time_buffer", which is a local character string in png.c.
+
+There are seven time-related functions:
+
+ png_convert_to_rfc_1123() in png.c
+ (formerly png_convert_to_rfc_1152() in error)
+ png_convert_from_struct_tm() in pngwrite.c, called
+ in pngwrite.c
+ png_convert_from_time_t() in pngwrite.c
+ png_get_tIME() in pngget.c
+ png_handle_tIME() in pngrutil.c, called in pngread.c
+ png_set_tIME() in pngset.c
+ png_write_tIME() in pngwutil.c, called in pngwrite.c
+
+All appear to handle dates properly in a Y2K environment. The
+png_convert_from_time_t() function calls gmtime() to convert from system
+clock time, which returns (year - 1900), which we properly convert to
+the full 4-digit year. There is a possibility that applications using
+libpng are not passing 4-digit years into the png_convert_to_rfc_1123()
+function, or that they are incorrectly passing only a 2-digit year
+instead of "year - 1900" into the png_convert_from_struct_tm() function,
+but this is not under our control. The libpng documentation has always
+stated that it works with 4-digit years, and the APIs have been
+documented as such.
+
+The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned
+integer to hold the year, and can hold years as large as 65535.
+
+zlib, upon which libpng depends, is also Y2K compliant. It contains
+no date-related code.
+
+
+ Glenn Randers-Pehrson
+ libpng maintainer
+ PNG Development Group
+
+.SH NOTE
+
+Note about libpng version numbers:
+
+Due to various miscommunications, unforeseen code incompatibilities
+and occasional factors outside the authors' control, version numbering
+on the library has not always been consistent and straightforward.
+The following table summarizes matters since version 0.89c, which was
+the first widely used release:
+
+ source png.h png.h shared-lib
+ version string int version
+ ------- ------ ----- ----------
+ 0.89c ("beta 3") 0.89 89 1.0.89
+ 0.90 ("beta 4") 0.90 90 0.90
+ 0.95 ("beta 5") 0.95 95 0.95
+ 0.96 ("beta 6") 0.96 96 0.96
+ 0.97b ("beta 7") 1.00.97 97 1.0.1
+ 0.97c 0.97 97 2.0.97
+ 0.98 0.98 98 2.0.98
+ 0.99 0.99 98 2.0.99
+ 0.99a-m 0.99 99 2.0.99
+ 1.00 1.00 100 2.1.0
+ 1.0.0 1.0.0 100 2.1.0
+ 1.0.0 (from here on, the 100 2.1.0
+ 1.0.1 png.h string is 10001 2.1.0
+ 1.0.1a-e identical to the 10002 from here on, the
+ 1.0.2 source version) 10002 shared library is 2.V
+ 1.0.2a-b 10003 where V is the source
+ 1.0.1 10001 code version except as
+ 1.0.1a-e 10002 2.1.0.1a-e noted.
+ 1.0.2 10002 2.1.0.2
+ 1.0.2a-b 10003 2.1.0.2a-b
+ 1.0.3 10003 2.1.0.3
+ 1.0.3a-d 10004 2.1.0.3a-d
+ 1.0.4 10004 2.1.0.4
+ 1.0.4a-f 10005 2.1.0.4a-f
+ 1.0.5 (+ 2 patches) 10005 2.1.0.5
+ 1.0.5a-d 10006 2.1.0.5a-d
+ 1.0.5e-r 10100 2.1.0.5e-r
+ 1.0.5s-v 10006 2.1.0.5s-v
+ 1.0.6 (+ 3 patches) 10006 2.1.0.6
+ 1.0.6d-g 10007 2.1.0.6d-g
+ 1.0.6h 10007 10.6h
+ 1.0.6i 10007 10.6i
+ 1.0.6j 10007 2.1.0.6j
+ 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14
+ 1.0.7beta15-18 1 10007 2.1.0.7beta15-18
+ 1.0.7rc1-2 1 10007 2.1.0.7rc1-2
+ 1.0.7 1 10007 2.1.0.7
+ 1.0.8beta1-4 1 10008 2.1.0.8beta1-4
+ 1.0.8rc1 1 10008 2.1.0.8rc1
+ 1.0.8 1 10008 2.1.0.8
+ 1.0.9beta1-6 1 10009 2.1.0.9beta1-6
+ 1.0.9rc1 1 10009 2.1.0.9rc1
+ 1.0.9beta7-10 1 10009 2.1.0.9beta7-10
+ 1.0.9rc2 1 10009 2.1.0.9rc2
+ 1.0.9 1 10009 2.1.0.9
+ 1.0.10beta1 1 10010 2.1.0.10beta1
+ 1.0.10rc1 1 10010 2.1.0.10rc1
+ 1.0.10 1 10010 2.1.0.10
+ 1.0.11beta1-3 1 10011 2.1.0.11beta1-3
+ 1.0.11rc1 1 10011 2.1.0.11rc1
+ 1.0.11 1 10011 2.1.0.11
+ 1.0.12beta1-2 2 10012 2.1.0.12beta1-2
+ 1.0.12rc1 2 10012 2.1.0.12rc1
+ 1.0.12 2 10012 2.1.0.12
+ 1.1.0a-f - 10100 2.1.1.0a-f abandoned
+ 1.2.0beta1-2 2 10200 2.1.2.0beta1-2
+ 1.2.0beta3-4 3 10200 3.1.2.0beta3-4
+
+Henceforth the source version will match the shared-library minor
+and patch numbers; the shared-library major version number will be
+used for changes in backward compatibility, as it is intended. The
+PNG_PNGLIB_VER macro, which is not used within libpng but is available
+for applications, is an unsigned integer of the form xyyzz corresponding
+to the source version x.y.z (leading zeros in y and z). Beta versions
+were given the previous public release number plus a letter, until
+version 1.0.6j; from then on they were given the upcoming public
+release number plus "betaNN" or "rcN".
+
+.SH "SEE ALSO"
+libpngpf(3), png(5)
+.LP
+.IR libpng :
+.IP
+ftp://ftp.uu.net/graphics/png
+http://www.libpng.org/pub/png
+
+.LP
+.IR zlib :
+.IP
+(generally) at the same location as
+.I libpng
+or at
+.br
+ftp://ftp.uu.net/pub/archiving/zip/zlib
+.br
+ftp://ftp.info-zip.org/pub/infozip/zlib
+
+.LP
+.IR PNG specification: RFC 2083
+.IP
+(generally) at the same location as
+.I libpng
+or at
+.br
+ftp://ds.internic.net/rfc/rfc2083.txt
+.br
+or (as a W3C Recommendation) at
+.br
+http://www.w3.org/TR/REC-png.html
+
+.LP
+In the case of any inconsistency between the PNG specification
+and this library, the specification takes precedence.
+
+.SH AUTHORS
+This man page: Glenn Randers-Pehrson
+<randeg@alum.rpi.edu>
+
+The contributing authors would like to thank all those who helped
+with testing, bug fixes, and patience. This wouldn't have been
+possible without all of you.
+
+Thanks to Frank J. T. Wojcik for helping with the documentation.
+
+Libpng version 1.2.0 - September 1, 2001:
+Initially created in 1995 by Guy Eric Schalnat, then of Group 42, Inc.
+Currently maintained by Glenn Randers-Pehrson (randeg@alum.rpi.edu).
+
+Supported by the PNG development group
+.br
+(png-implement@ccrc.wustl.edu).
+
+.SH COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
+
+(This copy of the libpng notices is provided for your convenience. In case of
+any discrepancy between this copy and the notices in the file png.h that is
+included in the libpng distribution, the latter shall prevail.)
+
+If you modify libpng you may insert additional notices immediately following
+this sentence.
+
+libpng versions 1.0.7, July 1, 2000, through 1.2.0, September 1, 2001, are
+Copyright (c) 2000-2001 Glenn Randers-Pehrson, and are
+distributed according to the same disclaimer and license as libpng-1.0.6
+with the following individuals added to the list of Contributing Authors
+
+ Simon-Pierre Cadieux
+ Eric S. Raymond
+ Gilles Vollant
+
+and with the following additions to the disclaimer:
+
+ There is no warranty against interference with your
+ enjoyment of the library or against infringement.
+ There is no warranty that our efforts or the library
+ will fulfill any of your particular purposes or needs.
+ This library is provided with all faults, and the entire
+ risk of satisfactory quality, performance, accuracy, and
+ effort is with the user.
+
+libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are
+Copyright (c) 1998, 1999 Glenn Randers-Pehrson
+Distributed according to the same disclaimer and license as libpng-0.96,
+with the following individuals added to the list of Contributing Authors:
+
+ Tom Lane
+ Glenn Randers-Pehrson
+ Willem van Schaik
+
+libpng versions 0.89, June 1996, through 0.96, May 1997, are
+Copyright (c) 1996, 1997 Andreas Dilger
+Distributed according to the same disclaimer and license as libpng-0.88,
+with the following individuals added to the list of Contributing Authors:
+
+ John Bowler
+ Kevin Bracey
+ Sam Bushell
+ Magnus Holmgren
+ Greg Roelofs
+ Tom Tanner
+
+libpng versions 0.5, May 1995, through 0.88, January 1996, are
+Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+
+For the purposes of this copyright and license, "Contributing Authors"
+is defined as the following set of individuals:
+
+ Andreas Dilger
+ Dave Martindale
+ Guy Eric Schalnat
+ Paul Schmidt
+ Tim Wegner
+
+The PNG Reference Library is supplied "AS IS". The Contributing Authors
+and Group 42, Inc. disclaim all warranties, expressed or implied,
+including, without limitation, the warranties of merchantability and of
+fitness for any purpose. The Contributing Authors and Group 42, Inc.
+assume no liability for direct, indirect, incidental, special, exemplary,
+or consequential damages, which may result from the use of the PNG
+Reference Library, even if advised of the possibility of such damage.
+
+Permission is hereby granted to use, copy, modify, and distribute this
+source code, or portions hereof, for any purpose, without fee, subject
+to the following restrictions:
+
+1. The origin of this source code must not be misrepresented.
+
+2. Altered versions must be plainly marked as such and
+ must not be misrepresented as being the original source.
+
+3. This Copyright notice may not be removed or altered from
+ any source or altered source distribution.
+
+The Contributing Authors and Group 42, Inc. specifically permit, without
+fee, and encourage the use of this source code as a component to
+supporting the PNG file format in commercial products. If you use this
+source code in a product, acknowledgment is not required but would be
+appreciated.
+
+
+A "png_get_copyright" function is available, for convenient use in "about"
+boxes and the like:
+
+ printf("%s",png_get_copyright(NULL));
+
+Also, the PNG logo (in PNG format, of course) is supplied in the
+files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31).
+
+Libpng is OSI Certified Open Source Software. OSI Certified Open Source is a
+certification mark of the Open Source Initiative.
+
+Glenn Randers-Pehrson
+randeg@alum.rpi.edu
+September 1, 2001
+
+.\" end of man page
+
--- /dev/null
+libpng.txt - A description on how to use and modify libpng
+
+ libpng version 1.2.0 - September 1, 2001
+ Updated and distributed by Glenn Randers-Pehrson
+ <randeg@alum.rpi.edu>
+ Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ For conditions of distribution and use, see copyright
+ notice in png.h.
+
+ based on:
+
+ libpng 1.0 beta 6 version 0.96 May 28, 1997
+ Updated and distributed by Andreas Dilger
+ Copyright (c) 1996, 1997 Andreas Dilger
+
+ libpng 1.0 beta 2 - version 0.88 January 26, 1996
+ For conditions of distribution and use, see copyright
+ notice in png.h. Copyright (c) 1995, 1996 Guy Eric
+ Schalnat, Group 42, Inc.
+
+ Updated/rewritten per request in the libpng FAQ
+ Copyright (c) 1995, 1996 Frank J. T. Wojcik
+ December 18, 1995 & January 20, 1996
+
+I. Introduction
+
+This file describes how to use and modify the PNG reference library
+(known as libpng) for your own use. There are five sections to this
+file: introduction, structures, reading, writing, and modification and
+configuration notes for various special platforms. In addition to this
+file, example.c is a good starting point for using the library, as
+it is heavily commented and should include everything most people
+will need. We assume that libpng is already installed; see the
+INSTALL file for instructions on how to install libpng.
+
+Libpng was written as a companion to the PNG specification, as a way
+of reducing the amount of time and effort it takes to support the PNG
+file format in application programs.
+
+The PNG-1.2 specification is available at <http://www.libpng.org/pub/png>
+and at <ftp://ftp.uu.net/graphics/png/documents/>.
+
+The PNG-1.0 specification is available
+as RFC 2083 <ftp://ftp.uu.net/graphics/png/documents/> and as a
+W3C Recommendation <http://www.w3.org/TR/REC.png.html>. Some
+additional chunks are described in the special-purpose public chunks
+documents at <ftp://ftp.uu.net/graphics/png/documents/>.
+
+Other information
+about PNG, and the latest version of libpng, can be found at the PNG home
+page, <http://www.libpng.org/pub/png/>
+and at <ftp://ftp.uu.net/graphics/png/>.
+
+Most users will not have to modify the library significantly; advanced
+users may want to modify it more. All attempts were made to make it as
+complete as possible, while keeping the code easy to understand.
+Currently, this library only supports C. Support for other languages
+is being considered.
+
+Libpng has been designed to handle multiple sessions at one time,
+to be easily modifiable, to be portable to the vast majority of
+machines (ANSI, K&R, 16-, 32-, and 64-bit) available, and to be easy
+to use. The ultimate goal of libpng is to promote the acceptance of
+the PNG file format in whatever way possible. While there is still
+work to be done (see the TODO file), libpng should cover the
+majority of the needs of its users.
+
+Libpng uses zlib for its compression and decompression of PNG files.
+Further information about zlib, and the latest version of zlib, can
+be found at the zlib home page, <http://www.info-zip.org/pub/infozip/zlib/>.
+The zlib compression utility is a general purpose utility that is
+useful for more than PNG files, and can be used without libpng.
+See the documentation delivered with zlib for more details.
+You can usually find the source files for the zlib utility wherever you
+find the libpng source files.
+
+Libpng is thread safe, provided the threads are using different
+instances of the structures. Each thread should have its own
+png_struct and png_info instances, and thus its own image.
+Libpng does not protect itself against two threads using the
+same instance of a structure. Note: thread safety may be defeated
+by use of some of the MMX assembler code in pnggccrd.c, which is only
+compiled when the user defines PNG_THREAD_UNSAFE_OK.
+
+
+II. Structures
+
+There are two main structures that are important to libpng, png_struct
+and png_info. The first, png_struct, is an internal structure that
+will not, for the most part, be used by a user except as the first
+variable passed to every libpng function call.
+
+The png_info structure is designed to provide information about the
+PNG file. At one time, the fields of png_info were intended to be
+directly accessible to the user. However, this tended to cause problems
+with applications using dynamically loaded libraries, and as a result
+a set of interface functions for png_info (the png_get_*() and png_set_*()
+functions) was developed. The fields of png_info are still available for
+older applications, but it is suggested that applications use the new
+interfaces if at all possible.
+
+Applications that do make direct access to the members of png_struct (except
+for png_ptr->jmpbuf) must be recompiled whenever the library is updated,
+and applications that make direct access to the members of png_info must
+be recompiled if they were compiled or loaded with libpng version 1.0.6,
+in which the members were in a different order. In version 1.0.7, the
+members of the png_info structure reverted to the old order, as they were
+in versions 0.97c through 1.0.5. Starting with version 2.0.0, both
+structures are going to be hidden, and the contents of the structures will
+only be accessible through the png_get/png_set functions.
+
+The png.h header file is an invaluable reference for programming with libpng.
+And while I'm on the topic, make sure you include the libpng header file:
+
+#include <png.h>
+
+III. Reading
+
+We'll now walk you through the possible functions to call when reading
+in a PNG file sequentially, briefly explaining the syntax and purpose
+of each one. See example.c and png.h for more detail. While
+progressive reading is covered in the next section, you will still
+need some of the functions discussed in this section to read a PNG
+file.
+
+Setup
+
+You will want to do the I/O initialization(*) before you get into libpng,
+so if it doesn't work, you don't have much to undo. Of course, you
+will also want to insure that you are, in fact, dealing with a PNG
+file. Libpng provides a simple check to see if a file is a PNG file.
+To use it, pass in the first 1 to 8 bytes of the file to the function
+png_sig_cmp(), and it will return 0 if the bytes match the corresponding
+bytes of the PNG signature, or nonzero otherwise. Of course, the more bytes
+you pass in, the greater the accuracy of the prediction.
+
+If you are intending to keep the file pointer open for use in libpng,
+you must ensure you don't read more than 8 bytes from the beginning
+of the file, and you also have to make a call to png_set_sig_bytes_read()
+with the number of bytes you read from the beginning. Libpng will
+then only check the bytes (if any) that your program didn't read.
+
+(*): If you are not using the standard I/O functions, you will need
+to replace them with custom functions. See the discussion under
+Customizing libpng.
+
+
+ FILE *fp = fopen(file_name, "rb");
+ if (!fp)
+ {
+ return (ERROR);
+ }
+ fread(header, 1, number, fp);
+ is_png = !png_sig_cmp(header, 0, number);
+ if (!is_png)
+ {
+ return (NOT_PNG);
+ }
+
+
+Next, png_struct and png_info need to be allocated and initialized. In
+order to ensure that the size of these structures is correct even with a
+dynamically linked libpng, there are functions to initialize and
+allocate the structures. We also pass the library version, optional
+pointers to error handling functions, and a pointer to a data struct for
+use by the error functions, if necessary (the pointer and functions can
+be NULL if the default error handlers are to be used). See the section
+on Changes to Libpng below regarding the old initialization functions.
+The structure allocation functions quietly return NULL if they fail to
+create the structure, so your application should check for that.
+
+ png_structp png_ptr = png_create_read_struct
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn);
+ if (!png_ptr)
+ return (ERROR);
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_read_struct(&png_ptr,
+ (png_infopp)NULL, (png_infopp)NULL);
+ return (ERROR);
+ }
+
+ png_infop end_info = png_create_info_struct(png_ptr);
+ if (!end_info)
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ (png_infopp)NULL);
+ return (ERROR);
+ }
+
+If you want to use your own memory allocation routines,
+define PNG_USER_MEM_SUPPORTED and use
+png_create_read_struct_2() instead of png_create_read_struct():
+
+ png_structp png_ptr = png_create_read_struct_2
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn, (png_voidp)
+ user_mem_ptr, user_malloc_fn, user_free_fn);
+
+The error handling routines passed to png_create_read_struct()
+and the memory alloc/free routines passed to png_create_struct_2()
+are only necessary if you are not using the libpng supplied error
+handling and memory alloc/free functions.
+
+When libpng encounters an error, it expects to longjmp back
+to your routine. Therefore, you will need to call setjmp and pass
+your png_jmpbuf(png_ptr). If you read the file from different
+routines, you will need to update the jmpbuf field every time you enter
+a new routine that will call a png_*() function.
+
+See your documentation of setjmp/longjmp for your compiler for more
+information on setjmp/longjmp. See the discussion on libpng error
+handling in the Customizing Libpng section below for more information
+on the libpng error handling. If an error occurs, and libpng longjmp's
+back to your setjmp, you will want to call png_destroy_read_struct() to
+free any memory.
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ &end_info);
+ fclose(fp);
+ return (ERROR);
+ }
+
+If you would rather avoid the complexity of setjmp/longjmp issues,
+you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case
+errors will result in a call to PNG_ABORT() which defaults to abort().
+
+Now you need to set up the input code. The default for libpng is to
+use the C function fread(). If you use this, you will need to pass a
+valid FILE * in the function png_init_io(). Be sure that the file is
+opened in binary mode. If you wish to handle reading data in another
+way, you need not call the png_init_io() function, but you must then
+implement the libpng I/O methods discussed in the Customizing Libpng
+section below.
+
+ png_init_io(png_ptr, fp);
+
+If you had previously opened the file and read any of the signature from
+the beginning in order to see if this was a PNG file, you need to let
+libpng know that there are some bytes missing from the start of the file.
+
+ png_set_sig_bytes(png_ptr, number);
+
+Setting up callback code
+
+You can set up a callback function to handle any unknown chunks in the
+input stream. You must supply the function
+
+ read_chunk_callback(png_ptr ptr,
+ png_unknown_chunkp chunk);
+ {
+ /* The unknown chunk structure contains your
+ chunk data: */
+ png_byte name[5];
+ png_byte *data;
+ png_size_t size;
+ /* Note that libpng has already taken care of
+ the CRC handling */
+
+ /* put your code here. Return one of the
+ following: */
+
+ return (-n); /* chunk had an error */
+ return (0); /* did not recognize */
+ return (n); /* success */
+ }
+
+(You can give your function another name that you like instead of
+"read_chunk_callback")
+
+To inform libpng about your function, use
+
+ png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr,
+ read_chunk_callback);
+
+This names not only the callback function, but also a user pointer that
+you can retrieve with
+
+ png_get_user_chunk_ptr(png_ptr);
+
+At this point, you can set up a callback function that will be
+called after each row has been read, which you can use to control
+a progress meter or the like. It's demonstrated in pngtest.c.
+You must supply a function
+
+ void read_row_callback(png_ptr ptr, png_uint_32 row,
+ int pass);
+ {
+ /* put your code here */
+ }
+
+(You can give it another name that you like instead of "read_row_callback")
+
+To inform libpng about your function, use
+
+ png_set_read_status_fn(png_ptr, read_row_callback);
+
+Unknown-chunk handling
+
+Now you get to set the way the library processes unknown chunks in the
+input PNG stream. Both known and unknown chunks will be read. Normal
+behavior is that known chunks will be parsed into information in
+various info_ptr members; unknown chunks will be discarded. To change
+this, you can call:
+
+ png_set_keep_unknown_chunks(png_ptr, info_ptr, keep,
+ chunk_list, num_chunks);
+ keep - 0: do not keep
+ 1: keep only if safe-to-copy
+ 2: keep even if unsafe-to-copy
+ chunk_list - list of chunks affected (a byte string,
+ five bytes per chunk, NULL or '\0' if
+ num_chunks is 0)
+ num_chunks - number of chunks affected; if 0, all
+ unknown chunks are affected
+
+Unknown chunks declared in this way will be saved as raw data onto a
+list of png_unknown_chunk structures. If a chunk that is normally
+known to libpng is named in the list, it will be handled as unknown,
+according to the "keep" directive. If a chunk is named in successive
+instances of png_set_keep_unknown_chunks(), the final instance will
+take precedence.
+
+The high-level read interface
+
+At this point there are two ways to proceed; through the high-level
+read interface, or through a sequence of low-level read operations.
+You can use the high-level interface if (a) you are willing to read
+the entire image into memory, and (b) the input transformations
+you want to do are limited to the following set:
+
+ PNG_TRANSFORM_IDENTITY No transformation
+ PNG_TRANSFORM_STRIP_16 Strip 16-bit samples to
+ 8 bits
+ PNG_TRANSFORM_STRIP_ALPHA Discard the alpha channel
+ PNG_TRANSFORM_PACKING Expand 1, 2 and 4-bit
+ samples to bytes
+ PNG_TRANSFORM_PACKSWAP Change order of packed
+ pixels to LSB first
+ PNG_TRANSFORM_EXPAND Perform set_expand()
+ PNG_TRANSFORM_INVERT_MONO Invert monochrome images
+ PNG_TRANSFORM_SHIFT Normalize pixels to the
+ sBIT depth
+ PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA
+ to BGRA
+ PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA
+ to AG
+ PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity
+ to transparency
+ PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples
+
+(This excludes setting a background color, doing gamma transformation,
+dithering, and setting filler.) If this is the case, simply do this:
+
+ png_read_png(png_ptr, info_ptr, png_transforms, NULL)
+
+where png_transforms is an integer containing the logical OR of
+some set of transformation flags. This call is equivalent to png_read_info(),
+followed the set of transformations indicated by the transform mask,
+then png_read_image(), and finally png_read_end().
+
+(The final parameter of this call is not yet used. Someday it might point
+to transformation parameters required by some future input transform.)
+
+After you have called png_read_png(), you can retrieve the image data
+with
+
+ row_pointers = png_get_rows(png_ptr, info_ptr);
+
+where row_pointers is an array of pointers to the pixel data for each row:
+
+ png_bytep row_pointers[height];
+
+If you know your image size and pixel size ahead of time, you can allocate
+row_pointers prior to calling png_read_png() with
+
+ row_pointers = png_malloc(png_ptr,
+ height*sizeof(png_bytep));
+ for (int i=0; i<height, i++)
+ row_pointers[i]=png_malloc(png_ptr,
+ width*pixel_size);
+ png_set_rows(png_ptr, info_ptr, &row_pointers);
+
+Alternatively you could allocate your image in one big block and define
+row_pointers[i] to point into the proper places in your block.
+
+If you use png_set_rows(), the application is responsible for freeing
+row_pointers (and row_pointers[i], if they were separately allocated).
+
+If you don't allocate row_pointers ahead of time, png_read_png() will
+do it, and it'll be free'ed when you call png_destroy_*().
+
+The low-level read interface
+
+If you are going the low-level route, you are now ready to read all
+the file information up to the actual image data. You do this with a
+call to png_read_info().
+
+ png_read_info(png_ptr, info_ptr);
+
+This will process all chunks up to but not including the image data.
+
+Querying the info structure
+
+Functions are used to get the information from the info_ptr once it
+has been read. Note that these fields may not be completely filled
+in until png_read_end() has read the chunk data following the image.
+
+ png_get_IHDR(png_ptr, info_ptr, &width, &height,
+ &bit_depth, &color_type, &interlace_type,
+ &compression_type, &filter_method);
+
+ width - holds the width of the image
+ in pixels (up to 2^31).
+ height - holds the height of the image
+ in pixels (up to 2^31).
+ bit_depth - holds the bit depth of one of the
+ image channels. (valid values are
+ 1, 2, 4, 8, 16 and depend also on
+ the color_type. See also
+ significant bits (sBIT) below).
+ color_type - describes which color/alpha channels
+ are present.
+ PNG_COLOR_TYPE_GRAY
+ (bit depths 1, 2, 4, 8, 16)
+ PNG_COLOR_TYPE_GRAY_ALPHA
+ (bit depths 8, 16)
+ PNG_COLOR_TYPE_PALETTE
+ (bit depths 1, 2, 4, 8)
+ PNG_COLOR_TYPE_RGB
+ (bit_depths 8, 16)
+ PNG_COLOR_TYPE_RGB_ALPHA
+ (bit_depths 8, 16)
+
+ PNG_COLOR_MASK_PALETTE
+ PNG_COLOR_MASK_COLOR
+ PNG_COLOR_MASK_ALPHA
+
+ filter_method - (must be PNG_FILTER_TYPE_BASE
+ for PNG 1.0, and can also be
+ PNG_INTRAPIXEL_DIFFERENCING if
+ the PNG datastream is embedded in
+ a MNG-1.0 datastream)
+ compression_type - (must be PNG_COMPRESSION_TYPE_BASE
+ for PNG 1.0)
+ interlace_type - (PNG_INTERLACE_NONE or
+ PNG_INTERLACE_ADAM7)
+ Any or all of interlace_type, compression_type, of
+ filter_method can be NULL if you are
+ not interested in their values.
+
+ channels = png_get_channels(png_ptr, info_ptr);
+ channels - number of channels of info for the
+ color type (valid values are 1 (GRAY,
+ PALETTE), 2 (GRAY_ALPHA), 3 (RGB),
+ 4 (RGB_ALPHA or RGB + filler byte))
+ rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+ rowbytes - number of bytes needed to hold a row
+
+ signature = png_get_signature(png_ptr, info_ptr);
+ signature - holds the signature read from the
+ file (if any). The data is kept in
+ the same offset it would be if the
+ whole signature were read (i.e. if an
+ application had already read in 4
+ bytes of signature before starting
+ libpng, the remaining 4 bytes would
+ be in signature[4] through signature[7]
+ (see png_set_sig_bytes())).
+
+
+ width = png_get_image_width(png_ptr,
+ info_ptr);
+ height = png_get_image_height(png_ptr,
+ info_ptr);
+ bit_depth = png_get_bit_depth(png_ptr,
+ info_ptr);
+ color_type = png_get_color_type(png_ptr,
+ info_ptr);
+ filter_method = png_get_filter_type(png_ptr,
+ info_ptr);
+ compression_type = png_get_compression_type(png_ptr,
+ info_ptr);
+ interlace_type = png_get_interlace_type(png_ptr,
+ info_ptr);
+
+
+These are also important, but their validity depends on whether the chunk
+has been read. The png_get_valid(png_ptr, info_ptr, PNG_INFO_<chunk>) and
+png_get_<chunk>(png_ptr, info_ptr, ...) functions return non-zero if the
+data has been read, or zero if it is missing. The parameters to the
+png_get_<chunk> are set directly if they are simple data types, or a pointer
+into the info_ptr is returned for any complex types.
+
+ png_get_PLTE(png_ptr, info_ptr, &palette,
+ &num_palette);
+ palette - the palette for the file
+ (array of png_color)
+ num_palette - number of entries in the palette
+
+ png_get_gAMA(png_ptr, info_ptr, &gamma);
+ gamma - the gamma the file is written
+ at (PNG_INFO_gAMA)
+
+ png_get_sRGB(png_ptr, info_ptr, &srgb_intent);
+ srgb_intent - the rendering intent (PNG_INFO_sRGB)
+ The presence of the sRGB chunk
+ means that the pixel data is in the
+ sRGB color space. This chunk also
+ implies specific values of gAMA and
+ cHRM.
+
+ png_get_iCCP(png_ptr, info_ptr, &name,
+ &compression_type, &profile, &proflen);
+ name - The profile name.
+ compression - The compression type; always
+ PNG_COMPRESSION_TYPE_BASE for PNG 1.0.
+ You may give NULL to this argument to
+ ignore it.
+ profile - International Color Consortium color
+ profile data. May contain NULs.
+ proflen - length of profile data in bytes.
+
+ png_get_sBIT(png_ptr, info_ptr, &sig_bit);
+ sig_bit - the number of significant bits for
+ (PNG_INFO_sBIT) each of the gray,
+ red, green, and blue channels,
+ whichever are appropriate for the
+ given color type (png_color_16)
+
+ png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans,
+ &trans_values);
+ trans - array of transparent entries for
+ palette (PNG_INFO_tRNS)
+ trans_values - graylevel or color sample values of
+ the single transparent color for
+ non-paletted images (PNG_INFO_tRNS)
+ num_trans - number of transparent entries
+ (PNG_INFO_tRNS)
+
+ png_get_hIST(png_ptr, info_ptr, &hist);
+ (PNG_INFO_hIST)
+ hist - histogram of palette (array of
+ png_uint_16)
+
+ png_get_tIME(png_ptr, info_ptr, &mod_time);
+ mod_time - time image was last modified
+ (PNG_VALID_tIME)
+
+ png_get_bKGD(png_ptr, info_ptr, &background);
+ background - background color (PNG_VALID_bKGD)
+ valid 16-bit red, green and blue
+ values, regardless of color_type
+
+ num_comments = png_get_text(png_ptr, info_ptr,
+ &text_ptr, &num_text);
+ num_comments - number of comments
+ text_ptr - array of png_text holding image
+ comments
+ text_ptr[i].compression - type of compression used
+ on "text" PNG_TEXT_COMPRESSION_NONE
+ PNG_TEXT_COMPRESSION_zTXt
+ PNG_ITXT_COMPRESSION_NONE
+ PNG_ITXT_COMPRESSION_zTXt
+ text_ptr[i].key - keyword for comment. Must contain
+ 1-79 characters.
+ text_ptr[i].text - text comments for current
+ keyword. Can be empty.
+ text_ptr[i].text_length - length of text string,
+ after decompression, 0 for iTXt
+ text_ptr[i].itxt_length - length of itxt string,
+ after decompression, 0 for tEXt/zTXt
+ text_ptr[i].lang - language of comment (empty
+ string for unknown).
+ text_ptr[i].translated_keyword - keyword in UTF-8
+ (empty string for unknown).
+ num_text - number of comments (same as
+ num_comments; you can put NULL here
+ to avoid the duplication)
+ Note while png_set_text() will accept text, language,
+ and translated keywords that can be NULL pointers, the
+ structure returned by png_get_text will always contain
+ regular zero-terminated C strings. They might be
+ empty strings but they will never be NULL pointers.
+
+ num_spalettes = png_get_sPLT(png_ptr, info_ptr,
+ &palette_ptr);
+ palette_ptr - array of palette structures holding
+ contents of one or more sPLT chunks
+ read.
+ num_spalettes - number of sPLT chunks read.
+
+ png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y,
+ &unit_type);
+ offset_x - positive offset from the left edge
+ of the screen
+ offset_y - positive offset from the top edge
+ of the screen
+ unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER
+
+ png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y,
+ &unit_type);
+ res_x - pixels/unit physical resolution in
+ x direction
+ res_y - pixels/unit physical resolution in
+ x direction
+ unit_type - PNG_RESOLUTION_UNKNOWN,
+ PNG_RESOLUTION_METER
+
+ png_get_sCAL(png_ptr, info_ptr, &unit, &width,
+ &height)
+ unit - physical scale units (an integer)
+ width - width of a pixel in physical scale units
+ height - height of a pixel in physical scale units
+ (width and height are doubles)
+
+ png_get_sCAL_s(png_ptr, info_ptr, &unit, &width,
+ &height)
+ unit - physical scale units (an integer)
+ width - width of a pixel in physical scale units
+ height - height of a pixel in physical scale units
+ (width and height are strings like "2.54")
+
+ num_unknown_chunks = png_get_unknown_chunks(png_ptr,
+ info_ptr, &unknowns)
+ unknowns - array of png_unknown_chunk
+ structures holding unknown chunks
+ unknowns[i].name - name of unknown chunk
+ unknowns[i].data - data of unknown chunk
+ unknowns[i].size - size of unknown chunk's data
+ unknowns[i].location - position of chunk in file
+
+ The value of "i" corresponds to the order in which the
+ chunks were read from the PNG file or inserted with the
+ png_set_unknown_chunks() function.
+
+The data from the pHYs chunk can be retrieved in several convenient
+forms:
+
+ res_x = png_get_x_pixels_per_meter(png_ptr,
+ info_ptr)
+ res_y = png_get_y_pixels_per_meter(png_ptr,
+ info_ptr)
+ res_x_and_y = png_get_pixels_per_meter(png_ptr,
+ info_ptr)
+ res_x = png_get_x_pixels_per_inch(png_ptr,
+ info_ptr)
+ res_y = png_get_y_pixels_per_inch(png_ptr,
+ info_ptr)
+ res_x_and_y = png_get_pixels_per_inch(png_ptr,
+ info_ptr)
+ aspect_ratio = png_get_pixel_aspect_ratio(png_ptr,
+ info_ptr)
+
+ (Each of these returns 0 [signifying "unknown"] if
+ the data is not present or if res_x is 0;
+ res_x_and_y is 0 if res_x != res_y)
+
+The data from the oFFs chunk can be retrieved in several convenient
+forms:
+
+ x_offset = png_get_x_offset_microns(png_ptr, info_ptr);
+ y_offset = png_get_y_offset_microns(png_ptr, info_ptr);
+ x_offset = png_get_x_offset_inches(png_ptr, info_ptr);
+ y_offset = png_get_y_offset_inches(png_ptr, info_ptr);
+
+ (Each of these returns 0 [signifying "unknown" if both
+ x and y are 0] if the data is not present or if the
+ chunk is present but the unit is the pixel)
+
+For more information, see the png_info definition in png.h and the
+PNG specification for chunk contents. Be careful with trusting
+rowbytes, as some of the transformations could increase the space
+needed to hold a row (expand, filler, gray_to_rgb, etc.).
+See png_read_update_info(), below.
+
+A quick word about text_ptr and num_text. PNG stores comments in
+keyword/text pairs, one pair per chunk, with no limit on the number
+of text chunks, and a 2^31 byte limit on their size. While there are
+suggested keywords, there is no requirement to restrict the use to these
+strings. It is strongly suggested that keywords and text be sensible
+to humans (that's the point), so don't use abbreviations. Non-printing
+symbols are not allowed. See the PNG specification for more details.
+There is also no requirement to have text after the keyword.
+
+Keywords should be limited to 79 Latin-1 characters without leading or
+trailing spaces, but non-consecutive spaces are allowed within the
+keyword. It is possible to have the same keyword any number of times.
+The text_ptr is an array of png_text structures, each holding a
+pointer to a language string, a pointer to a keyword and a pointer to
+a text string. The text string, language code, and translated
+keyword may be empty or NULL pointers. The keyword/text
+pairs are put into the array in the order that they are received.
+However, some or all of the text chunks may be after the image, so, to
+make sure you have read all the text chunks, don't mess with these
+until after you read the stuff after the image. This will be
+mentioned again below in the discussion that goes with png_read_end().
+
+Input transformations
+
+After you've read the header information, you can set up the library
+to handle any special transformations of the image data. The various
+ways to transform the data will be described in the order that they
+should occur. This is important, as some of these change the color
+type and/or bit depth of the data, and some others only work on
+certain color types and bit depths. Even though each transformation
+checks to see if it has data that it can do something with, you should
+make sure to only enable a transformation if it will be valid for the
+data. For example, don't swap red and blue on grayscale data.
+
+The colors used for the background and transparency values should be
+supplied in the same format/depth as the current image data. They
+are stored in the same format/depth as the image data in a bKGD or tRNS
+chunk, so this is what libpng expects for this data. The colors are
+transformed to keep in sync with the image data when an application
+calls the png_read_update_info() routine (see below).
+
+Data will be decoded into the supplied row buffers packed into bytes
+unless the library has been told to transform it into another format.
+For example, 4 bit/pixel paletted or grayscale data will be returned
+2 pixels/byte with the leftmost pixel in the high-order bits of the
+byte, unless png_set_packing() is called. 8-bit RGB data will be stored
+in RGB RGB RGB format unless png_set_filler() is called to insert filler
+bytes, either before or after each RGB triplet. 16-bit RGB data will
+be returned RRGGBB RRGGBB, with the most significant byte of the color
+value first, unless png_set_strip_16() is called to transform it to
+regular RGB RGB triplets, or png_set_filler() is called to insert
+filler bytes, either before or after each RRGGBB triplet. Similarly,
+8-bit or 16-bit grayscale data can be modified with png_set_filler()
+or png_set_strip_16().
+
+The following code transforms grayscale images of less than 8 to 8 bits,
+changes paletted images to RGB, and adds a full alpha channel if there is
+transparency information in a tRNS chunk. This is most useful on
+grayscale images with bit depths of 2 or 4 or if there is a multiple-image
+viewing application that wishes to treat all images in the same way.
+
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_palette_to_rgb(png_ptr);
+
+ if (color_type == PNG_COLOR_TYPE_GRAY &&
+ bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr);
+
+ if (png_get_valid(png_ptr, info_ptr,
+ PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr);
+
+These three functions are actually aliases for png_set_expand(), added
+in libpng version 1.0.4, with the function names expanded to improve code
+readability. In some future version they may actually do different
+things.
+
+PNG can have files with 16 bits per channel. If you only can handle
+8 bits per channel, this will strip the pixels down to 8 bit.
+
+ if (bit_depth == 16)
+ png_set_strip_16(png_ptr);
+
+If, for some reason, you don't need the alpha channel on an image,
+and you want to remove it rather than combining it with the background
+(but the image author certainly had in mind that you *would* combine
+it with the background, so that's what you should probably do):
+
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ png_set_strip_alpha(png_ptr);
+
+In PNG files, the alpha channel in an image
+is the level of opacity. If you need the alpha channel in an image to
+be the level of transparency instead of opacity, you can invert the
+alpha channel (or the tRNS chunk data) after it's read, so that 0 is
+fully opaque and 255 (in 8-bit or paletted images) or 65535 (in 16-bit
+images) is fully transparent, with
+
+ png_set_invert_alpha(png_ptr);
+
+PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as
+they can, resulting in, for example, 8 pixels per byte for 1 bit
+files. This code expands to 1 pixel per byte without changing the
+values of the pixels:
+
+ if (bit_depth < 8)
+ png_set_packing(png_ptr);
+
+PNG files have possible bit depths of 1, 2, 4, 8, and 16. All pixels
+stored in a PNG image have been "scaled" or "shifted" up to the next
+higher possible bit depth (e.g. from 5 bits/sample in the range [0,31] to
+8 bits/sample in the range [0, 255]). However, it is also possible to
+convert the PNG pixel data back to the original bit depth of the image.
+This call reduces the pixels back down to the original bit depth:
+
+ png_color_8p sig_bit;
+
+ if (png_get_sBIT(png_ptr, info_ptr, &sig_bit))
+ png_set_shift(png_ptr, sig_bit);
+
+PNG files store 3-color pixels in red, green, blue order. This code
+changes the storage of the pixels to blue, green, red:
+
+ if (color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_bgr(png_ptr);
+
+PNG files store RGB pixels packed into 3 or 6 bytes. This code expands them
+into 4 or 8 bytes for windowing systems that need them in this format:
+
+ if (color_type == PNG_COLOR_TYPE_RGB)
+ png_set_filler(png_ptr, filler, PNG_FILLER_BEFORE);
+
+where "filler" is the 8 or 16-bit number to fill with, and the location is
+either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether
+you want the filler before the RGB or after. This transformation
+does not affect images that already have full alpha channels. To add an
+opaque alpha channel, use filler=0xff or 0xffff and PNG_FILLER_AFTER which
+will generate RGBA pixels.
+
+If you are reading an image with an alpha channel, and you need the
+data as ARGB instead of the normal PNG format RGBA:
+
+ if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_swap_alpha(png_ptr);
+
+For some uses, you may want a grayscale image to be represented as
+RGB. This code will do that conversion:
+
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb(png_ptr);
+
+Conversely, you can convert an RGB or RGBA image to grayscale or grayscale
+with alpha.
+
+ if (color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_rgb_to_gray_fixed(png_ptr, error_action,
+ int red_weight, int green_weight);
+
+ error_action = 1: silently do the conversion
+ error_action = 2: issue a warning if the original
+ image has any pixel where
+ red != green or red != blue
+ error_action = 3: issue an error and abort the
+ conversion if the original
+ image has any pixel where
+ red != green or red != blue
+
+ red_weight: weight of red component times 100000
+ green_weight: weight of green component times 100000
+ If either weight is negative, default
+ weights (21268, 71514) are used.
+
+If you have set error_action = 1 or 2, you can
+later check whether the image really was gray, after processing
+the image rows, with the png_get_rgb_to_gray_status(png_ptr) function.
+It will return a png_byte that is zero if the image was gray or
+1 if there were any non-gray pixels. bKGD and sBIT data
+will be silently converted to grayscale, using the green channel
+data, regardless of the error_action setting.
+
+With red_weight+green_weight<=100000,
+the normalized graylevel is computed:
+
+ int rw = red_weight * 65536;
+ int gw = green_weight * 65536;
+ int bw = 65536 - (rw + gw);
+ gray = (rw*red + gw*green + bw*blue)/65536;
+
+The default values approximate those recommended in the Charles
+Poynton's Color FAQ, <http://www.inforamp.net/~poynton/>
+Copyright (c) 1998-01-04 Charles Poynton poynton@inforamp.net
+
+ Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
+
+Libpng approximates this with
+
+ Y = 0.21268 * R + 0.7151 * G + 0.07217 * B
+
+which can be expressed with integers as
+
+ Y = (6969 * R + 23434 * G + 2365 * B)/32768
+
+The calculation is done in a linear colorspace, if the image gamma
+is known.
+
+If you have a grayscale and you are using png_set_expand_depth() or
+png_set_expand() to change to
+a higher bit-depth, you must either supply the background color as a gray
+value at the original file bit-depth (need_expand = 1) or else supply the
+background color as an RGB triplet at the final, expanded bit depth
+(need_expand = 0). Similarly, if you are reading a paletted image, you
+must either supply the background color as a palette index (need_expand = 1)
+or as an RGB triplet that may or may not be in the palette (need_expand = 0).
+
+ png_color_16 my_background;
+ png_color_16p image_background;
+
+ if (png_get_bKGD(png_ptr, info_ptr, &image_background))
+ png_set_background(png_ptr, image_background,
+ PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+ else
+ png_set_background(png_ptr, &my_background,
+ PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
+
+The png_set_background() function tells libpng to composite images
+with alpha or simple transparency against the supplied background
+color. If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid),
+you may use this color, or supply another color more suitable for
+the current display (e.g., the background color from a web page). You
+need to tell libpng whether the color is in the gamma space of the
+display (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file
+(PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one
+that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't
+know why anyone would use this, but it's here).
+
+To properly display PNG images on any kind of system, the application needs
+to know what the display gamma is. Ideally, the user will know this, and
+the application will allow them to set it. One method of allowing the user
+to set the display gamma separately for each system is to check for a
+SCREEN_GAMMA or DISPLAY_GAMMA environment variable, which will hopefully be
+correctly set.
+
+Note that display_gamma is the overall gamma correction required to produce
+pleasing results, which depends on the lighting conditions in the surrounding
+environment. In a dim or brightly lit room, no compensation other than
+the physical gamma exponent of the monitor is needed, while in a dark room
+a slightly smaller exponent is better.
+
+ double gamma, screen_gamma;
+
+ if (/* We have a user-defined screen
+ gamma value */)
+ {
+ screen_gamma = user_defined_screen_gamma;
+ }
+ /* One way that applications can share the same
+ screen gamma value */
+ else if ((gamma_str = getenv("SCREEN_GAMMA"))
+ != NULL)
+ {
+ screen_gamma = (double)atof(gamma_str);
+ }
+ /* If we don't have another value */
+ else
+ {
+ screen_gamma = 2.2; /* A good guess for a
+ PC monitor in a bright office or a dim room */
+ screen_gamma = 2.0; /* A good guess for a
+ PC monitor in a dark room */
+ screen_gamma = 1.7 or 1.0; /* A good
+ guess for Mac systems */
+ }
+
+The png_set_gamma() function handles gamma transformations of the data.
+Pass both the file gamma and the current screen_gamma. If the file does
+not have a gamma value, you can pass one anyway if you have an idea what
+it is (usually 0.45455 is a good guess for GIF images on PCs). Note
+that file gammas are inverted from screen gammas. See the discussions
+on gamma in the PNG specification for an excellent description of what
+gamma is, and why all applications should support it. It is strongly
+recommended that PNG viewers support gamma correction.
+
+ if (png_get_gAMA(png_ptr, info_ptr, &gamma))
+ png_set_gamma(png_ptr, screen_gamma, gamma);
+ else
+ png_set_gamma(png_ptr, screen_gamma, 0.45455);
+
+If you need to reduce an RGB file to a paletted file, or if a paletted
+file has more entries then will fit on your screen, png_set_dither()
+will do that. Note that this is a simple match dither that merely
+finds the closest color available. This should work fairly well with
+optimized palettes, and fairly badly with linear color cubes. If you
+pass a palette that is larger then maximum_colors, the file will
+reduce the number of colors in the palette so it will fit into
+maximum_colors. If there is a histogram, it will use it to make
+more intelligent choices when reducing the palette. If there is no
+histogram, it may not do as good a job.
+
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ if (png_get_valid(png_ptr, info_ptr,
+ PNG_INFO_PLTE))
+ {
+ png_uint_16p histogram;
+
+ png_get_hIST(png_ptr, info_ptr,
+ &histogram);
+ png_set_dither(png_ptr, palette, num_palette,
+ max_screen_colors, histogram, 1);
+ }
+ else
+ {
+ png_color std_color_cube[MAX_SCREEN_COLORS] =
+ { ... colors ... };
+
+ png_set_dither(png_ptr, std_color_cube,
+ MAX_SCREEN_COLORS, MAX_SCREEN_COLORS,
+ NULL,0);
+ }
+ }
+
+PNG files describe monochrome as black being zero and white being one.
+The following code will reverse this (make black be one and white be
+zero):
+
+ if (bit_depth == 1 && color_type == PNG_COLOR_TYPE_GRAY)
+ png_set_invert_mono(png_ptr);
+
+This function can also be used to invert grayscale and gray-alpha images:
+
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_invert_mono(png_ptr);
+
+PNG files store 16 bit pixels in network byte order (big-endian,
+ie. most significant bits first). This code changes the storage to the
+other way (little-endian, i.e. least significant bits first, the
+way PCs store them):
+
+ if (bit_depth == 16)
+ png_set_swap(png_ptr);
+
+If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you
+need to change the order the pixels are packed into bytes, you can use:
+
+ if (bit_depth < 8)
+ png_set_packswap(png_ptr);
+
+Finally, you can write your own transformation function if none of
+the existing ones meets your needs. This is done by setting a callback
+with
+
+ png_set_read_user_transform_fn(png_ptr,
+ read_transform_fn);
+
+You must supply the function
+
+ void read_transform_fn(png_ptr ptr, row_info_ptr
+ row_info, png_bytep data)
+
+See pngtest.c for a working example. Your function will be called
+after all of the other transformations have been processed.
+
+You can also set up a pointer to a user structure for use by your
+callback function, and you can inform libpng that your transform
+function will change the number of channels or bit depth with the
+function
+
+ png_set_user_transform_info(png_ptr, user_ptr,
+ user_depth, user_channels);
+
+The user's application, not libpng, is responsible for allocating and
+freeing any memory required for the user structure.
+
+You can retrieve the pointer via the function
+png_get_user_transform_ptr(). For example:
+
+ voidp read_user_transform_ptr =
+ png_get_user_transform_ptr(png_ptr);
+
+The last thing to handle is interlacing; this is covered in detail below,
+but you must call the function here if you want libpng to handle expansion
+of the interlaced image.
+
+ number_of_passes = png_set_interlace_handling(png_ptr);
+
+After setting the transformations, libpng can update your png_info
+structure to reflect any transformations you've requested with this
+call. This is most useful to update the info structure's rowbytes
+field so you can use it to allocate your image memory. This function
+will also update your palette with the correct screen_gamma and
+background if these have been given with the calls above.
+
+ png_read_update_info(png_ptr, info_ptr);
+
+After you call png_read_update_info(), you can allocate any
+memory you need to hold the image. The row data is simply
+raw byte data for all forms of images. As the actual allocation
+varies among applications, no example will be given. If you
+are allocating one large chunk, you will need to build an
+array of pointers to each row, as it will be needed for some
+of the functions below.
+
+Reading image data
+
+After you've allocated memory, you can read the image data.
+The simplest way to do this is in one function call. If you are
+allocating enough memory to hold the whole image, you can just
+call png_read_image() and libpng will read in all the image data
+and put it in the memory area supplied. You will need to pass in
+an array of pointers to each row.
+
+This function automatically handles interlacing, so you don't need
+to call png_set_interlace_handling() or call this function multiple
+times, or any of that other stuff necessary with png_read_rows().
+
+ png_read_image(png_ptr, row_pointers);
+
+where row_pointers is:
+
+ png_bytep row_pointers[height];
+
+You can point to void or char or whatever you use for pixels.
+
+If you don't want to read in the whole image at once, you can
+use png_read_rows() instead. If there is no interlacing (check
+interlace_type == PNG_INTERLACE_NONE), this is simple:
+
+ png_read_rows(png_ptr, row_pointers, NULL,
+ number_of_rows);
+
+where row_pointers is the same as in the png_read_image() call.
+
+If you are doing this just one row at a time, you can do this with
+a single row_pointer instead of an array of row_pointers:
+
+ png_bytep row_pointer = row;
+ png_read_row(png_ptr, row_pointer, NULL);
+
+If the file is interlaced (interlace_type != 0 in the IHDR chunk), things
+get somewhat harder. The only current (PNG Specification version 1.2)
+interlacing type for PNG is (interlace_type == PNG_INTERLACE_ADAM7)
+is a somewhat complicated 2D interlace scheme, known as Adam7, that
+breaks down an image into seven smaller images of varying size, based
+on an 8x8 grid.
+
+libpng can fill out those images or it can give them to you "as is".
+If you want them filled out, there are two ways to do that. The one
+mentioned in the PNG specification is to expand each pixel to cover
+those pixels that have not been read yet (the "rectangle" method).
+This results in a blocky image for the first pass, which gradually
+smooths out as more pixels are read. The other method is the "sparkle"
+method, where pixels are drawn only in their final locations, with the
+rest of the image remaining whatever colors they were initialized to
+before the start of the read. The first method usually looks better,
+but tends to be slower, as there are more pixels to put in the rows.
+
+If you don't want libpng to handle the interlacing details, just call
+png_read_rows() seven times to read in all seven images. Each of the
+images is a valid image by itself, or they can all be combined on an
+8x8 grid to form a single image (although if you intend to combine them
+you would be far better off using the libpng interlace handling).
+
+The first pass will return an image 1/8 as wide as the entire image
+(every 8th column starting in column 0) and 1/8 as high as the original
+(every 8th row starting in row 0), the second will be 1/8 as wide
+(starting in column 4) and 1/8 as high (also starting in row 0). The
+third pass will be 1/4 as wide (every 4th pixel starting in column 0) and
+1/8 as high (every 8th row starting in row 4), and the fourth pass will
+be 1/4 as wide and 1/4 as high (every 4th column starting in column 2,
+and every 4th row starting in row 0). The fifth pass will return an
+image 1/2 as wide, and 1/4 as high (starting at column 0 and row 2),
+while the sixth pass will be 1/2 as wide and 1/2 as high as the original
+(starting in column 1 and row 0). The seventh and final pass will be as
+wide as the original, and 1/2 as high, containing all of the odd
+numbered scanlines. Phew!
+
+If you want libpng to expand the images, call this before calling
+png_start_read_image() or png_read_update_info():
+
+ if (interlace_type == PNG_INTERLACE_ADAM7)
+ number_of_passes
+ = png_set_interlace_handling(png_ptr);
+
+This will return the number of passes needed. Currently, this
+is seven, but may change if another interlace type is added.
+This function can be called even if the file is not interlaced,
+where it will return one pass.
+
+If you are not going to display the image after each pass, but are
+going to wait until the entire image is read in, use the sparkle
+effect. This effect is faster and the end result of either method
+is exactly the same. If you are planning on displaying the image
+after each pass, the "rectangle" effect is generally considered the
+better looking one.
+
+If you only want the "sparkle" effect, just call png_read_rows() as
+normal, with the third parameter NULL. Make sure you make pass over
+the image number_of_passes times, and you don't change the data in the
+rows between calls. You can change the locations of the data, just
+not the data. Each pass only writes the pixels appropriate for that
+pass, and assumes the data from previous passes is still valid.
+
+ png_read_rows(png_ptr, row_pointers, NULL,
+ number_of_rows);
+
+If you only want the first effect (the rectangles), do the same as
+before except pass the row buffer in the third parameter, and leave
+the second parameter NULL.
+
+ png_read_rows(png_ptr, NULL, row_pointers,
+ number_of_rows);
+
+Finishing a sequential read
+
+After you are finished reading the image through either the high- or
+low-level interfaces, you can finish reading the file. If you are
+interested in comments or time, which may be stored either before or
+after the image data, you should pass the separate png_info struct if
+you want to keep the comments from before and after the image
+separate. If you are not interested, you can pass NULL.
+
+ png_read_end(png_ptr, end_info);
+
+When you are done, you can free all memory allocated by libpng like this:
+
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ &end_info);
+
+It is also possible to individually free the info_ptr members that
+point to libpng-allocated storage with the following function:
+
+ png_free_data(png_ptr, info_ptr, mask, seq)
+ mask - identifies data to be freed, a mask
+ containing the logical OR of one or
+ more of
+ PNG_FREE_PLTE, PNG_FREE_TRNS,
+ PNG_FREE_HIST, PNG_FREE_ICCP,
+ PNG_FREE_PCAL, PNG_FREE_ROWS,
+ PNG_FREE_SCAL, PNG_FREE_SPLT,
+ PNG_FREE_TEXT, PNG_FREE_UNKN,
+ or simply PNG_FREE_ALL
+ seq - sequence number of item to be freed
+ (-1 for all items)
+
+This function may be safely called when the relevant storage has
+already been freed, or has not yet been allocated, or was allocated
+by the user and not by libpng, and will in those
+cases do nothing. The "seq" parameter is ignored if only one item
+of the selected data type, such as PLTE, is allowed. If "seq" is not
+-1, and multiple items are allowed for the data type identified in
+the mask, such as text or sPLT, only the n'th item in the structure
+is freed, where n is "seq".
+
+The default behavior is only to free data that was allocated internally
+by libpng. This can be changed, so that libpng will not free the data,
+or so that it will free data that was allocated by the user with png_malloc()
+or png_zalloc() and passed in via a png_set_*() function, with
+
+ png_data_freer(png_ptr, info_ptr, freer, mask)
+ mask - which data elements are affected
+ same choices as in png_free_data()
+ freer - one of
+ PNG_DESTROY_WILL_FREE_DATA
+ PNG_SET_WILL_FREE_DATA
+ PNG_USER_WILL_FREE_DATA
+
+This function only affects data that has already been allocated.
+You can call this function after reading the PNG data but before calling
+any png_set_*() functions, to control whether the user or the png_set_*()
+function is responsible for freeing any existing data that might be present,
+and again after the png_set_*() functions to control whether the user
+or png_destroy_*() is supposed to free the data. When the user assumes
+responsibility for libpng-allocated data, the application must use
+png_free() to free it, and when the user transfers responsibility to libpng
+for data that the user has allocated, the user must have used png_malloc()
+or png_zalloc() to allocate it.
+
+If you allocated your row_pointers in a single block, as suggested above in
+the description of the high level read interface, you must not transfer
+responsibility for freeing it to the png_set_rows or png_read_destroy function,
+because they would also try to free the individual row_pointers[i].
+
+If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword
+separately, do not transfer responsibility for freeing text_ptr to libpng,
+because when libpng fills a png_text structure it combines these members with
+the key member, and png_free_data() will free only text_ptr.key. Similarly,
+if you transfer responsibility for free'ing text_ptr from libpng to your
+application, your application must not separately free those members.
+
+The png_free_data() function will turn off the "valid" flag for anything
+it frees. If you need to turn the flag off for a chunk that was freed by your
+application instead of by libpng, you can use
+
+ png_set_invalid(png_ptr, info_ptr, mask);
+ mask - identifies the chunks to be made invalid,
+ containing the logical OR of one or
+ more of
+ PNG_INFO_gAMA, PNG_INFO_sBIT,
+ PNG_INFO_cHRM, PNG_INFO_PLTE,
+ PNG_INFO_tRNS, PNG_INFO_bKGD,
+ PNG_INFO_hIST, PNG_INFO_pHYs,
+ PNG_INFO_oFFs, PNG_INFO_tIME,
+ PNG_INFO_pCAL, PNG_INFO_sRGB,
+ PNG_INFO_iCCP, PNG_INFO_sPLT,
+ PNG_INFO_sCAL, PNG_INFO_IDAT
+
+For a more compact example of reading a PNG image, see the file example.c.
+
+Reading PNG files progressively
+
+The progressive reader is slightly different then the non-progressive
+reader. Instead of calling png_read_info(), png_read_rows(), and
+png_read_end(), you make one call to png_process_data(), which calls
+callbacks when it has the info, a row, or the end of the image. You
+set up these callbacks with png_set_progressive_read_fn(). You don't
+have to worry about the input/output functions of libpng, as you are
+giving the library the data directly in png_process_data(). I will
+assume that you have read the section on reading PNG files above,
+so I will only highlight the differences (although I will show
+all of the code).
+
+png_structp png_ptr;
+png_infop info_ptr;
+
+ /* An example code fragment of how you would
+ initialize the progressive reader in your
+ application. */
+ int
+ initialize_png_reader()
+ {
+ png_ptr = png_create_read_struct
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn);
+ if (!png_ptr)
+ return (ERROR);
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_read_struct(&png_ptr, (png_infopp)NULL,
+ (png_infopp)NULL);
+ return (ERROR);
+ }
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ (png_infopp)NULL);
+ return (ERROR);
+ }
+
+ /* This one's new. You can provide functions
+ to be called when the header info is valid,
+ when each row is completed, and when the image
+ is finished. If you aren't using all functions,
+ you can specify NULL parameters. Even when all
+ three functions are NULL, you need to call
+ png_set_progressive_read_fn(). You can use
+ any struct as the user_ptr (cast to a void pointer
+ for the function call), and retrieve the pointer
+ from inside the callbacks using the function
+
+ png_get_progressive_ptr(png_ptr);
+
+ which will return a void pointer, which you have
+ to cast appropriately.
+ */
+ png_set_progressive_read_fn(png_ptr, (void *)user_ptr,
+ info_callback, row_callback, end_callback);
+
+ return 0;
+ }
+
+ /* A code fragment that you call as you receive blocks
+ of data */
+ int
+ process_data(png_bytep buffer, png_uint_32 length)
+ {
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ (png_infopp)NULL);
+ return (ERROR);
+ }
+
+ /* This one's new also. Simply give it a chunk
+ of data from the file stream (in order, of
+ course). On machines with segmented memory
+ models machines, don't give it any more than
+ 64K. The library seems to run fine with sizes
+ of 4K. Although you can give it much less if
+ necessary (I assume you can give it chunks of
+ 1 byte, I haven't tried less then 256 bytes
+ yet). When this function returns, you may
+ want to display any rows that were generated
+ in the row callback if you don't already do
+ so there.
+ */
+ png_process_data(png_ptr, info_ptr, buffer, length);
+ return 0;
+ }
+
+ /* This function is called (as set by
+ png_set_progressive_read_fn() above) when enough data
+ has been supplied so all of the header has been
+ read.
+ */
+ void
+ info_callback(png_structp png_ptr, png_infop info)
+ {
+ /* Do any setup here, including setting any of
+ the transformations mentioned in the Reading
+ PNG files section. For now, you _must_ call
+ either png_start_read_image() or
+ png_read_update_info() after all the
+ transformations are set (even if you don't set
+ any). You may start getting rows before
+ png_process_data() returns, so this is your
+ last chance to prepare for that.
+ */
+ }
+
+ /* This function is called when each row of image
+ data is complete */
+ void
+ row_callback(png_structp png_ptr, png_bytep new_row,
+ png_uint_32 row_num, int pass)
+ {
+ /* If the image is interlaced, and you turned
+ on the interlace handler, this function will
+ be called for every row in every pass. Some
+ of these rows will not be changed from the
+ previous pass. When the row is not changed,
+ the new_row variable will be NULL. The rows
+ and passes are called in order, so you don't
+ really need the row_num and pass, but I'm
+ supplying them because it may make your life
+ easier.
+
+ For the non-NULL rows of interlaced images,
+ you must call png_progressive_combine_row()
+ passing in the row and the old row. You can
+ call this function for NULL rows (it will just
+ return) and for non-interlaced images (it just
+ does the memcpy for you) if it will make the
+ code easier. Thus, you can just do this for
+ all cases:
+ */
+
+ png_progressive_combine_row(png_ptr, old_row,
+ new_row);
+
+ /* where old_row is what was displayed for
+ previously for the row. Note that the first
+ pass (pass == 0, really) will completely cover
+ the old row, so the rows do not have to be
+ initialized. After the first pass (and only
+ for interlaced images), you will have to pass
+ the current row, and the function will combine
+ the old row and the new row.
+ */
+ }
+
+ void
+ end_callback(png_structp png_ptr, png_infop info)
+ {
+ /* This function is called after the whole image
+ has been read, including any chunks after the
+ image (up to and including the IEND). You
+ will usually have the same info chunk as you
+ had in the header, although some data may have
+ been added to the comments and time fields.
+
+ Most people won't do much here, perhaps setting
+ a flag that marks the image as finished.
+ */
+ }
+
+
+
+IV. Writing
+
+Much of this is very similar to reading. However, everything of
+importance is repeated here, so you won't have to constantly look
+back up in the reading section to understand writing.
+
+Setup
+
+You will want to do the I/O initialization before you get into libpng,
+so if it doesn't work, you don't have anything to undo. If you are not
+using the standard I/O functions, you will need to replace them with
+custom writing functions. See the discussion under Customizing libpng.
+
+ FILE *fp = fopen(file_name, "wb");
+ if (!fp)
+ {
+ return (ERROR);
+ }
+
+Next, png_struct and png_info need to be allocated and initialized.
+As these can be both relatively large, you may not want to store these
+on the stack, unless you have stack space to spare. Of course, you
+will want to check if they return NULL. If you are also reading,
+you won't want to name your read structure and your write structure
+both "png_ptr"; you can call them anything you like, such as
+"read_ptr" and "write_ptr". Look at pngtest.c, for example.
+
+ png_structp png_ptr = png_create_write_struct
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn);
+ if (!png_ptr)
+ return (ERROR);
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_write_struct(&png_ptr,
+ (png_infopp)NULL);
+ return (ERROR);
+ }
+
+If you want to use your own memory allocation routines,
+define PNG_USER_MEM_SUPPORTED and use
+png_create_write_struct_2() instead of png_create_write_struct():
+
+ png_structp png_ptr = png_create_write_struct_2
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn, (png_voidp)
+ user_mem_ptr, user_malloc_fn, user_free_fn);
+
+After you have these structures, you will need to set up the
+error handling. When libpng encounters an error, it expects to
+longjmp() back to your routine. Therefore, you will need to call
+setjmp() and pass the png_jmpbuf(png_ptr). If you
+write the file from different routines, you will need to update
+the png_jmpbuf(png_ptr) every time you enter a new routine that will
+call a png_*() function. See your documentation of setjmp/longjmp
+for your compiler for more information on setjmp/longjmp. See
+the discussion on libpng error handling in the Customizing Libpng
+section below for more information on the libpng error handling.
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ fclose(fp);
+ return (ERROR);
+ }
+ ...
+ return;
+
+If you would rather avoid the complexity of setjmp/longjmp issues,
+you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case
+errors will result in a call to PNG_ABORT() which defaults to abort().
+
+Now you need to set up the output code. The default for libpng is to
+use the C function fwrite(). If you use this, you will need to pass a
+valid FILE * in the function png_init_io(). Be sure that the file is
+opened in binary mode. Again, if you wish to handle writing data in
+another way, see the discussion on libpng I/O handling in the Customizing
+Libpng section below.
+
+ png_init_io(png_ptr, fp);
+
+Write callbacks
+
+At this point, you can set up a callback function that will be
+called after each row has been written, which you can use to control
+a progress meter or the like. It's demonstrated in pngtest.c.
+You must supply a function
+
+ void write_row_callback(png_ptr, png_uint_32 row,
+ int pass);
+ {
+ /* put your code here */
+ }
+
+(You can give it another name that you like instead of "write_row_callback")
+
+To inform libpng about your function, use
+
+ png_set_write_status_fn(png_ptr, write_row_callback);
+
+You now have the option of modifying how the compression library will
+run. The following functions are mainly for testing, but may be useful
+in some cases, like if you need to write PNG files extremely fast and
+are willing to give up some compression, or if you want to get the
+maximum possible compression at the expense of slower writing. If you
+have no special needs in this area, let the library do what it wants by
+not calling this function at all, as it has been tuned to deliver a good
+speed/compression ratio. The second parameter to png_set_filter() is
+the filter method, for which the only valid values are 0 (as of the
+July 1999 PNG specification, version 1.2) or 64 (if you are writing
+a PNG datastream that is to be embedded in a MNG datastream). The third
+parameter is a flag that indicates which filter type(s) are to be tested
+for each scanline. See the PNG specification for details on the specific filter
+types.
+
+
+ /* turn on or off filtering, and/or choose
+ specific filters. You can use either a single
+ PNG_FILTER_VALUE_NAME or the logical OR of one
+ or more PNG_FILTER_NAME masks. */
+ png_set_filter(png_ptr, 0,
+ PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE |
+ PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB |
+ PNG_FILTER_UP | PNG_FILTER_VALUE_UP |
+ PNG_FILTER_AVE | PNG_FILTER_VALUE_AVE |
+ PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH|
+ PNG_ALL_FILTERS);
+
+If an application
+wants to start and stop using particular filters during compression,
+it should start out with all of the filters (to ensure that the previous
+row of pixels will be stored in case it's needed later), and then add
+and remove them after the start of compression.
+
+If you are writing a PNG datastream that is to be embedded in a MNG
+datastream, the second parameter can be either 0 or 64.
+
+The png_set_compression_*() functions interface to the zlib compression
+library, and should mostly be ignored unless you really know what you are
+doing. The only generally useful call is png_set_compression_level()
+which changes how much time zlib spends on trying to compress the image
+data. See the Compression Library (zlib.h and algorithm.txt, distributed
+with zlib) for details on the compression levels.
+
+ /* set the zlib compression level */
+ png_set_compression_level(png_ptr,
+ Z_BEST_COMPRESSION);
+
+ /* set other zlib parameters */
+ png_set_compression_mem_level(png_ptr, 8);
+ png_set_compression_strategy(png_ptr,
+ Z_DEFAULT_STRATEGY);
+ png_set_compression_window_bits(png_ptr, 15);
+ png_set_compression_method(png_ptr, 8);
+ png_set_compression_buffer_size(png_ptr, 8192)
+
+extern PNG_EXPORT(void,png_set_zbuf_size)
+
+Setting the contents of info for output
+
+You now need to fill in the png_info structure with all the data you
+wish to write before the actual image. Note that the only thing you
+are allowed to write after the image is the text chunks and the time
+chunk (as of PNG Specification 1.2, anyway). See png_write_end() and
+the latest PNG specification for more information on that. If you
+wish to write them before the image, fill them in now, and flag that
+data as being valid. If you want to wait until after the data, don't
+fill them until png_write_end(). For all the fields in png_info and
+their data types, see png.h. For explanations of what the fields
+contain, see the PNG specification.
+
+Some of the more important parts of the png_info are:
+
+ png_set_IHDR(png_ptr, info_ptr, width, height,
+ bit_depth, color_type, interlace_type,
+ compression_type, filter_method)
+ width - holds the width of the image
+ in pixels (up to 2^31).
+ height - holds the height of the image
+ in pixels (up to 2^31).
+ bit_depth - holds the bit depth of one of the
+ image channels.
+ (valid values are 1, 2, 4, 8, 16
+ and depend also on the
+ color_type. See also significant
+ bits (sBIT) below).
+ color_type - describes which color/alpha
+ channels are present.
+ PNG_COLOR_TYPE_GRAY
+ (bit depths 1, 2, 4, 8, 16)
+ PNG_COLOR_TYPE_GRAY_ALPHA
+ (bit depths 8, 16)
+ PNG_COLOR_TYPE_PALETTE
+ (bit depths 1, 2, 4, 8)
+ PNG_COLOR_TYPE_RGB
+ (bit_depths 8, 16)
+ PNG_COLOR_TYPE_RGB_ALPHA
+ (bit_depths 8, 16)
+
+ PNG_COLOR_MASK_PALETTE
+ PNG_COLOR_MASK_COLOR
+ PNG_COLOR_MASK_ALPHA
+
+ interlace_type - PNG_INTERLACE_NONE or
+ PNG_INTERLACE_ADAM7
+ compression_type - (must be
+ PNG_COMPRESSION_TYPE_DEFAULT)
+ filter_method - (must be PNG_FILTER_TYPE_DEFAULT
+ or, if you are writing a PNG to
+ be embedded in a MNG datastream,
+ can also be
+ PNG_INTRAPIXEL_DIFFERENCING)
+
+ png_set_PLTE(png_ptr, info_ptr, palette,
+ num_palette);
+ palette - the palette for the file
+ (array of png_color)
+ num_palette - number of entries in the palette
+
+ png_set_gAMA(png_ptr, info_ptr, gamma);
+ gamma - the gamma the image was created
+ at (PNG_INFO_gAMA)
+
+ png_set_sRGB(png_ptr, info_ptr, srgb_intent);
+ srgb_intent - the rendering intent
+ (PNG_INFO_sRGB) The presence of
+ the sRGB chunk means that the pixel
+ data is in the sRGB color space.
+ This chunk also implies specific
+ values of gAMA and cHRM. Rendering
+ intent is the CSS-1 property that
+ has been defined by the International
+ Color Consortium
+ (http://www.color.org).
+ It can be one of
+ PNG_sRGB_INTENT_SATURATION,
+ PNG_sRGB_INTENT_PERCEPTUAL,
+ PNG_sRGB_INTENT_ABSOLUTE, or
+ PNG_sRGB_INTENT_RELATIVE.
+
+
+ png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr,
+ srgb_intent);
+ srgb_intent - the rendering intent
+ (PNG_INFO_sRGB) The presence of the
+ sRGB chunk means that the pixel
+ data is in the sRGB color space.
+ This function also causes gAMA and
+ cHRM chunks with the specific values
+ that are consistent with sRGB to be
+ written.
+
+ png_set_iCCP(png_ptr, info_ptr, name, compression_type,
+ profile, proflen);
+ name - The profile name.
+ compression - The compression type; always
+ PNG_COMPRESSION_TYPE_BASE for PNG 1.0.
+ You may give NULL to this argument to
+ ignore it.
+ profile - International Color Consortium color
+ profile data. May contain NULs.
+ proflen - length of profile data in bytes.
+
+ png_set_sBIT(png_ptr, info_ptr, sig_bit);
+ sig_bit - the number of significant bits for
+ (PNG_INFO_sBIT) each of the gray, red,
+ green, and blue channels, whichever are
+ appropriate for the given color type
+ (png_color_16)
+
+ png_set_tRNS(png_ptr, info_ptr, trans, num_trans,
+ trans_values);
+ trans - array of transparent entries for
+ palette (PNG_INFO_tRNS)
+ trans_values - graylevel or color sample values of
+ the single transparent color for
+ non-paletted images (PNG_INFO_tRNS)
+ num_trans - number of transparent entries
+ (PNG_INFO_tRNS)
+
+ png_set_hIST(png_ptr, info_ptr, hist);
+ (PNG_INFO_hIST)
+ hist - histogram of palette (array of
+ png_uint_16)
+
+ png_set_tIME(png_ptr, info_ptr, mod_time);
+ mod_time - time image was last modified
+ (PNG_VALID_tIME)
+
+ png_set_bKGD(png_ptr, info_ptr, background);
+ background - background color (PNG_VALID_bKGD)
+
+ png_set_text(png_ptr, info_ptr, text_ptr, num_text);
+ text_ptr - array of png_text holding image
+ comments
+ text_ptr[i].compression - type of compression used
+ on "text" PNG_TEXT_COMPRESSION_NONE
+ PNG_TEXT_COMPRESSION_zTXt
+ PNG_ITXT_COMPRESSION_NONE
+ PNG_ITXT_COMPRESSION_zTXt
+ text_ptr[i].key - keyword for comment. Must contain
+ 1-79 characters.
+ text_ptr[i].text - text comments for current
+ keyword. Can be NULL or empty.
+ text_ptr[i].text_length - length of text string,
+ after decompression, 0 for iTXt
+ text_ptr[i].itxt_length - length of itxt string,
+ after decompression, 0 for tEXt/zTXt
+ text_ptr[i].lang - language of comment (NULL or
+ empty for unknown).
+ text_ptr[i].translated_keyword - keyword in UTF-8 (NULL
+ or empty for unknown).
+ num_text - number of comments
+
+ png_set_sPLT(png_ptr, info_ptr, &palette_ptr,
+ num_spalettes);
+ palette_ptr - array of png_sPLT_struct structures
+ to be added to the list of palettes
+ in the info structure.
+ num_spalettes - number of palette structures to be
+ added.
+
+ png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y,
+ unit_type);
+ offset_x - positive offset from the left
+ edge of the screen
+ offset_y - positive offset from the top
+ edge of the screen
+ unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER
+
+ png_set_pHYs(png_ptr, info_ptr, res_x, res_y,
+ unit_type);
+ res_x - pixels/unit physical resolution
+ in x direction
+ res_y - pixels/unit physical resolution
+ in y direction
+ unit_type - PNG_RESOLUTION_UNKNOWN,
+ PNG_RESOLUTION_METER
+
+ png_set_sCAL(png_ptr, info_ptr, unit, width, height)
+ unit - physical scale units (an integer)
+ width - width of a pixel in physical scale units
+ height - height of a pixel in physical scale units
+ (width and height are doubles)
+
+ png_set_sCAL_s(png_ptr, info_ptr, unit, width, height)
+ unit - physical scale units (an integer)
+ width - width of a pixel in physical scale units
+ height - height of a pixel in physical scale units
+ (width and height are strings like "2.54")
+
+ png_set_unknown_chunks(png_ptr, info_ptr, &unknowns,
+ num_unknowns)
+ unknowns - array of png_unknown_chunk
+ structures holding unknown chunks
+ unknowns[i].name - name of unknown chunk
+ unknowns[i].data - data of unknown chunk
+ unknowns[i].size - size of unknown chunk's data
+ unknowns[i].location - position to write chunk in file
+ 0: do not write chunk
+ PNG_HAVE_IHDR: before PLTE
+ PNG_HAVE_PLTE: before IDAT
+ PNG_AFTER_IDAT: after IDAT
+
+The "location" member is set automatically according to
+what part of the output file has already been written.
+You can change its value after calling png_set_unknown_chunks()
+as demonstrated in pngtest.c. Within each of the "locations",
+the chunks are sequenced according to their position in the
+structure (that is, the value of "i", which is the order in which
+the chunk was either read from the input file or defined with
+png_set_unknown_chunks).
+
+A quick word about text and num_text. text is an array of png_text
+structures. num_text is the number of valid structures in the array.
+Each png_text structure holds a language code, a keyword, a text value,
+and a compression type.
+
+The compression types have the same valid numbers as the compression
+types of the image data. Currently, the only valid number is zero.
+However, you can store text either compressed or uncompressed, unlike
+images, which always have to be compressed. So if you don't want the
+text compressed, set the compression type to PNG_TEXT_COMPRESSION_NONE.
+Because tEXt and zTXt chunks don't have a language field, if you
+specify PNG_TEXT_COMPRESSION_NONE or PNG_TEXT_COMPRESSION_zTXt
+any language code or translated keyword will not be written out.
+
+Until text gets around 1000 bytes, it is not worth compressing it.
+After the text has been written out to the file, the compression type
+is set to PNG_TEXT_COMPRESSION_NONE_WR or PNG_TEXT_COMPRESSION_zTXt_WR,
+so that it isn't written out again at the end (in case you are calling
+png_write_end() with the same struct.
+
+The keywords that are given in the PNG Specification are:
+
+ Title Short (one line) title or
+ caption for image
+ Author Name of image's creator
+ Description Description of image (possibly long)
+ Copyright Copyright notice
+ Creation Time Time of original image creation
+ (usually RFC 1123 format, see below)
+ Software Software used to create the image
+ Disclaimer Legal disclaimer
+ Warning Warning of nature of content
+ Source Device used to create the image
+ Comment Miscellaneous comment; conversion
+ from other image format
+
+The keyword-text pairs work like this. Keywords should be short
+simple descriptions of what the comment is about. Some typical
+keywords are found in the PNG specification, as is some recommendations
+on keywords. You can repeat keywords in a file. You can even write
+some text before the image and some after. For example, you may want
+to put a description of the image before the image, but leave the
+disclaimer until after, so viewers working over modem connections
+don't have to wait for the disclaimer to go over the modem before
+they start seeing the image. Finally, keywords should be full
+words, not abbreviations. Keywords and text are in the ISO 8859-1
+(Latin-1) character set (a superset of regular ASCII) and can not
+contain NUL characters, and should not contain control or other
+unprintable characters. To make the comments widely readable, stick
+with basic ASCII, and avoid machine specific character set extensions
+like the IBM-PC character set. The keyword must be present, but
+you can leave off the text string on non-compressed pairs.
+Compressed pairs must have a text string, as only the text string
+is compressed anyway, so the compression would be meaningless.
+
+PNG supports modification time via the png_time structure. Two
+conversion routines are provided, png_convert_from_time_t() for
+time_t and png_convert_from_struct_tm() for struct tm. The
+time_t routine uses gmtime(). You don't have to use either of
+these, but if you wish to fill in the png_time structure directly,
+you should provide the time in universal time (GMT) if possible
+instead of your local time. Note that the year number is the full
+year (e.g. 1998, rather than 98 - PNG is year 2000 compliant!), and
+that months start with 1.
+
+If you want to store the time of the original image creation, you should
+use a plain tEXt chunk with the "Creation Time" keyword. This is
+necessary because the "creation time" of a PNG image is somewhat vague,
+depending on whether you mean the PNG file, the time the image was
+created in a non-PNG format, a still photo from which the image was
+scanned, or possibly the subject matter itself. In order to facilitate
+machine-readable dates, it is recommended that the "Creation Time"
+tEXt chunk use RFC 1123 format dates (e.g. "22 May 1997 18:07:10 GMT"),
+although this isn't a requirement. Unlike the tIME chunk, the
+"Creation Time" tEXt chunk is not expected to be automatically changed
+by the software. To facilitate the use of RFC 1123 dates, a function
+png_convert_to_rfc1123(png_timep) is provided to convert from PNG
+time to an RFC 1123 format string.
+
+Writing unknown chunks
+
+You can use the png_set_unknown_chunks function to queue up chunks
+for writing. You give it a chunk name, raw data, and a size; that's
+all there is to it. The chunks will be written by the next following
+png_write_info_before_PLTE, png_write_info, or png_write_end function.
+Any chunks previously read into the info structure's unknown-chunk
+list will also be written out in a sequence that satisfies the PNG
+specification's ordering rules.
+
+The high-level write interface
+
+At this point there are two ways to proceed; through the high-level
+write interface, or through a sequence of low-level write operations.
+You can use the high-level interface if your image data is present
+in the info structure. All defined output
+transformations are permitted, enabled by the following masks.
+
+ PNG_TRANSFORM_IDENTITY No transformation
+ PNG_TRANSFORM_PACKING Pack 1, 2 and 4-bit samples
+ PNG_TRANSFORM_PACKSWAP Change order of packed
+ pixels to LSB first
+ PNG_TRANSFORM_INVERT_MONO Invert monochrome images
+ PNG_TRANSFORM_SHIFT Normalize pixels to the
+ sBIT depth
+ PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA
+ to BGRA
+ PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA
+ to AG
+ PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity
+ to transparency
+ PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples
+ PNG_TRANSFORM_STRIP_FILLER Strip out filler bytes.
+
+If you have valid image data in the info structure (you can use
+png_set_rows() to put image data in the info structure), simply do this:
+
+ png_write_png(png_ptr, info_ptr, png_transforms, NULL)
+
+where png_transforms is an integer containing the logical OR of some set of
+transformation flags. This call is equivalent to png_write_info(),
+followed the set of transformations indicated by the transform mask,
+then png_write_image(), and finally png_write_end().
+
+(The final parameter of this call is not yet used. Someday it might point
+to transformation parameters required by some future output transform.)
+
+The low-level write interface
+
+If you are going the low-level route instead, you are now ready to
+write all the file information up to the actual image data. You do
+this with a call to png_write_info().
+
+ png_write_info(png_ptr, info_ptr);
+
+Note that there is one transformation you may need to do before
+png_write_info(). In PNG files, the alpha channel in an image is the
+level of opacity. If your data is supplied as a level of
+transparency, you can invert the alpha channel before you write it, so
+that 0 is fully transparent and 255 (in 8-bit or paletted images) or
+65535 (in 16-bit images) is fully opaque, with
+
+ png_set_invert_alpha(png_ptr);
+
+This must appear before png_write_info() instead of later with the
+other transformations because in the case of paletted images the tRNS
+chunk data has to be inverted before the tRNS chunk is written. If
+your image is not a paletted image, the tRNS data (which in such cases
+represents a single color to be rendered as transparent) won't need to
+be changed, and you can safely do this transformation after your
+png_write_info() call.
+
+If you need to write a private chunk that you want to appear before
+the PLTE chunk when PLTE is present, you can write the PNG info in
+two steps, and insert code to write your own chunk between them:
+
+ png_write_info_before_PLTE(png_ptr, info_ptr);
+ png_set_unknown_chunks(png_ptr, info_ptr, ...);
+ png_write_info(png_ptr, info_ptr);
+
+After you've written the file information, you can set up the library
+to handle any special transformations of the image data. The various
+ways to transform the data will be described in the order that they
+should occur. This is important, as some of these change the color
+type and/or bit depth of the data, and some others only work on
+certain color types and bit depths. Even though each transformation
+checks to see if it has data that it can do something with, you should
+make sure to only enable a transformation if it will be valid for the
+data. For example, don't swap red and blue on grayscale data.
+
+PNG files store RGB pixels packed into 3 or 6 bytes. This code tells
+the library to strip input data that has 4 or 8 bytes per pixel down
+to 3 or 6 bytes (or strip 2 or 4-byte grayscale+filler data to 1 or 2
+bytes per pixel).
+
+ png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
+
+where the 0 is unused, and the location is either PNG_FILLER_BEFORE or
+PNG_FILLER_AFTER, depending upon whether the filler byte in the pixel
+is stored XRGB or RGBX.
+
+PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as
+they can, resulting in, for example, 8 pixels per byte for 1 bit files.
+If the data is supplied at 1 pixel per byte, use this code, which will
+correctly pack the pixels into a single byte:
+
+ png_set_packing(png_ptr);
+
+PNG files reduce possible bit depths to 1, 2, 4, 8, and 16. If your
+data is of another bit depth, you can write an sBIT chunk into the
+file so that decoders can recover the original data if desired.
+
+ /* Set the true bit depth of the image data */
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ sig_bit.red = true_bit_depth;
+ sig_bit.green = true_bit_depth;
+ sig_bit.blue = true_bit_depth;
+ }
+ else
+ {
+ sig_bit.gray = true_bit_depth;
+ }
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ sig_bit.alpha = true_bit_depth;
+ }
+
+ png_set_sBIT(png_ptr, info_ptr, &sig_bit);
+
+If the data is stored in the row buffer in a bit depth other than
+one supported by PNG (e.g. 3 bit data in the range 0-7 for a 4-bit PNG),
+this will scale the values to appear to be the correct bit depth as
+is required by PNG.
+
+ png_set_shift(png_ptr, &sig_bit);
+
+PNG files store 16 bit pixels in network byte order (big-endian,
+ie. most significant bits first). This code would be used if they are
+supplied the other way (little-endian, i.e. least significant bits
+first, the way PCs store them):
+
+ if (bit_depth > 8)
+ png_set_swap(png_ptr);
+
+If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you
+need to change the order the pixels are packed into bytes, you can use:
+
+ if (bit_depth < 8)
+ png_set_packswap(png_ptr);
+
+PNG files store 3 color pixels in red, green, blue order. This code
+would be used if they are supplied as blue, green, red:
+
+ png_set_bgr(png_ptr);
+
+PNG files describe monochrome as black being zero and white being
+one. This code would be used if the pixels are supplied with this reversed
+(black being one and white being zero):
+
+ png_set_invert_mono(png_ptr);
+
+Finally, you can write your own transformation function if none of
+the existing ones meets your needs. This is done by setting a callback
+with
+
+ png_set_write_user_transform_fn(png_ptr,
+ write_transform_fn);
+
+You must supply the function
+
+ void write_transform_fn(png_ptr ptr, row_info_ptr
+ row_info, png_bytep data)
+
+See pngtest.c for a working example. Your function will be called
+before any of the other transformations are processed.
+
+You can also set up a pointer to a user structure for use by your
+callback function.
+
+ png_set_user_transform_info(png_ptr, user_ptr, 0, 0);
+
+The user_channels and user_depth parameters of this function are ignored
+when writing; you can set them to zero as shown.
+
+You can retrieve the pointer via the function png_get_user_transform_ptr().
+For example:
+
+ voidp write_user_transform_ptr =
+ png_get_user_transform_ptr(png_ptr);
+
+It is possible to have libpng flush any pending output, either manually,
+or automatically after a certain number of lines have been written. To
+flush the output stream a single time call:
+
+ png_write_flush(png_ptr);
+
+and to have libpng flush the output stream periodically after a certain
+number of scanlines have been written, call:
+
+ png_set_flush(png_ptr, nrows);
+
+Note that the distance between rows is from the last time png_write_flush()
+was called, or the first row of the image if it has never been called.
+So if you write 50 lines, and then png_set_flush 25, it will flush the
+output on the next scanline, and every 25 lines thereafter, unless
+png_write_flush() is called before 25 more lines have been written.
+If nrows is too small (less than about 10 lines for a 640 pixel wide
+RGB image) the image compression may decrease noticeably (although this
+may be acceptable for real-time applications). Infrequent flushing will
+only degrade the compression performance by a few percent over images
+that do not use flushing.
+
+Writing the image data
+
+That's it for the transformations. Now you can write the image data.
+The simplest way to do this is in one function call. If you have the
+whole image in memory, you can just call png_write_image() and libpng
+will write the image. You will need to pass in an array of pointers to
+each row. This function automatically handles interlacing, so you don't
+need to call png_set_interlace_handling() or call this function multiple
+times, or any of that other stuff necessary with png_write_rows().
+
+ png_write_image(png_ptr, row_pointers);
+
+where row_pointers is:
+
+ png_byte *row_pointers[height];
+
+You can point to void or char or whatever you use for pixels.
+
+If you don't want to write the whole image at once, you can
+use png_write_rows() instead. If the file is not interlaced,
+this is simple:
+
+ png_write_rows(png_ptr, row_pointers,
+ number_of_rows);
+
+row_pointers is the same as in the png_write_image() call.
+
+If you are just writing one row at a time, you can do this with
+a single row_pointer instead of an array of row_pointers:
+
+ png_bytep row_pointer = row;
+
+ png_write_row(png_ptr, row_pointer);
+
+When the file is interlaced, things can get a good deal more
+complicated. The only currently (as of the PNG Specification
+version 1.2, dated July 1999) defined interlacing scheme for PNG files
+is the "Adam7" interlace scheme, that breaks down an
+image into seven smaller images of varying size. libpng will build
+these images for you, or you can do them yourself. If you want to
+build them yourself, see the PNG specification for details of which
+pixels to write when.
+
+If you don't want libpng to handle the interlacing details, just
+use png_set_interlace_handling() and call png_write_rows() the
+correct number of times to write all seven sub-images.
+
+If you want libpng to build the sub-images, call this before you start
+writing any rows:
+
+ number_of_passes =
+ png_set_interlace_handling(png_ptr);
+
+This will return the number of passes needed. Currently, this
+is seven, but may change if another interlace type is added.
+
+Then write the complete image number_of_passes times.
+
+ png_write_rows(png_ptr, row_pointers,
+ number_of_rows);
+
+As some of these rows are not used, and thus return immediately,
+you may want to read about interlacing in the PNG specification,
+and only update the rows that are actually used.
+
+Finishing a sequential write
+
+After you are finished writing the image, you should finish writing
+the file. If you are interested in writing comments or time, you should
+pass an appropriately filled png_info pointer. If you are not interested,
+you can pass NULL.
+
+ png_write_end(png_ptr, info_ptr);
+
+When you are done, you can free all memory used by libpng like this:
+
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+It is also possible to individually free the info_ptr members that
+point to libpng-allocated storage with the following function:
+
+ png_free_data(png_ptr, info_ptr, mask, seq)
+ mask - identifies data to be freed, a mask
+ containing the logical OR of one or
+ more of
+ PNG_FREE_PLTE, PNG_FREE_TRNS,
+ PNG_FREE_HIST, PNG_FREE_ICCP,
+ PNG_FREE_PCAL, PNG_FREE_ROWS,
+ PNG_FREE_SCAL, PNG_FREE_SPLT,
+ PNG_FREE_TEXT, PNG_FREE_UNKN,
+ or simply PNG_FREE_ALL
+ seq - sequence number of item to be freed
+ (-1 for all items)
+
+This function may be safely called when the relevant storage has
+already been freed, or has not yet been allocated, or was allocated
+by the user and not by libpng, and will in those
+cases do nothing. The "seq" parameter is ignored if only one item
+of the selected data type, such as PLTE, is allowed. If "seq" is not
+-1, and multiple items are allowed for the data type identified in
+the mask, such as text or sPLT, only the n'th item in the structure
+is freed, where n is "seq".
+
+If you allocated data such as a palette that you passed
+in to libpng with png_set_*, you must not free it until just before the call to
+png_destroy_write_struct().
+
+The default behavior is only to free data that was allocated internally
+by libpng. This can be changed, so that libpng will not free the data,
+or so that it will free data that was allocated by the user with png_malloc()
+or png_zalloc() and passed in via a png_set_*() function, with
+
+ png_data_freer(png_ptr, info_ptr, freer, mask)
+ mask - which data elements are affected
+ same choices as in png_free_data()
+ freer - one of
+ PNG_DESTROY_WILL_FREE_DATA
+ PNG_SET_WILL_FREE_DATA
+ PNG_USER_WILL_FREE_DATA
+
+For example, to transfer responsibility for some data from a read structure
+to a write structure, you could use
+
+ png_data_freer(read_ptr, read_info_ptr,
+ PNG_USER_WILL_FREE_DATA,
+ PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST)
+ png_data_freer(write_ptr, write_info_ptr,
+ PNG_DESTROY_WILL_FREE_DATA,
+ PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST)
+
+thereby briefly reassigning responsibility for freeing to the user but
+immediately afterwards reassigning it once more to the write_destroy
+function. Having done this, it would then be safe to destroy the read
+structure and continue to use the PLTE, tRNS, and hIST data in the write
+structure.
+
+This function only affects data that has already been allocated.
+You can call this function before calling after the png_set_*() functions
+to control whether the user or png_destroy_*() is supposed to free the data.
+When the user assumes responsibility for libpng-allocated data, the
+application must use
+png_free() to free it, and when the user transfers responsibility to libpng
+for data that the user has allocated, the user must have used png_malloc()
+or png_zalloc() to allocate it.
+
+If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword
+separately, do not transfer responsibility for freeing text_ptr to libpng,
+because when libpng fills a png_text structure it combines these members with
+the key member, and png_free_data() will free only text_ptr.key. Similarly,
+if you transfer responsibility for free'ing text_ptr from libpng to your
+application, your application must not separately free those members.
+For a more compact example of writing a PNG image, see the file example.c.
+
+V. Modifying/Customizing libpng:
+
+There are three issues here. The first is changing how libpng does
+standard things like memory allocation, input/output, and error handling.
+The second deals with more complicated things like adding new chunks,
+adding new transformations, and generally changing how libpng works.
+Both of those are compile-time issues; that is, they are generally
+determined at the time the code is written, and there is rarely a need
+to provide the user with a means of changing them. The third is a
+run-time issue: choosing between and/or tuning one or more alternate
+versions of computationally intensive routines; specifically, optimized
+assembly-language (and therefore compiler- and platform-dependent)
+versions.
+
+Memory allocation, input/output, and error handling
+
+All of the memory allocation, input/output, and error handling in libpng
+goes through callbacks that are user-settable. The default routines are
+in pngmem.c, pngrio.c, pngwio.c, and pngerror.c, respectively. To change
+these functions, call the appropriate png_set_*_fn() function.
+
+Memory allocation is done through the functions png_malloc(), png_zalloc(),
+and png_free(). These currently just call the standard C functions. If
+your pointers can't access more then 64K at a time, you will want to set
+MAXSEG_64K in zlib.h. Since it is unlikely that the method of handling
+memory allocation on a platform will change between applications, these
+functions must be modified in the library at compile time. If you prefer
+to use a different method of allocating and freeing data, you can use
+
+ png_set_mem_fn(png_structp png_ptr, png_voidp mem_ptr,
+ png_malloc_ptr malloc_fn, png_free_ptr free_fn)
+
+This function also provides a void pointer that can be retrieved via
+
+ mem_ptr=png_get_mem_ptr(png_ptr);
+
+Your replacement memory functions must have prototypes as follows:
+
+ png_voidp malloc_fn(png_structp png_ptr,
+ png_uint_32 size);
+ void free_fn(png_structp png_ptr, png_voidp ptr);
+
+Your malloc_fn() can return NULL in case of failure. The png_malloc()
+function will call png_error() if it receives a NULL from the system
+memory allocator or from your replacement malloc_fn().
+
+Input/Output in libpng is done through png_read() and png_write(),
+which currently just call fread() and fwrite(). The FILE * is stored in
+png_struct and is initialized via png_init_io(). If you wish to change
+the method of I/O, the library supplies callbacks that you can set
+through the function png_set_read_fn() and png_set_write_fn() at run
+time, instead of calling the png_init_io() function. These functions
+also provide a void pointer that can be retrieved via the function
+png_get_io_ptr(). For example:
+
+ png_set_read_fn(png_structp read_ptr,
+ voidp read_io_ptr, png_rw_ptr read_data_fn)
+
+ png_set_write_fn(png_structp write_ptr,
+ voidp write_io_ptr, png_rw_ptr write_data_fn,
+ png_flush_ptr output_flush_fn);
+
+ voidp read_io_ptr = png_get_io_ptr(read_ptr);
+ voidp write_io_ptr = png_get_io_ptr(write_ptr);
+
+The replacement I/O functions must have prototypes as follows:
+
+ void user_read_data(png_structp png_ptr,
+ png_bytep data, png_uint_32 length);
+ void user_write_data(png_structp png_ptr,
+ png_bytep data, png_uint_32 length);
+ void user_flush_data(png_structp png_ptr);
+
+Supplying NULL for the read, write, or flush functions sets them back
+to using the default C stream functions. It is an error to read from
+a write stream, and vice versa.
+
+Error handling in libpng is done through png_error() and png_warning().
+Errors handled through png_error() are fatal, meaning that png_error()
+should never return to its caller. Currently, this is handled via
+setjmp() and longjmp() (unless you have compiled libpng with
+PNG_SETJMP_NOT_SUPPORTED, in which case it is handled via PNG_ABORT()),
+but you could change this to do things like exit() if you should wish.
+
+On non-fatal errors, png_warning() is called
+to print a warning message, and then control returns to the calling code.
+By default png_error() and png_warning() print a message on stderr via
+fprintf() unless the library is compiled with PNG_NO_CONSOLE_IO defined
+(because you don't want the messages) or PNG_NO_STDIO defined (because
+fprintf() isn't available). If you wish to change the behavior of the error
+functions, you will need to set up your own message callbacks. These
+functions are normally supplied at the time that the png_struct is created.
+It is also possible to redirect errors and warnings to your own replacement
+functions after png_create_*_struct() has been called by calling:
+
+ png_set_error_fn(png_structp png_ptr,
+ png_voidp error_ptr, png_error_ptr error_fn,
+ png_error_ptr warning_fn);
+
+ png_voidp error_ptr = png_get_error_ptr(png_ptr);
+
+If NULL is supplied for either error_fn or warning_fn, then the libpng
+default function will be used, calling fprintf() and/or longjmp() if a
+problem is encountered. The replacement error functions should have
+parameters as follows:
+
+ void user_error_fn(png_structp png_ptr,
+ png_const_charp error_msg);
+ void user_warning_fn(png_structp png_ptr,
+ png_const_charp warning_msg);
+
+The motivation behind using setjmp() and longjmp() is the C++ throw and
+catch exception handling methods. This makes the code much easier to write,
+as there is no need to check every return code of every function call.
+However, there are some uncertainties about the status of local variables
+after a longjmp, so the user may want to be careful about doing anything after
+setjmp returns non-zero besides returning itself. Consult your compiler
+documentation for more details. For an alternative approach, you may wish
+to use the "cexcept" facility (see http://cexcept.sourceforge.net).
+
+Custom chunks
+
+If you need to read or write custom chunks, you may need to get deeper
+into the libpng code. The library now has mechanisms for storing
+and writing chunks of unknown type; you can even declare callbacks
+for custom chunks. Hoewver, this may not be good enough if the
+library code itself needs to know about interactions between your
+chunk and existing `intrinsic' chunks.
+
+If you need to write a new intrinsic chunk, first read the PNG
+specification. Acquire a first level of
+understanding of how it works. Pay particular attention to the
+sections that describe chunk names, and look at how other chunks were
+designed, so you can do things similarly. Second, check out the
+sections of libpng that read and write chunks. Try to find a chunk
+that is similar to yours and use it as a template. More details can
+be found in the comments inside the code. It is best to handle unknown
+chunks in a generic method, via callback functions, instead of by
+modifying libpng functions.
+
+If you wish to write your own transformation for the data, look through
+the part of the code that does the transformations, and check out some of
+the simpler ones to get an idea of how they work. Try to find a similar
+transformation to the one you want to add and copy off of it. More details
+can be found in the comments inside the code itself.
+
+Configuring for 16 bit platforms
+
+You will want to look into zconf.h to tell zlib (and thus libpng) that
+it cannot allocate more then 64K at a time. Even if you can, the memory
+won't be accessible. So limit zlib and libpng to 64K by defining MAXSEG_64K.
+
+Configuring for DOS
+
+For DOS users who only have access to the lower 640K, you will
+have to limit zlib's memory usage via a png_set_compression_mem_level()
+call. See zlib.h or zconf.h in the zlib library for more information.
+
+Configuring for Medium Model
+
+Libpng's support for medium model has been tested on most of the popular
+compilers. Make sure MAXSEG_64K gets defined, USE_FAR_KEYWORD gets
+defined, and FAR gets defined to far in pngconf.h, and you should be
+all set. Everything in the library (except for zlib's structure) is
+expecting far data. You must use the typedefs with the p or pp on
+the end for pointers (or at least look at them and be careful). Make
+note that the rows of data are defined as png_bytepp, which is an
+unsigned char far * far *.
+
+Configuring for gui/windowing platforms:
+
+You will need to write new error and warning functions that use the GUI
+interface, as described previously, and set them to be the error and
+warning functions at the time that png_create_*_struct() is called,
+in order to have them available during the structure initialization.
+They can be changed later via png_set_error_fn(). On some compilers,
+you may also have to change the memory allocators (png_malloc, etc.).
+
+Configuring for compiler xxx:
+
+All includes for libpng are in pngconf.h. If you need to add/change/delete
+an include, this is the place to do it. The includes that are not
+needed outside libpng are protected by the PNG_INTERNAL definition,
+which is only defined for those routines inside libpng itself. The
+files in libpng proper only include png.h, which includes pngconf.h.
+
+Configuring zlib:
+
+There are special functions to configure the compression. Perhaps the
+most useful one changes the compression level, which currently uses
+input compression values in the range 0 - 9. The library normally
+uses the default compression level (Z_DEFAULT_COMPRESSION = 6). Tests
+have shown that for a large majority of images, compression values in
+the range 3-6 compress nearly as well as higher levels, and do so much
+faster. For online applications it may be desirable to have maximum speed
+(Z_BEST_SPEED = 1). With versions of zlib after v0.99, you can also
+specify no compression (Z_NO_COMPRESSION = 0), but this would create
+files larger than just storing the raw bitmap. You can specify the
+compression level by calling:
+
+ png_set_compression_level(png_ptr, level);
+
+Another useful one is to reduce the memory level used by the library.
+The memory level defaults to 8, but it can be lowered if you are
+short on memory (running DOS, for example, where you only have 640K).
+
+ png_set_compression_mem_level(png_ptr, level);
+
+The other functions are for configuring zlib. They are not recommended
+for normal use and may result in writing an invalid PNG file. See
+zlib.h for more information on what these mean.
+
+ png_set_compression_strategy(png_ptr,
+ strategy);
+ png_set_compression_window_bits(png_ptr,
+ window_bits);
+ png_set_compression_method(png_ptr, method);
+ png_set_compression_buffer_size(png_ptr, size);
+
+Controlling row filtering
+
+If you want to control whether libpng uses filtering or not, which
+filters are used, and how it goes about picking row filters, you
+can call one of these functions. The selection and configuration
+of row filters can have a significant impact on the size and
+encoding speed and a somewhat lesser impact on the decoding speed
+of an image. Filtering is enabled by default for RGB and grayscale
+images (with and without alpha), but not for paletted images nor
+for any images with bit depths less than 8 bits/pixel.
+
+The 'method' parameter sets the main filtering method, which is
+currently only '0' in the PNG 1.2 specification. The 'filters'
+parameter sets which filter(s), if any, should be used for each
+scanline. Possible values are PNG_ALL_FILTERS and PNG_NO_FILTERS
+to turn filtering on and off, respectively.
+
+Individual filter types are PNG_FILTER_NONE, PNG_FILTER_SUB,
+PNG_FILTER_UP, PNG_FILTER_AVG, PNG_FILTER_PAETH, which can be bitwise
+ORed together with '|' to specify one or more filters to use.
+These filters are described in more detail in the PNG specification. If
+you intend to change the filter type during the course of writing
+the image, you should start with flags set for all of the filters
+you intend to use so that libpng can initialize its internal
+structures appropriately for all of the filter types.
+
+ filters = PNG_FILTER_NONE | PNG_FILTER_SUB
+ PNG_FILTER_UP | PNG_FILTER_AVE |
+ PNG_FILTER_PAETH | PNG_ALL_FILTERS;
+ or
+ filters = one of PNG_FILTER_VALUE_NONE,
+ PNG_FILTER_VALUE_SUB, PNG_FILTER_VALUE_UP,
+ PNG_FILTER_VALUE_AVE, PNG_FILTER_VALUE_PAETH
+
+ png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE,
+ filters);
+ The second parameter can also be
+ PNG_INTRAPIXEL_DIFFERENCING if you are
+ writing a PNG to be embedded in a MNG
+ datastream. This parameter must be the
+ same as the value of filter_method used
+ in png_set_IHDR().
+
+It is also possible to influence how libpng chooses from among the
+available filters. This is done in two ways - by telling it how
+important it is to keep the same filter for successive rows, and
+by telling it the relative computational costs of the filters.
+
+ double weights[3] = {1.5, 1.3, 1.1},
+ costs[PNG_FILTER_VALUE_LAST] =
+ {1.0, 1.3, 1.3, 1.5, 1.7};
+
+ png_set_filter_selection(png_ptr,
+ PNG_FILTER_SELECTION_WEIGHTED, 3,
+ weights, costs);
+
+The weights are multiplying factors that indicate to libpng that the
+row filter should be the same for successive rows unless another row filter
+is that many times better than the previous filter. In the above example,
+if the previous 3 filters were SUB, SUB, NONE, the SUB filter could have a
+"sum of absolute differences" 1.5 x 1.3 times higher than other filters
+and still be chosen, while the NONE filter could have a sum 1.1 times
+higher than other filters and still be chosen. Unspecified weights are
+taken to be 1.0, and the specified weights should probably be declining
+like those above in order to emphasize recent filters over older filters.
+
+The filter costs specify for each filter type a relative decoding cost
+to be considered when selecting row filters. This means that filters
+with higher costs are less likely to be chosen over filters with lower
+costs, unless their "sum of absolute differences" is that much smaller.
+The costs do not necessarily reflect the exact computational speeds of
+the various filters, since this would unduly influence the final image
+size.
+
+Note that the numbers above were invented purely for this example and
+are given only to help explain the function usage. Little testing has
+been done to find optimum values for either the costs or the weights.
+
+Removing unwanted object code
+
+There are a bunch of #define's in pngconf.h that control what parts of
+libpng are compiled. All the defines end in _SUPPORTED. If you are
+never going to use a capability, you can change the #define to #undef
+before recompiling libpng and save yourself code and data space, or
+you can turn off individual capabilities with defines that begin with
+PNG_NO_.
+
+You can also turn all of the transforms and ancillary chunk capabilities
+off en masse with compiler directives that define
+PNG_NO_READ[or WRITE]_TRANSFORMS, or PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS,
+or all four,
+along with directives to turn on any of the capabilities that you do
+want. The PNG_NO_READ[or WRITE]_TRANSFORMS directives disable
+the extra transformations but still leave the library fully capable of reading
+and writing PNG files with all known public chunks
+Use of the PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS directive
+produces a library that is incapable of reading or writing ancillary chunks.
+If you are not using the progressive reading capability, you can
+turn that off with PNG_NO_PROGRESSIVE_READ (don't confuse
+this with the INTERLACING capability, which you'll still have).
+
+All the reading and writing specific code are in separate files, so the
+linker should only grab the files it needs. However, if you want to
+make sure, or if you are building a stand alone library, all the
+reading files start with pngr and all the writing files start with
+pngw. The files that don't match either (like png.c, pngtrans.c, etc.)
+are used for both reading and writing, and always need to be included.
+The progressive reader is in pngpread.c
+
+If you are creating or distributing a dynamically linked library (a .so
+or DLL file), you should not remove or disable any parts of the library,
+as this will cause applications linked with different versions of the
+library to fail if they call functions not available in your library.
+The size of the library itself should not be an issue, because only
+those sections that are actually used will be loaded into memory.
+
+Requesting debug printout
+
+The macro definition PNG_DEBUG can be used to request debugging
+printout. Set it to an integer value in the range 0 to 3. Higher
+numbers result in increasing amounts of debugging information. The
+information is printed to the "stderr" file, unless another file
+name is specified in the PNG_DEBUG_FILE macro definition.
+
+When PNG_DEBUG > 0, the following functions (macros) become available:
+
+ png_debug(level, message)
+ png_debug1(level, message, p1)
+ png_debug2(level, message, p1, p2)
+
+in which "level" is compared to PNG_DEBUG to decide whether to print
+the message, "message" is the formatted string to be printed,
+and p1 and p2 are parameters that are to be embedded in the string
+according to printf-style formatting directives. For example,
+
+ png_debug1(2, "foo=%d\n", foo);
+
+is expanded to
+
+ if(PNG_DEBUG > 2)
+ fprintf(PNG_DEBUG_FILE, "foo=%d\n", foo);
+
+When PNG_DEBUG is defined but is zero, the macros aren't defined, but you
+can still use PNG_DEBUG to control your own debugging:
+
+ #ifdef PNG_DEBUG
+ fprintf(stderr, ...
+ #endif
+
+When PNG_DEBUG = 1, the macros are defined, but only png_debug statements
+having level = 0 will be printed. There aren't any such statements in
+this version of libpng, but if you insert some they will be printed.
+
+VI. Runtime optimization
+
+A new feature in libpng 1.2.0 is the ability to dynamically switch between
+standard and optimized versions of some routines. Currently these are
+limited to three computationally intensive tasks when reading PNG files:
+decoding row filters, expanding interlacing, and combining interlaced or
+transparent row data with previous row data. Currently the optimized
+versions are available only for x86 (Intel, AMD, etc.) platforms with
+MMX support, though this may change in future versions. (For example,
+the non-MMX assembler optimizations for zlib might become similarly
+runtime-selectable in future releases, in which case libpng could be
+extended to support them. Alternatively, the compile-time choice of
+floating-point versus integer routines for gamma correction might become
+runtime-selectable.)
+
+Because such optimizations tend to be very platform- and compiler-dependent,
+both in how they are written and in how they perform, the new runtime code
+in libpng has been written to allow programs to query, enable, and disable
+either specific optimizations or all such optimizations. For example, to
+enable all possible optimizations (bearing in mind that some "optimizations"
+may actually run more slowly in rare cases):
+
+ #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
+ png_uint_32 mask, flags;
+
+ flags = png_get_asm_flags(png_ptr);
+ mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
+ png_set_asm_flags(png_ptr, flags | mask);
+ #endif
+
+To enable only optimizations relevant to reading PNGs, use PNG_SELECT_READ
+by itself when calling png_get_asm_flagmask(); similarly for optimizing
+only writing. To disable all optimizations:
+
+ #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
+ flags = png_get_asm_flags(png_ptr);
+ mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
+ png_set_asm_flags(png_ptr, flags & ~mask);
+ #endif
+
+To enable or disable only MMX-related features, use png_get_mmx_flagmask()
+in place of png_get_asm_flagmask(). The mmx version takes one additional
+parameter:
+
+ #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
+ int selection = PNG_SELECT_READ | PNG_SELECT_WRITE;
+ int compilerID;
+
+ mask = png_get_mmx_flagmask(selection, &compilerID);
+ #endif
+
+On return, compilerID will indicate which version of the MMX assembler
+optimizations was compiled. Currently two flavors exist: Microsoft
+Visual C++ (compilerID == 1) and GNU C (a.k.a. gcc/gas, compilerID == 2).
+On non-x86 platforms or on systems compiled without MMX optimizations, a
+value of -1 is used.
+
+Note that both png_get_asm_flagmask() and png_get_mmx_flagmask() return
+all valid, settable optimization bits for the version of the library that's
+currently in use. In the case of shared (dynamically linked) libraries,
+this may include optimizations that did not exist at the time the code was
+written and compiled. It is also possible, of course, to enable only known,
+specific optimizations; for example:
+
+ #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
+ flags = PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
+ | PNG_ASM_FLAG_MMX_READ_INTERLACE \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_UP \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ;
+ png_set_asm_flags(png_ptr, flags);
+ #endif
+
+This method would enable only the MMX read-optimizations available at the
+time of libpng 1.2.0's release, regardless of whether a later version of
+the DLL were actually being used. (Also note that these functions did not
+exist in versions older than 1.2.0, so any attempt to run a dynamically
+linked app on such an older version would fail.)
+
+To determine whether the processor supports MMX instructions at all, use
+the png_mmx_support() function:
+
+ #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
+ mmxsupport = png_mmx_support();
+ #endif
+
+It returns -1 if MMX support is not compiled into libpng, 0 if MMX code
+is compiled but MMX is not supported by the processor, or 1 if MMX support
+is fully available. Note that png_mmx_support(), png_get_mmx_flagmask(),
+and png_get_asm_flagmask() all may be called without allocating and ini-
+tializing any PNG structures (for example, as part of a usage screen or
+"about" box).
+
+The following code can be used to prevent an application from using the
+thread_unsafe features, even if libpng was built with PNG_THREAD_UNSAFE_OK
+defined:
+
+#if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) \
+ && defined(PNG_THREAD_UNSAFE_OK)
+ /* Disable thread-unsafe features of pnggccrd */
+ if (png_access_version() >= 10200)
+ {
+ png_uint_32 mmx_disable_mask = 0;
+ png_uint_32 asm_flags;
+
+ mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
+ asm_flags = png_get_asm_flags(png_ptr);
+ png_set_asm_flags(png_ptr, asm_flags & ~mmx_disable_mask);
+ }
+#endif
+
+For more extensive examples of runtime querying, enabling and disabling
+of optimized features, see contrib/gregbook/readpng2.c in the libpng
+source-code distribution.
+
+
+VII. MNG support
+
+The MNG specification (available at http://www.libpng.org/pub/mng) allows
+certain extensions to PNG for PNG images that are embedded in MNG datastreams.
+Libpng can support some of these extensions. To enable them, use the
+png_permit_mng_features() function:
+
+ feature_set = png_permit_mng_features(png_ptr, mask)
+ mask is a png_uint_32 containing the logical OR of the
+ features you want to enable. These include
+ PNG_FLAG_MNG_EMPTY_PLTE
+ PNG_FLAG_MNG_FILTER_64
+ PNG_ALL_MNG_FEATURES
+ feature_set is a png_32_uint that is the logical AND of
+ your mask with the set of MNG features that is
+ supported by the version of libpng that you are using.
+
+It is an error to use this function when reading or writing a standalone
+PNG file with the PNG 8-byte signature. The PNG datastream must be wrapped
+in a MNG datastream. As a minimum, it must have the MNG 8-byte signature
+and the MHDR and MEND chunks. Libpng does not provide support for these
+or any other MNG chunks; your application must provide its own support for
+them. You may wish to consider using libmng (available at
+http://www.libmng.com) instead.
+
+VIII. Changes to Libpng from version 0.88
+
+It should be noted that versions of libpng later than 0.96 are not
+distributed by the original libpng author, Guy Schalnat, nor by
+Andreas Dilger, who had taken over from Guy during 1996 and 1997, and
+distributed versions 0.89 through 0.96, but rather by another member
+of the original PNG Group, Glenn Randers-Pehrson. Guy and Andreas are
+still alive and well, but they have moved on to other things.
+
+The old libpng functions png_read_init(), png_write_init(),
+png_info_init(), png_read_destroy(), and png_write_destroy() have been
+moved to PNG_INTERNAL in version 0.95 to discourage their use. These
+functions will be removed from libpng version 2.0.0.
+
+The preferred method of creating and initializing the libpng structures is
+via the png_create_read_struct(), png_create_write_struct(), and
+png_create_info_struct() because they isolate the size of the structures
+from the application, allow version error checking, and also allow the
+use of custom error handling routines during the initialization, which
+the old functions do not. The functions png_read_destroy() and
+png_write_destroy() do not actually free the memory that libpng
+allocated for these structs, but just reset the data structures, so they
+can be used instead of png_destroy_read_struct() and
+png_destroy_write_struct() if you feel there is too much system overhead
+allocating and freeing the png_struct for each image read.
+
+Setting the error callbacks via png_set_message_fn() before
+png_read_init() as was suggested in libpng-0.88 is no longer supported
+because this caused applications that do not use custom error functions
+to fail if the png_ptr was not initialized to zero. It is still possible
+to set the error callbacks AFTER png_read_init(), or to change them with
+png_set_error_fn(), which is essentially the same function, but with a new
+name to force compilation errors with applications that try to use the old
+method.
+
+Starting with version 1.0.7, you can find out which version of the library
+you are using at run-time:
+
+ png_uint_32 libpng_vn = png_access_version_number();
+
+The number libpng_vn is constructed from the major version, minor
+version with leading zero, and release number with leading zero,
+(e.g., libpng_vn for version 1.0.7 is 10007).
+
+You can also check which version of png.h you used when compiling your
+application:
+
+ png_uint_32 application_vn = PNG_LIBPNG_VER;
+
+IX. Y2K Compliance in libpng
+
+September 1, 2001
+
+Since the PNG Development group is an ad-hoc body, we can't make
+an official declaration.
+
+This is your unofficial assurance that libpng from version 0.71 and
+upward through 1.2.0 are Y2K compliant. It is my belief that earlier
+versions were also Y2K compliant.
+
+Libpng only has three year fields. One is a 2-byte unsigned integer that
+will hold years up to 65535. The other two hold the date in text
+format, and will hold years up to 9999.
+
+The integer is
+ "png_uint_16 year" in png_time_struct.
+
+The strings are
+ "png_charp time_buffer" in png_struct and
+ "near_time_buffer", which is a local character string in png.c.
+
+There are seven time-related functions:
+
+ png_convert_to_rfc_1123() in png.c
+ (formerly png_convert_to_rfc_1152() in error)
+ png_convert_from_struct_tm() in pngwrite.c, called
+ in pngwrite.c
+ png_convert_from_time_t() in pngwrite.c
+ png_get_tIME() in pngget.c
+ png_handle_tIME() in pngrutil.c, called in pngread.c
+ png_set_tIME() in pngset.c
+ png_write_tIME() in pngwutil.c, called in pngwrite.c
+
+All appear to handle dates properly in a Y2K environment. The
+png_convert_from_time_t() function calls gmtime() to convert from system
+clock time, which returns (year - 1900), which we properly convert to
+the full 4-digit year. There is a possibility that applications using
+libpng are not passing 4-digit years into the png_convert_to_rfc_1123()
+function, or that they are incorrectly passing only a 2-digit year
+instead of "year - 1900" into the png_convert_from_struct_tm() function,
+but this is not under our control. The libpng documentation has always
+stated that it works with 4-digit years, and the APIs have been
+documented as such.
+
+The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned
+integer to hold the year, and can hold years as large as 65535.
+
+zlib, upon which libpng depends, is also Y2K compliant. It contains
+no date-related code.
+
+
+ Glenn Randers-Pehrson
+ libpng maintainer
+ PNG Development Group
--- /dev/null
+.TH LIBPNGPF 3 "September 1, 2001"
+.SH NAME
+libpng \- Portable Network Graphics (PNG) Reference Library 1.2.0
+(private functions)
+.SH SYNOPSIS
+\fB#include <png.h>\fP
+
+\fI\fB
+
+\fBvoid png_build_gamma_table (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_build_grayscale_palette (int \fP\fIbit_depth\fP\fB, png_colorp \fIpalette\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_calculate_crc (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIptr\fP\fB, png_size_t \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_check_chunk_name (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIchunk_name\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_size_t png_check_keyword (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIkey\fP\fB, png_charpp \fInew_key\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_combine_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIrow\fP\fB, int \fImask\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_correct_palette (png_structp \fP\fIpng_ptr\fP\fB, png_colorp \fP\fIpalette\fP\fB, int \fInum_palette\fP\fB);\fP
+
+\fI\fB
+
+\fBint png_crc_error (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBint png_crc_finish (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIskip\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_crc_read (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIbuf\fP\fB, png_size_t \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_voidp png_create_struct (int \fItype\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_voidp png_create_struct_2 (int \fP\fItype\fP\fB, png_malloc_ptr \fP\fImalloc_fn\fP\fB, png_voidp \fImem_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_charp png_decompress_chunk (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIcomp_type\fP\fB, png_charp \fP\fIchunkdata\fP\fB, png_size_t \fP\fIchunklength\fP\fB, png_size_t \fP\fIprefix_length\fP\fB, png_size_t \fI*data_length\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_destroy_struct (png_voidp \fIstruct_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_destroy_struct_2 (png_voidp \fP\fIstruct_ptr\fP\fB, png_free_ptr \fP\fIfree_fn\fP\fB, png_voidp \fImem_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_background (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_color_16p \fP\fItrans_values\fP\fB, png_color_16p \fP\fIbackground\fP\fB, png_color_16p \fP\fIbackground_1\fP\fB, png_bytep \fP\fIgamma_table\fP\fB, png_bytep \fP\fIgamma_from_1\fP\fB, png_bytep \fP\fIgamma_to_1\fP\fB, png_uint_16pp \fP\fIgamma_16\fP\fB, png_uint_16pp \fP\fIgamma_16_from_1\fP\fB, png_uint_16pp \fP\fIgamma_16_to_1\fP\fB, int \fIgamma_shift\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_bgr (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_chop (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_dither (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_bytep \fP\fIpalette_lookup\fP\fB, png_bytep \fIdither_lookup\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_expand (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_color_16p \fItrans_value\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_expand_palette (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_colorp \fP\fIpalette\fP\fB, png_bytep \fP\fItrans\fP\fB, int \fInum_trans\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_gamma (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_bytep \fP\fIgamma_table\fP\fB, png_uint_16pp \fP\fIgamma_16_table\fP\fB, int \fIgamma_shift\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_gray_to_rgb (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_invert (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_pack (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_uint_32 \fIbit_depth\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_packswap (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_read_filler (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_uint_32 \fP\fIfiller\fP\fB, png_uint_32 \fIflags\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_read_interlace (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, int \fP\fIpass\fP\fB, png_uint_32 \fItransformations\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_read_invert_alpha (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_read_swap_alpha (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_read_transformations (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBint png_do_rgb_to_gray (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_shift (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_color_8p \fIbit_depth\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_strip_filler (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_uint_32 \fIflags\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_swap (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_unpack (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_unshift (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_color_8p \fIsig_bits\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_write_interlace (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, int \fIpass\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_write_invert_alpha (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_write_swap_alpha (png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fIrow\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_do_write_transformations (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid *png_far_to_near (png_structp png_ptr,png_voidp \fP\fIptr\fP\fB, int \fIcheck\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_flush (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_int_32 png_get_int_32 (png_bytep \fIbuf\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_16 png_get_uint_16 (png_bytep \fIbuf\fP\fB);\fP
+
+\fI\fB
+
+\fBpng_uint_32 png_get_uint_32 (png_bytep \fIbuf\fP\fB);\fP
+
+\fI\fB
+
+\fBint png_handle_as_unknown (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIchunk_name\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_handle_bKGD (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_handle_cHRM (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_handle_gAMA (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_handle_hIST (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_handle_IEND (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_handle_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_handle_iCCP (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_handle_iTXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_handle_oFFs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_handle_pCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_handle_pHYs (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_handle_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_handle_sBIT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_handle_sCAL (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_handle_sPLT (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_handle_sRGB (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_handle_tEXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_handle_tIME (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_handle_tRNS (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_handle_unknown (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_handle_zTXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_info_destroy (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_init_mmx_flags (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_init_read_transformations (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_process_IDAT_data (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIbuffer\fP\fB, png_size_t \fIbuffer_length\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_process_some_data (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_push_check_crc (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_push_crc_finish (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_push_crc_skip (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_push_fill_buffer (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIbuffer\fP\fB, png_size_t \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_push_handle_tEXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_push_handle_unknown (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_push_handle_zTXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fP\fIinfo_ptr\fP\fB, png_uint_32 \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_push_have_end (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_push_have_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_push_have_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIrow\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_push_process_row (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_push_read_chunk (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_push_read_end (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_push_read_IDAT (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_push_read_sig (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_push_read_tEXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_push_read_zTXt (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_push_restore_buffer (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIbuffer\fP\fB, png_size_t \fIbuffer_length\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_push_save_buffer (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_read_data (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_read_filter_row (png_structp \fP\fIpng_ptr\fP\fB, png_row_infop \fP\fIrow_info\fP\fB, png_bytep \fP\fIrow\fP\fB, png_bytep \fP\fIprev_row\fP\fB, int \fIfilter\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_read_finish_row (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_read_push_finish_row (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_read_start_row (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_read_transform_info (png_structp \fP\fIpng_ptr\fP\fB, png_infop \fIinfo_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_reset_crc (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_save_int_32 (png_bytep \fP\fIbuf\fP\fB, png_int_32 \fIi\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_save_uint_16 (png_bytep \fP\fIbuf\fP\fB, unsigned int \fIi\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_save_uint_32 (png_bytep \fP\fIbuf\fP\fB, png_uint_32 \fIi\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_bKGD (png_structp \fP\fIpng_ptr\fP\fB, png_color_16p \fP\fIvalues\fP\fB, int \fIcolor_type\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_cHRM (png_structp \fP\fIpng_ptr\fP\fB, double \fP\fIwhite_x\fP\fB, double \fP\fIwhite_y\fP\fB, double \fP\fIred_x\fP\fB, double \fP\fIred_y\fP\fB, double \fP\fIgreen_x\fP\fB, double \fP\fIgreen_y\fP\fB, double \fP\fIblue_x\fP\fB, double \fIblue_y\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_cHRM_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIwhite_x\fP\fB, png_uint_32 \fP\fIwhite_y\fP\fB, png_uint_32 \fP\fIred_x\fP\fB, png_uint_32 \fP\fIred_y\fP\fB, png_uint_32 \fP\fIgreen_x\fP\fB, png_uint_32 \fP\fIgreen_y\fP\fB, png_uint_32 \fP\fIblue_x\fP\fB, png_uint_32 \fIblue_y\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_data (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_filtered_row (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fIfiltered_row\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_find_filter (png_structp \fP\fIpng_ptr\fP\fB, png_row_infop \fIrow_info\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_finish_row (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_gAMA (png_structp \fP\fIpng_ptr\fP\fB, double \fIfile_gamma\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_gAMA_fixed (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fIint_file_gamma\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_hIST (png_structp \fP\fIpng_ptr\fP\fB, png_uint_16p \fP\fIhist\fP\fB, int \fInum_hist\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_iCCP (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIname\fP\fB, int \fP\fIcompression_type\fP\fB, png_charp \fP\fIprofile\fP\fB, int \fIproflen\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_IDAT (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fIdata\fP\fB, png_size_t \fIlength\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_IEND (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_IHDR (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIwidth\fP\fB, png_uint_32 \fP\fIheight\fP\fB, int \fP\fIbit_depth\fP\fB, int \fP\fIcolor_type\fP\fB, int \fP\fIcompression_type\fP\fB, int \fP\fIfilter_type\fP\fB, int \fIinterlace_type\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_iTXt (png_structp \fP\fIpng_ptr\fP\fB, int \fP\fIcompression\fP\fB, png_charp \fP\fIkey\fP\fB, png_charp \fP\fIlang\fP\fB, png_charp \fP\fItranslated_key\fP\fB, png_charp \fItext)\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_oFFs (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIx_offset\fP\fB, png_uint_32 \fP\fIy_offset\fP\fB, int \fIunit_type\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_pCAL (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIpurpose\fP\fB, png_int_32 \fP\fIX0\fP\fB, png_int_32 \fP\fIX1\fP\fB, int \fP\fItype\fP\fB, int \fP\fInparams\fP\fB, png_charp \fP\fIunits\fP\fB, png_charpp \fIparams\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_pHYs (png_structp \fP\fIpng_ptr\fP\fB, png_uint_32 \fP\fIx_pixels_per_unit\fP\fB, png_uint_32 \fP\fIy_pixels_per_unit\fP\fB, int \fIunit_type\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_PLTE (png_structp \fP\fIpng_ptr\fP\fB, png_colorp \fP\fIpalette\fP\fB, png_uint_32 \fInum_pal\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_sBIT (png_structp \fP\fIpng_ptr\fP\fB, png_color_8p \fP\fIsbit\fP\fB, int \fIcolor_type\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_sCAL (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIunit\fP\fB, double \fP\fIwidth\fP\fB, double \fIheight\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_sCAL_s (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIunit\fP\fB, png_charp \fP\fIwidth\fP\fB, png_charp \fIheight\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_sig (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_sRGB (png_structp \fP\fIpng_ptr\fP\fB, int \fIintent\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_sPLT (png_structp \fP\fIpng_ptr\fP\fB, png_spalette_p \fIpalette\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_start_row (png_structp \fIpng_ptr\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_tEXt (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIkey\fP\fB, png_charp \fP\fItext\fP\fB, png_size_t \fItext_len\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_tIME (png_structp \fP\fIpng_ptr\fP\fB, png_timep \fImod_time\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_tRNS (png_structp \fP\fIpng_ptr\fP\fB, png_bytep \fP\fItrans\fP\fB, png_color_16p \fP\fIvalues\fP\fB, int \fP\fInumber\fP\fB, int \fIcolor_type\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_write_zTXt (png_structp \fP\fIpng_ptr\fP\fB, png_charp \fP\fIkey\fP\fB, png_charp \fP\fItext\fP\fB, png_size_t \fP\fItext_len\fP\fB, int \fIcompression\fP\fB);\fP
+
+\fI\fB
+
+\fBvoidpf png_zalloc (voidpf \fP\fIpng_ptr\fP\fB, uInt \fP\fIitems\fP\fB, uInt \fIsize\fP\fB);\fP
+
+\fI\fB
+
+\fBvoid png_zfree (voidpf \fP\fIpng_ptr\fP\fB, voidpf \fIptr\fP\fB);\fP
+
+\fI\fB
+
+.SH DESCRIPTION
+The functions listed above are used privately by libpng
+and are not recommended for use by applications. They are
+not "exported" to applications using shared libraries. They
+are listed alphabetically here as an aid to libpng maintainers.
+See png.h for more information on these functions.
+
+.SH SEE ALSO
+libpng(3), png(5)
+.SH AUTHOR
+Glenn Randers-Pehrson
--- /dev/null
+.TH PNG 5 "September 1, 2001"
+.SH NAME
+png \- Portable Network Graphics (PNG) format
+.SH DESCRIPTION
+PNG (Portable Network Graphics) is an extensible file format for the
+lossless, portable, well-compressed storage of raster images. PNG provides
+a patent-free replacement for GIF and can also replace many
+common uses of TIFF. Indexed-color, grayscale, and truecolor images are
+supported, plus an optional alpha channel. Sample depths range from
+1 to 16 bits.
+.br
+
+PNG is designed to work well in online viewing applications, such as the
+World Wide Web, so it is fully streamable with a progressive display
+option. PNG is robust, providing both full file integrity checking and
+fast, simple detection of common transmission errors. Also, PNG can store
+gamma and chromaticity data for improved color matching on heterogeneous
+platforms.
+
+.SH "SEE ALSO"
+.IR libpng(3), zlib(3), deflate(5), and zlib(5)
+.LP
+PNG 1.2 specification, July 1999:
+.IP
+.br
+http://www.libpng.org/pub/png
+.br
+or ftp://ftp.uu.net/graphics/png/documents
+.LP
+PNG 1.0 specification, October 1996:
+.IP
+.br
+RFC 2083
+.IP
+.br
+ftp://ds.internic.net/rfc/rfc2083.txt
+.br
+or (as a W3C Recommendation) at
+.br
+http://www.w3.org/TR/REC-png.html
+.SH AUTHORS
+This man page: Glenn Randers-Pehrson
+.LP
+Portable Network Graphics (PNG) Specification Version 1.2 (July 8, 1999):
+Glenn Randers-Pehrson and others (png-list@ccrc.wustl.edu).
+.LP
+Portable Network Graphics (PNG) Specification Version 1.0 (October 1, 1996):
+Thomas Boutell and others (png-list@ccrc.wustl.edu).
+.LP
+
+
+.SH COPYRIGHT NOTICE
+The PNG-1.2 specification is copyright (c) 1999 Glenn Randers-Pehrson.
+See the specification for conditions of use and distribution.
+.LP
+The PNG-1.0 specification is copyright (c) 1996 Massachussets Institute of
+Technology. See the specification for conditions of use and distribution.
+.LP
+.\" end of man page
+
--- /dev/null
+
+/* png.c - location for general purpose libpng functions
+ *
+ * libpng version 1.2.0 - September 1, 2001
+ * Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ *
+ */
+
+#define PNG_INTERNAL
+#define PNG_NO_EXTERN
+#include "png.h"
+
+/* Generate a compiler error if there is an old png.h in the search path. */
+typedef version_1_2_0 Your_png_h_is_not_version_1_2_0;
+
+/* Version information for C files. This had better match the version
+ * string defined in png.h. */
+
+#ifdef PNG_USE_GLOBAL_ARRAYS
+/* png_libpng_ver was changed to a function in version 1.0.5c */
+const char png_libpng_ver[18] = "1.2.0";
+
+/* png_sig was changed to a function in version 1.0.5c */
+/* Place to hold the signature string for a PNG file. */
+const png_byte FARDATA png_sig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
+
+/* Invoke global declarations for constant strings for known chunk types */
+PNG_IHDR;
+PNG_IDAT;
+PNG_IEND;
+PNG_PLTE;
+PNG_bKGD;
+PNG_cHRM;
+PNG_gAMA;
+PNG_hIST;
+PNG_iCCP;
+PNG_iTXt;
+PNG_oFFs;
+PNG_pCAL;
+PNG_sCAL;
+PNG_pHYs;
+PNG_sBIT;
+PNG_sPLT;
+PNG_sRGB;
+PNG_tEXt;
+PNG_tIME;
+PNG_tRNS;
+PNG_zTXt;
+
+/* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+
+/* start of interlace block */
+const int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
+
+/* offset to next interlace block */
+const int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
+
+/* start of interlace block in the y direction */
+const int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
+
+/* offset to next interlace block in the y direction */
+const int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
+
+/* width of interlace block (used in assembler routines only) */
+#ifdef PNG_HAVE_ASSEMBLER_COMBINE_ROW
+const int FARDATA png_pass_width[] = {8, 4, 4, 2, 2, 1, 1};
+#endif
+
+/* Height of interlace block. This is not currently used - if you need
+ * it, uncomment it here and in png.h
+const int FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1};
+*/
+
+/* Mask to determine which pixels are valid in a pass */
+const int FARDATA png_pass_mask[] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff};
+
+/* Mask to determine which pixels to overwrite while displaying */
+const int FARDATA png_pass_dsp_mask[]
+ = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff};
+
+#endif
+
+/* Tells libpng that we have already handled the first "num_bytes" bytes
+ * of the PNG file signature. If the PNG data is embedded into another
+ * stream we can set num_bytes = 8 so that libpng will not attempt to read
+ * or write any of the magic bytes before it starts on the IHDR.
+ */
+
+void PNGAPI
+png_set_sig_bytes(png_structp png_ptr, int num_bytes)
+{
+ png_debug(1, "in png_set_sig_bytes\n");
+ if (num_bytes > 8)
+ png_error(png_ptr, "Too many bytes for PNG signature.");
+
+ png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes);
+}
+
+/* Checks whether the supplied bytes match the PNG signature. We allow
+ * checking less than the full 8-byte signature so that those apps that
+ * already read the first few bytes of a file to determine the file type
+ * can simply check the remaining bytes for extra assurance. Returns
+ * an integer less than, equal to, or greater than zero if sig is found,
+ * respectively, to be less than, to match, or be greater than the correct
+ * PNG signature (this is the same behaviour as strcmp, memcmp, etc).
+ */
+int PNGAPI
+png_sig_cmp(png_bytep sig, png_size_t start, png_size_t num_to_check)
+{
+ png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
+ if (num_to_check > 8)
+ num_to_check = 8;
+ else if (num_to_check < 1)
+ return (0);
+
+ if (start > 7)
+ return (0);
+
+ if (start + num_to_check > 8)
+ num_to_check = 8 - start;
+
+ return ((int)(png_memcmp(&sig[start], &png_signature[start], num_to_check)));
+}
+
+/* (Obsolete) function to check signature bytes. It does not allow one
+ * to check a partial signature. This function might be removed in the
+ * future - use png_sig_cmp(). Returns true (nonzero) if the file is a PNG.
+ */
+int PNGAPI
+png_check_sig(png_bytep sig, int num)
+{
+ return ((int)!png_sig_cmp(sig, (png_size_t)0, (png_size_t)num));
+}
+
+/* Function to allocate memory for zlib and clear it to 0. */
+voidpf /* PRIVATE */
+png_zalloc(voidpf png_ptr, uInt items, uInt size)
+{
+ png_uint_32 num_bytes = (png_uint_32)items * size;
+ png_voidp ptr = (png_voidp)png_malloc((png_structp)png_ptr, num_bytes);
+
+#ifndef PNG_NO_ZALLOC_ZERO
+ if (num_bytes > (png_uint_32)0x8000L)
+ {
+ png_memset(ptr, 0, (png_size_t)0x8000L);
+ png_memset((png_bytep)ptr + (png_size_t)0x8000L, 0,
+ (png_size_t)(num_bytes - (png_uint_32)0x8000L));
+ }
+ else
+ {
+ png_memset(ptr, 0, (png_size_t)num_bytes);
+ }
+#endif
+ return ((voidpf)ptr);
+}
+
+/* function to free memory for zlib */
+void /* PRIVATE */
+png_zfree(voidpf png_ptr, voidpf ptr)
+{
+ png_free((png_structp)png_ptr, (png_voidp)ptr);
+}
+
+/* Reset the CRC variable to 32 bits of 1's. Care must be taken
+ * in case CRC is > 32 bits to leave the top bits 0.
+ */
+void /* PRIVATE */
+png_reset_crc(png_structp png_ptr)
+{
+ png_ptr->crc = crc32(0, Z_NULL, 0);
+}
+
+/* Calculate the CRC over a section of data. We can only pass as
+ * much data to this routine as the largest single buffer size. We
+ * also check that this data will actually be used before going to the
+ * trouble of calculating it.
+ */
+void /* PRIVATE */
+png_calculate_crc(png_structp png_ptr, png_bytep ptr, png_size_t length)
+{
+ int need_crc = 1;
+
+ if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
+ {
+ if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
+ (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
+ need_crc = 0;
+ }
+ else /* critical */
+ {
+ if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
+ need_crc = 0;
+ }
+
+ if (need_crc)
+ png_ptr->crc = crc32(png_ptr->crc, ptr, (uInt)length);
+}
+
+/* Allocate the memory for an info_struct for the application. We don't
+ * really need the png_ptr, but it could potentially be useful in the
+ * future. This should be used in favour of malloc(sizeof(png_info))
+ * and png_info_init() so that applications that want to use a shared
+ * libpng don't have to be recompiled if png_info changes size.
+ */
+png_infop PNGAPI
+png_create_info_struct(png_structp png_ptr)
+{
+ png_infop info_ptr;
+
+ png_debug(1, "in png_create_info_struct\n");
+ if(png_ptr == NULL) return (NULL);
+#ifdef PNG_USER_MEM_SUPPORTED
+ if ((info_ptr = (png_infop)png_create_struct_2(PNG_STRUCT_INFO,
+ png_ptr->malloc_fn, png_ptr->mem_ptr)) != NULL)
+#else
+ if ((info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO)) != NULL)
+#endif
+ {
+ png_info_init_3(&info_ptr, sizeof(png_info));
+ }
+
+ return (info_ptr);
+}
+
+/* This function frees the memory associated with a single info struct.
+ * Normally, one would use either png_destroy_read_struct() or
+ * png_destroy_write_struct() to free an info struct, but this may be
+ * useful for some applications.
+ */
+void PNGAPI
+png_destroy_info_struct(png_structp png_ptr, png_infopp info_ptr_ptr)
+{
+ png_infop info_ptr = NULL;
+
+ png_debug(1, "in png_destroy_info_struct\n");
+ if (info_ptr_ptr != NULL)
+ info_ptr = *info_ptr_ptr;
+
+ if (info_ptr != NULL)
+ {
+ png_info_destroy(png_ptr, info_ptr);
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2((png_voidp)info_ptr, png_ptr->free_fn,
+ png_ptr->mem_ptr);
+#else
+ png_destroy_struct((png_voidp)info_ptr);
+#endif
+ *info_ptr_ptr = (png_infop)NULL;
+ }
+}
+
+/* Initialize the info structure. This is now an internal function (0.89)
+ * and applications using it are urged to use png_create_info_struct()
+ * instead.
+ */
+#undef png_info_init
+void PNGAPI
+png_info_init(png_infop info_ptr)
+{
+ /* We only come here via pre-1.0.12-compiled applications */
+ png_info_init_3(&info_ptr, 0);
+}
+
+void PNGAPI
+png_info_init_3(png_infopp ptr_ptr, png_size_t png_info_struct_size)
+{
+ png_infop info_ptr = *ptr_ptr;
+
+ png_debug(1, "in png_info_init_3\n");
+
+ if(sizeof(png_info) > png_info_struct_size)
+ {
+ png_destroy_struct(info_ptr);
+ info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO);
+ *ptr_ptr = info_ptr;
+ }
+
+ /* set everything to 0 */
+ png_memset(info_ptr, 0, sizeof (png_info));
+}
+
+#ifdef PNG_FREE_ME_SUPPORTED
+void PNGAPI
+png_data_freer(png_structp png_ptr, png_infop info_ptr,
+ int freer, png_uint_32 mask)
+{
+ png_debug(1, "in png_data_freer\n");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+ if(freer == PNG_DESTROY_WILL_FREE_DATA)
+ info_ptr->free_me |= mask;
+ else if(freer == PNG_USER_WILL_FREE_DATA)
+ info_ptr->free_me &= ~mask;
+ else
+ png_warning(png_ptr,
+ "Unknown freer parameter in png_data_freer.");
+}
+#endif
+
+void PNGAPI
+png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask,
+ int num)
+{
+ png_debug(1, "in png_free_data\n");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+#if defined(PNG_TEXT_SUPPORTED)
+/* free text item num or (if num == -1) all text items */
+#ifdef PNG_FREE_ME_SUPPORTED
+if ((mask & PNG_FREE_TEXT) & info_ptr->free_me)
+#else
+if (mask & PNG_FREE_TEXT)
+#endif
+{
+ if (num != -1)
+ {
+ if (info_ptr->text && info_ptr->text[num].key)
+ {
+ png_free(png_ptr, info_ptr->text[num].key);
+ info_ptr->text[num].key = NULL;
+ }
+ }
+ else
+ {
+ int i;
+ for (i = 0; i < info_ptr->num_text; i++)
+ png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i);
+ png_free(png_ptr, info_ptr->text);
+ info_ptr->text = NULL;
+ info_ptr->num_text=0;
+ }
+}
+#endif
+
+#if defined(PNG_tRNS_SUPPORTED)
+/* free any tRNS entry */
+#ifdef PNG_FREE_ME_SUPPORTED
+if ((mask & PNG_FREE_TRNS) & info_ptr->free_me)
+#else
+if ((mask & PNG_FREE_TRNS) && (png_ptr->flags & PNG_FLAG_FREE_TRNS))
+#endif
+{
+ png_free(png_ptr, info_ptr->trans);
+ info_ptr->valid &= ~PNG_INFO_tRNS;
+ info_ptr->trans = NULL;
+}
+#endif
+
+#if defined(PNG_sCAL_SUPPORTED)
+/* free any sCAL entry */
+#ifdef PNG_FREE_ME_SUPPORTED
+if ((mask & PNG_FREE_SCAL) & info_ptr->free_me)
+#else
+if (mask & PNG_FREE_SCAL)
+#endif
+{
+#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
+ png_free(png_ptr, info_ptr->scal_s_width);
+ png_free(png_ptr, info_ptr->scal_s_height);
+ info_ptr->scal_s_width = NULL;
+ info_ptr->scal_s_height = NULL;
+#endif
+ info_ptr->valid &= ~PNG_INFO_sCAL;
+}
+#endif
+
+#if defined(PNG_pCAL_SUPPORTED)
+/* free any pCAL entry */
+#ifdef PNG_FREE_ME_SUPPORTED
+if ((mask & PNG_FREE_PCAL) & info_ptr->free_me)
+#else
+if (mask & PNG_FREE_PCAL)
+#endif
+{
+ png_free(png_ptr, info_ptr->pcal_purpose);
+ png_free(png_ptr, info_ptr->pcal_units);
+ info_ptr->pcal_purpose = NULL;
+ info_ptr->pcal_units = NULL;
+ if (info_ptr->pcal_params != NULL)
+ {
+ int i;
+ for (i = 0; i < (int)info_ptr->pcal_nparams; i++)
+ {
+ png_free(png_ptr, info_ptr->pcal_params[i]);
+ info_ptr->pcal_params[i]=NULL;
+ }
+ png_free(png_ptr, info_ptr->pcal_params);
+ info_ptr->pcal_params = NULL;
+ }
+ info_ptr->valid &= ~PNG_INFO_pCAL;
+}
+#endif
+
+#if defined(PNG_iCCP_SUPPORTED)
+/* free any iCCP entry */
+#ifdef PNG_FREE_ME_SUPPORTED
+if ((mask & PNG_FREE_ICCP) & info_ptr->free_me)
+#else
+if (mask & PNG_FREE_ICCP)
+#endif
+{
+ png_free(png_ptr, info_ptr->iccp_name);
+ png_free(png_ptr, info_ptr->iccp_profile);
+ info_ptr->iccp_name = NULL;
+ info_ptr->iccp_profile = NULL;
+ info_ptr->valid &= ~PNG_INFO_iCCP;
+}
+#endif
+
+#if defined(PNG_sPLT_SUPPORTED)
+/* free a given sPLT entry, or (if num == -1) all sPLT entries */
+#ifdef PNG_FREE_ME_SUPPORTED
+if ((mask & PNG_FREE_SPLT) & info_ptr->free_me)
+#else
+if (mask & PNG_FREE_SPLT)
+#endif
+{
+ if (num != -1)
+ {
+ if(info_ptr->splt_palettes)
+ {
+ png_free(png_ptr, info_ptr->splt_palettes[num].name);
+ png_free(png_ptr, info_ptr->splt_palettes[num].entries);
+ info_ptr->splt_palettes[num].name = NULL;
+ info_ptr->splt_palettes[num].entries = NULL;
+ }
+ }
+ else
+ {
+ if(info_ptr->splt_palettes_num)
+ {
+ int i;
+ for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
+ png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, i);
+
+ png_free(png_ptr, info_ptr->splt_palettes);
+ info_ptr->splt_palettes = NULL;
+ info_ptr->splt_palettes_num = 0;
+ }
+ info_ptr->valid &= ~PNG_INFO_sPLT;
+ }
+}
+#endif
+
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+#ifdef PNG_FREE_ME_SUPPORTED
+if ((mask & PNG_FREE_UNKN) & info_ptr->free_me)
+#else
+if (mask & PNG_FREE_UNKN)
+#endif
+{
+ if (num != -1)
+ {
+ if(info_ptr->unknown_chunks)
+ {
+ png_free(png_ptr, info_ptr->unknown_chunks[num].data);
+ info_ptr->unknown_chunks[num].data = NULL;
+ }
+ }
+ else
+ {
+ int i;
+
+ if(info_ptr->unknown_chunks_num)
+ {
+ for (i = 0; i < (int)info_ptr->unknown_chunks_num; i++)
+ png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, i);
+
+ png_free(png_ptr, info_ptr->unknown_chunks);
+ info_ptr->unknown_chunks = NULL;
+ info_ptr->unknown_chunks_num = 0;
+ }
+ }
+}
+#endif
+
+#if defined(PNG_hIST_SUPPORTED)
+/* free any hIST entry */
+#ifdef PNG_FREE_ME_SUPPORTED
+if ((mask & PNG_FREE_HIST) & info_ptr->free_me)
+#else
+if ((mask & PNG_FREE_HIST) && (png_ptr->flags & PNG_FLAG_FREE_HIST))
+#endif
+{
+ png_free(png_ptr, info_ptr->hist);
+ info_ptr->hist = NULL;
+ info_ptr->valid &= ~PNG_INFO_hIST;
+}
+#endif
+
+/* free any PLTE entry that was internally allocated */
+#ifdef PNG_FREE_ME_SUPPORTED
+if ((mask & PNG_FREE_PLTE) & info_ptr->free_me)
+#else
+if ((mask & PNG_FREE_PLTE) && (png_ptr->flags & PNG_FLAG_FREE_PLTE))
+#endif
+{
+ png_zfree(png_ptr, info_ptr->palette);
+ info_ptr->palette = NULL;
+ info_ptr->valid &= ~PNG_INFO_PLTE;
+ info_ptr->num_palette = 0;
+}
+
+#if defined(PNG_INFO_IMAGE_SUPPORTED)
+/* free any image bits attached to the info structure */
+#ifdef PNG_FREE_ME_SUPPORTED
+if ((mask & PNG_FREE_ROWS) & info_ptr->free_me)
+#else
+if (mask & PNG_FREE_ROWS)
+#endif
+{
+ if(info_ptr->row_pointers)
+ {
+ int row;
+ for (row = 0; row < (int)info_ptr->height; row++)
+ {
+ png_free(png_ptr, info_ptr->row_pointers[row]);
+ info_ptr->row_pointers[row]=NULL;
+ }
+ png_free(png_ptr, info_ptr->row_pointers);
+ info_ptr->row_pointers=NULL;
+ }
+ info_ptr->valid &= ~PNG_INFO_IDAT;
+}
+#endif
+
+#ifdef PNG_FREE_ME_SUPPORTED
+ if(num == -1)
+ info_ptr->free_me &= ~mask;
+ else
+ info_ptr->free_me &= ~(mask & ~PNG_FREE_MUL);
+#endif
+}
+
+/* This is an internal routine to free any memory that the info struct is
+ * pointing to before re-using it or freeing the struct itself. Recall
+ * that png_free() checks for NULL pointers for us.
+ */
+void /* PRIVATE */
+png_info_destroy(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_info_destroy\n");
+
+ png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
+
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+ if (png_ptr->num_chunk_list)
+ {
+ png_free(png_ptr, png_ptr->chunk_list);
+ png_ptr->chunk_list=(png_bytep)NULL;
+ png_ptr->num_chunk_list=0;
+ }
+#endif
+
+ png_info_init_3(&info_ptr, sizeof(png_info));
+}
+
+/* This function returns a pointer to the io_ptr associated with the user
+ * functions. The application should free any memory associated with this
+ * pointer before png_write_destroy() or png_read_destroy() are called.
+ */
+png_voidp PNGAPI
+png_get_io_ptr(png_structp png_ptr)
+{
+ return (png_ptr->io_ptr);
+}
+
+#if !defined(PNG_NO_STDIO)
+/* Initialize the default input/output functions for the PNG file. If you
+ * use your own read or write routines, you can call either png_set_read_fn()
+ * or png_set_write_fn() instead of png_init_io(). If you have defined
+ * PNG_NO_STDIO, you must use a function of your own because "FILE *" isn't
+ * necessarily available.
+ */
+void PNGAPI
+png_init_io(png_structp png_ptr, png_FILE_p fp)
+{
+ png_debug(1, "in png_init_io\n");
+ png_ptr->io_ptr = (png_voidp)fp;
+}
+#endif
+
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+/* Convert the supplied time into an RFC 1123 string suitable for use in
+ * a "Creation Time" or other text-based time string.
+ */
+png_charp PNGAPI
+png_convert_to_rfc1123(png_structp png_ptr, png_timep ptime)
+{
+ static PNG_CONST char short_months[12][4] =
+ {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+ if (png_ptr->time_buffer == NULL)
+ {
+ png_ptr->time_buffer = (png_charp)png_malloc(png_ptr, (png_uint_32)(29*
+ sizeof(char)));
+ }
+
+#if defined(_WIN32_WCE)
+ {
+ wchar_t time_buf[29];
+ wsprintf(time_buf, TEXT("%d %S %d %02d:%02d:%02d +0000"),
+ ptime->day % 32, short_months[(ptime->month - 1) % 12],
+ ptime->year, ptime->hour % 24, ptime->minute % 60,
+ ptime->second % 61);
+ WideCharToMultiByte(CP_ACP, 0, time_buf, -1, png_ptr->time_buffer, 29,
+ NULL, NULL);
+ }
+#else
+#ifdef USE_FAR_KEYWORD
+ {
+ char near_time_buf[29];
+ sprintf(near_time_buf, "%d %s %d %02d:%02d:%02d +0000",
+ ptime->day % 32, short_months[(ptime->month - 1) % 12],
+ ptime->year, ptime->hour % 24, ptime->minute % 60,
+ ptime->second % 61);
+ png_memcpy(png_ptr->time_buffer, near_time_buf,
+ 29*sizeof(char));
+ }
+#else
+ sprintf(png_ptr->time_buffer, "%d %s %d %02d:%02d:%02d +0000",
+ ptime->day % 32, short_months[(ptime->month - 1) % 12],
+ ptime->year, ptime->hour % 24, ptime->minute % 60,
+ ptime->second % 61);
+#endif
+#endif /* _WIN32_WCE */
+ return ((png_charp)png_ptr->time_buffer);
+}
+#endif /* PNG_TIME_RFC1123_SUPPORTED */
+
+#if 0
+/* Signature string for a PNG file. */
+png_bytep PNGAPI
+png_sig_bytes(void)
+{
+ return ((png_bytep)"\211\120\116\107\015\012\032\012");
+}
+#endif
+
+png_charp PNGAPI
+png_get_copyright(png_structp png_ptr)
+{
+ if (png_ptr != NULL || png_ptr == NULL) /* silence compiler warning */
+ return ((png_charp) "\n libpng version 1.2.0 - September 1, 2001\n\
+ Copyright (c) 1998-2001 Glenn Randers-Pehrson\n\
+ Copyright (c) 1996, 1997 Andreas Dilger\n\
+ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.\n");
+ return ((png_charp) "");
+}
+
+/* The following return the library version as a short string in the
+ * format 1.0.0 through 99.99.99zz. To get the version of *.h files used
+ * with your application, print out PNG_LIBPNG_VER_STRING, which is defined
+ * in png.h.
+ */
+
+png_charp PNGAPI
+png_get_libpng_ver(png_structp png_ptr)
+{
+ /* Version of *.c files used when building libpng */
+ if(png_ptr != NULL) /* silence compiler warning about unused png_ptr */
+ return((png_charp) "1.2.0");
+ return((png_charp) "1.2.0");
+}
+
+png_charp PNGAPI
+png_get_header_ver(png_structp png_ptr)
+{
+ /* Version of *.h files used when building libpng */
+ if(png_ptr != NULL) /* silence compiler warning about unused png_ptr */
+ return((png_charp) PNG_LIBPNG_VER_STRING);
+ return((png_charp) PNG_LIBPNG_VER_STRING);
+}
+
+png_charp PNGAPI
+png_get_header_version(png_structp png_ptr)
+{
+ /* Returns longer string containing both version and date */
+ if(png_ptr != NULL) /* silence compiler warning about unused png_ptr */
+ return((png_charp) PNG_HEADER_VERSION_STRING);
+ return((png_charp) PNG_HEADER_VERSION_STRING);
+}
+
+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+int /* PRIVATE */
+png_handle_as_unknown(png_structp png_ptr, png_bytep chunk_name)
+{
+ /* check chunk_name and return "keep" value if it's on the list, else 0 */
+ int i;
+ png_bytep p;
+ if((png_ptr == NULL && chunk_name == NULL) || png_ptr->num_chunk_list<=0)
+ return 0;
+ p=png_ptr->chunk_list+png_ptr->num_chunk_list*5-5;
+ for (i = png_ptr->num_chunk_list; i; i--, p-=5)
+ if (!png_memcmp(chunk_name, p, 4))
+ return ((int)*(p+4));
+ return 0;
+}
+#endif
+
+/* This function, added to libpng-1.0.6g, is untested. */
+int PNGAPI
+png_reset_zstream(png_structp png_ptr)
+{
+ return (inflateReset(&png_ptr->zstream));
+}
+
+/* This function was added to libpng-1.0.7 */
+png_uint_32 PNGAPI
+png_access_version_number(void)
+{
+ /* Version of *.c files used when building libpng */
+ return((png_uint_32) 10200L);
+}
+
+
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
+ /* GRR: could add this: && defined(PNG_MMX_CODE_SUPPORTED) */
+/* this INTERNAL function was added to libpng 1.2.0 */
+void /* PRIVATE */
+png_init_mmx_flags (png_structp png_ptr)
+{
+ png_ptr->mmx_rowbytes_threshold = 0;
+ png_ptr->mmx_bitdepth_threshold = 0;
+
+# if (defined(PNG_USE_PNGVCRD) || defined(PNG_USE_PNGGCCRD))
+
+ png_ptr->asm_flags |= PNG_ASM_FLAG_MMX_SUPPORT_COMPILED;
+
+ if (png_mmx_support()) {
+ png_ptr->asm_flags |= PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU
+# ifdef PNG_HAVE_ASSEMBLER_COMBINE_ROW
+ | PNG_ASM_FLAG_MMX_READ_COMBINE_ROW
+# endif
+# ifdef PNG_HAVE_ASSEMBLER_READ_INTERLACE
+ | PNG_ASM_FLAG_MMX_READ_INTERLACE
+# endif
+# ifndef PNG_HAVE_ASSEMBLER_READ_FILTER_ROW
+ ;
+# else
+ | PNG_ASM_FLAG_MMX_READ_FILTER_SUB
+ | PNG_ASM_FLAG_MMX_READ_FILTER_UP
+ | PNG_ASM_FLAG_MMX_READ_FILTER_AVG
+ | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ;
+
+ png_ptr->mmx_rowbytes_threshold = PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT;
+ png_ptr->mmx_bitdepth_threshold = PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT;
+# endif
+ } else {
+ png_ptr->asm_flags &= ~( PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU
+ | PNG_MMX_READ_FLAGS
+ | PNG_MMX_WRITE_FLAGS );
+ }
+
+# else /* !((PNGVCRD || PNGGCCRD) && PNG_ASSEMBLER_CODE_SUPPORTED)) */
+
+ /* clear all MMX flags; no support is compiled in */
+ png_ptr->asm_flags &= ~( PNG_MMX_FLAGS );
+
+# endif /* ?(PNGVCRD || PNGGCCRD) */
+}
+
+#endif /* !(PNG_ASSEMBLER_CODE_SUPPORTED) */
+
+/* this function was added to libpng 1.2.0 */
+#if !defined(PNG_USE_PNGGCCRD) && \
+ !(defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_USE_PNGVCRD))
+int PNGAPI
+png_mmx_support(void)
+{
+ return -1;
+}
+#endif
--- /dev/null
+
+/* png.h - header file for PNG reference library
+ *
+ * libpng version 1.2.0 - September 1, 2001
+ * Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ *
+ * Authors and maintainers:
+ * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat
+ * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger
+ * libpng versions 0.97, January 1998, through 1.2.0 - September 1, 2001: Glenn
+ * See also "Contributing Authors", below.
+ *
+ * Note about libpng version numbers:
+ *
+ * Due to various miscommunications, unforeseen code incompatibilities
+ * and occasional factors outside the authors' control, version numbering
+ * on the library has not always been consistent and straightforward.
+ * The following table summarizes matters since version 0.89c, which was
+ * the first widely used release:
+ *
+ * source png.h png.h shared-lib
+ * version string int version
+ * ------- ------ ----- ----------
+ * 0.89c "1.0 beta 3" 0.89 89 1.0.89
+ * 0.90 "1.0 beta 4" 0.90 90 0.90 [should have been 2.0.90]
+ * 0.95 "1.0 beta 5" 0.95 95 0.95 [should have been 2.0.95]
+ * 0.96 "1.0 beta 6" 0.96 96 0.96 [should have been 2.0.96]
+ * 0.97b "1.00.97 beta 7" 1.00.97 97 1.0.1 [should have been 2.0.97]
+ * 0.97c 0.97 97 2.0.97
+ * 0.98 0.98 98 2.0.98
+ * 0.99 0.99 98 2.0.99
+ * 0.99a-m 0.99 99 2.0.99
+ * 1.00 1.00 100 2.1.0 [100 should be 10000]
+ * 1.0.0 (from here on, the 100 2.1.0 [100 should be 10000]
+ * 1.0.1 png.h string is 10001 2.1.0
+ * 1.0.1a-e identical to the 10002 from here on, the shared library
+ * 1.0.2 source version) 10002 is 2.V where V is the source code
+ * 1.0.2a-b 10003 version, except as noted.
+ * 1.0.3 10003
+ * 1.0.3a-d 10004
+ * 1.0.4 10004
+ * 1.0.4a-f 10005
+ * 1.0.5 (+ 2 patches) 10005
+ * 1.0.5a-d 10006
+ * 1.0.5e-r 10100 (not source compatible)
+ * 1.0.5s-v 10006 (not binary compatible)
+ * 1.0.6 (+ 3 patches) 10006 (still binary incompatible)
+ * 1.0.6d-f 10007 (still binary incompatible)
+ * 1.0.6g 10007
+ * 1.0.6h 10007 10.6h (testing xy.z so-numbering)
+ * 1.0.6i 10007 10.6i
+ * 1.0.6j 10007 2.1.0.6j (incompatible with 1.0.0)
+ * 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 (binary compatible)
+ * 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible)
+ * 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible)
+ * 1.0.7 1 10007 (still compatible)
+ * 1.0.8beta1-4 1 10008 2.1.0.8beta1-4
+ * 1.0.8rc1 1 10008 2.1.0.8rc1
+ * 1.0.8 1 10008 2.1.0.8
+ * 1.0.9beta1-6 1 10009 2.1.0.9beta1-6
+ * 1.0.9rc1 1 10009 2.1.0.9rc1
+ * 1.0.9beta7-10 1 10009 2.1.0.9beta7-10
+ * 1.0.9rc2 1 10009 2.1.0.9rc2
+ * 1.0.9 1 10009 2.1.0.9
+ * 1.0.10beta1 1 10010 2.1.0.10beta1
+ * 1.0.10rc1 1 10010 2.1.0.10rc1
+ * 1.0.10 1 10010 2.1.0.10
+ * 1.0.11beta1-3 1 10011 2.1.0.11beta1-3
+ * 1.0.11rc1 1 10011 2.1.0.11rc1
+ * 1.0.11 1 10011 2.1.0.11
+ * 1.0.12beta1-2 2 10012 2.1.0.12beta1-2
+ * 1.0.12rc1 2 10012 2.1.0.12rc1
+ * 1.0.12 2 10012 2.1.0.12
+ * 1.1.0a-f - 10100 2.1.1.0a-f (branch abandoned)
+ * 1.2.0beta1-2 2 10200 2.1.2.0beta1-2
+ * 1.2.0beta3-4 3 10200 3.1.2.0beta3-4
+ *
+ * Henceforth the source version will match the shared-library major
+ * and minor numbers; the shared-library major version number will be
+ * used for changes in backward compatibility, as it is intended. The
+ * PNG_LIBPNG_VER macro, which is not used within libpng but is available
+ * for applications, is an unsigned integer of the form xyyzz corresponding
+ * to the source version x.y.z (leading zeros in y and z). Beta versions
+ * were given the previous public release number plus a letter, until
+ * version 1.0.6j; from then on they were given the upcoming public
+ * release number plus "betaNN" or "rcN".
+ *
+ * Binary incompatibility exists only when applications make direct access
+ * to the info_ptr or png_ptr members through png.h, and the compiled
+ * application is loaded with a different version of the library.
+ *
+ * DLLNUM will change each time there are forward or backward changes
+ * in binary compatibility (e.g., when a new feature is added).
+ *
+ * See libpng.txt or libpng.3 for more information. The PNG specification
+ * is available as RFC 2083 <ftp://ftp.uu.net/graphics/png/documents/>
+ * and as a W3C Recommendation <http://www.w3.org/TR/REC.png.html>
+ */
+
+/*
+ * COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
+ *
+ * If you modify libpng you may insert additional notices immediately following
+ * this sentence.
+ *
+ * libpng versions 1.0.7, July 1, 2000, through 1.2.0, September 1, 2001, are
+ * Copyright (c) 2000, 2001 Glenn Randers-Pehrson, and are
+ * distributed according to the same disclaimer and license as libpng-1.0.6
+ * with the following individuals added to the list of Contributing Authors
+ *
+ * Simon-Pierre Cadieux
+ * Eric S. Raymond
+ * Gilles Vollant
+ *
+ * and with the following additions to the disclaimer:
+ *
+ * There is no warranty against interference with your enjoyment of the
+ * library or against infringement. There is no warranty that our
+ * efforts or the library will fulfill any of your particular purposes
+ * or needs. This library is provided with all faults, and the entire
+ * risk of satisfactory quality, performance, accuracy, and effort is with
+ * the user.
+ *
+ * libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are
+ * Copyright (c) 1998, 1999, 2000 Glenn Randers-Pehrson
+ * Distributed according to the same disclaimer and license as libpng-0.96,
+ * with the following individuals added to the list of Contributing Authors:
+ *
+ * Tom Lane
+ * Glenn Randers-Pehrson
+ * Willem van Schaik
+ *
+ * libpng versions 0.89, June 1996, through 0.96, May 1997, are
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Distributed according to the same disclaimer and license as libpng-0.88,
+ * with the following individuals added to the list of Contributing Authors:
+ *
+ * John Bowler
+ * Kevin Bracey
+ * Sam Bushell
+ * Magnus Holmgren
+ * Greg Roelofs
+ * Tom Tanner
+ *
+ * libpng versions 0.5, May 1995, through 0.88, January 1996, are
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ *
+ * For the purposes of this copyright and license, "Contributing Authors"
+ * is defined as the following set of individuals:
+ *
+ * Andreas Dilger
+ * Dave Martindale
+ * Guy Eric Schalnat
+ * Paul Schmidt
+ * Tim Wegner
+ *
+ * The PNG Reference Library is supplied "AS IS". The Contributing Authors
+ * and Group 42, Inc. disclaim all warranties, expressed or implied,
+ * including, without limitation, the warranties of merchantability and of
+ * fitness for any purpose. The Contributing Authors and Group 42, Inc.
+ * assume no liability for direct, indirect, incidental, special, exemplary,
+ * or consequential damages, which may result from the use of the PNG
+ * Reference Library, even if advised of the possibility of such damage.
+ *
+ * Permission is hereby granted to use, copy, modify, and distribute this
+ * source code, or portions hereof, for any purpose, without fee, subject
+ * to the following restrictions:
+ *
+ * 1. The origin of this source code must not be misrepresented.
+ *
+ * 2. Altered versions must be plainly marked as such and
+ * must not be misrepresented as being the original source.
+ *
+ * 3. This Copyright notice may not be removed or altered from
+ * any source or altered source distribution.
+ *
+ * The Contributing Authors and Group 42, Inc. specifically permit, without
+ * fee, and encourage the use of this source code as a component to
+ * supporting the PNG file format in commercial products. If you use this
+ * source code in a product, acknowledgment is not required but would be
+ * appreciated.
+ */
+
+/*
+ * A "png_get_copyright" function is available, for convenient use in "about"
+ * boxes and the like:
+ *
+ * printf("%s",png_get_copyright(NULL));
+ *
+ * Also, the PNG logo (in PNG format, of course) is supplied in the
+ * files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31).
+ */
+
+/*
+ * Libpng is OSI Certified Open Source Software. OSI Certified is a
+ * certification mark of the Open Source Initiative.
+ */
+
+/*
+ * The contributing authors would like to thank all those who helped
+ * with testing, bug fixes, and patience. This wouldn't have been
+ * possible without all of you.
+ *
+ * Thanks to Frank J. T. Wojcik for helping with the documentation.
+ */
+
+/*
+ * Y2K compliance in libpng:
+ * =========================
+ *
+ * September 1, 2001
+ *
+ * Since the PNG Development group is an ad-hoc body, we can't make
+ * an official declaration.
+ *
+ * This is your unofficial assurance that libpng from version 0.71 and
+ * upward through 1.2.0 are Y2K compliant. It is my belief that earlier
+ * versions were also Y2K compliant.
+ *
+ * Libpng only has three year fields. One is a 2-byte unsigned integer
+ * that will hold years up to 65535. The other two hold the date in text
+ * format, and will hold years up to 9999.
+ *
+ * The integer is
+ * "png_uint_16 year" in png_time_struct.
+ *
+ * The strings are
+ * "png_charp time_buffer" in png_struct and
+ * "near_time_buffer", which is a local character string in png.c.
+ *
+ * There are seven time-related functions:
+ * png.c: png_convert_to_rfc_1123() in png.c
+ * (formerly png_convert_to_rfc_1152() in error)
+ * png_convert_from_struct_tm() in pngwrite.c, called in pngwrite.c
+ * png_convert_from_time_t() in pngwrite.c
+ * png_get_tIME() in pngget.c
+ * png_handle_tIME() in pngrutil.c, called in pngread.c
+ * png_set_tIME() in pngset.c
+ * png_write_tIME() in pngwutil.c, called in pngwrite.c
+ *
+ * All handle dates properly in a Y2K environment. The
+ * png_convert_from_time_t() function calls gmtime() to convert from system
+ * clock time, which returns (year - 1900), which we properly convert to
+ * the full 4-digit year. There is a possibility that applications using
+ * libpng are not passing 4-digit years into the png_convert_to_rfc_1123()
+ * function, or that they are incorrectly passing only a 2-digit year
+ * instead of "year - 1900" into the png_convert_from_struct_tm() function,
+ * but this is not under our control. The libpng documentation has always
+ * stated that it works with 4-digit years, and the APIs have been
+ * documented as such.
+ *
+ * The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned
+ * integer to hold the year, and can hold years as large as 65535.
+ *
+ * zlib, upon which libpng depends, is also Y2K compliant. It contains
+ * no date-related code.
+ *
+ * Glenn Randers-Pehrson
+ * libpng maintainer
+ * PNG Development Group
+ */
+
+#ifndef PNG_H
+#define PNG_H
+
+/* This is not the place to learn how to use libpng. The file libpng.txt
+ * describes how to use libpng, and the file example.c summarizes it
+ * with some code on which to build. This file is useful for looking
+ * at the actual function definitions and structure components.
+ */
+
+/* Version information for png.h - this should match the version in png.c */
+#define PNG_LIBPNG_VER_STRING "1.2.0"
+
+#define PNG_LIBPNG_VER_SONUM 3
+#define PNG_LIBPNG_VER_DLLNUM %DLLNUM%
+
+/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
+#define PNG_LIBPNG_VER_MAJOR 1
+#define PNG_LIBPNG_VER_MINOR 2
+#define PNG_LIBPNG_VER_RELEASE 0
+/* This should match the numeric part of the final component of
+ * PNG_LIBPNG_VER_STRING, omitting any leading zero: */
+
+#define PNG_LIBPNG_VER_BUILD 0
+
+#define PNG_LIBPNG_BUILD_ALPHA 1
+#define PNG_LIBPNG_BUILD_BETA 2
+#define PNG_LIBPNG_BUILD_RC 3
+#define PNG_LIBPNG_BUILD_STABLE 4
+#define PNG_LIBPNG_BUILD_TYPEMASK 7
+#define PNG_LIBPNG_BUILD_PATCH 8 /* Can be OR'ed with STABLE only */
+#define PNG_LIBPNG_BUILD_TYPE 4
+
+/* Careful here. At one time, Guy wanted to use 082, but that would be octal.
+ * We must not include leading zeros.
+ * Versions 0.7 through 1.0.0 were in the range 0 to 100 here (only
+ * version 1.0.0 was mis-numbered 100 instead of 10000). From
+ * version 1.0.1 it's xxyyzz, where x=major, y=minor, z=release */
+#define PNG_LIBPNG_VER 10200 /* 1.2.0 */
+
+#ifndef PNG_VERSION_INFO_ONLY
+
+/* include the compression library's header */
+#include "zlib.h"
+
+/* include all user configurable info, including optional assembler routines */
+#include "pngconf.h"
+
+/* Inhibit C++ name-mangling for libpng functions but not for system calls. */
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* This file is arranged in several sections. The first section contains
+ * structure and type definitions. The second section contains the external
+ * library functions, while the third has the internal library functions,
+ * which applications aren't expected to use directly.
+ */
+
+/* variables declared in png.c - only it needs to define PNG_NO_EXTERN */
+#if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN)
+/* Version information for C files, stored in png.c. This had better match
+ * the version above.
+ */
+#ifdef PNG_USE_GLOBAL_ARRAYS
+PNG_EXPORT_VAR (const char) png_libpng_ver[18];
+ /* need room for 99.99.99beta99z*/
+#else
+#define png_libpng_ver png_get_header_ver(NULL)
+#endif
+
+#ifdef PNG_USE_GLOBAL_ARRAYS
+/* This was removed in version 1.0.5c */
+/* Structures to facilitate easy interlacing. See png.c for more details */
+PNG_EXPORT_VAR (const int FARDATA) png_pass_start[7];
+PNG_EXPORT_VAR (const int FARDATA) png_pass_inc[7];
+PNG_EXPORT_VAR (const int FARDATA) png_pass_ystart[7];
+PNG_EXPORT_VAR (const int FARDATA) png_pass_yinc[7];
+PNG_EXPORT_VAR (const int FARDATA) png_pass_mask[7];
+PNG_EXPORT_VAR (const int FARDATA) png_pass_dsp_mask[7];
+#ifdef PNG_HAVE_ASSEMBLER_COMBINE_ROW
+PNG_EXPORT_VAR (const int FARDATA) png_pass_width[7];
+#endif
+/* This isn't currently used. If you need it, see png.c for more details.
+PNG_EXPORT_VAR (const int FARDATA) png_pass_height[7];
+*/
+#endif
+
+#endif /* PNG_NO_EXTERN */
+
+/* Three color definitions. The order of the red, green, and blue, (and the
+ * exact size) is not important, although the size of the fields need to
+ * be png_byte or png_uint_16 (as defined below).
+ */
+typedef struct png_color_struct
+{
+ png_byte red;
+ png_byte green;
+ png_byte blue;
+} png_color;
+typedef png_color FAR * png_colorp;
+typedef png_color FAR * FAR * png_colorpp;
+
+typedef struct png_color_16_struct
+{
+ png_byte index; /* used for palette files */
+ png_uint_16 red; /* for use in red green blue files */
+ png_uint_16 green;
+ png_uint_16 blue;
+ png_uint_16 gray; /* for use in grayscale files */
+} png_color_16;
+typedef png_color_16 FAR * png_color_16p;
+typedef png_color_16 FAR * FAR * png_color_16pp;
+
+typedef struct png_color_8_struct
+{
+ png_byte red; /* for use in red green blue files */
+ png_byte green;
+ png_byte blue;
+ png_byte gray; /* for use in grayscale files */
+ png_byte alpha; /* for alpha channel files */
+} png_color_8;
+typedef png_color_8 FAR * png_color_8p;
+typedef png_color_8 FAR * FAR * png_color_8pp;
+
+/*
+ * The following two structures are used for the in-core representation
+ * of sPLT chunks.
+ */
+typedef struct png_sPLT_entry_struct
+{
+ png_uint_16 red;
+ png_uint_16 green;
+ png_uint_16 blue;
+ png_uint_16 alpha;
+ png_uint_16 frequency;
+} png_sPLT_entry;
+typedef png_sPLT_entry FAR * png_sPLT_entryp;
+typedef png_sPLT_entry FAR * FAR * png_sPLT_entrypp;
+
+/* When the depth of the sPLT palette is 8 bits, the color and alpha samples
+ * occupy the LSB of their respective members, and the MSB of each member
+ * is zero-filled. The frequency member always occupies the full 16 bits.
+ */
+
+typedef struct png_sPLT_struct
+{
+ png_charp name; /* palette name */
+ png_byte depth; /* depth of palette samples */
+ png_sPLT_entryp entries; /* palette entries */
+ png_int_32 nentries; /* number of palette entries */
+} png_sPLT_t;
+typedef png_sPLT_t FAR * png_sPLT_tp;
+typedef png_sPLT_t FAR * FAR * png_sPLT_tpp;
+
+#ifdef PNG_TEXT_SUPPORTED
+/* png_text holds the contents of a text/ztxt/itxt chunk in a PNG file,
+ * and whether that contents is compressed or not. The "key" field
+ * points to a regular zero-terminated C string. The "text", "lang", and
+ * "lang_key" fields can be regular C strings, empty strings, or NULL pointers.
+ * However, the * structure returned by png_get_text() will always contain
+ * regular zero-terminated C strings (possibly empty), never NULL pointers,
+ * so they can be safely used in printf() and other string-handling functions.
+ */
+typedef struct png_text_struct
+{
+ int compression; /* compression value:
+ -1: tEXt, none
+ 0: zTXt, deflate
+ 1: iTXt, none
+ 2: iTXt, deflate */
+ png_charp key; /* keyword, 1-79 character description of "text" */
+ png_charp text; /* comment, may be an empty string (ie "")
+ or a NULL pointer */
+ png_size_t text_length; /* length of the text string */
+#ifdef PNG_iTXt_SUPPORTED
+ png_size_t itxt_length; /* length of the itxt string */
+ png_charp lang; /* language code, 0-79 characters
+ or a NULL pointer */
+ png_charp lang_key; /* keyword translated UTF-8 string, 0 or more
+ chars or a NULL pointer */
+#endif
+} png_text;
+typedef png_text FAR * png_textp;
+typedef png_text FAR * FAR * png_textpp;
+#endif
+
+/* Supported compression types for text in PNG files (tEXt, and zTXt).
+ * The values of the PNG_TEXT_COMPRESSION_ defines should NOT be changed. */
+#define PNG_TEXT_COMPRESSION_NONE_WR -3
+#define PNG_TEXT_COMPRESSION_zTXt_WR -2
+#define PNG_TEXT_COMPRESSION_NONE -1
+#define PNG_TEXT_COMPRESSION_zTXt 0
+#define PNG_ITXT_COMPRESSION_NONE 1
+#define PNG_ITXT_COMPRESSION_zTXt 2
+#define PNG_TEXT_COMPRESSION_LAST 3 /* Not a valid value */
+
+/* png_time is a way to hold the time in an machine independent way.
+ * Two conversions are provided, both from time_t and struct tm. There
+ * is no portable way to convert to either of these structures, as far
+ * as I know. If you know of a portable way, send it to me. As a side
+ * note - PNG has always been Year 2000 compliant!
+ */
+typedef struct png_time_struct
+{
+ png_uint_16 year; /* full year, as in, 1995 */
+ png_byte month; /* month of year, 1 - 12 */
+ png_byte day; /* day of month, 1 - 31 */
+ png_byte hour; /* hour of day, 0 - 23 */
+ png_byte minute; /* minute of hour, 0 - 59 */
+ png_byte second; /* second of minute, 0 - 60 (for leap seconds) */
+} png_time;
+typedef png_time FAR * png_timep;
+typedef png_time FAR * FAR * png_timepp;
+
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+/* png_unknown_chunk is a structure to hold queued chunks for which there is
+ * no specific support. The idea is that we can use this to queue
+ * up private chunks for output even though the library doesn't actually
+ * know about their semantics.
+ */
+typedef struct png_unknown_chunk_t
+{
+ png_byte name[5];
+ png_byte *data;
+ png_size_t size;
+
+ /* libpng-using applications should NOT directly modify this byte. */
+ png_byte location; /* mode of operation at read time */
+}
+png_unknown_chunk;
+typedef png_unknown_chunk FAR * png_unknown_chunkp;
+typedef png_unknown_chunk FAR * FAR * png_unknown_chunkpp;
+#endif
+
+/* png_info is a structure that holds the information in a PNG file so
+ * that the application can find out the characteristics of the image.
+ * If you are reading the file, this structure will tell you what is
+ * in the PNG file. If you are writing the file, fill in the information
+ * you want to put into the PNG file, then call png_write_info().
+ * The names chosen should be very close to the PNG specification, so
+ * consult that document for information about the meaning of each field.
+ *
+ * With libpng < 0.95, it was only possible to directly set and read the
+ * the values in the png_info_struct, which meant that the contents and
+ * order of the values had to remain fixed. With libpng 0.95 and later,
+ * however, there are now functions that abstract the contents of
+ * png_info_struct from the application, so this makes it easier to use
+ * libpng with dynamic libraries, and even makes it possible to use
+ * libraries that don't have all of the libpng ancillary chunk-handing
+ * functionality.
+ *
+ * In any case, the order of the parameters in png_info_struct should NOT
+ * be changed for as long as possible to keep compatibility with applications
+ * that use the old direct-access method with png_info_struct.
+ *
+ * The following members may have allocated storage attached that should be
+ * cleaned up before the structure is discarded: palette, trans, text,
+ * pcal_purpose, pcal_units, pcal_params, hist, iccp_name, iccp_profile,
+ * splt_palettes, scal_unit, row_pointers, and unknowns. By default, these
+ * are automatically freed when the info structure is deallocated, if they were
+ * allocated internally by libpng. This behavior can be changed by means
+ * of the png_data_freer() function.
+ *
+ * More allocation details: all the chunk-reading functions that
+ * change these members go through the corresponding png_set_*
+ * functions. A function to clear these members is available: see
+ * png_free_data(). The png_set_* functions do not depend on being
+ * able to point info structure members to any of the storage they are
+ * passed (they make their own copies), EXCEPT that the png_set_text
+ * functions use the same storage passed to them in the text_ptr or
+ * itxt_ptr structure argument, and the png_set_rows and png_set_unknowns
+ * functions do not make their own copies.
+ */
+typedef struct png_info_struct
+{
+ /* the following are necessary for every PNG file */
+ png_uint_32 width; /* width of image in pixels (from IHDR) */
+ png_uint_32 height; /* height of image in pixels (from IHDR) */
+ png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */
+ png_uint_32 rowbytes; /* bytes needed to hold an untransformed row */
+ png_colorp palette; /* array of color values (valid & PNG_INFO_PLTE) */
+ png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */
+ png_uint_16 num_trans; /* number of transparent palette color (tRNS) */
+ png_byte bit_depth; /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */
+ png_byte color_type; /* see PNG_COLOR_TYPE_ below (from IHDR) */
+ /* The following three should have been named *_method not *_type */
+ png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */
+ png_byte filter_type; /* must be PNG_FILTER_TYPE_BASE (from IHDR) */
+ png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */
+
+ /* The following is informational only on read, and not used on writes. */
+ png_byte channels; /* number of data channels per pixel (1, 2, 3, 4)*/
+ png_byte pixel_depth; /* number of bits per pixel */
+ png_byte spare_byte; /* to align the data, and for future use */
+ png_byte signature[8]; /* magic bytes read by libpng from start of file */
+
+ /* The rest of the data is optional. If you are reading, check the
+ * valid field to see if the information in these are valid. If you
+ * are writing, set the valid field to those chunks you want written,
+ * and initialize the appropriate fields below.
+ */
+
+#if defined(PNG_gAMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
+ /* The gAMA chunk describes the gamma characteristics of the system
+ * on which the image was created, normally in the range [1.0, 2.5].
+ * Data is valid if (valid & PNG_INFO_gAMA) is non-zero.
+ */
+ float gamma; /* gamma value of image, if (valid & PNG_INFO_gAMA) */
+#endif
+
+#if defined(PNG_sRGB_SUPPORTED)
+ /* GR-P, 0.96a */
+ /* Data valid if (valid & PNG_INFO_sRGB) non-zero. */
+ png_byte srgb_intent; /* sRGB rendering intent [0, 1, 2, or 3] */
+#endif
+
+#if defined(PNG_TEXT_SUPPORTED)
+ /* The tEXt, and zTXt chunks contain human-readable textual data in
+ * uncompressed, compressed, and optionally compressed forms, respectively.
+ * The data in "text" is an array of pointers to uncompressed,
+ * null-terminated C strings. Each chunk has a keyword that describes the
+ * textual data contained in that chunk. Keywords are not required to be
+ * unique, and the text string may be empty. Any number of text chunks may
+ * be in an image.
+ */
+ int num_text; /* number of comments read/to write */
+ int max_text; /* current size of text array */
+ png_textp text; /* array of comments read/to write */
+#endif /* PNG_TEXT_SUPPORTED */
+
+#if defined(PNG_tIME_SUPPORTED)
+ /* The tIME chunk holds the last time the displayed image data was
+ * modified. See the png_time struct for the contents of this struct.
+ */
+ png_time mod_time;
+#endif
+
+#if defined(PNG_sBIT_SUPPORTED)
+ /* The sBIT chunk specifies the number of significant high-order bits
+ * in the pixel data. Values are in the range [1, bit_depth], and are
+ * only specified for the channels in the pixel data. The contents of
+ * the low-order bits is not specified. Data is valid if
+ * (valid & PNG_INFO_sBIT) is non-zero.
+ */
+ png_color_8 sig_bit; /* significant bits in color channels */
+#endif
+
+#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_EXPAND_SUPPORTED) || \
+defined(PNG_READ_BACKGROUND_SUPPORTED)
+ /* The tRNS chunk supplies transparency data for paletted images and
+ * other image types that don't need a full alpha channel. There are
+ * "num_trans" transparency values for a paletted image, stored in the
+ * same order as the palette colors, starting from index 0. Values
+ * for the data are in the range [0, 255], ranging from fully transparent
+ * to fully opaque, respectively. For non-paletted images, there is a
+ * single color specified that should be treated as fully transparent.
+ * Data is valid if (valid & PNG_INFO_tRNS) is non-zero.
+ */
+ png_bytep trans; /* transparent values for paletted image */
+ png_color_16 trans_values; /* transparent color for non-palette image */
+#endif
+
+#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ /* The bKGD chunk gives the suggested image background color if the
+ * display program does not have its own background color and the image
+ * is needs to composited onto a background before display. The colors
+ * in "background" are normally in the same color space/depth as the
+ * pixel data. Data is valid if (valid & PNG_INFO_bKGD) is non-zero.
+ */
+ png_color_16 background;
+#endif
+
+#if defined(PNG_oFFs_SUPPORTED)
+ /* The oFFs chunk gives the offset in "offset_unit_type" units rightwards
+ * and downwards from the top-left corner of the display, page, or other
+ * application-specific co-ordinate space. See the PNG_OFFSET_ defines
+ * below for the unit types. Valid if (valid & PNG_INFO_oFFs) non-zero.
+ */
+ png_int_32 x_offset; /* x offset on page */
+ png_int_32 y_offset; /* y offset on page */
+ png_byte offset_unit_type; /* offset units type */
+#endif
+
+#if defined(PNG_pHYs_SUPPORTED)
+ /* The pHYs chunk gives the physical pixel density of the image for
+ * display or printing in "phys_unit_type" units (see PNG_RESOLUTION_
+ * defines below). Data is valid if (valid & PNG_INFO_pHYs) is non-zero.
+ */
+ png_uint_32 x_pixels_per_unit; /* horizontal pixel density */
+ png_uint_32 y_pixels_per_unit; /* vertical pixel density */
+ png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */
+#endif
+
+#if defined(PNG_hIST_SUPPORTED)
+ /* The hIST chunk contains the relative frequency or importance of the
+ * various palette entries, so that a viewer can intelligently select a
+ * reduced-color palette, if required. Data is an array of "num_palette"
+ * values in the range [0,65535]. Data valid if (valid & PNG_INFO_hIST)
+ * is non-zero.
+ */
+ png_uint_16p hist;
+#endif
+
+#ifdef PNG_cHRM_SUPPORTED
+ /* The cHRM chunk describes the CIE color characteristics of the monitor
+ * on which the PNG was created. This data allows the viewer to do gamut
+ * mapping of the input image to ensure that the viewer sees the same
+ * colors in the image as the creator. Values are in the range
+ * [0.0, 0.8]. Data valid if (valid & PNG_INFO_cHRM) non-zero.
+ */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ float x_white;
+ float y_white;
+ float x_red;
+ float y_red;
+ float x_green;
+ float y_green;
+ float x_blue;
+ float y_blue;
+#endif
+#endif
+
+#if defined(PNG_pCAL_SUPPORTED)
+ /* The pCAL chunk describes a transformation between the stored pixel
+ * values and original physical data values used to create the image.
+ * The integer range [0, 2^bit_depth - 1] maps to the floating-point
+ * range given by [pcal_X0, pcal_X1], and are further transformed by a
+ * (possibly non-linear) transformation function given by "pcal_type"
+ * and "pcal_params" into "pcal_units". Please see the PNG_EQUATION_
+ * defines below, and the PNG-Group's PNG extensions document for a
+ * complete description of the transformations and how they should be
+ * implemented, and for a description of the ASCII parameter strings.
+ * Data values are valid if (valid & PNG_INFO_pCAL) non-zero.
+ */
+ png_charp pcal_purpose; /* pCAL chunk description string */
+ png_int_32 pcal_X0; /* minimum value */
+ png_int_32 pcal_X1; /* maximum value */
+ png_charp pcal_units; /* Latin-1 string giving physical units */
+ png_charpp pcal_params; /* ASCII strings containing parameter values */
+ png_byte pcal_type; /* equation type (see PNG_EQUATION_ below) */
+ png_byte pcal_nparams; /* number of parameters given in pcal_params */
+#endif
+
+/* New members added in libpng-1.0.6 */
+#ifdef PNG_FREE_ME_SUPPORTED
+ png_uint_32 free_me; /* flags items libpng is responsible for freeing */
+#endif
+
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+ /* storage for unknown chunks that the library doesn't recognize. */
+ png_unknown_chunkp unknown_chunks;
+ png_size_t unknown_chunks_num;
+#endif
+
+#if defined(PNG_iCCP_SUPPORTED)
+ /* iCCP chunk data. */
+ png_charp iccp_name; /* profile name */
+ png_charp iccp_profile; /* International Color Consortium profile data */
+ /* Note to maintainer: should be png_bytep */
+ png_uint_32 iccp_proflen; /* ICC profile data length */
+ png_byte iccp_compression; /* Always zero */
+#endif
+
+#if defined(PNG_sPLT_SUPPORTED)
+ /* data on sPLT chunks (there may be more than one). */
+ png_sPLT_tp splt_palettes;
+ png_uint_32 splt_palettes_num;
+#endif
+
+#if defined(PNG_sCAL_SUPPORTED)
+ /* The sCAL chunk describes the actual physical dimensions of the
+ * subject matter of the graphic. The chunk contains a unit specification
+ * a byte value, and two ASCII strings representing floating-point
+ * values. The values are width and height corresponsing to one pixel
+ * in the image. This external representation is converted to double
+ * here. Data values are valid if (valid & PNG_INFO_sCAL) is non-zero.
+ */
+ png_byte scal_unit; /* unit of physical scale */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ double scal_pixel_width; /* width of one pixel */
+ double scal_pixel_height; /* height of one pixel */
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ png_charp scal_s_width; /* string containing height */
+ png_charp scal_s_height; /* string containing width */
+#endif
+#endif
+
+#if defined(PNG_INFO_IMAGE_SUPPORTED)
+ /* Memory has been allocated if (valid & PNG_ALLOCATED_INFO_ROWS) non-zero */
+ /* Data valid if (valid & PNG_INFO_IDAT) non-zero */
+ png_bytepp row_pointers; /* the image bits */
+#endif
+
+#if defined(PNG_FIXED_POINT_SUPPORTED) && defined(PNG_gAMA_SUPPORTED)
+ png_fixed_point int_gamma; /* gamma of image, if (valid & PNG_INFO_gAMA) */
+#endif
+
+#if defined(PNG_cHRM_SUPPORTED) && defined(PNG_FIXED_POINT_SUPPORTED)
+ png_fixed_point int_x_white;
+ png_fixed_point int_y_white;
+ png_fixed_point int_x_red;
+ png_fixed_point int_y_red;
+ png_fixed_point int_x_green;
+ png_fixed_point int_y_green;
+ png_fixed_point int_x_blue;
+ png_fixed_point int_y_blue;
+#endif
+
+} png_info;
+
+typedef png_info FAR * png_infop;
+typedef png_info FAR * FAR * png_infopp;
+
+/* Maximum positive integer used in PNG is (2^31)-1 */
+#define PNG_MAX_UINT ((png_uint_32)0x7fffffffL)
+
+/* These describe the color_type field in png_info. */
+/* color type masks */
+#define PNG_COLOR_MASK_PALETTE 1
+#define PNG_COLOR_MASK_COLOR 2
+#define PNG_COLOR_MASK_ALPHA 4
+
+/* color types. Note that not all combinations are legal */
+#define PNG_COLOR_TYPE_GRAY 0
+#define PNG_COLOR_TYPE_PALETTE (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE)
+#define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR)
+#define PNG_COLOR_TYPE_RGB_ALPHA (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA)
+#define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA)
+/* aliases */
+#define PNG_COLOR_TYPE_RGBA PNG_COLOR_TYPE_RGB_ALPHA
+#define PNG_COLOR_TYPE_GA PNG_COLOR_TYPE_GRAY_ALPHA
+
+/* This is for compression type. PNG 1.0-1.2 only define the single type. */
+#define PNG_COMPRESSION_TYPE_BASE 0 /* Deflate method 8, 32K window */
+#define PNG_COMPRESSION_TYPE_DEFAULT PNG_COMPRESSION_TYPE_BASE
+
+/* This is for filter type. PNG 1.0-1.2 only define the single type. */
+#define PNG_FILTER_TYPE_BASE 0 /* Single row per-byte filtering */
+#define PNG_INTRAPIXEL_DIFFERENCING 64 /* Used only in MNG datastreams */
+#define PNG_FILTER_TYPE_DEFAULT PNG_FILTER_TYPE_BASE
+
+/* These are for the interlacing type. These values should NOT be changed. */
+#define PNG_INTERLACE_NONE 0 /* Non-interlaced image */
+#define PNG_INTERLACE_ADAM7 1 /* Adam7 interlacing */
+#define PNG_INTERLACE_LAST 2 /* Not a valid value */
+
+/* These are for the oFFs chunk. These values should NOT be changed. */
+#define PNG_OFFSET_PIXEL 0 /* Offset in pixels */
+#define PNG_OFFSET_MICROMETER 1 /* Offset in micrometers (1/10^6 meter) */
+#define PNG_OFFSET_LAST 2 /* Not a valid value */
+
+/* These are for the pCAL chunk. These values should NOT be changed. */
+#define PNG_EQUATION_LINEAR 0 /* Linear transformation */
+#define PNG_EQUATION_BASE_E 1 /* Exponential base e transform */
+#define PNG_EQUATION_ARBITRARY 2 /* Arbitrary base exponential transform */
+#define PNG_EQUATION_HYPERBOLIC 3 /* Hyperbolic sine transformation */
+#define PNG_EQUATION_LAST 4 /* Not a valid value */
+
+/* These are for the sCAL chunk. These values should NOT be changed. */
+#define PNG_SCALE_UNKNOWN 0 /* unknown unit (image scale) */
+#define PNG_SCALE_METER 1 /* meters per pixel */
+#define PNG_SCALE_RADIAN 2 /* radians per pixel */
+#define PNG_SCALE_LAST 3 /* Not a valid value */
+
+/* These are for the pHYs chunk. These values should NOT be changed. */
+#define PNG_RESOLUTION_UNKNOWN 0 /* pixels/unknown unit (aspect ratio) */
+#define PNG_RESOLUTION_METER 1 /* pixels/meter */
+#define PNG_RESOLUTION_LAST 2 /* Not a valid value */
+
+/* These are for the sRGB chunk. These values should NOT be changed. */
+#define PNG_sRGB_INTENT_PERCEPTUAL 0
+#define PNG_sRGB_INTENT_RELATIVE 1
+#define PNG_sRGB_INTENT_SATURATION 2
+#define PNG_sRGB_INTENT_ABSOLUTE 3
+#define PNG_sRGB_INTENT_LAST 4 /* Not a valid value */
+
+/* This is for text chunks */
+#define PNG_KEYWORD_MAX_LENGTH 79
+
+/* Maximum number of entries in PLTE/sPLT/tRNS arrays */
+#define PNG_MAX_PALETTE_LENGTH 256
+
+/* These determine if an ancillary chunk's data has been successfully read
+ * from the PNG header, or if the application has filled in the corresponding
+ * data in the info_struct to be written into the output file. The values
+ * of the PNG_INFO_<chunk> defines should NOT be changed.
+ */
+#define PNG_INFO_gAMA 0x0001
+#define PNG_INFO_sBIT 0x0002
+#define PNG_INFO_cHRM 0x0004
+#define PNG_INFO_PLTE 0x0008
+#define PNG_INFO_tRNS 0x0010
+#define PNG_INFO_bKGD 0x0020
+#define PNG_INFO_hIST 0x0040
+#define PNG_INFO_pHYs 0x0080
+#define PNG_INFO_oFFs 0x0100
+#define PNG_INFO_tIME 0x0200
+#define PNG_INFO_pCAL 0x0400
+#define PNG_INFO_sRGB 0x0800 /* GR-P, 0.96a */
+#define PNG_INFO_iCCP 0x1000 /* ESR, 1.0.6 */
+#define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */
+#define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */
+#define PNG_INFO_IDAT 0x8000L /* ESR, 1.0.6 */
+
+/* This is used for the transformation routines, as some of them
+ * change these values for the row. It also should enable using
+ * the routines for other purposes.
+ */
+typedef struct png_row_info_struct
+{
+ png_uint_32 width; /* width of row */
+ png_uint_32 rowbytes; /* number of bytes in row */
+ png_byte color_type; /* color type of row */
+ png_byte bit_depth; /* bit depth of row */
+ png_byte channels; /* number of channels (1, 2, 3, or 4) */
+ png_byte pixel_depth; /* bits per pixel (depth * channels) */
+} png_row_info;
+
+typedef png_row_info FAR * png_row_infop;
+typedef png_row_info FAR * FAR * png_row_infopp;
+
+/* These are the function types for the I/O functions and for the functions
+ * that allow the user to override the default I/O functions with his or her
+ * own. The png_error_ptr type should match that of user-supplied warning
+ * and error functions, while the png_rw_ptr type should match that of the
+ * user read/write data functions.
+ */
+typedef struct png_struct_def png_struct;
+typedef png_struct FAR * png_structp;
+
+typedef void (PNGAPI *png_error_ptr) PNGARG((png_structp, png_const_charp));
+typedef void (PNGAPI *png_rw_ptr) PNGARG((png_structp, png_bytep, png_size_t));
+typedef void (PNGAPI *png_flush_ptr) PNGARG((png_structp));
+typedef void (PNGAPI *png_read_status_ptr) PNGARG((png_structp, png_uint_32,
+ int));
+typedef void (PNGAPI *png_write_status_ptr) PNGARG((png_structp, png_uint_32,
+ int));
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+typedef void (PNGAPI *png_progressive_info_ptr) PNGARG((png_structp, png_infop));
+typedef void (PNGAPI *png_progressive_end_ptr) PNGARG((png_structp, png_infop));
+typedef void (PNGAPI *png_progressive_row_ptr) PNGARG((png_structp, png_bytep,
+ png_uint_32, int));
+#endif
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_LEGACY_SUPPORTED)
+typedef void (PNGAPI *png_user_transform_ptr) PNGARG((png_structp,
+ png_row_infop, png_bytep));
+#endif
+
+#if defined(PNG_USER_CHUNKS_SUPPORTED)
+typedef int (PNGAPI *png_user_chunk_ptr) PNGARG((png_structp, png_unknown_chunkp));
+#endif
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+typedef void (PNGAPI *png_unknown_chunk_ptr) PNGARG((png_structp));
+#endif
+
+/* Transform masks for the high-level interface */
+#define PNG_TRANSFORM_IDENTITY 0x0000 /* read and write */
+#define PNG_TRANSFORM_STRIP_16 0x0001 /* read only */
+#define PNG_TRANSFORM_STRIP_ALPHA 0x0002 /* read only */
+#define PNG_TRANSFORM_PACKING 0x0004 /* read and write */
+#define PNG_TRANSFORM_PACKSWAP 0x0008 /* read and write */
+#define PNG_TRANSFORM_EXPAND 0x0010 /* read only */
+#define PNG_TRANSFORM_INVERT_MONO 0x0020 /* read and write */
+#define PNG_TRANSFORM_SHIFT 0x0040 /* read and write */
+#define PNG_TRANSFORM_BGR 0x0080 /* read and write */
+#define PNG_TRANSFORM_SWAP_ALPHA 0x0100 /* read and write */
+#define PNG_TRANSFORM_SWAP_ENDIAN 0x0200 /* read and write */
+#define PNG_TRANSFORM_INVERT_ALPHA 0x0400 /* read and write */
+#define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* WRITE only */
+
+/* Flags for MNG supported features */
+#define PNG_FLAG_MNG_EMPTY_PLTE 0x01
+#define PNG_FLAG_MNG_FILTER_64 0x04
+#define PNG_ALL_MNG_FEATURES 0x05
+
+typedef png_voidp (*png_malloc_ptr) PNGARG((png_structp, png_size_t));
+typedef void (*png_free_ptr) PNGARG((png_structp, png_voidp));
+
+/* The structure that holds the information to read and write PNG files.
+ * The only people who need to care about what is inside of this are the
+ * people who will be modifying the library for their own special needs.
+ * It should NOT be accessed directly by an application, except to store
+ * the jmp_buf.
+ */
+
+struct png_struct_def
+{
+#ifdef PNG_SETJMP_SUPPORTED
+ jmp_buf jmpbuf; /* used in png_error */
+#endif
+ png_error_ptr error_fn; /* function for printing errors and aborting */
+ png_error_ptr warning_fn; /* function for printing warnings */
+ png_voidp error_ptr; /* user supplied struct for error functions */
+ png_rw_ptr write_data_fn; /* function for writing output data */
+ png_rw_ptr read_data_fn; /* function for reading input data */
+ png_voidp io_ptr; /* ptr to application struct for I/O functions*/
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
+ png_user_transform_ptr read_user_transform_fn; /* user read transform */
+#endif
+
+#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+ png_user_transform_ptr write_user_transform_fn; /* user write transform */
+#endif
+
+/* These were added in libpng-1.0.2 */
+#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+ png_voidp user_transform_ptr; /* user supplied struct for user transform */
+ png_byte user_transform_depth; /* bit depth of user transformed pixels */
+ png_byte user_transform_channels; /* channels in user transformed pixels */
+#endif
+#endif
+
+ png_uint_32 mode; /* tells us where we are in the PNG file */
+ png_uint_32 flags; /* flags indicating various things to libpng */
+ png_uint_32 transformations; /* which transformations to perform */
+
+ z_stream zstream; /* pointer to decompression structure (below) */
+ png_bytep zbuf; /* buffer for zlib */
+ png_size_t zbuf_size; /* size of zbuf */
+ int zlib_level; /* holds zlib compression level */
+ int zlib_method; /* holds zlib compression method */
+ int zlib_window_bits; /* holds zlib compression window bits */
+ int zlib_mem_level; /* holds zlib compression memory level */
+ int zlib_strategy; /* holds zlib compression strategy */
+
+ png_uint_32 width; /* width of image in pixels */
+ png_uint_32 height; /* height of image in pixels */
+ png_uint_32 num_rows; /* number of rows in current pass */
+ png_uint_32 usr_width; /* width of row at start of write */
+ png_uint_32 rowbytes; /* size of row in bytes */
+ png_uint_32 irowbytes; /* size of current interlaced row in bytes */
+ png_uint_32 iwidth; /* width of current interlaced row in pixels */
+ png_uint_32 row_number; /* current row in interlace pass */
+ png_bytep prev_row; /* buffer to save previous (unfiltered) row */
+ png_bytep row_buf; /* buffer to save current (unfiltered) row */
+ png_bytep sub_row; /* buffer to save "sub" row when filtering */
+ png_bytep up_row; /* buffer to save "up" row when filtering */
+ png_bytep avg_row; /* buffer to save "avg" row when filtering */
+ png_bytep paeth_row; /* buffer to save "Paeth" row when filtering */
+ png_row_info row_info; /* used for transformation routines */
+
+ png_uint_32 idat_size; /* current IDAT size for read */
+ png_uint_32 crc; /* current chunk CRC value */
+ png_colorp palette; /* palette from the input file */
+ png_uint_16 num_palette; /* number of color entries in palette */
+ png_uint_16 num_trans; /* number of transparency values */
+ png_byte chunk_name[5]; /* null-terminated name of current chunk */
+ png_byte compression; /* file compression type (always 0) */
+ png_byte filter; /* file filter type (always 0) */
+ png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */
+ png_byte pass; /* current interlace pass (0 - 6) */
+ png_byte do_filter; /* row filter flags (see PNG_FILTER_ below ) */
+ png_byte color_type; /* color type of file */
+ png_byte bit_depth; /* bit depth of file */
+ png_byte usr_bit_depth; /* bit depth of users row */
+ png_byte pixel_depth; /* number of bits per pixel */
+ png_byte channels; /* number of channels in file */
+ png_byte usr_channels; /* channels at start of write */
+ png_byte sig_bytes; /* magic bytes read/written from start of file */
+
+#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
+#ifdef PNG_LEGACY_SUPPORTED
+ png_byte filler; /* filler byte for pixel expansion */
+#else
+ png_uint_16 filler; /* filler bytes for pixel expansion */
+#endif
+#endif
+
+#if defined(PNG_bKGD_SUPPORTED)
+ png_byte background_gamma_type;
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+ float background_gamma;
+# endif
+ png_color_16 background; /* background color in screen gamma space */
+# if defined(PNG_READ_GAMMA_SUPPORTED)
+ png_color_16 background_1; /* background normalized to gamma 1.0 */
+# endif /* PNG_READ_GAMMA && PNG_bKGD_SUPPORTED */
+#endif /* PNG_bKGD_SUPPORTED */
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+ png_flush_ptr output_flush_fn;/* Function for flushing output */
+ png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */
+ png_uint_32 flush_rows; /* number of rows written since last flush */
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ int gamma_shift; /* number of "insignificant" bits 16-bit gamma */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ float gamma; /* file gamma value */
+ float screen_gamma; /* screen gamma value (display_exponent) */
+#endif
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ png_bytep gamma_table; /* gamma table for 8-bit depth files */
+ png_bytep gamma_from_1; /* converts from 1.0 to screen */
+ png_bytep gamma_to_1; /* converts from file to 1.0 */
+ png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */
+ png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */
+ png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED)
+ png_color_8 sig_bit; /* significant bits in each available channel */
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
+ png_color_8 shift; /* shift for significant bit tranformation */
+#endif
+
+#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \
+ || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ png_bytep trans; /* transparency values for paletted files */
+ png_color_16 trans_values; /* transparency values for non-paletted files */
+#endif
+
+ png_read_status_ptr read_row_fn; /* called after each row is decoded */
+ png_write_status_ptr write_row_fn; /* called after each row is encoded */
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+ png_progressive_info_ptr info_fn; /* called after header data fully read */
+ png_progressive_row_ptr row_fn; /* called after each prog. row is decoded */
+ png_progressive_end_ptr end_fn; /* called after image is complete */
+ png_bytep save_buffer_ptr; /* current location in save_buffer */
+ png_bytep save_buffer; /* buffer for previously read data */
+ png_bytep current_buffer_ptr; /* current location in current_buffer */
+ png_bytep current_buffer; /* buffer for recently used data */
+ png_uint_32 push_length; /* size of current input chunk */
+ png_uint_32 skip_length; /* bytes to skip in input data */
+ png_size_t save_buffer_size; /* amount of data now in save_buffer */
+ png_size_t save_buffer_max; /* total size of save_buffer */
+ png_size_t buffer_size; /* total amount of available input data */
+ png_size_t current_buffer_size; /* amount of data now in current_buffer */
+ int process_mode; /* what push library is currently doing */
+ int cur_palette; /* current push library palette index */
+
+# if defined(PNG_TEXT_SUPPORTED)
+ png_size_t current_text_size; /* current size of text input data */
+ png_size_t current_text_left; /* how much text left to read in input */
+ png_charp current_text; /* current text chunk buffer */
+ png_charp current_text_ptr; /* current location in current_text */
+# endif /* PNG_PROGRESSIVE_READ_SUPPORTED && PNG_TEXT_SUPPORTED */
+
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+
+#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__)
+/* for the Borland special 64K segment handler */
+ png_bytepp offset_table_ptr;
+ png_bytep offset_table;
+ png_uint_16 offset_table_number;
+ png_uint_16 offset_table_count;
+ png_uint_16 offset_table_count_free;
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+ png_bytep palette_lookup; /* lookup table for dithering */
+ png_bytep dither_index; /* index translation for palette files */
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED) || defined(PNG_hIST_SUPPORTED)
+ png_uint_16p hist; /* histogram */
+#endif
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ png_byte heuristic_method; /* heuristic for row filter selection */
+ png_byte num_prev_filters; /* number of weights for previous rows */
+ png_bytep prev_filters; /* filter type(s) of previous row(s) */
+ png_uint_16p filter_weights; /* weight(s) for previous line(s) */
+ png_uint_16p inv_filter_weights; /* 1/weight(s) for previous line(s) */
+ png_uint_16p filter_costs; /* relative filter calculation cost */
+ png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */
+#endif
+
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+ png_charp time_buffer; /* String to hold RFC 1123 time text */
+#endif
+
+/* New members added in libpng-1.0.6 */
+
+#ifdef PNG_FREE_ME_SUPPORTED
+ png_uint_32 free_me; /* flags items libpng is responsible for freeing */
+#endif
+
+#if defined(PNG_USER_CHUNKS_SUPPORTED)
+ png_voidp user_chunk_ptr;
+ png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */
+#endif
+
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+ int num_chunk_list;
+ png_bytep chunk_list;
+#endif
+
+/* New members added in libpng-1.0.3 */
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+ png_byte rgb_to_gray_status;
+ /* These were changed from png_byte in libpng-1.0.6 */
+ png_uint_16 rgb_to_gray_red_coeff;
+ png_uint_16 rgb_to_gray_green_coeff;
+ png_uint_16 rgb_to_gray_blue_coeff;
+#endif
+
+/* New member added in libpng-1.0.4 (renamed in 1.0.9) */
+#if defined(PNG_MNG_FEATURES_SUPPORTED) || \
+ defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \
+ defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED)
+/* changed from png_byte to png_uint_32 at version 1.2.0 */
+ png_uint_32 mng_features_permitted;
+#endif
+
+/* New member added in libpng-1.0.7 */
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ png_fixed_point int_gamma;
+#endif
+
+/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ png_byte filter_type;
+#endif
+
+#if defined(PNG_DEBUG) && defined(PNG_USE_PNGGCCRD)
+/* New member added in libpng-1.0.10, ifdef'ed out in 1.2.0 */
+ png_uint_32 row_buf_size;
+#endif
+
+/* New members added in libpng-1.2.0 */
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
+ png_byte mmx_bitdepth_threshold;
+ png_uint_32 mmx_rowbytes_threshold;
+ png_uint_32 asm_flags;
+#endif
+
+/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_voidp mem_ptr; /* user supplied struct for mem functions */
+ png_malloc_ptr malloc_fn; /* function for allocating memory */
+ png_free_ptr free_fn; /* function for freeing memory */
+#endif
+
+ png_bytep big_row_buf; /* buffer to save current (unfiltered) row */
+
+};
+
+
+/* This prevents a compiler error in png_get_copyright() in png.c if png.c
+ and png.h are both at version 1.2.0
+ */
+typedef png_structp version_1_2_0;
+
+typedef png_struct FAR * FAR * png_structpp;
+
+/* Here are the function definitions most commonly used. This is not
+ * the place to find out how to use libpng. See libpng.txt for the
+ * full explanation, see example.c for the summary. This just provides
+ * a simple one line description of the use of each function.
+ */
+
+/* Returns the version number of the library */
+extern PNG_EXPORT(png_uint_32,png_access_version_number) PNGARG((void));
+
+/* Tell lib we have already handled the first <num_bytes> magic bytes.
+ * Handling more than 8 bytes from the beginning of the file is an error.
+ */
+extern PNG_EXPORT(void,png_set_sig_bytes) PNGARG((png_structp png_ptr,
+ int num_bytes));
+
+/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a
+ * PNG file. Returns zero if the supplied bytes match the 8-byte PNG
+ * signature, and non-zero otherwise. Having num_to_check == 0 or
+ * start > 7 will always fail (ie return non-zero).
+ */
+extern PNG_EXPORT(int,png_sig_cmp) PNGARG((png_bytep sig, png_size_t start,
+ png_size_t num_to_check));
+
+/* Simple signature checking function. This is the same as calling
+ * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n).
+ */
+extern PNG_EXPORT(int,png_check_sig) PNGARG((png_bytep sig, int num));
+
+/* Allocate and initialize png_ptr struct for reading, and any other memory. */
+extern PNG_EXPORT(png_structp,png_create_read_struct)
+ PNGARG((png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn));
+
+/* Allocate and initialize png_ptr struct for writing, and any other memory */
+extern PNG_EXPORT(png_structp,png_create_write_struct)
+ PNGARG((png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn));
+
+extern PNG_EXPORT(png_uint_32,png_get_compression_buffer_size)
+ PNGARG((png_structp png_ptr));
+
+extern PNG_EXPORT(void,png_set_compression_buffer_size)
+ PNGARG((png_structp png_ptr, png_uint_32 size));
+
+/* Reset the compression stream */
+extern PNG_EXPORT(int,png_reset_zstream) PNGARG((png_structp png_ptr));
+
+/* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */
+#ifdef PNG_USER_MEM_SUPPORTED
+extern PNG_EXPORT(png_structp,png_create_read_struct_2)
+ PNGARG((png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
+ png_malloc_ptr malloc_fn, png_free_ptr free_fn));
+extern PNG_EXPORT(png_structp,png_create_write_struct_2)
+ PNGARG((png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
+ png_malloc_ptr malloc_fn, png_free_ptr free_fn));
+#endif
+
+/* Write a PNG chunk - size, type, (optional) data, CRC. */
+extern PNG_EXPORT(void,png_write_chunk) PNGARG((png_structp png_ptr,
+ png_bytep chunk_name, png_bytep data, png_size_t length));
+
+/* Write the start of a PNG chunk - length and chunk name. */
+extern PNG_EXPORT(void,png_write_chunk_start) PNGARG((png_structp png_ptr,
+ png_bytep chunk_name, png_uint_32 length));
+
+/* Write the data of a PNG chunk started with png_write_chunk_start(). */
+extern PNG_EXPORT(void,png_write_chunk_data) PNGARG((png_structp png_ptr,
+ png_bytep data, png_size_t length));
+
+/* Finish a chunk started with png_write_chunk_start() (includes CRC). */
+extern PNG_EXPORT(void,png_write_chunk_end) PNGARG((png_structp png_ptr));
+
+/* Allocate and initialize the info structure */
+extern PNG_EXPORT(png_infop,png_create_info_struct)
+ PNGARG((png_structp png_ptr));
+
+/* Initialize the info structure (old interface - DEPRECATED) */
+extern PNG_EXPORT(void,png_info_init) PNGARG((png_infop info_ptr));
+#define png_info_init(info_ptr) png_info_init_3(&info_ptr, sizeof(png_info));
+extern PNG_EXPORT(void,png_info_init_3) PNGARG((png_infopp info_ptr,
+ png_size_t png_info_struct_size));
+
+/* Writes all the PNG information before the image. */
+extern PNG_EXPORT(void,png_write_info_before_PLTE) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+extern PNG_EXPORT(void,png_write_info) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+/* read the information before the actual image data. */
+extern PNG_EXPORT(void,png_read_info) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+extern PNG_EXPORT(png_charp,png_convert_to_rfc1123)
+ PNGARG((png_structp png_ptr, png_timep ptime));
+#endif
+
+#if !defined(_WIN32_WCE)
+/* "time.h" functions are not supported on WindowsCE */
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+/* convert from a struct tm to png_time */
+extern PNG_EXPORT(void,png_convert_from_struct_tm) PNGARG((png_timep ptime,
+ struct tm FAR * ttime));
+
+/* convert from time_t to png_time. Uses gmtime() */
+extern PNG_EXPORT(void,png_convert_from_time_t) PNGARG((png_timep ptime,
+ time_t ttime));
+#endif /* PNG_WRITE_tIME_SUPPORTED */
+#endif /* _WIN32_WCE */
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+/* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */
+extern PNG_EXPORT(void,png_set_expand) PNGARG((png_structp png_ptr));
+extern PNG_EXPORT(void,png_set_gray_1_2_4_to_8) PNGARG((png_structp png_ptr));
+extern PNG_EXPORT(void,png_set_palette_to_rgb) PNGARG((png_structp png_ptr));
+extern PNG_EXPORT(void,png_set_tRNS_to_alpha) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
+/* Use blue, green, red order for pixels. */
+extern PNG_EXPORT(void,png_set_bgr) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+/* Expand the grayscale to 24-bit RGB if necessary. */
+extern PNG_EXPORT(void,png_set_gray_to_rgb) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+/* Reduce RGB to grayscale. */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(void,png_set_rgb_to_gray) PNGARG((png_structp png_ptr,
+ int error_action, double red, double green ));
+#endif
+extern PNG_EXPORT(void,png_set_rgb_to_gray_fixed) PNGARG((png_structp png_ptr,
+ int error_action, png_fixed_point red, png_fixed_point green ));
+extern PNG_EXPORT(png_byte,png_get_rgb_to_gray_status) PNGARG((png_structp
+ png_ptr));
+#endif
+
+extern PNG_EXPORT(void,png_build_grayscale_palette) PNGARG((int bit_depth,
+ png_colorp palette));
+
+#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+extern PNG_EXPORT(void,png_set_strip_alpha) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \
+ defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+extern PNG_EXPORT(void,png_set_swap_alpha) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \
+ defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
+extern PNG_EXPORT(void,png_set_invert_alpha) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
+/* Add a filler byte to 24-bit RGB images. */
+extern PNG_EXPORT(void,png_set_filler) PNGARG((png_structp png_ptr,
+ png_uint_32 filler, int flags));
+/* The values of the PNG_FILLER_ defines should NOT be changed */
+#define PNG_FILLER_BEFORE 0
+#define PNG_FILLER_AFTER 1
+#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */
+
+#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
+/* Swap bytes in 16-bit depth files. */
+extern PNG_EXPORT(void,png_set_swap) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
+/* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */
+extern PNG_EXPORT(void,png_set_packing) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+/* Swap packing order of pixels in bytes. */
+extern PNG_EXPORT(void,png_set_packswap) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
+/* Converts files to legal bit depths. */
+extern PNG_EXPORT(void,png_set_shift) PNGARG((png_structp png_ptr,
+ png_color_8p true_bits));
+#endif
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
+ defined(PNG_WRITE_INTERLACING_SUPPORTED)
+/* Have the code handle the interlacing. Returns the number of passes. */
+extern PNG_EXPORT(int,png_set_interlace_handling) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
+/* Invert monochrome files */
+extern PNG_EXPORT(void,png_set_invert_mono) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+/* Handle alpha and tRNS by replacing with a background color. */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(void,png_set_background) PNGARG((png_structp png_ptr,
+ png_color_16p background_color, int background_gamma_code,
+ int need_expand, double background_gamma));
+#endif
+#define PNG_BACKGROUND_GAMMA_UNKNOWN 0
+#define PNG_BACKGROUND_GAMMA_SCREEN 1
+#define PNG_BACKGROUND_GAMMA_FILE 2
+#define PNG_BACKGROUND_GAMMA_UNIQUE 3
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+/* strip the second byte of information from a 16-bit depth file. */
+extern PNG_EXPORT(void,png_set_strip_16) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+/* Turn on dithering, and reduce the palette to the number of colors available. */
+extern PNG_EXPORT(void,png_set_dither) PNGARG((png_structp png_ptr,
+ png_colorp palette, int num_palette, int maximum_colors,
+ png_uint_16p histogram, int full_dither));
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+/* Handle gamma correction. Screen_gamma=(display_exponent) */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(void,png_set_gamma) PNGARG((png_structp png_ptr,
+ double screen_gamma, double default_file_gamma));
+#endif
+#endif
+
+#if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \
+ defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED)
+/* Permit or disallow empty PLTE (0: not permitted, 1: permitted) */
+/* Deprecated and will be removed. Use png_permit_mng_features() instead. */
+extern PNG_EXPORT(void,png_permit_empty_plte) PNGARG((png_structp png_ptr,
+ int empty_plte_permitted));
+#endif
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+/* Set how many lines between output flushes - 0 for no flushing */
+extern PNG_EXPORT(void,png_set_flush) PNGARG((png_structp png_ptr, int nrows));
+/* Flush the current PNG output buffer */
+extern PNG_EXPORT(void,png_write_flush) PNGARG((png_structp png_ptr));
+#endif
+
+/* optional update palette with requested transformations */
+extern PNG_EXPORT(void,png_start_read_image) PNGARG((png_structp png_ptr));
+
+/* optional call to update the users info structure */
+extern PNG_EXPORT(void,png_read_update_info) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+/* read a one or more rows of image data.*/
+extern PNG_EXPORT(void,png_read_rows) PNGARG((png_structp png_ptr,
+ png_bytepp row, png_bytepp display_row, png_uint_32 num_rows));
+
+/* read a row of data.*/
+extern PNG_EXPORT(void,png_read_row) PNGARG((png_structp png_ptr,
+ png_bytep row,
+ png_bytep display_row));
+
+/* read the whole image into memory at once. */
+extern PNG_EXPORT(void,png_read_image) PNGARG((png_structp png_ptr,
+ png_bytepp image));
+
+/* write a row of image data */
+extern PNG_EXPORT(void,png_write_row) PNGARG((png_structp png_ptr,
+ png_bytep row));
+
+/* write a few rows of image data */
+extern PNG_EXPORT(void,png_write_rows) PNGARG((png_structp png_ptr,
+ png_bytepp row, png_uint_32 num_rows));
+
+/* write the image data */
+extern PNG_EXPORT(void,png_write_image) PNGARG((png_structp png_ptr,
+ png_bytepp image));
+
+/* writes the end of the PNG file. */
+extern PNG_EXPORT(void,png_write_end) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+/* read the end of the PNG file. */
+extern PNG_EXPORT(void,png_read_end) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+/* free any memory associated with the png_info_struct */
+extern PNG_EXPORT(void,png_destroy_info_struct) PNGARG((png_structp png_ptr,
+ png_infopp info_ptr_ptr));
+
+/* free any memory associated with the png_struct and the png_info_structs */
+extern PNG_EXPORT(void,png_destroy_read_struct) PNGARG((png_structpp
+ png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr));
+
+/* free all memory used by the read (old method - NOT DLL EXPORTED) */
+extern void png_read_destroy PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_infop end_info_ptr));
+
+/* free any memory associated with the png_struct and the png_info_structs */
+extern PNG_EXPORT(void,png_destroy_write_struct)
+ PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr));
+
+/* free any memory used in info_ptr struct (old method - NOT DLL EXPORTED) */
+extern void png_write_destroy_info PNGARG((png_infop info_ptr));
+
+/* free any memory used in png_ptr struct (old method - NOT DLL EXPORTED) */
+extern void png_write_destroy PNGARG((png_structp png_ptr));
+
+/* set the libpng method of handling chunk CRC errors */
+extern PNG_EXPORT(void,png_set_crc_action) PNGARG((png_structp png_ptr,
+ int crit_action, int ancil_action));
+
+/* Values for png_set_crc_action() to say how to handle CRC errors in
+ * ancillary and critical chunks, and whether to use the data contained
+ * therein. Note that it is impossible to "discard" data in a critical
+ * chunk. For versions prior to 0.90, the action was always error/quit,
+ * whereas in version 0.90 and later, the action for CRC errors in ancillary
+ * chunks is warn/discard. These values should NOT be changed.
+ *
+ * value action:critical action:ancillary
+ */
+#define PNG_CRC_DEFAULT 0 /* error/quit warn/discard data */
+#define PNG_CRC_ERROR_QUIT 1 /* error/quit error/quit */
+#define PNG_CRC_WARN_DISCARD 2 /* (INVALID) warn/discard data */
+#define PNG_CRC_WARN_USE 3 /* warn/use data warn/use data */
+#define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */
+#define PNG_CRC_NO_CHANGE 5 /* use current value use current value */
+
+/* These functions give the user control over the scan-line filtering in
+ * libpng and the compression methods used by zlib. These functions are
+ * mainly useful for testing, as the defaults should work with most users.
+ * Those users who are tight on memory or want faster performance at the
+ * expense of compression can modify them. See the compression library
+ * header file (zlib.h) for an explination of the compression functions.
+ */
+
+/* set the filtering method(s) used by libpng. Currently, the only valid
+ * value for "method" is 0.
+ */
+extern PNG_EXPORT(void,png_set_filter) PNGARG((png_structp png_ptr, int method,
+ int filters));
+
+/* Flags for png_set_filter() to say which filters to use. The flags
+ * are chosen so that they don't conflict with real filter types
+ * below, in case they are supplied instead of the #defined constants.
+ * These values should NOT be changed.
+ */
+#define PNG_NO_FILTERS 0x00
+#define PNG_FILTER_NONE 0x08
+#define PNG_FILTER_SUB 0x10
+#define PNG_FILTER_UP 0x20
+#define PNG_FILTER_AVG 0x40
+#define PNG_FILTER_PAETH 0x80
+#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \
+ PNG_FILTER_AVG | PNG_FILTER_PAETH)
+
+/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now.
+ * These defines should NOT be changed.
+ */
+#define PNG_FILTER_VALUE_NONE 0
+#define PNG_FILTER_VALUE_SUB 1
+#define PNG_FILTER_VALUE_UP 2
+#define PNG_FILTER_VALUE_AVG 3
+#define PNG_FILTER_VALUE_PAETH 4
+#define PNG_FILTER_VALUE_LAST 5
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* EXPERIMENTAL */
+/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_
+ * defines, either the default (minimum-sum-of-absolute-differences), or
+ * the experimental method (weighted-minimum-sum-of-absolute-differences).
+ *
+ * Weights are factors >= 1.0, indicating how important it is to keep the
+ * filter type consistent between rows. Larger numbers mean the current
+ * filter is that many times as likely to be the same as the "num_weights"
+ * previous filters. This is cumulative for each previous row with a weight.
+ * There needs to be "num_weights" values in "filter_weights", or it can be
+ * NULL if the weights aren't being specified. Weights have no influence on
+ * the selection of the first row filter. Well chosen weights can (in theory)
+ * improve the compression for a given image.
+ *
+ * Costs are factors >= 1.0 indicating the relative decoding costs of a
+ * filter type. Higher costs indicate more decoding expense, and are
+ * therefore less likely to be selected over a filter with lower computational
+ * costs. There needs to be a value in "filter_costs" for each valid filter
+ * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't
+ * setting the costs. Costs try to improve the speed of decompression without
+ * unduly increasing the compressed image size.
+ *
+ * A negative weight or cost indicates the default value is to be used, and
+ * values in the range [0.0, 1.0) indicate the value is to remain unchanged.
+ * The default values for both weights and costs are currently 1.0, but may
+ * change if good general weighting/cost heuristics can be found. If both
+ * the weights and costs are set to 1.0, this degenerates the WEIGHTED method
+ * to the UNWEIGHTED method, but with added encoding time/computation.
+ */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(void,png_set_filter_heuristics) PNGARG((png_structp png_ptr,
+ int heuristic_method, int num_weights, png_doublep filter_weights,
+ png_doublep filter_costs));
+#endif
+#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
+
+/* Heuristic used for row filter selection. These defines should NOT be
+ * changed.
+ */
+#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */
+#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */
+#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */
+#define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */
+
+/* Set the library compression level. Currently, valid values range from
+ * 0 - 9, corresponding directly to the zlib compression levels 0 - 9
+ * (0 - no compression, 9 - "maximal" compression). Note that tests have
+ * shown that zlib compression levels 3-6 usually perform as well as level 9
+ * for PNG images, and do considerably fewer caclulations. In the future,
+ * these values may not correspond directly to the zlib compression levels.
+ */
+extern PNG_EXPORT(void,png_set_compression_level) PNGARG((png_structp png_ptr,
+ int level));
+
+extern PNG_EXPORT(void,png_set_compression_mem_level)
+ PNGARG((png_structp png_ptr, int mem_level));
+
+extern PNG_EXPORT(void,png_set_compression_strategy)
+ PNGARG((png_structp png_ptr, int strategy));
+
+extern PNG_EXPORT(void,png_set_compression_window_bits)
+ PNGARG((png_structp png_ptr, int window_bits));
+
+extern PNG_EXPORT(void,png_set_compression_method) PNGARG((png_structp png_ptr,
+ int method));
+
+/* These next functions are called for input/output, memory, and error
+ * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c,
+ * and call standard C I/O routines such as fread(), fwrite(), and
+ * fprintf(). These functions can be made to use other I/O routines
+ * at run time for those applications that need to handle I/O in a
+ * different manner by calling png_set_???_fn(). See libpng.txt for
+ * more information.
+ */
+
+#if !defined(PNG_NO_STDIO)
+/* Initialize the input/output for the PNG file to the default functions. */
+extern PNG_EXPORT(void,png_init_io) PNGARG((png_structp png_ptr, png_FILE_p fp));
+#endif
+
+/* Replace the (error and abort), and warning functions with user
+ * supplied functions. If no messages are to be printed you must still
+ * write and use replacement functions. The replacement error_fn should
+ * still do a longjmp to the last setjmp location if you are using this
+ * method of error handling. If error_fn or warning_fn is NULL, the
+ * default function will be used.
+ */
+
+extern PNG_EXPORT(void,png_set_error_fn) PNGARG((png_structp png_ptr,
+ png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn));
+
+/* Return the user pointer associated with the error functions */
+extern PNG_EXPORT(png_voidp,png_get_error_ptr) PNGARG((png_structp png_ptr));
+
+/* Replace the default data output functions with a user supplied one(s).
+ * If buffered output is not used, then output_flush_fn can be set to NULL.
+ * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time
+ * output_flush_fn will be ignored (and thus can be NULL).
+ */
+extern PNG_EXPORT(void,png_set_write_fn) PNGARG((png_structp png_ptr,
+ png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn));
+
+/* Replace the default data input function with a user supplied one. */
+extern PNG_EXPORT(void,png_set_read_fn) PNGARG((png_structp png_ptr,
+ png_voidp io_ptr, png_rw_ptr read_data_fn));
+
+/* Return the user pointer associated with the I/O functions */
+extern PNG_EXPORT(png_voidp,png_get_io_ptr) PNGARG((png_structp png_ptr));
+
+extern PNG_EXPORT(void,png_set_read_status_fn) PNGARG((png_structp png_ptr,
+ png_read_status_ptr read_row_fn));
+
+extern PNG_EXPORT(void,png_set_write_status_fn) PNGARG((png_structp png_ptr,
+ png_write_status_ptr write_row_fn));
+
+#ifdef PNG_USER_MEM_SUPPORTED
+/* Replace the default memory allocation functions with user supplied one(s). */
+extern PNG_EXPORT(void,png_set_mem_fn) PNGARG((png_structp png_ptr,
+ png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn));
+/* Return the user pointer associated with the memory functions */
+extern PNG_EXPORT(png_voidp,png_get_mem_ptr) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_LEGACY_SUPPORTED)
+extern PNG_EXPORT(void,png_set_read_user_transform_fn) PNGARG((png_structp
+ png_ptr, png_user_transform_ptr read_user_transform_fn));
+#endif
+
+#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_LEGACY_SUPPORTED)
+extern PNG_EXPORT(void,png_set_write_user_transform_fn) PNGARG((png_structp
+ png_ptr, png_user_transform_ptr write_user_transform_fn));
+#endif
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_LEGACY_SUPPORTED)
+extern PNG_EXPORT(void,png_set_user_transform_info) PNGARG((png_structp
+ png_ptr, png_voidp user_transform_ptr, int user_transform_depth,
+ int user_transform_channels));
+/* Return the user pointer associated with the user transform functions */
+extern PNG_EXPORT(png_voidp,png_get_user_transform_ptr)
+ PNGARG((png_structp png_ptr));
+#endif
+
+#ifdef PNG_USER_CHUNKS_SUPPORTED
+extern PNG_EXPORT(void,png_set_read_user_chunk_fn) PNGARG((png_structp png_ptr,
+ png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn));
+extern PNG_EXPORT(png_voidp,png_get_user_chunk_ptr) PNGARG((png_structp
+ png_ptr));
+#endif
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+/* Sets the function callbacks for the push reader, and a pointer to a
+ * user-defined structure available to the callback functions.
+ */
+extern PNG_EXPORT(void,png_set_progressive_read_fn) PNGARG((png_structp png_ptr,
+ png_voidp progressive_ptr,
+ png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn,
+ png_progressive_end_ptr end_fn));
+
+/* returns the user pointer associated with the push read functions */
+extern PNG_EXPORT(png_voidp,png_get_progressive_ptr)
+ PNGARG((png_structp png_ptr));
+
+/* function to be called when data becomes available */
+extern PNG_EXPORT(void,png_process_data) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_bytep buffer, png_size_t buffer_size));
+
+/* function that combines rows. Not very much different than the
+ * png_combine_row() call. Is this even used?????
+ */
+extern PNG_EXPORT(void,png_progressive_combine_row) PNGARG((png_structp png_ptr,
+ png_bytep old_row, png_bytep new_row));
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+
+extern PNG_EXPORT(png_voidp,png_malloc) PNGARG((png_structp png_ptr,
+ png_uint_32 size));
+
+/* frees a pointer allocated by png_malloc() */
+extern PNG_EXPORT(void,png_free) PNGARG((png_structp png_ptr, png_voidp ptr));
+
+/* Free data that was allocated internally */
+extern PNG_EXPORT(void,png_free_data) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 free_me, int num));
+#ifdef PNG_FREE_ME_SUPPORTED
+/* Reassign responsibility for freeing existing data, whether allocated
+ * by libpng or by the application */
+extern PNG_EXPORT(void,png_data_freer) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, int freer, png_uint_32 mask));
+#endif
+/* assignments for png_data_freer */
+#define PNG_DESTROY_WILL_FREE_DATA 1
+#define PNG_SET_WILL_FREE_DATA 1
+#define PNG_USER_WILL_FREE_DATA 2
+/* Flags for png_ptr->free_me and info_ptr->free_me */
+#define PNG_FREE_HIST 0x0008
+#define PNG_FREE_ICCP 0x0010
+#define PNG_FREE_SPLT 0x0020
+#define PNG_FREE_ROWS 0x0040
+#define PNG_FREE_PCAL 0x0080
+#define PNG_FREE_SCAL 0x0100
+#define PNG_FREE_UNKN 0x0200
+#define PNG_FREE_LIST 0x0400
+#define PNG_FREE_PLTE 0x1000
+#define PNG_FREE_TRNS 0x2000
+#define PNG_FREE_TEXT 0x4000
+#define PNG_FREE_ALL 0x7fff
+#define PNG_FREE_MUL 0x4220 /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */
+
+#ifdef PNG_USER_MEM_SUPPORTED
+extern PNG_EXPORT(png_voidp,png_malloc_default) PNGARG((png_structp png_ptr,
+ png_uint_32 size));
+extern PNG_EXPORT(void,png_free_default) PNGARG((png_structp png_ptr,
+ png_voidp ptr));
+#endif
+
+extern PNG_EXPORT(png_voidp,png_memcpy_check) PNGARG((png_structp png_ptr,
+ png_voidp s1, png_voidp s2, png_uint_32 size));
+
+extern PNG_EXPORT(png_voidp,png_memset_check) PNGARG((png_structp png_ptr,
+ png_voidp s1, int value, png_uint_32 size));
+
+#if defined(USE_FAR_KEYWORD) /* memory model conversion function */
+extern void *png_far_to_near PNGARG((png_structp png_ptr,png_voidp ptr,
+ int check));
+#endif /* USE_FAR_KEYWORD */
+
+/* Fatal error in PNG image of libpng - can't continue */
+extern PNG_EXPORT(void,png_error) PNGARG((png_structp png_ptr,
+ png_const_charp error));
+
+/* The same, but the chunk name is prepended to the error string. */
+extern PNG_EXPORT(void,png_chunk_error) PNGARG((png_structp png_ptr,
+ png_const_charp error));
+
+/* Non-fatal error in libpng. Can continue, but may have a problem. */
+extern PNG_EXPORT(void,png_warning) PNGARG((png_structp png_ptr,
+ png_const_charp message));
+
+/* Non-fatal error in libpng, chunk name is prepended to message. */
+extern PNG_EXPORT(void,png_chunk_warning) PNGARG((png_structp png_ptr,
+ png_const_charp message));
+
+/* The png_set_<chunk> functions are for storing values in the png_info_struct.
+ * Similarly, the png_get_<chunk> calls are used to read values from the
+ * png_info_struct, either storing the parameters in the passed variables, or
+ * setting pointers into the png_info_struct where the data is stored. The
+ * png_get_<chunk> functions return a non-zero value if the data was available
+ * in info_ptr, or return zero and do not change any of the parameters if the
+ * data was not available.
+ *
+ * These functions should be used instead of directly accessing png_info
+ * to avoid problems with future changes in the size and internal layout of
+ * png_info_struct.
+ */
+/* Returns "flag" if chunk data is valid in info_ptr. */
+extern PNG_EXPORT(png_uint_32,png_get_valid) PNGARG((png_structp png_ptr,
+png_infop info_ptr, png_uint_32 flag));
+
+/* Returns number of bytes needed to hold a transformed row. */
+extern PNG_EXPORT(png_uint_32,png_get_rowbytes) PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+
+#if defined(PNG_INFO_IMAGE_SUPPORTED)
+/* Returns row_pointers, which is an array of pointers to scanlines that was
+returned from png_read_png(). */
+extern PNG_EXPORT(png_bytepp,png_get_rows) PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+/* Set row_pointers, which is an array of pointers to scanlines for use
+by png_write_png(). */
+extern PNG_EXPORT(void,png_set_rows) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_bytepp row_pointers));
+#endif
+
+/* Returns number of color channels in image. */
+extern PNG_EXPORT(png_byte,png_get_channels) PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+
+#ifdef PNG_EASY_ACCESS_SUPPORTED
+/* Returns image width in pixels. */
+extern PNG_EXPORT(png_uint_32, png_get_image_width) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image height in pixels. */
+extern PNG_EXPORT(png_uint_32, png_get_image_height) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image bit_depth. */
+extern PNG_EXPORT(png_byte, png_get_bit_depth) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image color_type. */
+extern PNG_EXPORT(png_byte, png_get_color_type) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image filter_type. */
+extern PNG_EXPORT(png_byte, png_get_filter_type) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image interlace_type. */
+extern PNG_EXPORT(png_byte, png_get_interlace_type) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image compression_type. */
+extern PNG_EXPORT(png_byte, png_get_compression_type) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image resolution in pixels per meter, from pHYs chunk data. */
+extern PNG_EXPORT(png_uint_32, png_get_pixels_per_meter) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+extern PNG_EXPORT(png_uint_32, png_get_x_pixels_per_meter) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+extern PNG_EXPORT(png_uint_32, png_get_y_pixels_per_meter) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns pixel aspect ratio, computed from pHYs chunk data. */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(float, png_get_pixel_aspect_ratio) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+#endif
+
+/* Returns image x, y offset in pixels or microns, from oFFs chunk data. */
+extern PNG_EXPORT(png_int_32, png_get_x_offset_pixels) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+extern PNG_EXPORT(png_int_32, png_get_y_offset_pixels) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+extern PNG_EXPORT(png_int_32, png_get_x_offset_microns) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+extern PNG_EXPORT(png_int_32, png_get_y_offset_microns) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+#endif /* PNG_EASY_ACCESS_SUPPORTED */
+
+/* Returns pointer to signature string read from PNG header */
+extern PNG_EXPORT(png_bytep,png_get_signature) PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+
+#if defined(PNG_bKGD_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_bKGD) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_color_16p *background));
+#endif
+
+#if defined(PNG_bKGD_SUPPORTED)
+extern PNG_EXPORT(void,png_set_bKGD) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_color_16p background));
+#endif
+
+#if defined(PNG_cHRM_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(png_uint_32,png_get_cHRM) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, double *white_x, double *white_y, double *red_x,
+ double *red_y, double *green_x, double *green_y, double *blue_x,
+ double *blue_y));
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+extern PNG_EXPORT(png_uint_32,png_get_cHRM_fixed) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_fixed_point *int_white_x, png_fixed_point
+ *int_white_y, png_fixed_point *int_red_x, png_fixed_point *int_red_y,
+ png_fixed_point *int_green_x, png_fixed_point *int_green_y, png_fixed_point
+ *int_blue_x, png_fixed_point *int_blue_y));
+#endif
+#endif
+
+#if defined(PNG_cHRM_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(void,png_set_cHRM) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, double white_x, double white_y, double red_x,
+ double red_y, double green_x, double green_y, double blue_x, double blue_y));
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+extern PNG_EXPORT(void,png_set_cHRM_fixed) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_fixed_point int_white_x, png_fixed_point int_white_y,
+ png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point
+ int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x,
+ png_fixed_point int_blue_y));
+#endif
+#endif
+
+#if defined(PNG_gAMA_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(png_uint_32,png_get_gAMA) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, double *file_gamma));
+#endif
+extern PNG_EXPORT(png_uint_32,png_get_gAMA_fixed) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_fixed_point *int_file_gamma));
+#endif
+
+#if defined(PNG_gAMA_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(void,png_set_gAMA) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, double file_gamma));
+#endif
+extern PNG_EXPORT(void,png_set_gAMA_fixed) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_fixed_point int_file_gamma));
+#endif
+
+#if defined(PNG_hIST_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_hIST) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_16p *hist));
+#endif
+
+#if defined(PNG_hIST_SUPPORTED)
+extern PNG_EXPORT(void,png_set_hIST) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_16p hist));
+#endif
+
+extern PNG_EXPORT(png_uint_32,png_get_IHDR) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 *width, png_uint_32 *height,
+ int *bit_depth, int *color_type, int *interlace_method,
+ int *compression_method, int *filter_method));
+
+extern PNG_EXPORT(void,png_set_IHDR) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth,
+ int color_type, int interlace_method, int compression_method,
+ int filter_method));
+
+#if defined(PNG_oFFs_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_oFFs) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_int_32 *offset_x, png_int_32 *offset_y,
+ int *unit_type));
+#endif
+
+#if defined(PNG_oFFs_SUPPORTED)
+extern PNG_EXPORT(void,png_set_oFFs) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_int_32 offset_x, png_int_32 offset_y,
+ int unit_type));
+#endif
+
+#if defined(PNG_pCAL_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_pCAL) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_charp *purpose, png_int_32 *X0, png_int_32 *X1,
+ int *type, int *nparams, png_charp *units, png_charpp *params));
+#endif
+
+#if defined(PNG_pCAL_SUPPORTED)
+extern PNG_EXPORT(void,png_set_pCAL) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_charp purpose, png_int_32 X0, png_int_32 X1,
+ int type, int nparams, png_charp units, png_charpp params));
+#endif
+
+#if defined(PNG_pHYs_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_pHYs) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type));
+#endif
+
+#if defined(PNG_pHYs_SUPPORTED)
+extern PNG_EXPORT(void,png_set_pHYs) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type));
+#endif
+
+extern PNG_EXPORT(png_uint_32,png_get_PLTE) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_colorp *palette, int *num_palette));
+
+extern PNG_EXPORT(void,png_set_PLTE) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_colorp palette, int num_palette));
+
+#if defined(PNG_sBIT_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_sBIT) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_color_8p *sig_bit));
+#endif
+
+#if defined(PNG_sBIT_SUPPORTED)
+extern PNG_EXPORT(void,png_set_sBIT) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_color_8p sig_bit));
+#endif
+
+#if defined(PNG_sRGB_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_sRGB) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, int *intent));
+#endif
+
+#if defined(PNG_sRGB_SUPPORTED)
+extern PNG_EXPORT(void,png_set_sRGB) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, int intent));
+extern PNG_EXPORT(void,png_set_sRGB_gAMA_and_cHRM) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, int intent));
+#endif
+
+#if defined(PNG_iCCP_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_iCCP) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_charpp name, int *compression_type,
+ png_charpp profile, png_uint_32 *proflen));
+ /* Note to maintainer: profile should be png_bytepp */
+#endif
+
+#if defined(PNG_iCCP_SUPPORTED)
+extern PNG_EXPORT(void,png_set_iCCP) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_charp name, int compression_type,
+ png_charp profile, png_uint_32 proflen));
+ /* Note to maintainer: profile should be png_bytep */
+#endif
+
+#if defined(PNG_sPLT_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_sPLT) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_sPLT_tpp entries));
+#endif
+
+#if defined(PNG_sPLT_SUPPORTED)
+extern PNG_EXPORT(void,png_set_sPLT) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_sPLT_tp entries, int nentries));
+#endif
+
+#if defined(PNG_TEXT_SUPPORTED)
+/* png_get_text also returns the number of text chunks in *num_text */
+extern PNG_EXPORT(png_uint_32,png_get_text) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_textp *text_ptr, int *num_text));
+#endif
+
+/*
+ * Note while png_set_text() will accept a structure whose text,
+ * language, and translated keywords are NULL pointers, the structure
+ * returned by png_get_text will always contain regular
+ * zero-terminated C strings. They might be empty strings but
+ * they will never be NULL pointers.
+ */
+
+#if defined(PNG_TEXT_SUPPORTED)
+extern PNG_EXPORT(void,png_set_text) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_textp text_ptr, int num_text));
+#endif
+
+#if defined(PNG_tIME_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_tIME) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_timep *mod_time));
+#endif
+
+#if defined(PNG_tIME_SUPPORTED)
+extern PNG_EXPORT(void,png_set_tIME) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_timep mod_time));
+#endif
+
+#if defined(PNG_tRNS_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_tRNS) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_bytep *trans, int *num_trans,
+ png_color_16p *trans_values));
+#endif
+
+#if defined(PNG_tRNS_SUPPORTED)
+extern PNG_EXPORT(void,png_set_tRNS) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_bytep trans, int num_trans,
+ png_color_16p trans_values));
+#endif
+
+#if defined(PNG_tRNS_SUPPORTED)
+#endif
+
+#if defined(PNG_sCAL_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(png_uint_32,png_get_sCAL) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, int *unit, double *width, double *height));
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+extern PNG_EXPORT(png_uint_32,png_get_sCAL_s) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, int *unit, png_charpp swidth, png_charpp sheight));
+#endif
+#endif
+#endif /* PNG_sCAL_SUPPORTED */
+
+#if defined(PNG_sCAL_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(void,png_set_sCAL) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, int unit, double width, double height));
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+extern PNG_EXPORT(void,png_set_sCAL_s) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, int unit, png_charp swidth, png_charp sheight));
+#endif
+#endif /* PNG_sCAL_SUPPORTED || PNG_WRITE_sCAL_SUPPORTED */
+
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+/* provide a list of chunks and how they are to be handled, if the built-in
+ handling or default unknown chunk handling is not desired. Any chunks not
+ listed will be handled in the default manner. The IHDR and IEND chunks
+ must not be listed.
+ keep = 0: follow default behavour
+ = 1: do not keep
+ = 2: keep only if safe-to-copy
+ = 3: keep even if unsafe-to-copy
+*/
+extern PNG_EXPORT(void, png_set_keep_unknown_chunks) PNGARG((png_structp
+ png_ptr, int keep, png_bytep chunk_list, int num_chunks));
+extern PNG_EXPORT(void, png_set_unknown_chunks) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns));
+extern PNG_EXPORT(void, png_set_unknown_chunk_location)
+ PNGARG((png_structp png_ptr, png_infop info_ptr, int chunk, int location));
+extern PNG_EXPORT(png_uint_32,png_get_unknown_chunks) PNGARG((png_structp
+ png_ptr, png_infop info_ptr, png_unknown_chunkpp entries));
+#endif
+
+/* Png_free_data() will turn off the "valid" flag for anything it frees.
+ If you need to turn it off for a chunk that your application has freed,
+ you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK); */
+extern PNG_EXPORT(void, png_set_invalid) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, int mask));
+
+#if defined(PNG_INFO_IMAGE_SUPPORTED)
+/* The "params" pointer is currently not used and is for future expansion. */
+extern PNG_EXPORT(void, png_read_png) PNGARG((png_structp png_ptr,
+ png_infop info_ptr,
+ int transforms,
+ png_voidp params));
+extern PNG_EXPORT(void, png_write_png) PNGARG((png_structp png_ptr,
+ png_infop info_ptr,
+ int transforms,
+ png_voidp params));
+#endif
+
+/* Define PNG_DEBUG at compile time for debugging information. Higher
+ * numbers for PNG_DEBUG mean more debugging information. This has
+ * only been added since version 0.95 so it is not implemented throughout
+ * libpng yet, but more support will be added as needed.
+ */
+#ifdef PNG_DEBUG
+#if (PNG_DEBUG > 0)
+#if !defined(PNG_DEBUG_FILE) && defined(_MSC_VER)
+#include <crtdbg.h>
+#if (PNG_DEBUG > 1)
+#define png_debug(l,m) _RPT0(_CRT_WARN,m)
+#define png_debug1(l,m,p1) _RPT1(_CRT_WARN,m,p1)
+#define png_debug2(l,m,p1,p2) _RPT2(_CRT_WARN,m,p1,p2)
+#endif
+#else /* PNG_DEBUG_FILE || !_MSC_VER */
+#ifndef PNG_DEBUG_FILE
+#define PNG_DEBUG_FILE stderr
+#endif /* PNG_DEBUG_FILE */
+#if (PNG_DEBUG > 1)
+#define png_debug(l,m) \
+{ \
+ int num_tabs=l; \
+ fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \
+ (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":"")))); \
+}
+#define png_debug1(l,m,p1) \
+{ \
+ int num_tabs=l; \
+ fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \
+ (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1); \
+}
+#define png_debug2(l,m,p1,p2) \
+{ \
+ int num_tabs=l; \
+ fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \
+ (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1,p2); \
+}
+#endif /* (PNG_DEBUG > 1) */
+#endif /* _MSC_VER */
+#endif /* (PNG_DEBUG > 0) */
+#endif /* PNG_DEBUG */
+#ifndef png_debug
+#define png_debug(l, m)
+#endif
+#ifndef png_debug1
+#define png_debug1(l, m, p1)
+#endif
+#ifndef png_debug2
+#define png_debug2(l, m, p1, p2)
+#endif
+
+extern PNG_EXPORT(png_bytep,png_sig_bytes) PNGARG((void));
+
+extern PNG_EXPORT(png_charp,png_get_copyright) PNGARG((png_structp png_ptr));
+extern PNG_EXPORT(png_charp,png_get_header_ver) PNGARG((png_structp png_ptr));
+extern PNG_EXPORT(png_charp,png_get_header_version) PNGARG((png_structp png_ptr));
+extern PNG_EXPORT(png_charp,png_get_libpng_ver) PNGARG((png_structp png_ptr));
+
+#ifdef PNG_MNG_FEATURES_SUPPORTED
+extern PNG_EXPORT(png_uint_32,png_permit_mng_features) PNGARG((png_structp
+ png_ptr, png_uint_32 mng_features_permitted));
+#endif
+
+/* Added to version 1.2.0 */
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
+#define PNG_ASM_FLAG_MMX_SUPPORT_COMPILED 0x01 /* not user-settable */
+#define PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU 0x02 /* not user-settable */
+#define PNG_ASM_FLAG_MMX_READ_COMBINE_ROW 0x04
+#define PNG_ASM_FLAG_MMX_READ_INTERLACE 0x08
+#define PNG_ASM_FLAG_MMX_READ_FILTER_SUB 0x10
+#define PNG_ASM_FLAG_MMX_READ_FILTER_UP 0x20
+#define PNG_ASM_FLAG_MMX_READ_FILTER_AVG 0x40
+#define PNG_ASM_FLAG_MMX_READ_FILTER_PAETH 0x80
+#define PNG_ASM_FLAGS_INITIALIZED 0x80000000 /* not user-settable */
+
+#define PNG_MMX_READ_FLAGS ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
+ | PNG_ASM_FLAG_MMX_READ_INTERLACE \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_UP \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH )
+#define PNG_MMX_WRITE_FLAGS ( 0 )
+
+#define PNG_MMX_FLAGS ( PNG_ASM_FLAG_MMX_SUPPORT_COMPILED \
+ | PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU \
+ | PNG_MMX_READ_FLAGS \
+ | PNG_MMX_WRITE_FLAGS )
+
+#define PNG_SELECT_READ 1
+#define PNG_SELECT_WRITE 2
+
+
+/* pngget.c */
+extern PNG_EXPORT(png_uint_32,png_get_mmx_flagmask)
+ PNGARG((int flag_select, int *compilerID));
+
+/* pngget.c */
+extern PNG_EXPORT(png_uint_32,png_get_asm_flagmask)
+ PNGARG((int flag_select));
+
+/* pngget.c */
+extern PNG_EXPORT(png_uint_32,png_get_asm_flags)
+ PNGARG((png_structp png_ptr));
+
+/* pngget.c */
+extern PNG_EXPORT(png_byte,png_get_mmx_bitdepth_threshold)
+ PNGARG((png_structp png_ptr));
+
+/* pngget.c */
+extern PNG_EXPORT(png_uint_32,png_get_mmx_rowbytes_threshold)
+ PNGARG((png_structp png_ptr));
+
+/* pngset.c */
+extern PNG_EXPORT(void,png_set_asm_flags)
+ PNGARG((png_structp png_ptr, png_uint_32 asm_flags));
+
+/* pngset.c */
+extern PNG_EXPORT(void,png_set_mmx_thresholds)
+ PNGARG((png_structp png_ptr, png_byte mmx_bitdepth_threshold,
+ png_uint_32 mmx_rowbytes_threshold));
+
+#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
+
+/* png.c, pnggccrd.c, or pngvcrd.c */
+extern PNG_EXPORT(int,png_mmx_support) PNGARG((void));
+
+/* Strip the prepended error numbers ("#nnn ") from error and warning
+ * messages before passing them to the error or warning handler. */
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+extern PNG_EXPORT(void,png_set_strip_error_numbers) PNGARG((png_structp
+ png_ptr, png_uint_32 strip_mode));
+#endif
+
+/* Maintainer: Put new public prototypes here ^, in libpng.3, and project defs */
+
+#define PNG_HEADER_VERSION_STRING \
+ " libpng version 1.2.0 - September 1, 2001 (header)\n"
+
+#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED
+/* With these routines we avoid an integer divide, which will be slower on
+ * most machines. However, it does take more operations than the corresponding
+ * divide method, so it may be slower on a few RISC systems. There are two
+ * shifts (by 8 or 16 bits) and an addition, versus a single integer divide.
+ *
+ * Note that the rounding factors are NOT supposed to be the same! 128 and
+ * 32768 are correct for the NODIV code; 127 and 32767 are correct for the
+ * standard method.
+ *
+ * [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ]
+ */
+
+ /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */
+
+# define png_composite(composite, fg, alpha, bg) \
+ { png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) * (png_uint_16)(alpha) \
+ + (png_uint_16)(bg)*(png_uint_16)(255 - \
+ (png_uint_16)(alpha)) + (png_uint_16)128); \
+ (composite) = (png_byte)((temp + (temp >> 8)) >> 8); }
+
+# define png_composite_16(composite, fg, alpha, bg) \
+ { png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) * (png_uint_32)(alpha) \
+ + (png_uint_32)(bg)*(png_uint_32)(65535L - \
+ (png_uint_32)(alpha)) + (png_uint_32)32768L); \
+ (composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); }
+
+#else /* standard method using integer division */
+
+# define png_composite(composite, fg, alpha, bg) \
+ (composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) + \
+ (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \
+ (png_uint_16)127) / 255)
+
+# define png_composite_16(composite, fg, alpha, bg) \
+ (composite) = (png_uint_16)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \
+ (png_uint_32)(bg)*(png_uint_32)(65535L - (png_uint_32)(alpha)) + \
+ (png_uint_32)32767) / (png_uint_32)65535L)
+
+#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */
+
+/* These next functions are used internally in the code. They generally
+ * shouldn't be used unless you are writing code to add or replace some
+ * functionality in libpng. More information about most functions can
+ * be found in the files where the functions are located.
+ */
+
+#if defined(PNG_INTERNAL)
+
+/* Various modes of operation. Note that after an init, mode is set to
+ * zero automatically when the structure is created.
+ */
+#define PNG_HAVE_IHDR 0x01
+#define PNG_HAVE_PLTE 0x02
+#define PNG_HAVE_IDAT 0x04
+#define PNG_AFTER_IDAT 0x08
+#define PNG_HAVE_IEND 0x10
+#define PNG_HAVE_gAMA 0x20
+#define PNG_HAVE_cHRM 0x40
+#define PNG_HAVE_sRGB 0x80
+#define PNG_HAVE_CHUNK_HEADER 0x100
+#define PNG_WROTE_tIME 0x200
+#define PNG_WROTE_INFO_BEFORE_PLTE 0x400
+#define PNG_BACKGROUND_IS_GRAY 0x800
+#define PNG_HAVE_PNG_SIGNATURE 0x1000
+
+/* flags for the transformations the PNG library does on the image data */
+#define PNG_BGR 0x0001
+#define PNG_INTERLACE 0x0002
+#define PNG_PACK 0x0004
+#define PNG_SHIFT 0x0008
+#define PNG_SWAP_BYTES 0x0010
+#define PNG_INVERT_MONO 0x0020
+#define PNG_DITHER 0x0040
+#define PNG_BACKGROUND 0x0080
+#define PNG_BACKGROUND_EXPAND 0x0100
+ /* 0x0200 unused */
+#define PNG_16_TO_8 0x0400
+#define PNG_RGBA 0x0800
+#define PNG_EXPAND 0x1000
+#define PNG_GAMMA 0x2000
+#define PNG_GRAY_TO_RGB 0x4000
+#define PNG_FILLER 0x8000L
+#define PNG_PACKSWAP 0x10000L
+#define PNG_SWAP_ALPHA 0x20000L
+#define PNG_STRIP_ALPHA 0x40000L
+#define PNG_INVERT_ALPHA 0x80000L
+#define PNG_USER_TRANSFORM 0x100000L
+#define PNG_RGB_TO_GRAY_ERR 0x200000L
+#define PNG_RGB_TO_GRAY_WARN 0x400000L
+#define PNG_RGB_TO_GRAY 0x600000L /* two bits, RGB_TO_GRAY_ERR|WARN */
+
+/* flags for png_create_struct */
+#define PNG_STRUCT_PNG 0x0001
+#define PNG_STRUCT_INFO 0x0002
+
+/* Scaling factor for filter heuristic weighting calculations */
+#define PNG_WEIGHT_SHIFT 8
+#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT))
+#define PNG_COST_SHIFT 3
+#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT))
+
+/* flags for the png_ptr->flags rather than declaring a byte for each one */
+#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001
+#define PNG_FLAG_ZLIB_CUSTOM_LEVEL 0x0002
+#define PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL 0x0004
+#define PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS 0x0008
+#define PNG_FLAG_ZLIB_CUSTOM_METHOD 0x0010
+#define PNG_FLAG_ZLIB_FINISHED 0x0020
+#define PNG_FLAG_ROW_INIT 0x0040
+#define PNG_FLAG_FILLER_AFTER 0x0080
+#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100
+#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200
+#define PNG_FLAG_CRC_CRITICAL_USE 0x0400
+#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800
+#define PNG_FLAG_FREE_PLTE 0x1000
+#define PNG_FLAG_FREE_TRNS 0x2000
+#define PNG_FLAG_FREE_HIST 0x4000
+#define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000L
+#define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000L
+#define PNG_FLAG_LIBRARY_MISMATCH 0x20000L
+#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000L
+#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000L
+
+/* For use in png_set_keep_unknown, png_handle_as_unknown */
+#define HANDLE_CHUNK_AS_DEFAULT 0
+#define HANDLE_CHUNK_NEVER 1
+#define HANDLE_CHUNK_IF_SAFE 2
+#define HANDLE_CHUNK_ALWAYS 3
+
+#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \
+ PNG_FLAG_CRC_ANCILLARY_NOWARN)
+
+#define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \
+ PNG_FLAG_CRC_CRITICAL_IGNORE)
+
+#define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \
+ PNG_FLAG_CRC_CRITICAL_MASK)
+
+/* save typing and make code easier to understand */
+#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \
+ abs((int)((c1).green) - (int)((c2).green)) + \
+ abs((int)((c1).blue) - (int)((c2).blue)))
+
+/* variables declared in png.c - only it needs to define PNG_NO_EXTERN */
+#if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN)
+/* place to hold the signature string for a PNG file. */
+#ifdef PNG_USE_GLOBAL_ARRAYS
+ PNG_EXPORT_VAR (const png_byte FARDATA) png_sig[8];
+#else
+#define png_sig png_sig_bytes(NULL)
+#endif
+#endif /* PNG_NO_EXTERN */
+
+/* Constant strings for known chunk types. If you need to add a chunk,
+ * define the name here, and add an invocation of the macro in png.c and
+ * wherever it's needed.
+ */
+#define PNG_IHDR const png_byte png_IHDR[5] = { 73, 72, 68, 82, '\0'}
+#define PNG_IDAT const png_byte png_IDAT[5] = { 73, 68, 65, 84, '\0'}
+#define PNG_IEND const png_byte png_IEND[5] = { 73, 69, 78, 68, '\0'}
+#define PNG_PLTE const png_byte png_PLTE[5] = { 80, 76, 84, 69, '\0'}
+#define PNG_bKGD const png_byte png_bKGD[5] = { 98, 75, 71, 68, '\0'}
+#define PNG_cHRM const png_byte png_cHRM[5] = { 99, 72, 82, 77, '\0'}
+#define PNG_gAMA const png_byte png_gAMA[5] = {103, 65, 77, 65, '\0'}
+#define PNG_hIST const png_byte png_hIST[5] = {104, 73, 83, 84, '\0'}
+#define PNG_iCCP const png_byte png_iCCP[5] = {105, 67, 67, 80, '\0'}
+#define PNG_iTXt const png_byte png_iTXt[5] = {105, 84, 88, 116, '\0'}
+#define PNG_oFFs const png_byte png_oFFs[5] = {111, 70, 70, 115, '\0'}
+#define PNG_pCAL const png_byte png_pCAL[5] = {112, 67, 65, 76, '\0'}
+#define PNG_sCAL const png_byte png_sCAL[5] = {115, 67, 65, 76, '\0'}
+#define PNG_pHYs const png_byte png_pHYs[5] = {112, 72, 89, 115, '\0'}
+#define PNG_sBIT const png_byte png_sBIT[5] = {115, 66, 73, 84, '\0'}
+#define PNG_sPLT const png_byte png_sPLT[5] = {115, 80, 76, 84, '\0'}
+#define PNG_sRGB const png_byte png_sRGB[5] = {115, 82, 71, 66, '\0'}
+#define PNG_tEXt const png_byte png_tEXt[5] = {116, 69, 88, 116, '\0'}
+#define PNG_tIME const png_byte png_tIME[5] = {116, 73, 77, 69, '\0'}
+#define PNG_tRNS const png_byte png_tRNS[5] = {116, 82, 78, 83, '\0'}
+#define PNG_zTXt const png_byte png_zTXt[5] = {122, 84, 88, 116, '\0'}
+
+#ifdef PNG_USE_GLOBAL_ARRAYS
+PNG_EXPORT_VAR (const png_byte FARDATA) png_IHDR[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_IDAT[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_IEND[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_PLTE[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_bKGD[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_cHRM[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_gAMA[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_hIST[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_iCCP[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_iTXt[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_oFFs[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_pCAL[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_sCAL[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_pHYs[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_sBIT[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_sPLT[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_sRGB[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_tEXt[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_tIME[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_tRNS[5];
+PNG_EXPORT_VAR (const png_byte FARDATA) png_zTXt[5];
+#endif /* PNG_USE_GLOBAL_ARRAYS */
+
+
+/* Inline macros to do direct reads of bytes from the input buffer. These
+ * require that you are using an architecture that uses PNG byte ordering
+ * (MSB first) and supports unaligned data storage. I think that PowerPC
+ * in big-endian mode and 680x0 are the only ones that will support this.
+ * The x86 line of processors definitely do not. The png_get_int_32()
+ * routine also assumes we are using two's complement format for negative
+ * values, which is almost certainly true.
+ */
+#if defined(PNG_READ_BIG_ENDIAN_SUPPORTED)
+# if defined(PNG_pCAL_SUPPORTED) || defined(PNG_oFFs_SUPPORTED)
+# define png_get_int_32(buf) ( *((png_int_32p) (buf)))
+# endif
+# define png_get_uint_32(buf) ( *((png_uint_32p) (buf)))
+# define png_get_uint_16(buf) ( *((png_uint_16p) (buf)))
+#else
+# if defined(PNG_pCAL_SUPPORTED) || defined(PNG_oFFs_SUPPORTED)
+PNG_EXTERN png_int_32 png_get_int_32 PNGARG((png_bytep buf));
+# endif
+PNG_EXTERN png_uint_32 png_get_uint_32 PNGARG((png_bytep buf));
+PNG_EXTERN png_uint_16 png_get_uint_16 PNGARG((png_bytep buf));
+#endif /* !PNG_READ_BIG_ENDIAN_SUPPORTED */
+
+/* Initialize png_ptr struct for reading, and allocate any other memory.
+ * (old interface - DEPRECATED - use png_create_read_struct instead).
+ */
+extern PNG_EXPORT(void,png_read_init) PNGARG((png_structp png_ptr));
+#define png_read_init(png_ptr) png_read_init_3(&png_ptr, \
+ PNG_LIBPNG_VER_STRING, sizeof(png_struct));
+extern PNG_EXPORT(void,png_read_init_3) PNGARG((png_structpp ptr_ptr,
+ png_const_charp user_png_ver, png_size_t png_struct_size));
+extern PNG_EXPORT(void,png_read_init_2) PNGARG((png_structp png_ptr,
+ png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t
+ png_info_size));
+
+/* Initialize png_ptr struct for writing, and allocate any other memory.
+ * (old interface - DEPRECATED - use png_create_write_struct instead).
+ */
+extern PNG_EXPORT(void,png_write_init) PNGARG((png_structp png_ptr));
+#define png_write_init(png_ptr) png_write_init_3(&png_ptr, \
+ PNG_LIBPNG_VER_STRING, sizeof(png_struct));
+extern PNG_EXPORT(void,png_write_init_3) PNGARG((png_structpp ptr_ptr,
+ png_const_charp user_png_ver, png_size_t png_struct_size));
+extern PNG_EXPORT(void,png_write_init_2) PNGARG((png_structp png_ptr,
+ png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t
+ png_info_size));
+
+/* Allocate memory for an internal libpng struct */
+PNG_EXTERN png_voidp png_create_struct PNGARG((int type));
+
+/* Free memory from internal libpng struct */
+PNG_EXTERN void png_destroy_struct PNGARG((png_voidp struct_ptr));
+
+PNG_EXTERN png_voidp png_create_struct_2 PNGARG((int type, png_malloc_ptr
+ malloc_fn, png_voidp mem_ptr));
+PNG_EXTERN void png_destroy_struct_2 PNGARG((png_voidp struct_ptr,
+ png_free_ptr free_fn, png_voidp mem_ptr));
+
+/* Free any memory that info_ptr points to and reset struct. */
+PNG_EXTERN void png_info_destroy PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+/* Function to allocate memory for zlib. */
+PNG_EXTERN voidpf png_zalloc PNGARG((voidpf png_ptr, uInt items, uInt size));
+
+/* Function to free memory for zlib */
+PNG_EXTERN void png_zfree PNGARG((voidpf png_ptr, voidpf ptr));
+
+/* Reset the CRC variable */
+PNG_EXTERN void png_reset_crc PNGARG((png_structp png_ptr));
+
+/* Write the "data" buffer to whatever output you are using. */
+PNG_EXTERN void png_write_data PNGARG((png_structp png_ptr, png_bytep data,
+ png_size_t length));
+
+/* Read data from whatever input you are using into the "data" buffer */
+PNG_EXTERN void png_read_data PNGARG((png_structp png_ptr, png_bytep data,
+ png_size_t length));
+
+/* Read bytes into buf, and update png_ptr->crc */
+PNG_EXTERN void png_crc_read PNGARG((png_structp png_ptr, png_bytep buf,
+ png_size_t length));
+
+/* Decompress data in a chunk that uses compression */
+#if defined(PNG_zTXt_SUPPORTED) || defined(PNG_iTXt_SUPPORTED) || \
+ defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED)
+PNG_EXTERN png_charp png_decompress_chunk PNGARG((png_structp png_ptr,
+ int comp_type, png_charp chunkdata, png_size_t chunklength,
+ png_size_t prefix_length, png_size_t *data_length));
+#endif
+
+/* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */
+PNG_EXTERN int png_crc_finish PNGARG((png_structp png_ptr, png_uint_32 skip));
+
+/* Read the CRC from the file and compare it to the libpng calculated CRC */
+PNG_EXTERN int png_crc_error PNGARG((png_structp png_ptr));
+
+/* Calculate the CRC over a section of data. Note that we are only
+ * passing a maximum of 64K on systems that have this as a memory limit,
+ * since this is the maximum buffer size we can specify.
+ */
+PNG_EXTERN void png_calculate_crc PNGARG((png_structp png_ptr, png_bytep ptr,
+ png_size_t length));
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+PNG_EXTERN void png_flush PNGARG((png_structp png_ptr));
+#endif
+
+/* Place a 32-bit number into a buffer in PNG byte order (big-endian).
+ * The only currently known PNG chunks that use signed numbers are
+ * the ancillary extension chunks, oFFs and pCAL.
+ */
+PNG_EXTERN void png_save_uint_32 PNGARG((png_bytep buf, png_uint_32 i));
+
+#if defined(PNG_WRITE_pCAL_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED)
+PNG_EXTERN void png_save_int_32 PNGARG((png_bytep buf, png_int_32 i));
+#endif
+
+/* Place a 16-bit number into a buffer in PNG byte order.
+ * The parameter is declared unsigned int, not png_uint_16,
+ * just to avoid potential problems on pre-ANSI C compilers.
+ */
+PNG_EXTERN void png_save_uint_16 PNGARG((png_bytep buf, unsigned int i));
+
+/* simple function to write the signature */
+PNG_EXTERN void png_write_sig PNGARG((png_structp png_ptr));
+
+/* write various chunks */
+
+/* Write the IHDR chunk, and update the png_struct with the necessary
+ * information.
+ */
+PNG_EXTERN void png_write_IHDR PNGARG((png_structp png_ptr, png_uint_32 width,
+ png_uint_32 height,
+ int bit_depth, int color_type, int compression_method, int filter_method,
+ int interlace_method));
+
+PNG_EXTERN void png_write_PLTE PNGARG((png_structp png_ptr, png_colorp palette,
+ png_uint_32 num_pal));
+
+PNG_EXTERN void png_write_IDAT PNGARG((png_structp png_ptr, png_bytep data,
+ png_size_t length));
+
+PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr));
+
+#if defined(PNG_WRITE_gAMA_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+PNG_EXTERN void png_write_gAMA PNGARG((png_structp png_ptr, double file_gamma));
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+PNG_EXTERN void png_write_gAMA_fixed PNGARG((png_structp png_ptr, png_fixed_point
+ file_gamma));
+#endif
+#endif
+
+#if defined(PNG_WRITE_sBIT_SUPPORTED)
+PNG_EXTERN void png_write_sBIT PNGARG((png_structp png_ptr, png_color_8p sbit,
+ int color_type));
+#endif
+
+#if defined(PNG_WRITE_cHRM_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+PNG_EXTERN void png_write_cHRM PNGARG((png_structp png_ptr,
+ double white_x, double white_y,
+ double red_x, double red_y, double green_x, double green_y,
+ double blue_x, double blue_y));
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+PNG_EXTERN void png_write_cHRM_fixed PNGARG((png_structp png_ptr,
+ png_fixed_point int_white_x, png_fixed_point int_white_y,
+ png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point
+ int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x,
+ png_fixed_point int_blue_y));
+#endif
+#endif
+
+#if defined(PNG_WRITE_sRGB_SUPPORTED)
+PNG_EXTERN void png_write_sRGB PNGARG((png_structp png_ptr,
+ int intent));
+#endif
+
+#if defined(PNG_WRITE_iCCP_SUPPORTED)
+PNG_EXTERN void png_write_iCCP PNGARG((png_structp png_ptr,
+ png_charp name, int compression_type,
+ png_charp profile, int proflen));
+ /* Note to maintainer: profile should be png_bytep */
+#endif
+
+#if defined(PNG_WRITE_sPLT_SUPPORTED)
+PNG_EXTERN void png_write_sPLT PNGARG((png_structp png_ptr,
+ png_sPLT_tp palette));
+#endif
+
+#if defined(PNG_WRITE_tRNS_SUPPORTED)
+PNG_EXTERN void png_write_tRNS PNGARG((png_structp png_ptr, png_bytep trans,
+ png_color_16p values, int number, int color_type));
+#endif
+
+#if defined(PNG_WRITE_bKGD_SUPPORTED)
+PNG_EXTERN void png_write_bKGD PNGARG((png_structp png_ptr,
+ png_color_16p values, int color_type));
+#endif
+
+#if defined(PNG_WRITE_hIST_SUPPORTED)
+PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr, png_uint_16p hist,
+ int num_hist));
+#endif
+
+#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
+ defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
+PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr,
+ png_charp key, png_charpp new_key));
+#endif
+
+#if defined(PNG_WRITE_tEXt_SUPPORTED)
+PNG_EXTERN void png_write_tEXt PNGARG((png_structp png_ptr, png_charp key,
+ png_charp text, png_size_t text_len));
+#endif
+
+#if defined(PNG_WRITE_zTXt_SUPPORTED)
+PNG_EXTERN void png_write_zTXt PNGARG((png_structp png_ptr, png_charp key,
+ png_charp text, png_size_t text_len, int compression));
+#endif
+
+#if defined(PNG_WRITE_iTXt_SUPPORTED)
+PNG_EXTERN void png_write_iTXt PNGARG((png_structp png_ptr,
+ int compression, png_charp key, png_charp lang, png_charp lang_key,
+ png_charp text));
+#endif
+
+#if defined(PNG_WRITE_oFFs_SUPPORTED)
+PNG_EXTERN void png_write_oFFs PNGARG((png_structp png_ptr,
+ png_int_32 x_offset, png_int_32 y_offset, int unit_type));
+#endif
+
+#if defined(PNG_WRITE_pCAL_SUPPORTED)
+PNG_EXTERN void png_write_pCAL PNGARG((png_structp png_ptr, png_charp purpose,
+ png_int_32 X0, png_int_32 X1, int type, int nparams,
+ png_charp units, png_charpp params));
+#endif
+
+#if defined(PNG_WRITE_pHYs_SUPPORTED)
+PNG_EXTERN void png_write_pHYs PNGARG((png_structp png_ptr,
+ png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit,
+ int unit_type));
+#endif
+
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+PNG_EXTERN void png_write_tIME PNGARG((png_structp png_ptr,
+ png_timep mod_time));
+#endif
+
+#if defined(PNG_WRITE_sCAL_SUPPORTED)
+#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
+PNG_EXTERN void png_write_sCAL PNGARG((png_structp png_ptr,
+ int unit, double width, double height));
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+PNG_EXTERN void png_write_sCAL_s PNGARG((png_structp png_ptr,
+ int unit, png_charp width, png_charp height));
+#endif
+#endif
+#endif
+
+/* Called when finished processing a row of data */
+PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr));
+
+/* Internal use only. Called before first row of data */
+PNG_EXTERN void png_write_start_row PNGARG((png_structp png_ptr));
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr));
+#endif
+
+/* combine a row of data, dealing with alpha, etc. if requested */
+PNG_EXTERN void png_combine_row PNGARG((png_structp png_ptr, png_bytep row,
+ int mask));
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+/* expand an interlaced row */
+/* OLD pre-1.0.9 interface:
+PNG_EXTERN void png_do_read_interlace PNGARG((png_row_infop row_info,
+ png_bytep row, int pass, png_uint_32 transformations));
+ */
+PNG_EXTERN void png_do_read_interlace PNGARG((png_structp png_ptr));
+#endif
+
+/* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */
+
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+/* grab pixels out of a row for an interlaced pass */
+PNG_EXTERN void png_do_write_interlace PNGARG((png_row_infop row_info,
+ png_bytep row, int pass));
+#endif
+
+/* unfilter a row */
+PNG_EXTERN void png_read_filter_row PNGARG((png_structp png_ptr,
+ png_row_infop row_info, png_bytep row, png_bytep prev_row, int filter));
+
+/* Choose the best filter to use and filter the row data */
+PNG_EXTERN void png_write_find_filter PNGARG((png_structp png_ptr,
+ png_row_infop row_info));
+
+/* Write out the filtered row. */
+PNG_EXTERN void png_write_filtered_row PNGARG((png_structp png_ptr,
+ png_bytep filtered_row));
+/* finish a row while reading, dealing with interlacing passes, etc. */
+PNG_EXTERN void png_read_finish_row PNGARG((png_structp png_ptr));
+
+/* initialize the row buffers, etc. */
+PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr));
+/* optional call to update the users info structure */
+PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+/* these are the functions that do the transformations */
+#if defined(PNG_READ_FILLER_SUPPORTED)
+PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info,
+ png_bytep row, png_uint_32 filler, png_uint_32 flags));
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
+PNG_EXTERN void png_do_read_swap_alpha PNGARG((png_row_infop row_info,
+ png_bytep row));
+#endif
+
+#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+PNG_EXTERN void png_do_write_swap_alpha PNGARG((png_row_infop row_info,
+ png_bytep row));
+#endif
+
+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
+PNG_EXTERN void png_do_read_invert_alpha PNGARG((png_row_infop row_info,
+ png_bytep row));
+#endif
+
+#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
+PNG_EXTERN void png_do_write_invert_alpha PNGARG((png_row_infop row_info,
+ png_bytep row));
+#endif
+
+#if defined(PNG_WRITE_FILLER_SUPPORTED) || \
+ defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+PNG_EXTERN void png_do_strip_filler PNGARG((png_row_infop row_info,
+ png_bytep row, png_uint_32 flags));
+#endif
+
+#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
+PNG_EXTERN void png_do_swap PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+PNG_EXTERN void png_do_packswap PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+PNG_EXTERN int png_do_rgb_to_gray PNGARG((png_structp png_ptr, png_row_infop
+ row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+PNG_EXTERN void png_do_gray_to_rgb PNGARG((png_row_infop row_info,
+ png_bytep row));
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED)
+PNG_EXTERN void png_do_unpack PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED)
+PNG_EXTERN void png_do_unshift PNGARG((png_row_infop row_info, png_bytep row,
+ png_color_8p sig_bits));
+#endif
+
+#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
+PNG_EXTERN void png_do_invert PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+PNG_EXTERN void png_do_chop PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+PNG_EXTERN void png_do_dither PNGARG((png_row_infop row_info,
+ png_bytep row, png_bytep palette_lookup, png_bytep dither_lookup));
+
+# if defined(PNG_CORRECT_PALETTE_SUPPORTED)
+PNG_EXTERN void png_correct_palette PNGARG((png_structp png_ptr,
+ png_colorp palette, int num_palette));
+# endif
+#endif
+
+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
+PNG_EXTERN void png_do_bgr PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_WRITE_PACK_SUPPORTED)
+PNG_EXTERN void png_do_pack PNGARG((png_row_infop row_info,
+ png_bytep row, png_uint_32 bit_depth));
+#endif
+
+#if defined(PNG_WRITE_SHIFT_SUPPORTED)
+PNG_EXTERN void png_do_shift PNGARG((png_row_infop row_info, png_bytep row,
+ png_color_8p bit_depth));
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row,
+ png_color_16p trans_values, png_color_16p background,
+ png_color_16p background_1,
+ png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
+ png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
+ png_uint_16pp gamma_16_to_1, int gamma_shift));
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+PNG_EXTERN void png_do_gamma PNGARG((png_row_infop row_info, png_bytep row,
+ png_bytep gamma_table, png_uint_16pp gamma_16_table,
+ int gamma_shift));
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+PNG_EXTERN void png_do_expand_palette PNGARG((png_row_infop row_info,
+ png_bytep row, png_colorp palette, png_bytep trans, int num_trans));
+PNG_EXTERN void png_do_expand PNGARG((png_row_infop row_info,
+ png_bytep row, png_color_16p trans_value));
+#endif
+
+/* The following decodes the appropriate chunks, and does error correction,
+ * then calls the appropriate callback for the chunk if it is valid.
+ */
+
+/* decode the IHDR chunk */
+PNG_EXTERN void png_handle_IHDR PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+PNG_EXTERN void png_handle_PLTE PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+PNG_EXTERN void png_handle_IEND PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+
+#if defined(PNG_READ_bKGD_SUPPORTED)
+PNG_EXTERN void png_handle_bKGD PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_cHRM_SUPPORTED)
+PNG_EXTERN void png_handle_cHRM PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_gAMA_SUPPORTED)
+PNG_EXTERN void png_handle_gAMA PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_hIST_SUPPORTED)
+PNG_EXTERN void png_handle_hIST PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_iCCP_SUPPORTED)
+extern void png_handle_iCCP PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif /* PNG_READ_iCCP_SUPPORTED */
+
+#if defined(PNG_READ_iTXt_SUPPORTED)
+PNG_EXTERN void png_handle_iTXt PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_oFFs_SUPPORTED)
+PNG_EXTERN void png_handle_oFFs PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_pCAL_SUPPORTED)
+PNG_EXTERN void png_handle_pCAL PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_pHYs_SUPPORTED)
+PNG_EXTERN void png_handle_pHYs PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_sBIT_SUPPORTED)
+PNG_EXTERN void png_handle_sBIT PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_sCAL_SUPPORTED)
+PNG_EXTERN void png_handle_sCAL PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_sPLT_SUPPORTED)
+extern void png_handle_sPLT PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif /* PNG_READ_sPLT_SUPPORTED */
+
+#if defined(PNG_READ_sRGB_SUPPORTED)
+PNG_EXTERN void png_handle_sRGB PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_tEXt_SUPPORTED)
+PNG_EXTERN void png_handle_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_tIME_SUPPORTED)
+PNG_EXTERN void png_handle_tIME PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_tRNS_SUPPORTED)
+PNG_EXTERN void png_handle_tRNS PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_zTXt_SUPPORTED)
+PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+PNG_EXTERN int png_handle_as_unknown PNGARG((png_structp png_ptr, png_bytep
+ chunk_name));
+#endif
+
+PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 length));
+
+PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr,
+ png_bytep chunk_name));
+
+/* handle the transformations for reading and writing */
+PNG_EXTERN void png_do_read_transformations PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_do_write_transformations PNGARG((png_structp png_ptr));
+
+PNG_EXTERN void png_init_read_transformations PNGARG((png_structp png_ptr));
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_push_read_sig PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_push_check_crc PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_push_crc_skip PNGARG((png_structp png_ptr,
+ png_uint_32 length));
+PNG_EXTERN void png_push_crc_finish PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_push_fill_buffer PNGARG((png_structp png_ptr,
+ png_bytep buffer, png_size_t length));
+PNG_EXTERN void png_push_save_buffer PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_push_restore_buffer PNGARG((png_structp png_ptr,
+ png_bytep buffer, png_size_t buffer_length));
+PNG_EXTERN void png_push_read_IDAT PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_process_IDAT_data PNGARG((png_structp png_ptr,
+ png_bytep buffer, png_size_t buffer_length));
+PNG_EXTERN void png_push_process_row PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_push_handle_unknown PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 length));
+PNG_EXTERN void png_push_have_info PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_push_have_end PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_push_have_row PNGARG((png_structp png_ptr, png_bytep row));
+PNG_EXTERN void png_push_read_end PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_process_some_data PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_read_push_finish_row PNGARG((png_structp png_ptr));
+#if defined(PNG_READ_tEXt_SUPPORTED)
+PNG_EXTERN void png_push_handle_tEXt PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 length));
+PNG_EXTERN void png_push_read_tEXt PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+PNG_EXTERN void png_push_handle_zTXt PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 length));
+PNG_EXTERN void png_push_read_zTXt PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+#endif
+#if defined(PNG_READ_iTXt_SUPPORTED)
+PNG_EXTERN void png_push_handle_iTXt PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 length));
+PNG_EXTERN void png_push_read_iTXt PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+#endif
+
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+
+#ifdef PNG_MNG_FEATURES_SUPPORTED
+PNG_EXTERN void png_do_read_intrapixel PNGARG((png_row_infop row_info,
+ png_bytep row));
+PNG_EXTERN void png_do_write_intrapixel PNGARG((png_row_infop row_info,
+ png_bytep row));
+#endif
+
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
+/* png.c */ /* PRIVATE */
+PNG_EXTERN void png_init_mmx_flags PNGARG((png_structp png_ptr));
+#endif
+/* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */
+
+#endif /* PNG_INTERNAL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PNG_VERSION_INFO_ONLY */
+/* do not put anything past this line */
+#endif /* PNG_H */
--- /dev/null
+/* pngasmrd.h - assembler version of utilities to read a PNG file
+ *
+ * libpng 1.2.0 - September 1, 2001
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 2001 Glenn Randers-Pehrson
+ *
+ */
+
+/* This file is obsolete in libpng-1.0.9 and later; its contents now appear
+ * at the end of pngconf.h.
+ */
--- /dev/null
+/* pngconf.h - machine configurable file for libpng
+ *
+ * libpng 1.2.0 - September 1, 2001
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ */
+
+/* Any machine specific code is near the front of this file, so if you
+ * are configuring libpng for a machine, you may want to read the section
+ * starting here down to where it starts to typedef png_color, png_text,
+ * and png_info.
+ */
+
+#ifndef PNGCONF_H
+#define PNGCONF_H
+
+/* This is the size of the compression buffer, and thus the size of
+ * an IDAT chunk. Make this whatever size you feel is best for your
+ * machine. One of these will be allocated per png_struct. When this
+ * is full, it writes the data to the disk, and does some other
+ * calculations. Making this an extremely small size will slow
+ * the library down, but you may want to experiment to determine
+ * where it becomes significant, if you are concerned with memory
+ * usage. Note that zlib allocates at least 32Kb also. For readers,
+ * this describes the size of the buffer available to read the data in.
+ * Unless this gets smaller than the size of a row (compressed),
+ * it should not make much difference how big this is.
+ */
+
+#ifndef PNG_ZBUF_SIZE
+# define PNG_ZBUF_SIZE 8192
+#endif
+
+/* Enable if you want a write-only libpng */
+
+#ifndef PNG_NO_READ_SUPPORTED
+# define PNG_READ_SUPPORTED
+#endif
+
+/* Enable if you want a read-only libpng */
+
+#ifndef PNG_NO_WRITE_SUPPORTED
+# define PNG_WRITE_SUPPORTED
+#endif
+
+/* Enabled by default in 1.2.0. You can disable this if you don't need to
+ support PNGs that are embedded in MNG datastreams */
+#ifndef PNG_NO_MNG_FEATURES
+# ifndef PNG_MNG_FEATURES_SUPPORTED
+# define PNG_MNG_FEATURES_SUPPORTED
+# endif
+#endif
+
+#ifndef PNG_NO_FLOATING_POINT_SUPPORTED
+# ifndef PNG_FLOATING_POINT_SUPPORTED
+# define PNG_FLOATING_POINT_SUPPORTED
+# endif
+#endif
+
+/* If you are running on a machine where you cannot allocate more
+ * than 64K of memory at once, uncomment this. While libpng will not
+ * normally need that much memory in a chunk (unless you load up a very
+ * large file), zlib needs to know how big of a chunk it can use, and
+ * libpng thus makes sure to check any memory allocation to verify it
+ * will fit into memory.
+#define PNG_MAX_MALLOC_64K
+ */
+#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
+# define PNG_MAX_MALLOC_64K
+#endif
+
+/* Special munging to support doing things the 'cygwin' way:
+ * 'Normal' png-on-win32 defines/defaults:
+ * PNG_BUILD_DLL -- building dll
+ * PNG_USE_DLL -- building an application, linking to dll
+ * (no define) -- building static library, or building an
+ * application and linking to the static lib
+ * 'Cygwin' defines/defaults:
+ * PNG_BUILD_DLL -- building the dll
+ * (no define) -- building an application, linking to the dll
+ * PNG_STATIC -- building the static lib, or building an application
+ * that links to the static lib.
+ * ALL_STATIC -- building various static libs, or building an application
+ * that links to the static libs.
+ * Thus,
+ * a cygwin user should define either PNG_BUILD_DLL or PNG_STATIC, and
+ * this bit of #ifdefs will define the 'correct' config variables based on
+ * that. If a cygwin user *wants* to define 'PNG_USE_DLL' that's okay, but
+ * unnecessary.
+ *
+ * Also, the precedence order is:
+ * ALL_STATIC (since we can't #undef something outside our namespace)
+ * PNG_BUILD_DLL
+ * PNG_STATIC
+ * (nothing) == PNG_USE_DLL
+ */
+#if defined(__CYGWIN__)
+# if defined(ALL_STATIC)
+# if defined(PNG_BUILD_DLL)
+# undef PNG_BUILD_DLL
+# endif
+# if defined(PNG_USE_DLL)
+# undef PNG_USE_DLL
+# endif
+# if defined(PNG_DLL)
+# undef PNG_DLL
+# endif
+# if !defined(PNG_STATIC)
+# define PNG_STATIC
+# endif
+# else
+# if defined (PNG_BUILD_DLL)
+# if defined(PNG_STATIC)
+# undef PNG_STATIC
+# endif
+# if defined(PNG_USE_DLL)
+# undef PNG_USE_DLL
+# endif
+# if !defined(PNG_DLL)
+# define PNG_DLL
+# endif
+# else
+# if defined(PNG_STATIC)
+# if defined(PNG_USE_DLL)
+# undef PNG_USE_DLL
+# endif
+# if defined(PNG_DLL)
+# undef PNG_DLL
+# endif
+# else
+# if !defined(PNG_USE_DLL)
+# define PNG_USE_DLL
+# endif
+# if !defined(PNG_DLL)
+# define PNG_DLL
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* This protects us against compilers that run on a windowing system
+ * and thus don't have or would rather us not use the stdio types:
+ * stdin, stdout, and stderr. The only one currently used is stderr
+ * in png_error() and png_warning(). #defining PNG_NO_CONSOLE_IO will
+ * prevent these from being compiled and used. #defining PNG_NO_STDIO
+ * will also prevent these, plus will prevent the entire set of stdio
+ * macros and functions (FILE *, printf, etc.) from being compiled and used,
+ * unless (PNG_DEBUG > 0) has been #defined.
+ *
+ * #define PNG_NO_CONSOLE_IO
+ * #define PNG_NO_STDIO
+ */
+
+#if defined(_WIN32_WCE)
+# include <windows.h>
+ /* Console I/O functions are not supported on WindowsCE */
+# define PNG_NO_CONSOLE_IO
+# ifdef PNG_DEBUG
+# undef PNG_DEBUG
+# endif
+#endif
+
+#ifdef PNG_BUILD_DLL
+# ifndef PNG_CONSOLE_IO_SUPPORTED
+# ifndef PNG_NO_CONSOLE_IO
+# define PNG_NO_CONSOLE_IO
+# endif
+# endif
+#endif
+
+# ifdef PNG_NO_STDIO
+# ifndef PNG_NO_CONSOLE_IO
+# define PNG_NO_CONSOLE_IO
+# endif
+# ifdef PNG_DEBUG
+# if (PNG_DEBUG > 0)
+# include <stdio.h>
+# endif
+# endif
+# else
+# if !defined(_WIN32_WCE)
+/* "stdio.h" functions are not supported on WindowsCE */
+# include <stdio.h>
+# endif
+# endif
+
+/* This macro protects us against machines that don't have function
+ * prototypes (ie K&R style headers). If your compiler does not handle
+ * function prototypes, define this macro and use the included ansi2knr.
+ * I've always been able to use _NO_PROTO as the indicator, but you may
+ * need to drag the empty declaration out in front of here, or change the
+ * ifdef to suit your own needs.
+ */
+#ifndef PNGARG
+
+#ifdef OF /* zlib prototype munger */
+# define PNGARG(arglist) OF(arglist)
+#else
+
+#ifdef _NO_PROTO
+# define PNGARG(arglist) ()
+#else
+# define PNGARG(arglist) arglist
+#endif /* _NO_PROTO */
+
+#endif /* OF */
+
+#endif /* PNGARG */
+
+/* Try to determine if we are compiling on a Mac. Note that testing for
+ * just __MWERKS__ is not good enough, because the Codewarrior is now used
+ * on non-Mac platforms.
+ */
+#ifndef MACOS
+# if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \
+ defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC)
+# define MACOS
+# endif
+#endif
+
+/* enough people need this for various reasons to include it here */
+#if !defined(MACOS) && !defined(RISCOS) && !defined(_WIN32_WCE)
+# include <sys/types.h>
+#endif
+
+#if !defined(PNG_SETJMP_NOT_SUPPORTED) && !defined(PNG_NO_SETJMP_SUPPORTED)
+# define PNG_SETJMP_SUPPORTED
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+/* This is an attempt to force a single setjmp behaviour on Linux. If
+ * the X config stuff didn't define _BSD_SOURCE we wouldn't need this.
+ */
+
+# ifdef __linux__
+# ifdef _BSD_SOURCE
+# define PNG_SAVE_BSD_SOURCE
+# undef _BSD_SOURCE
+# endif
+# ifdef _SETJMP_H
+ __png.h__ already includes setjmp.h;
+ __dont__ include it again.;
+# endif
+# endif /* __linux__ */
+
+ /* include setjmp.h for error handling */
+# include <setjmp.h>
+
+# ifdef __linux__
+# ifdef PNG_SAVE_BSD_SOURCE
+# define _BSD_SOURCE
+# undef PNG_SAVE_BSD_SOURCE
+# endif
+# endif /* __linux__ */
+#endif /* PNG_SETJMP_SUPPORTED */
+
+#ifdef BSD
+# include <strings.h>
+#else
+# include <string.h>
+#endif
+
+/* Other defines for things like memory and the like can go here. */
+#ifdef PNG_INTERNAL
+
+#include <stdlib.h>
+
+/* The functions exported by PNG_EXTERN are PNG_INTERNAL functions, which
+ * aren't usually used outside the library (as far as I know), so it is
+ * debatable if they should be exported at all. In the future, when it is
+ * possible to have run-time registry of chunk-handling functions, some of
+ * these will be made available again.
+#define PNG_EXTERN extern
+ */
+#define PNG_EXTERN
+
+/* Other defines specific to compilers can go here. Try to keep
+ * them inside an appropriate ifdef/endif pair for portability.
+ */
+
+#if defined(PNG_FLOATING_POINT_SUPPORTED)
+# if defined(MACOS)
+ /* We need to check that <math.h> hasn't already been included earlier
+ * as it seems it doesn't agree with <fp.h>, yet we should really use
+ * <fp.h> if possible.
+ */
+# if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__)
+# include <fp.h>
+# endif
+# else
+# include <math.h>
+# endif
+# if defined(_AMIGA) && defined(__SASC) && defined(_M68881)
+ /* Amiga SAS/C: We must include builtin FPU functions when compiling using
+ * MATH=68881
+ */
+# include <m68881.h>
+# endif
+#endif
+
+/* Codewarrior on NT has linking problems without this. */
+#if (defined(__MWERKS__) && defined(WIN32)) || defined(__STDC__)
+# define PNG_ALWAYS_EXTERN
+#endif
+
+/* For some reason, Borland C++ defines memcmp, etc. in mem.h, not
+ * stdlib.h like it should (I think). Or perhaps this is a C++
+ * "feature"?
+ */
+#ifdef __TURBOC__
+# include <mem.h>
+# include "alloc.h"
+#endif
+
+#if defined(_MSC_VER) && (defined(WIN32) || defined(_Windows) || \
+ defined(_WINDOWS) || defined(_WIN32) || defined(__WIN32__))
+# include <malloc.h>
+#endif
+
+/* This controls how fine the dithering gets. As this allocates
+ * a largish chunk of memory (32K), those who are not as concerned
+ * with dithering quality can decrease some or all of these.
+ */
+#ifndef PNG_DITHER_RED_BITS
+# define PNG_DITHER_RED_BITS 5
+#endif
+#ifndef PNG_DITHER_GREEN_BITS
+# define PNG_DITHER_GREEN_BITS 5
+#endif
+#ifndef PNG_DITHER_BLUE_BITS
+# define PNG_DITHER_BLUE_BITS 5
+#endif
+
+/* This controls how fine the gamma correction becomes when you
+ * are only interested in 8 bits anyway. Increasing this value
+ * results in more memory being used, and more pow() functions
+ * being called to fill in the gamma tables. Don't set this value
+ * less then 8, and even that may not work (I haven't tested it).
+ */
+
+#ifndef PNG_MAX_GAMMA_8
+# define PNG_MAX_GAMMA_8 11
+#endif
+
+/* This controls how much a difference in gamma we can tolerate before
+ * we actually start doing gamma conversion.
+ */
+#ifndef PNG_GAMMA_THRESHOLD
+# define PNG_GAMMA_THRESHOLD 0.05
+#endif
+
+#endif /* PNG_INTERNAL */
+
+/* The following uses const char * instead of char * for error
+ * and warning message functions, so some compilers won't complain.
+ * If you do not want to use const, define PNG_NO_CONST here.
+ */
+
+#ifndef PNG_NO_CONST
+# define PNG_CONST const
+#else
+# define PNG_CONST
+#endif
+
+/* The following defines give you the ability to remove code from the
+ * library that you will not be using. I wish I could figure out how to
+ * automate this, but I can't do that without making it seriously hard
+ * on the users. So if you are not using an ability, change the #define
+ * to and #undef, and that part of the library will not be compiled. If
+ * your linker can't find a function, you may want to make sure the
+ * ability is defined here. Some of these depend upon some others being
+ * defined. I haven't figured out all the interactions here, so you may
+ * have to experiment awhile to get everything to compile. If you are
+ * creating or using a shared library, you probably shouldn't touch this,
+ * as it will affect the size of the structures, and this will cause bad
+ * things to happen if the library and/or application ever change.
+ */
+
+/* Any features you will not be using can be undef'ed here */
+
+/* GR-P, 0.96a: Set "*TRANSFORMS_SUPPORTED as default but allow user
+ * to turn it off with "*TRANSFORMS_NOT_SUPPORTED" or *PNG_NO_*_TRANSFORMS
+ * on the compile line, then pick and choose which ones to define without
+ * having to edit this file. It is safe to use the *TRANSFORMS_NOT_SUPPORTED
+ * if you only want to have a png-compliant reader/writer but don't need
+ * any of the extra transformations. This saves about 80 kbytes in a
+ * typical installation of the library. (PNG_NO_* form added in version
+ * 1.0.1c, for consistency)
+ */
+
+/* The size of the png_text structure changed in libpng-1.0.6 when
+ * iTXt is supported. It is turned off by default, to support old apps
+ * that malloc the png_text structure instead of calling png_set_text()
+ * and letting libpng malloc it. It will be turned on by default in
+ * libpng-1.3.0.
+ */
+
+#ifndef PNG_iTXt_SUPPORTED
+# ifndef PNG_READ_iTXt_SUPPORTED
+# define PNG_NO_READ_iTXt
+# endif
+# ifndef PNG_WRITE_iTXt_SUPPORTED
+# define PNG_NO_WRITE_iTXt
+# endif
+#endif
+
+/* The following support, added after version 1.0.0, can be turned off here en
+ * masse by defining PNG_LEGACY_SUPPORTED in case you need binary compatibility
+ * with old applications that require the length of png_struct and png_info
+ * to remain unchanged.
+ */
+
+#ifdef PNG_LEGACY_SUPPORTED
+# define PNG_NO_FREE_ME
+# define PNG_NO_READ_UNKNOWN_CHUNKS
+# define PNG_NO_WRITE_UNKNOWN_CHUNKS
+# define PNG_NO_READ_USER_CHUNKS
+# define PNG_NO_READ_iCCP
+# define PNG_NO_WRITE_iCCP
+# define PNG_NO_READ_iTXt
+# define PNG_NO_WRITE_iTXt
+# define PNG_NO_READ_sCAL
+# define PNG_NO_WRITE_sCAL
+# define PNG_NO_READ_sPLT
+# define PNG_NO_WRITE_sPLT
+# define PNG_NO_INFO_IMAGE
+# define PNG_NO_READ_RGB_TO_GRAY
+# define PNG_NO_READ_USER_TRANSFORM
+# define PNG_NO_WRITE_USER_TRANSFORM
+# define PNG_NO_USER_MEM
+# define PNG_NO_READ_EMPTY_PLTE
+# define PNG_NO_MNG_FEATURES
+# define PNG_NO_FIXED_POINT_SUPPORTED
+#endif
+
+/* Ignore attempt to turn off both floating and fixed point support */
+#if !defined(PNG_FLOATING_POINT_SUPPORTED) || \
+ !defined(PNG_NO_FIXED_POINT_SUPPORTED)
+# define PNG_FIXED_POINT_SUPPORTED
+#endif
+
+#ifndef PNG_NO_FREE_ME
+# define PNG_FREE_ME_SUPPORTED
+#endif
+
+#if defined(PNG_READ_SUPPORTED)
+
+#if !defined(PNG_READ_TRANSFORMS_NOT_SUPPORTED) && \
+ !defined(PNG_NO_READ_TRANSFORMS)
+# define PNG_READ_TRANSFORMS_SUPPORTED
+#endif
+
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
+# ifndef PNG_NO_READ_EXPAND
+# define PNG_READ_EXPAND_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_SHIFT
+# define PNG_READ_SHIFT_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_PACK
+# define PNG_READ_PACK_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_BGR
+# define PNG_READ_BGR_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_SWAP
+# define PNG_READ_SWAP_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_PACKSWAP
+# define PNG_READ_PACKSWAP_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_INVERT
+# define PNG_READ_INVERT_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_DITHER
+# define PNG_READ_DITHER_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_BACKGROUND
+# define PNG_READ_BACKGROUND_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_16_TO_8
+# define PNG_READ_16_TO_8_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_FILLER
+# define PNG_READ_FILLER_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_GAMMA
+# define PNG_READ_GAMMA_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_GRAY_TO_RGB
+# define PNG_READ_GRAY_TO_RGB_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_SWAP_ALPHA
+# define PNG_READ_SWAP_ALPHA_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_INVERT_ALPHA
+# define PNG_READ_INVERT_ALPHA_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_STRIP_ALPHA
+# define PNG_READ_STRIP_ALPHA_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_USER_TRANSFORM
+# define PNG_READ_USER_TRANSFORM_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_RGB_TO_GRAY
+# define PNG_READ_RGB_TO_GRAY_SUPPORTED
+# endif
+#endif /* PNG_READ_TRANSFORMS_SUPPORTED */
+
+#if !defined(PNG_NO_PROGRESSIVE_READ) && \
+ !defined(PNG_PROGRESSIVE_READ_NOT_SUPPORTED) /* if you don't do progressive */
+# define PNG_PROGRESSIVE_READ_SUPPORTED /* reading. This is not talking */
+#endif /* about interlacing capability! You'll */
+ /* still have interlacing unless you change the following line: */
+
+#define PNG_READ_INTERLACING_SUPPORTED /* required for PNG-compliant decoders */
+
+#ifndef PNG_NO_READ_COMPOSITE_NODIV
+# ifndef PNG_NO_READ_COMPOSITED_NODIV /* libpng-1.0.x misspelling */
+# define PNG_READ_COMPOSITE_NODIV_SUPPORTED /* well tested on Intel, SGI */
+# endif
+#endif
+
+/* Deprecated, will be removed from version 2.0.0.
+ Use PNG_MNG_FEATURES_SUPPORTED instead. */
+#ifndef PNG_NO_READ_EMPTY_PLTE
+# define PNG_READ_EMPTY_PLTE_SUPPORTED
+#endif
+
+#endif /* PNG_READ_SUPPORTED */
+
+#if defined(PNG_WRITE_SUPPORTED)
+
+# if !defined(PNG_WRITE_TRANSFORMS_NOT_SUPPORTED) && \
+ !defined(PNG_NO_WRITE_TRANSFORMS)
+# define PNG_WRITE_TRANSFORMS_SUPPORTED
+#endif
+
+#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
+# ifndef PNG_NO_WRITE_SHIFT
+# define PNG_WRITE_SHIFT_SUPPORTED
+# endif
+# ifndef PNG_NO_WRITE_PACK
+# define PNG_WRITE_PACK_SUPPORTED
+# endif
+# ifndef PNG_NO_WRITE_BGR
+# define PNG_WRITE_BGR_SUPPORTED
+# endif
+# ifndef PNG_NO_WRITE_SWAP
+# define PNG_WRITE_SWAP_SUPPORTED
+# endif
+# ifndef PNG_NO_WRITE_PACKSWAP
+# define PNG_WRITE_PACKSWAP_SUPPORTED
+# endif
+# ifndef PNG_NO_WRITE_INVERT
+# define PNG_WRITE_INVERT_SUPPORTED
+# endif
+# ifndef PNG_NO_WRITE_FILLER
+# define PNG_WRITE_FILLER_SUPPORTED /* same as WRITE_STRIP_ALPHA */
+# endif
+# ifndef PNG_NO_WRITE_SWAP_ALPHA
+# define PNG_WRITE_SWAP_ALPHA_SUPPORTED
+# endif
+# ifndef PNG_NO_WRITE_INVERT_ALPHA
+# define PNG_WRITE_INVERT_ALPHA_SUPPORTED
+# endif
+# ifndef PNG_NO_WRITE_USER_TRANSFORM
+# define PNG_WRITE_USER_TRANSFORM_SUPPORTED
+# endif
+#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+# ifndef PNG_NO_USER_TRANSFORM_PTR
+# define PNG_USER_TRANSFORM_PTR_SUPPORTED
+# endif
+#endif
+
+#define PNG_WRITE_INTERLACING_SUPPORTED /* not required for PNG-compliant
+ encoders, but can cause trouble
+ if left undefined */
+
+#if !defined(PNG_NO_WRITE_WEIGHTED_FILTER) && \
+ defined(PNG_FLOATING_POINT_SUPPORTED)
+# define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
+#endif
+
+#ifndef PNG_NO_ERROR_NUMBERS
+#define PNG_ERROR_NUMBERS_SUPPORTED
+#endif
+
+#ifndef PNG_NO_WRITE_FLUSH
+# define PNG_WRITE_FLUSH_SUPPORTED
+#endif
+
+/* Deprecated, see PNG_MNG_FEATURES_SUPPORTED, above */
+#ifndef PNG_NO_WRITE_EMPTY_PLTE
+# define PNG_WRITE_EMPTY_PLTE_SUPPORTED
+#endif
+
+#endif /* PNG_WRITE_SUPPORTED */
+
+#ifndef PNG_NO_STDIO
+# define PNG_TIME_RFC1123_SUPPORTED
+#endif
+
+/* This adds extra functions in pngget.c for accessing data from the
+ * info pointer (added in version 0.99)
+ * png_get_image_width()
+ * png_get_image_height()
+ * png_get_bit_depth()
+ * png_get_color_type()
+ * png_get_compression_type()
+ * png_get_filter_type()
+ * png_get_interlace_type()
+ * png_get_pixel_aspect_ratio()
+ * png_get_pixels_per_meter()
+ * png_get_x_offset_pixels()
+ * png_get_y_offset_pixels()
+ * png_get_x_offset_microns()
+ * png_get_y_offset_microns()
+ */
+#if !defined(PNG_NO_EASY_ACCESS) && !defined(PNG_EASY_ACCESS_SUPPORTED)
+# define PNG_EASY_ACCESS_SUPPORTED
+#endif
+
+/* PNG_ASSEMBLER_CODE was enabled by default in version 1.2.0
+ even when PNG_USE_PNGVCRD or PNG_USE_PNGGCCRD is not defined */
+#if defined(PNG_READ_SUPPORTED) && !defined(PNG_NO_ASSEMBLER_CODE)
+# ifndef PNG_ASSEMBLER_CODE_SUPPORTED
+# define PNG_ASSEMBLER_CODE_SUPPORTED
+# endif
+# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE)
+# define PNG_MMX_CODE_SUPPORTED
+# endif
+#endif
+
+/* If you are sure that you don't need thread safety and you are compiling
+ with PNG_USE_PNGCCRD for an MMX application, you can define this for
+ faster execution. See pnggccrd.c.
+#define PNG_THREAD_UNSAFE_OK
+*/
+
+#if !defined(PNG_NO_USER_MEM) && !defined(PNG_USER_MEM_SUPPORTED)
+# define PNG_USER_MEM_SUPPORTED
+#endif
+
+/* These are currently experimental features, define them if you want */
+
+/* very little testing */
+/*
+#ifdef PNG_READ_SUPPORTED
+# ifndef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED
+# define PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED
+# endif
+#endif
+*/
+
+/* This is only for PowerPC big-endian and 680x0 systems */
+/* some testing */
+/*
+#ifdef PNG_READ_SUPPORTED
+# ifndef PNG_PNG_READ_BIG_ENDIAN_SUPPORTED
+# define PNG_READ_BIG_ENDIAN_SUPPORTED
+# endif
+#endif
+*/
+
+/* Buggy compilers (e.g., gcc 2.7.2.2) need this */
+/*
+#define PNG_NO_POINTER_INDEXING
+*/
+
+/* These functions are turned off by default, as they will be phased out. */
+/*
+#define PNG_USELESS_TESTS_SUPPORTED
+#define PNG_CORRECT_PALETTE_SUPPORTED
+*/
+
+/* Any chunks you are not interested in, you can undef here. The
+ * ones that allocate memory may be expecially important (hIST,
+ * tEXt, zTXt, tRNS, pCAL). Others will just save time and make png_info
+ * a bit smaller.
+ */
+
+#if defined(PNG_READ_SUPPORTED) && \
+ !defined(PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \
+ !defined(PNG_NO_READ_ANCILLARY_CHUNKS)
+# define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED
+#endif
+
+#if defined(PNG_WRITE_SUPPORTED) && \
+ !defined(PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \
+ !defined(PNG_NO_WRITE_ANCILLARY_CHUNKS)
+# define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED
+#endif
+
+#ifdef PNG_READ_ANCILLARY_CHUNKS_SUPPORTED
+
+#ifdef PNG_NO_READ_TEXT
+# define PNG_NO_READ_iTXt
+# define PNG_NO_READ_tEXt
+# define PNG_NO_READ_zTXt
+#endif
+#ifndef PNG_NO_READ_bKGD
+# define PNG_READ_bKGD_SUPPORTED
+# define PNG_bKGD_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_cHRM
+# define PNG_READ_cHRM_SUPPORTED
+# define PNG_cHRM_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_gAMA
+# define PNG_READ_gAMA_SUPPORTED
+# define PNG_gAMA_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_hIST
+# define PNG_READ_hIST_SUPPORTED
+# define PNG_hIST_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_iCCP
+# define PNG_READ_iCCP_SUPPORTED
+# define PNG_iCCP_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_iTXt
+# define PNG_READ_iTXt_SUPPORTED
+# define PNG_iTXt_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_oFFs
+# define PNG_READ_oFFs_SUPPORTED
+# define PNG_oFFs_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_pCAL
+# define PNG_READ_pCAL_SUPPORTED
+# define PNG_pCAL_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_sCAL
+# define PNG_READ_sCAL_SUPPORTED
+# define PNG_sCAL_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_pHYs
+# define PNG_READ_pHYs_SUPPORTED
+# define PNG_pHYs_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_sBIT
+# define PNG_READ_sBIT_SUPPORTED
+# define PNG_sBIT_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_sPLT
+# define PNG_READ_sPLT_SUPPORTED
+# define PNG_sPLT_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_sRGB
+# define PNG_READ_sRGB_SUPPORTED
+# define PNG_sRGB_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_tEXt
+# define PNG_READ_tEXt_SUPPORTED
+# define PNG_tEXt_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_tIME
+# define PNG_READ_tIME_SUPPORTED
+# define PNG_tIME_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_tRNS
+# define PNG_READ_tRNS_SUPPORTED
+# define PNG_tRNS_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_zTXt
+# define PNG_READ_zTXt_SUPPORTED
+# define PNG_zTXt_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_UNKNOWN_CHUNKS
+# define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
+# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED
+# define PNG_UNKNOWN_CHUNKS_SUPPORTED
+# endif
+# ifndef PNG_NO_HANDLE_AS_UNKNOWN
+# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+# endif
+#endif
+#if !defined(PNG_NO_READ_USER_CHUNKS) && \
+ defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
+# define PNG_READ_USER_CHUNKS_SUPPORTED
+# define PNG_USER_CHUNKS_SUPPORTED
+# ifdef PNG_NO_READ_UNKNOWN_CHUNKS
+# undef PNG_NO_READ_UNKNOWN_CHUNKS
+# endif
+# ifdef PNG_NO_HANDLE_AS_UNKNOWN
+# undef PNG_NO_HANDLE_AS_UNKNOWN
+# endif
+#endif
+#ifndef PNG_NO_READ_OPT_PLTE
+# define PNG_READ_OPT_PLTE_SUPPORTED /* only affects support of the */
+#endif /* optional PLTE chunk in RGB and RGBA images */
+#if defined(PNG_READ_iTXt_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) || \
+ defined(PNG_READ_zTXt_SUPPORTED)
+# define PNG_READ_TEXT_SUPPORTED
+# define PNG_TEXT_SUPPORTED
+#endif
+
+#endif /* PNG_READ_ANCILLARY_CHUNKS_SUPPORTED */
+
+#ifdef PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED
+
+#ifdef PNG_NO_WRITE_TEXT
+# define PNG_NO_WRITE_iTXt
+# define PNG_NO_WRITE_tEXt
+# define PNG_NO_WRITE_zTXt
+#endif
+#ifndef PNG_NO_WRITE_bKGD
+# define PNG_WRITE_bKGD_SUPPORTED
+# ifndef PNG_bKGD_SUPPORTED
+# define PNG_bKGD_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_cHRM
+# define PNG_WRITE_cHRM_SUPPORTED
+# ifndef PNG_cHRM_SUPPORTED
+# define PNG_cHRM_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_gAMA
+# define PNG_WRITE_gAMA_SUPPORTED
+# ifndef PNG_gAMA_SUPPORTED
+# define PNG_gAMA_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_hIST
+# define PNG_WRITE_hIST_SUPPORTED
+# ifndef PNG_hIST_SUPPORTED
+# define PNG_hIST_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_iCCP
+# define PNG_WRITE_iCCP_SUPPORTED
+# ifndef PNG_iCCP_SUPPORTED
+# define PNG_iCCP_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_iTXt
+# define PNG_WRITE_iTXt_SUPPORTED
+# ifndef PNG_iTXt_SUPPORTED
+# define PNG_iTXt_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_oFFs
+# define PNG_WRITE_oFFs_SUPPORTED
+# ifndef PNG_oFFs_SUPPORTED
+# define PNG_oFFs_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_pCAL
+# define PNG_WRITE_pCAL_SUPPORTED
+# ifndef PNG_pCAL_SUPPORTED
+# define PNG_pCAL_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_sCAL
+# define PNG_WRITE_sCAL_SUPPORTED
+# ifndef PNG_sCAL_SUPPORTED
+# define PNG_sCAL_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_pHYs
+# define PNG_WRITE_pHYs_SUPPORTED
+# ifndef PNG_pHYs_SUPPORTED
+# define PNG_pHYs_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_sBIT
+# define PNG_WRITE_sBIT_SUPPORTED
+# ifndef PNG_sBIT_SUPPORTED
+# define PNG_sBIT_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_sPLT
+# define PNG_WRITE_sPLT_SUPPORTED
+# ifndef PNG_sPLT_SUPPORTED
+# define PNG_sPLT_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_sRGB
+# define PNG_WRITE_sRGB_SUPPORTED
+# ifndef PNG_sRGB_SUPPORTED
+# define PNG_sRGB_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_tEXt
+# define PNG_WRITE_tEXt_SUPPORTED
+# ifndef PNG_tEXt_SUPPORTED
+# define PNG_tEXt_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_tIME
+# define PNG_WRITE_tIME_SUPPORTED
+# ifndef PNG_tIME_SUPPORTED
+# define PNG_tIME_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_tRNS
+# define PNG_WRITE_tRNS_SUPPORTED
+# ifndef PNG_tRNS_SUPPORTED
+# define PNG_tRNS_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_zTXt
+# define PNG_WRITE_zTXt_SUPPORTED
+# ifndef PNG_zTXt_SUPPORTED
+# define PNG_zTXt_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_UNKNOWN_CHUNKS
+# define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
+# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED
+# define PNG_UNKNOWN_CHUNKS_SUPPORTED
+# endif
+# ifndef PNG_NO_HANDLE_AS_UNKNOWN
+# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+# endif
+# endif
+#endif
+#if defined(PNG_WRITE_iTXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \
+ defined(PNG_WRITE_zTXt_SUPPORTED)
+# define PNG_WRITE_TEXT_SUPPORTED
+# ifndef PNG_TEXT_SUPPORTED
+# define PNG_TEXT_SUPPORTED
+# endif
+#endif
+
+#endif /* PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED */
+
+/* Turn this off to disable png_read_png() and
+ * png_write_png() and leave the row_pointers member
+ * out of the info structure.
+ */
+#ifndef PNG_NO_INFO_IMAGE
+# define PNG_INFO_IMAGE_SUPPORTED
+#endif
+
+/* need the time information for reading tIME chunks */
+#if defined(PNG_tIME_SUPPORTED)
+# if !defined(_WIN32_WCE)
+ /* "time.h" functions are not supported on WindowsCE */
+# include <time.h>
+# endif
+#endif
+
+/* Some typedefs to get us started. These should be safe on most of the
+ * common platforms. The typedefs should be at least as large as the
+ * numbers suggest (a png_uint_32 must be at least 32 bits long), but they
+ * don't have to be exactly that size. Some compilers dislike passing
+ * unsigned shorts as function parameters, so you may be better off using
+ * unsigned int for png_uint_16. Likewise, for 64-bit systems, you may
+ * want to have unsigned int for png_uint_32 instead of unsigned long.
+ */
+
+typedef unsigned long png_uint_32;
+typedef long png_int_32;
+typedef unsigned short png_uint_16;
+typedef short png_int_16;
+typedef unsigned char png_byte;
+
+/* This is usually size_t. It is typedef'ed just in case you need it to
+ change (I'm not sure if you will or not, so I thought I'd be safe) */
+typedef size_t png_size_t;
+
+/* The following is needed for medium model support. It cannot be in the
+ * PNG_INTERNAL section. Needs modification for other compilers besides
+ * MSC. Model independent support declares all arrays and pointers to be
+ * large using the far keyword. The zlib version used must also support
+ * model independent data. As of version zlib 1.0.4, the necessary changes
+ * have been made in zlib. The USE_FAR_KEYWORD define triggers other
+ * changes that are needed. (Tim Wegner)
+ */
+
+/* Separate compiler dependencies (problem here is that zlib.h always
+ defines FAR. (SJT) */
+#ifdef __BORLANDC__
+# if defined(__LARGE__) || defined(__HUGE__) || defined(__COMPACT__)
+# define LDATA 1
+# else
+# define LDATA 0
+# endif
+ /* GRR: why is Cygwin in here? Cygwin is not Borland C... */
+# if !defined(__WIN32__) && !defined(__FLAT__) && !defined(__CYGWIN__)
+# define PNG_MAX_MALLOC_64K
+# if (LDATA != 1)
+# ifndef FAR
+# define FAR __far
+# endif
+# define USE_FAR_KEYWORD
+# endif /* LDATA != 1 */
+ /* Possibly useful for moving data out of default segment.
+ * Uncomment it if you want. Could also define FARDATA as
+ * const if your compiler supports it. (SJT)
+# define FARDATA FAR
+ */
+# endif /* __WIN32__, __FLAT__, __CYGWIN__ */
+#endif /* __BORLANDC__ */
+
+
+/* Suggest testing for specific compiler first before testing for
+ * FAR. The Watcom compiler defines both __MEDIUM__ and M_I86MM,
+ * making reliance oncertain keywords suspect. (SJT)
+ */
+
+/* MSC Medium model */
+#if defined(FAR)
+# if defined(M_I86MM)
+# define USE_FAR_KEYWORD
+# define FARDATA FAR
+# include <dos.h>
+# endif
+#endif
+
+/* SJT: default case */
+#ifndef FAR
+# define FAR
+#endif
+
+/* At this point FAR is always defined */
+#ifndef FARDATA
+# define FARDATA
+#endif
+
+/* Typedef for floating-point numbers that are converted
+ to fixed-point with a multiple of 100,000, e.g., int_gamma */
+typedef png_int_32 png_fixed_point;
+
+/* Add typedefs for pointers */
+typedef void FAR * png_voidp;
+typedef png_byte FAR * png_bytep;
+typedef png_uint_32 FAR * png_uint_32p;
+typedef png_int_32 FAR * png_int_32p;
+typedef png_uint_16 FAR * png_uint_16p;
+typedef png_int_16 FAR * png_int_16p;
+typedef PNG_CONST char FAR * png_const_charp;
+typedef char FAR * png_charp;
+typedef png_fixed_point FAR * png_fixed_point_p;
+
+#ifndef PNG_NO_STDIO
+#if defined(_WIN32_WCE)
+typedef HANDLE png_FILE_p;
+#else
+typedef FILE * png_FILE_p;
+#endif
+#endif
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+typedef double FAR * png_doublep;
+#endif
+
+/* Pointers to pointers; i.e. arrays */
+typedef png_byte FAR * FAR * png_bytepp;
+typedef png_uint_32 FAR * FAR * png_uint_32pp;
+typedef png_int_32 FAR * FAR * png_int_32pp;
+typedef png_uint_16 FAR * FAR * png_uint_16pp;
+typedef png_int_16 FAR * FAR * png_int_16pp;
+typedef PNG_CONST char FAR * FAR * png_const_charpp;
+typedef char FAR * FAR * png_charpp;
+typedef png_fixed_point FAR * FAR * png_fixed_point_pp;
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+typedef double FAR * FAR * png_doublepp;
+#endif
+
+/* Pointers to pointers to pointers; i.e., pointer to array */
+typedef char FAR * FAR * FAR * png_charppp;
+
+/* libpng typedefs for types in zlib. If zlib changes
+ * or another compression library is used, then change these.
+ * Eliminates need to change all the source files.
+ */
+typedef charf * png_zcharp;
+typedef charf * FAR * png_zcharpp;
+typedef z_stream FAR * png_zstreamp;
+
+/*
+ * Define PNG_BUILD_DLL if the module being built is a Windows
+ * LIBPNG DLL.
+ *
+ * Define PNG_USE_DLL if you want to *link* to the Windows LIBPNG DLL.
+ * It is equivalent to Microsoft predefined macro _DLL that is
+ * automatically defined when you compile using the share
+ * version of the CRT (C Run-Time library)
+ *
+ * The cygwin mods make this behavior a little different:
+ * Define PNG_BUILD_DLL if you are building a dll for use with cygwin
+ * Define PNG_STATIC if you are building a static library for use with cygwin,
+ * -or- if you are building an application that you want to link to the
+ * static library.
+ * PNG_USE_DLL is defined by default (no user action needed) unless one of
+ * the other flags is defined.
+ */
+
+#if !defined(PNG_DLL) && (defined(PNG_BUILD_DLL) || defined(PNG_USE_DLL))
+# define PNG_DLL
+#endif
+/* If CYGWIN, then disallow GLOBAL ARRAYS unless building a static lib.
+ * When building a static lib, default to no GLOBAL ARRAYS, but allow
+ * command-line override
+ */
+#if defined(__CYGWIN__)
+# if !defined(PNG_STATIC)
+# if defined(PNG_USE_GLOBAL_ARRAYS)
+# undef PNG_USE_GLOBAL_ARRAYS
+# endif
+# if !defined(PNG_USE_LOCAL_ARRAYS)
+# define PNG_USE_LOCAL_ARRAYS
+# endif
+# else
+# if defined(PNG_USE_LOCAL_ARRAYS) || defined(PNG_NO_GLOBAL_ARRAYS)
+# if defined(PNG_USE_GLOBAL_ARRAYS)
+# undef PNG_USE_GLOBAL_ARRAYS
+# endif
+# endif
+# endif
+# if !defined(PNG_USE_LOCAL_ARRAYS) && !defined(PNG_USE_GLOBAL_ARRAYS)
+# define PNG_USE_LOCAL_ARRAYS
+# endif
+#endif
+
+/* Do not use global arrays (helps with building DLL's)
+ * They are no longer used in libpng itself, since version 1.0.5c,
+ * but might be required for some pre-1.0.5c applications.
+ */
+#if !defined(PNG_USE_LOCAL_ARRAYS) && !defined(PNG_USE_GLOBAL_ARRAYS)
+# if defined(PNG_NO_GLOBAL_ARRAYS) || (defined(__GNUC__) && defined(PNG_DLL))
+# define PNG_USE_LOCAL_ARRAYS
+# else
+# define PNG_USE_GLOBAL_ARRAYS
+# endif
+#endif
+
+
+#ifndef PNGAPI
+
+#if defined(__MINGW32__) || defined(__CYGWIN__) && !defined(PNG_MODULEDEF)
+# ifndef PNG_NO_MODULEDEF
+# define PNG_NO_MODULEDEF
+# endif
+#endif
+
+#if !defined(PNG_IMPEXP) && defined(PNG_BUILD_DLL) && !defined(PNG_NO_MODULEDEF)
+# define PNG_IMPEXP
+#endif
+
+#if defined(PNG_DLL) || defined(_DLL) || defined(__DLL__ ) || \
+ (( defined(_Windows) || defined(_WINDOWS) || \
+ defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \
+ ) && !defined(__CYGWIN__))
+
+# if defined(__GNUC__) || (defined (_MSC_VER) && (_MSC_VER >= 800))
+# define PNGAPI __cdecl
+# else
+# define PNGAPI _cdecl
+# endif
+
+# if !defined(PNG_IMPEXP) && (!defined(PNG_DLL) || \
+ 0 /* WINCOMPILER_WITH_NO_SUPPORT_FOR_DECLIMPEXP */)
+# define PNG_IMPEXP
+# endif
+
+# if !defined(PNG_IMPEXP)
+
+# define PNG_EXPORT_TYPE1(type,symbol) PNG_IMPEXP type PNGAPI symbol
+# define PNG_EXPORT_TYPE2(type,symbol) type PNG_IMPEXP PNGAPI symbol
+
+ /* Borland/Microsoft */
+# if defined(_MSC_VER) || defined(__BORLANDC__)
+# if (_MSC_VER >= 800) || (__BORLANDC__ >= 0x500)
+# define PNG_EXPORT PNG_EXPORT_TYPE1
+# else
+# define PNG_EXPORT PNG_EXPORT_TYPE2
+# if defined(PNG_BUILD_DLL)
+# define PNG_IMPEXP __export
+# else
+# define PNG_IMPEXP /*__import*/ /* doesn't exist AFAIK in
+ VC++*/
+# endif /* Exists in Borland C++ for
+ C++ classes (== huge) */
+# endif
+# endif
+
+# if !defined(PNG_IMPEXP)
+# if defined(PNG_BUILD_DLL)
+# define PNG_IMPEXP __declspec(dllexport)
+# else
+# define PNG_IMPEXP __declspec(dllimport)
+# endif
+# endif
+# endif /* PNG_IMPEXP */
+#else /* !(DLL || non-cygwin WINDOWS) */
+# if defined(__CYGWIN__) && !defined(PNG_DLL)
+# if !defined(PNG_IMPEXP)
+# define PNG_IMPEXP
+# endif
+# define PNGAPI __cdecl
+# else
+# if (defined(__IBMC__) || defined(IBMCPP__)) && defined(__OS2__)
+# define PNGAPI _System
+# define PNG_IMPEXP
+# else
+# if 0 /* ... other platforms, with other meanings */
+# else
+# define PNGAPI
+# define PNG_IMPEXP
+# endif
+# endif
+# endif
+#endif
+#endif
+
+#ifndef PNGAPI
+# define PNGAPI
+#endif
+#ifndef PNG_IMPEXP
+# define PNG_IMPEXP
+#endif
+
+#ifndef PNG_EXPORT
+# define PNG_EXPORT(type,symbol) PNG_IMPEXP type PNGAPI symbol
+#endif
+
+#ifdef PNG_USE_GLOBAL_ARRAYS
+# ifndef PNG_EXPORT_VAR
+# define PNG_EXPORT_VAR(type) extern PNG_IMPEXP type
+# endif
+#endif
+
+/* User may want to use these so they are not in PNG_INTERNAL. Any library
+ * functions that are passed far data must be model independent.
+ */
+
+#ifndef PNG_ABORT
+# define PNG_ABORT() abort()
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
+#else
+# define png_jmpbuf(png_ptr) \
+ (LIBPNG_WAS_COMPILED_WITH__PNG_SETJMP_NOT_SUPPORTED)
+#endif
+
+#if defined(USE_FAR_KEYWORD) /* memory model independent fns */
+/* use this to make far-to-near assignments */
+# define CHECK 1
+# define NOCHECK 0
+# define CVT_PTR(ptr) (png_far_to_near(png_ptr,ptr,CHECK))
+# define CVT_PTR_NOCHECK(ptr) (png_far_to_near(png_ptr,ptr,NOCHECK))
+# define png_strcpy _fstrcpy
+# define png_strlen _fstrlen
+# define png_memcmp _fmemcmp /* SJT: added */
+# define png_memcpy _fmemcpy
+# define png_memset _fmemset
+#else /* use the usual functions */
+# define CVT_PTR(ptr) (ptr)
+# define CVT_PTR_NOCHECK(ptr) (ptr)
+# define png_strcpy strcpy
+# define png_strlen strlen
+# define png_memcmp memcmp /* SJT: added */
+# define png_memcpy memcpy
+# define png_memset memset
+#endif
+/* End of memory model independent support */
+
+/* Just a little check that someone hasn't tried to define something
+ * contradictory.
+ */
+#if (PNG_ZBUF_SIZE > 65536) && defined(PNG_MAX_MALLOC_64K)
+# undef PNG_ZBUF_SIZE
+# define PNG_ZBUF_SIZE 65536
+#endif
+
+#ifdef PNG_READ_SUPPORTED
+/* Prior to libpng-1.0.9, this block was in pngasmrd.h */
+#if defined(PNG_INTERNAL)
+
+/* These are the default thresholds before the MMX code kicks in; if either
+ * rowbytes or bitdepth is below the threshold, plain C code is used. These
+ * can be overridden at runtime via the png_set_mmx_thresholds() call in
+ * libpng 1.2.0 and later. The values below were chosen by Intel.
+ */
+
+#ifndef PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT
+# define PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT 128 /* >= */
+#endif
+#ifndef PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT
+# define PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT 9 /* >= */
+#endif
+
+/* Set this in the makefile for VC++ on Pentium, not here. */
+/* Platform must be Pentium. Makefile must assemble and load pngvcrd.c .
+ * MMX will be detected at run time and used if present.
+ */
+#ifdef PNG_USE_PNGVCRD
+# define PNG_HAVE_ASSEMBLER_COMBINE_ROW
+# define PNG_HAVE_ASSEMBLER_READ_INTERLACE
+# define PNG_HAVE_ASSEMBLER_READ_FILTER_ROW
+#endif
+
+/* Set this in the makefile for gcc/as on Pentium, not here. */
+/* Platform must be Pentium. Makefile must assemble and load pnggccrd.c .
+ * MMX will be detected at run time and used if present.
+ */
+#ifdef PNG_USE_PNGGCCRD
+# define PNG_HAVE_ASSEMBLER_COMBINE_ROW
+# define PNG_HAVE_ASSEMBLER_READ_INTERLACE
+# define PNG_HAVE_ASSEMBLER_READ_FILTER_ROW
+#endif
+/* - see pnggccrd.c for info about what is currently enabled */
+
+#endif /* PNG_INTERNAL */
+#endif /* PNG_READ_SUPPORTED */
+
+#endif /* PNGCONF_H */
+
--- /dev/null
+
+/* pngerror.c - stub functions for i/o and memory allocation
+ *
+ * libpng 1.2.0 - September 1, 2001
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ *
+ * This file provides a location for all error handling. Users who
+ * need special error handling are expected to write replacement functions
+ * and use png_set_error_fn() to use those functions. See the instructions
+ * at each function.
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+static void /* PRIVATE */
+png_default_error PNGARG((png_structp png_ptr,
+ png_const_charp message));
+static void /* PRIVATE */
+png_default_warning PNGARG((png_structp png_ptr,
+ png_const_charp message));
+
+/* This function is called whenever there is a fatal error. This function
+ * should not be changed. If there is a need to handle errors differently,
+ * you should supply a replacement error function and use png_set_error_fn()
+ * to replace the error function at run-time.
+ */
+void PNGAPI
+png_error(png_structp png_ptr, png_const_charp message)
+{
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+ char msg[16];
+ if (png_ptr->flags&(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))
+ {
+ int offset = 0;
+ if (*message == '#')
+ {
+ for (offset=1; offset<15; offset++)
+ if (*(message+offset) == ' ')
+ break;
+ if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT)
+ {
+ int i;
+ for (i=0; i<offset-1; i++)
+ msg[i]=message[i+1];
+ msg[i]='\0';
+ message=msg;
+ }
+ else
+ message+=offset;
+ }
+ else
+ {
+ if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT)
+ {
+ msg[0]='0';
+ msg[1]='\0';
+ message=msg;
+ }
+ }
+ }
+#endif
+ if (png_ptr->error_fn != NULL)
+ (*(png_ptr->error_fn))(png_ptr, message);
+
+ /* if the following returns or doesn't exist, use the default function,
+ which will not return */
+ png_default_error(png_ptr, message);
+}
+
+/* This function is called whenever there is a non-fatal error. This function
+ * should not be changed. If there is a need to handle warnings differently,
+ * you should supply a replacement warning function and use
+ * png_set_error_fn() to replace the warning function at run-time.
+ */
+void PNGAPI
+png_warning(png_structp png_ptr, png_const_charp message)
+{
+ int offset = 0;
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+ if (png_ptr->flags&(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))
+#endif
+ {
+ if (*message == '#')
+ {
+ for (offset=1; offset<15; offset++)
+ if (*(message+offset) == ' ')
+ break;
+ }
+ }
+ if (png_ptr->warning_fn != NULL)
+ (*(png_ptr->warning_fn))(png_ptr, (png_const_charp)(message+offset));
+ else
+ png_default_warning(png_ptr, (png_const_charp)(message+offset));
+}
+
+/* These utilities are used internally to build an error message that relates
+ * to the current chunk. The chunk name comes from png_ptr->chunk_name,
+ * this is used to prefix the message. The message is limited in length
+ * to 63 bytes, the name characters are output as hex digits wrapped in []
+ * if the character is invalid.
+ */
+#define isnonalpha(c) ((c) < 41 || (c) > 122 || ((c) > 90 && (c) < 97))
+static PNG_CONST char png_digit[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
+ 'F' };
+
+static void /* PRIVATE */
+png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp
+ message)
+{
+ int iout = 0, iin = 0;
+
+ while (iin < 4)
+ {
+ int c = png_ptr->chunk_name[iin++];
+ if (isnonalpha(c))
+ {
+ buffer[iout++] = '[';
+ buffer[iout++] = png_digit[(c & 0xf0) >> 4];
+ buffer[iout++] = png_digit[c & 0x0f];
+ buffer[iout++] = ']';
+ }
+ else
+ {
+ buffer[iout++] = (png_byte)c;
+ }
+ }
+
+ if (message == NULL)
+ buffer[iout] = 0;
+ else
+ {
+ buffer[iout++] = ':';
+ buffer[iout++] = ' ';
+ png_memcpy(buffer+iout, message, 64);
+ buffer[iout+63] = 0;
+ }
+}
+
+void PNGAPI
+png_chunk_error(png_structp png_ptr, png_const_charp message)
+{
+ char msg[18+64];
+ png_format_buffer(png_ptr, msg, message);
+ png_error(png_ptr, msg);
+}
+
+void PNGAPI
+png_chunk_warning(png_structp png_ptr, png_const_charp message)
+{
+ char msg[18+64];
+ png_format_buffer(png_ptr, msg, message);
+ png_warning(png_ptr, msg);
+}
+
+/* This is the default error handling function. Note that replacements for
+ * this function MUST NOT RETURN, or the program will likely crash. This
+ * function is used by default, or if the program supplies NULL for the
+ * error function pointer in png_set_error_fn().
+ */
+static void /* PRIVATE */
+png_default_error(png_structp png_ptr, png_const_charp message)
+{
+#ifndef PNG_NO_CONSOLE_IO
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+ if (*message == '#')
+ {
+ int offset;
+ char error_number[16];
+ for (offset=0; offset<15; offset++)
+ {
+ error_number[offset] = *(message+offset+1);
+ if (*(message+offset) == ' ')
+ break;
+ }
+ if((offset > 1) && (offset < 15))
+ {
+ error_number[offset-1]='\0';
+ fprintf(stderr, "libpng error no. %s: %s\n", error_number, message+offset);
+ }
+ else
+ fprintf(stderr, "libpng error: %s, offset=%d\n", message,offset);
+ }
+ else
+#endif
+ fprintf(stderr, "libpng error: %s\n", message);
+#else
+ if (message)
+ /* make compiler happy */ ;
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+# ifdef USE_FAR_KEYWORD
+ {
+ jmp_buf jmpbuf;
+ png_memcpy(jmpbuf,png_ptr->jmpbuf,sizeof(jmp_buf));
+ longjmp(jmpbuf, 1);
+ }
+# else
+ longjmp(png_ptr->jmpbuf, 1);
+# endif
+#else
+ if (png_ptr)
+ /* make compiler happy */ ;
+ PNG_ABORT();
+#endif
+}
+
+/* This function is called when there is a warning, but the library thinks
+ * it can continue anyway. Replacement functions don't have to do anything
+ * here if you don't want them to. In the default configuration, png_ptr is
+ * not used, but it is passed in case it may be useful.
+ */
+static void /* PRIVATE */
+png_default_warning(png_structp png_ptr, png_const_charp message)
+{
+#ifndef PNG_NO_CONSOLE_IO
+# ifdef PNG_ERROR_NUMBERS_SUPPORTED
+ if (*message == '#')
+ {
+ int offset;
+ char warning_number[16];
+ for (offset=0; offset<15; offset++)
+ {
+ warning_number[offset]=*(message+offset+1);
+ if (*(message+offset) == ' ')
+ break;
+ }
+ if((offset > 1) && (offset < 15))
+ {
+ warning_number[offset-1]='\0';
+ fprintf(stderr, "libpng warning no. %s: %s\n", warning_number,
+ message+offset);
+ }
+ else
+ fprintf(stderr, "libpng warning: %s\n", message);
+ }
+ else
+# endif
+ fprintf(stderr, "libpng warning: %s\n", message);
+#else
+ if (message)
+ /* appease compiler */ ;
+#endif
+ if (png_ptr)
+ return;
+}
+
+/* This function is called when the application wants to use another method
+ * of handling errors and warnings. Note that the error function MUST NOT
+ * return to the calling routine or serious problems will occur. The return
+ * method used in the default routine calls longjmp(png_ptr->jmpbuf, 1)
+ */
+void PNGAPI
+png_set_error_fn(png_structp png_ptr, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warning_fn)
+{
+ png_ptr->error_ptr = error_ptr;
+ png_ptr->error_fn = error_fn;
+ png_ptr->warning_fn = warning_fn;
+}
+
+
+/* This function returns a pointer to the error_ptr associated with the user
+ * functions. The application should free any memory associated with this
+ * pointer before png_write_destroy and png_read_destroy are called.
+ */
+png_voidp PNGAPI
+png_get_error_ptr(png_structp png_ptr)
+{
+ return ((png_voidp)png_ptr->error_ptr);
+}
+
+
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+void
+png_set_strip_error_numbers(png_structp png_ptr, png_uint_32 strip_mode)
+{
+ if(png_ptr != NULL)
+ {
+ png_ptr->flags &=
+ ((~(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode);
+ }
+}
+#endif
--- /dev/null
+/* pnggccrd.c - mixed C/assembler version of utilities to read a PNG file
+ *
+ * For Intel x86 CPU (Pentium-MMX or later) and GNU C compiler.
+ *
+ * See http://www.intel.com/drg/pentiumII/appnotes/916/916.htm
+ * and http://www.intel.com/drg/pentiumII/appnotes/923/923.htm
+ * for Intel's performance analysis of the MMX vs. non-MMX code.
+ *
+ * libpng version 1.2.0 - September 1, 2001
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ * Copyright (c) 1998, Intel Corporation
+ *
+ * Based on MSVC code contributed by Nirav Chhatrapati, Intel Corp., 1998.
+ * Interface to libpng contributed by Gilles Vollant, 1999.
+ * GNU C port by Greg Roelofs, 1999-2001.
+ *
+ * Lines 2350-4300 converted in place with intel2gas 1.3.1:
+ *
+ * intel2gas -mdI pnggccrd.c.partially-msvc -o pnggccrd.c
+ *
+ * and then cleaned up by hand. See http://hermes.terminal.at/intel2gas/ .
+ *
+ * NOTE: A sufficiently recent version of GNU as (or as.exe under DOS/Windows)
+ * is required to assemble the newer MMX instructions such as movq.
+ * For djgpp, see
+ *
+ * ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bnu281b.zip
+ *
+ * (or a later version in the same directory). For Linux, check your
+ * distribution's web site(s) or try these links:
+ *
+ * http://rufus.w3.org/linux/RPM/binutils.html
+ * http://www.debian.org/Packages/stable/devel/binutils.html
+ * ftp://ftp.slackware.com/pub/linux/slackware/slackware/slakware/d1/
+ * binutils.tgz
+ *
+ * For other platforms, see the main GNU site:
+ *
+ * ftp://ftp.gnu.org/pub/gnu/binutils/
+ *
+ * Version 2.5.2l.15 is definitely too old...
+ */
+
+/*
+ * TEMPORARY PORTING NOTES AND CHANGELOG (mostly by Greg Roelofs)
+ * =====================================
+ *
+ * 19991006:
+ * - fixed sign error in post-MMX cleanup code (16- & 32-bit cases)
+ *
+ * 19991007:
+ * - additional optimizations (possible or definite):
+ * x [DONE] write MMX code for 64-bit case (pixel_bytes == 8) [not tested]
+ * - write MMX code for 48-bit case (pixel_bytes == 6)
+ * - figure out what's up with 24-bit case (pixel_bytes == 3):
+ * why subtract 8 from width_mmx in the pass 4/5 case?
+ * (only width_mmx case) (near line 1606)
+ * x [DONE] replace pixel_bytes within each block with the true
+ * constant value (or are compilers smart enough to do that?)
+ * - rewrite all MMX interlacing code so it's aligned with
+ * the *beginning* of the row buffer, not the end. This
+ * would not only allow one to eliminate half of the memory
+ * writes for odd passes (that is, pass == odd), it may also
+ * eliminate some unaligned-data-access exceptions (assuming
+ * there's a penalty for not aligning 64-bit accesses on
+ * 64-bit boundaries). The only catch is that the "leftover"
+ * pixel(s) at the end of the row would have to be saved,
+ * but there are enough unused MMX registers in every case,
+ * so this is not a problem. A further benefit is that the
+ * post-MMX cleanup code (C code) in at least some of the
+ * cases could be done within the assembler block.
+ * x [DONE] the "v3 v2 v1 v0 v7 v6 v5 v4" comments are confusing,
+ * inconsistent, and don't match the MMX Programmer's Reference
+ * Manual conventions anyway. They should be changed to
+ * "b7 b6 b5 b4 b3 b2 b1 b0," where b0 indicates the byte that
+ * was lowest in memory (e.g., corresponding to a left pixel)
+ * and b7 is the byte that was highest (e.g., a right pixel).
+ *
+ * 19991016:
+ * - Brennan's Guide notwithstanding, gcc under Linux does *not*
+ * want globals prefixed by underscores when referencing them--
+ * i.e., if the variable is const4, then refer to it as const4,
+ * not _const4. This seems to be a djgpp-specific requirement.
+ * Also, such variables apparently *must* be declared outside
+ * of functions; neither static nor automatic variables work if
+ * defined within the scope of a single function, but both
+ * static and truly global (multi-module) variables work fine.
+ *
+ * 19991023:
+ * - fixed png_combine_row() non-MMX replication bug (odd passes only?)
+ * - switched from string-concatenation-with-macros to cleaner method of
+ * renaming global variables for djgpp--i.e., always use prefixes in
+ * inlined assembler code (== strings) and conditionally rename the
+ * variables, not the other way around. Hence _const4, _mask8_0, etc.
+ *
+ * 19991024:
+ * - fixed mmxsupport()/png_do_read_interlace() first-row bug
+ * This one was severely weird: even though mmxsupport() doesn't touch
+ * ebx (where "row" pointer was stored), it nevertheless managed to zero
+ * the register (even in static/non-fPIC code--see below), which in turn
+ * caused png_do_read_interlace() to return prematurely on the first row of
+ * interlaced images (i.e., without expanding the interlaced pixels).
+ * Inspection of the generated assembly code didn't turn up any clues,
+ * although it did point at a minor optimization (i.e., get rid of
+ * mmx_supported_local variable and just use eax). Possibly the CPUID
+ * instruction is more destructive than it looks? (Not yet checked.)
+ * - "info gcc" was next to useless, so compared fPIC and non-fPIC assembly
+ * listings... Apparently register spillage has to do with ebx, since
+ * it's used to index the global offset table. Commenting it out of the
+ * input-reg lists in png_combine_row() eliminated compiler barfage, so
+ * ifdef'd with __PIC__ macro: if defined, use a global for unmask
+ *
+ * 19991107:
+ * - verified CPUID clobberage: 12-char string constant ("GenuineIntel",
+ * "AuthenticAMD", etc.) placed in ebx:ecx:edx. Still need to polish.
+ *
+ * 19991120:
+ * - made "diff" variable (now "_dif") global to simplify conversion of
+ * filtering routines (running out of regs, sigh). "diff" is still used
+ * in interlacing routines, however.
+ * - fixed up both versions of mmxsupport() (ORIG_THAT_USED_TO_CLOBBER_EBX
+ * macro determines which is used); original not yet tested.
+ *
+ * 20000213:
+ * - when compiling with gcc, be sure to use -fomit-frame-pointer
+ *
+ * 20000319:
+ * - fixed a register-name typo in png_do_read_interlace(), default (MMX) case,
+ * pass == 4 or 5, that caused visible corruption of interlaced images
+ *
+ * 20000623:
+ * - Various problems were reported with gcc 2.95.2 in the Cygwin environment,
+ * many of the form "forbidden register 0 (ax) was spilled for class AREG."
+ * This is explained at http://gcc.gnu.org/fom_serv/cache/23.html, and
+ * Chuck Wilson supplied a patch involving dummy output registers. See
+ * http://sourceforge.net/bugs/?func=detailbug&bug_id=108741&group_id=5624
+ * for the original (anonymous) SourceForge bug report.
+ *
+ * 20000706:
+ * - Chuck Wilson passed along these remaining gcc 2.95.2 errors:
+ * pnggccrd.c: In function `png_combine_row':
+ * pnggccrd.c:525: more than 10 operands in `asm'
+ * pnggccrd.c:669: more than 10 operands in `asm'
+ * pnggccrd.c:828: more than 10 operands in `asm'
+ * pnggccrd.c:994: more than 10 operands in `asm'
+ * pnggccrd.c:1177: more than 10 operands in `asm'
+ * They are all the same problem and can be worked around by using the
+ * global _unmask variable unconditionally, not just in the -fPIC case.
+ * Reportedly earlier versions of gcc also have the problem with more than
+ * 10 operands; they just don't report it. Much strangeness ensues, etc.
+ *
+ * 20000729:
+ * - enabled png_read_filter_row_mmx_up() (shortest remaining unconverted
+ * MMX routine); began converting png_read_filter_row_mmx_sub()
+ * - to finish remaining sections:
+ * - clean up indentation and comments
+ * - preload local variables
+ * - add output and input regs (order of former determines numerical
+ * mapping of latter)
+ * - avoid all usage of ebx (including bx, bh, bl) register [20000823]
+ * - remove "$" from addressing of Shift and Mask variables [20000823]
+ *
+ * 20000731:
+ * - global union vars causing segfaults in png_read_filter_row_mmx_sub()?
+ *
+ * 20000822:
+ * - ARGH, stupid png_read_filter_row_mmx_sub() segfault only happens with
+ * shared-library (-fPIC) version! Code works just fine as part of static
+ * library. Damn damn damn damn damn, should have tested that sooner.
+ * ebx is getting clobbered again (explicitly this time); need to save it
+ * on stack or rewrite asm code to avoid using it altogether. Blargh!
+ *
+ * 20000823:
+ * - first section was trickiest; all remaining sections have ebx -> edx now.
+ * (-fPIC works again.) Also added missing underscores to various Shift*
+ * and *Mask* globals and got rid of leading "$" signs.
+ *
+ * 20000826:
+ * - added visual separators to help navigate microscopic printed copies
+ * (http://pobox.com/~newt/code/gpr-latest.zip, mode 10); started working
+ * on png_read_filter_row_mmx_avg()
+ *
+ * 20000828:
+ * - finished png_read_filter_row_mmx_avg(): only Paeth left! (930 lines...)
+ * What the hell, did png_read_filter_row_mmx_paeth(), too. Comments not
+ * cleaned up/shortened in either routine, but functionality is complete
+ * and seems to be working fine.
+ *
+ * 20000829:
+ * - ahhh, figured out last(?) bit of gcc/gas asm-fu: if register is listed
+ * as an input reg (with dummy output variables, etc.), then it *cannot*
+ * also appear in the clobber list or gcc 2.95.2 will barf. The solution
+ * is simple enough...
+ *
+ * 20000914:
+ * - bug in png_read_filter_row_mmx_avg(): 16-bit grayscale not handled
+ * correctly (but 48-bit RGB just fine)
+ *
+ * 20000916:
+ * - fixed bug in png_read_filter_row_mmx_avg(), bpp == 2 case; three errors:
+ * - "_ShiftBpp.use = 24;" should have been "_ShiftBpp.use = 16;"
+ * - "_ShiftRem.use = 40;" should have been "_ShiftRem.use = 48;"
+ * - "psllq _ShiftRem, %%mm2" should have been "psrlq _ShiftRem, %%mm2"
+ *
+ * 20010101:
+ * - added new png_init_mmx_flags() function (here only because it needs to
+ * call mmxsupport(), which should probably become global png_mmxsupport());
+ * modified other MMX routines to run conditionally (png_ptr->asm_flags)
+ *
+ * 20010103:
+ * - renamed mmxsupport() to png_mmx_support(), with auto-set of mmx_supported,
+ * and made it public; moved png_init_mmx_flags() to png.c as internal func
+ *
+ * 20010104:
+ * - removed dependency on png_read_filter_row_c() (C code already duplicated
+ * within MMX version of png_read_filter_row()) so no longer necessary to
+ * compile it into pngrutil.o
+ *
+ * 20010310:
+ * - fixed buffer-overrun bug in png_combine_row() C code (non-MMX)
+ *
+ * STILL TO DO:
+ * - test png_do_read_interlace() 64-bit case (pixel_bytes == 8)
+ * - write MMX code for 48-bit case (pixel_bytes == 6)
+ * - figure out what's up with 24-bit case (pixel_bytes == 3):
+ * why subtract 8 from width_mmx in the pass 4/5 case?
+ * (only width_mmx case) (near line 1606)
+ * - rewrite all MMX interlacing code so it's aligned with beginning
+ * of the row buffer, not the end (see 19991007 for details)
+ * x pick one version of mmxsupport() and get rid of the other
+ * - add error messages to any remaining bogus default cases
+ * - enable pixel_depth == 8 cases in png_read_filter_row()? (test speed)
+ * x add support for runtime enable/disable/query of various MMX routines
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#if defined(PNG_USE_PNGGCCRD)
+
+int PNGAPI png_mmx_support(void);
+
+#ifdef PNG_USE_LOCAL_ARRAYS
+static const int FARDATA png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+static const int FARDATA png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+static const int FARDATA png_pass_width[7] = {8, 4, 4, 2, 2, 1, 1};
+#endif
+
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
+/* djgpp, Win32, and Cygwin add their own underscores to global variables,
+ * so define them without: */
+#if defined(__DJGPP__) || defined(WIN32) || defined(__CYGWIN__)
+# define _mmx_supported mmx_supported
+# define _const4 const4
+# define _const6 const6
+# define _mask8_0 mask8_0
+# define _mask16_1 mask16_1
+# define _mask16_0 mask16_0
+# define _mask24_2 mask24_2
+# define _mask24_1 mask24_1
+# define _mask24_0 mask24_0
+# define _mask32_3 mask32_3
+# define _mask32_2 mask32_2
+# define _mask32_1 mask32_1
+# define _mask32_0 mask32_0
+# define _mask48_5 mask48_5
+# define _mask48_4 mask48_4
+# define _mask48_3 mask48_3
+# define _mask48_2 mask48_2
+# define _mask48_1 mask48_1
+# define _mask48_0 mask48_0
+# define _LBCarryMask LBCarryMask
+# define _HBClearMask HBClearMask
+# define _ActiveMask ActiveMask
+# define _ActiveMask2 ActiveMask2
+# define _ActiveMaskEnd ActiveMaskEnd
+# define _ShiftBpp ShiftBpp
+# define _ShiftRem ShiftRem
+#ifdef PNG_THREAD_UNSAFE_OK
+# define _unmask unmask
+# define _FullLength FullLength
+# define _MMXLength MMXLength
+# define _dif dif
+# define _patemp patemp
+# define _pbtemp pbtemp
+# define _pctemp pctemp
+#endif
+#endif
+
+
+/* These constants are used in the inlined MMX assembly code.
+ Ignore gcc's "At top level: defined but not used" warnings. */
+
+/* GRR 20000706: originally _unmask was needed only when compiling with -fPIC,
+ * since that case uses the %ebx register for indexing the Global Offset Table
+ * and there were no other registers available. But gcc 2.95 and later emit
+ * "more than 10 operands in `asm'" errors when %ebx is used to preload unmask
+ * in the non-PIC case, so we'll just use the global unconditionally now.
+ */
+#ifdef PNG_THREAD_UNSAFE_OK
+static int _unmask;
+#endif
+
+static unsigned long long _mask8_0 = 0x0102040810204080LL;
+
+static unsigned long long _mask16_1 = 0x0101020204040808LL;
+static unsigned long long _mask16_0 = 0x1010202040408080LL;
+
+static unsigned long long _mask24_2 = 0x0101010202020404LL;
+static unsigned long long _mask24_1 = 0x0408080810101020LL;
+static unsigned long long _mask24_0 = 0x2020404040808080LL;
+
+static unsigned long long _mask32_3 = 0x0101010102020202LL;
+static unsigned long long _mask32_2 = 0x0404040408080808LL;
+static unsigned long long _mask32_1 = 0x1010101020202020LL;
+static unsigned long long _mask32_0 = 0x4040404080808080LL;
+
+static unsigned long long _mask48_5 = 0x0101010101010202LL;
+static unsigned long long _mask48_4 = 0x0202020204040404LL;
+static unsigned long long _mask48_3 = 0x0404080808080808LL;
+static unsigned long long _mask48_2 = 0x1010101010102020LL;
+static unsigned long long _mask48_1 = 0x2020202040404040LL;
+static unsigned long long _mask48_0 = 0x4040808080808080LL;
+
+static unsigned long long _const4 = 0x0000000000FFFFFFLL;
+//static unsigned long long _const5 = 0x000000FFFFFF0000LL; // NOT USED
+static unsigned long long _const6 = 0x00000000000000FFLL;
+
+// These are used in the row-filter routines and should/would be local
+// variables if not for gcc addressing limitations.
+// WARNING: Their presence probably defeats the thread safety of libpng.
+
+#ifdef PNG_THREAD_UNSAFE_OK
+static png_uint_32 _FullLength;
+static png_uint_32 _MMXLength;
+static int _dif;
+static int _patemp; // temp variables for Paeth routine
+static int _pbtemp;
+static int _pctemp;
+#endif
+
+void /* PRIVATE */
+png_squelch_warnings(void)
+{
+#ifdef PNG_THREAD_UNSAFE_OK
+ _dif = _dif;
+ _patemp = _patemp;
+ _pbtemp = _pbtemp;
+ _pctemp = _pctemp;
+ _MMXLength = _MMXLength;
+#endif
+ _const4 = _const4;
+ _const6 = _const6;
+ _mask8_0 = _mask8_0;
+ _mask16_1 = _mask16_1;
+ _mask16_0 = _mask16_0;
+ _mask24_2 = _mask24_2;
+ _mask24_1 = _mask24_1;
+ _mask24_0 = _mask24_0;
+ _mask32_3 = _mask32_3;
+ _mask32_2 = _mask32_2;
+ _mask32_1 = _mask32_1;
+ _mask32_0 = _mask32_0;
+ _mask48_5 = _mask48_5;
+ _mask48_4 = _mask48_4;
+ _mask48_3 = _mask48_3;
+ _mask48_2 = _mask48_2;
+ _mask48_1 = _mask48_1;
+ _mask48_0 = _mask48_0;
+}
+#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
+
+
+static int _mmx_supported = 2;
+
+/*===========================================================================*/
+/* */
+/* P N G _ C O M B I N E _ R O W */
+/* */
+/*===========================================================================*/
+
+#if defined(PNG_HAVE_ASSEMBLER_COMBINE_ROW)
+
+#define BPP2 2
+#define BPP3 3 /* bytes per pixel (a.k.a. pixel_bytes) */
+#define BPP4 4
+#define BPP6 6 /* (defined only to help avoid cut-and-paste errors) */
+#define BPP8 8
+
+/* Combines the row recently read in with the previous row.
+ This routine takes care of alpha and transparency if requested.
+ This routine also handles the two methods of progressive display
+ of interlaced images, depending on the mask value.
+ The mask value describes which pixels are to be combined with
+ the row. The pattern always repeats every 8 pixels, so just 8
+ bits are needed. A one indicates the pixel is to be combined; a
+ zero indicates the pixel is to be skipped. This is in addition
+ to any alpha or transparency value associated with the pixel.
+ If you want all pixels to be combined, pass 0xff (255) in mask. */
+
+/* Use this routine for the x86 platform - it uses a faster MMX routine
+ if the machine supports MMX. */
+
+void /* PRIVATE */
+png_combine_row(png_structp png_ptr, png_bytep row, int mask)
+{
+ png_debug(1, "in png_combine_row (pnggccrd.c)\n");
+
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
+ if (_mmx_supported == 2) {
+ /* this should have happened in png_init_mmx_flags() already */
+ png_warning(png_ptr, "asm_flags may not have been initialized");
+ png_mmx_support();
+ }
+#endif
+
+ if (mask == 0xff)
+ {
+ png_debug(2,"mask == 0xff: doing single png_memcpy()\n");
+ png_memcpy(row, png_ptr->row_buf + 1,
+ (png_size_t)((png_ptr->width * png_ptr->row_info.pixel_depth + 7) >> 3));
+ }
+ else /* (png_combine_row() is never called with mask == 0) */
+ {
+ switch (png_ptr->row_info.pixel_depth)
+ {
+ case 1: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int s_inc, s_start, s_end;
+ int m;
+ int shift;
+ png_uint_32 i;
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ m = 0x80;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 7;
+ s_inc = 1;
+ }
+ else
+#endif
+ {
+ s_start = 7;
+ s_end = 0;
+ s_inc = -1;
+ }
+
+ shift = s_start;
+
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ int value;
+
+ value = (*sp >> shift) & 0x1;
+ *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+
+ case 2: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int s_start, s_end, s_inc;
+ int m;
+ int shift;
+ png_uint_32 i;
+ int value;
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ m = 0x80;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 6;
+ s_inc = 2;
+ }
+ else
+#endif
+ {
+ s_start = 6;
+ s_end = 0;
+ s_inc = -2;
+ }
+
+ shift = s_start;
+
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ value = (*sp >> shift) & 0x3;
+ *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+
+ case 4: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int s_start, s_end, s_inc;
+ int m;
+ int shift;
+ png_uint_32 i;
+ int value;
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ m = 0x80;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 4;
+ s_inc = 4;
+ }
+ else
+#endif
+ {
+ s_start = 4;
+ s_end = 0;
+ s_inc = -4;
+ }
+ shift = s_start;
+
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ value = (*sp >> shift) & 0xf;
+ *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+
+ case 8: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
+ /* && _mmx_supported */ )
+ {
+ png_uint_32 len;
+ int diff;
+ int dummy_value_a; // fix 'forbidden register spilled' error
+ int dummy_value_d;
+ int dummy_value_c;
+ int dummy_value_S;
+ int dummy_value_D;
+ _unmask = ~mask; // global variable for -fPIC version
+ srcptr = png_ptr->row_buf + 1;
+ dstptr = row;
+ len = png_ptr->width &~7; // reduce to multiple of 8
+ diff = (int) (png_ptr->width & 7); // amount lost
+
+ __asm__ __volatile__ (
+ "movd _unmask, %%mm7 \n\t" // load bit pattern
+ "psubb %%mm6, %%mm6 \n\t" // zero mm6
+ "punpcklbw %%mm7, %%mm7 \n\t"
+ "punpcklwd %%mm7, %%mm7 \n\t"
+ "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks
+
+ "movq _mask8_0, %%mm0 \n\t"
+ "pand %%mm7, %%mm0 \n\t" // nonzero if keep byte
+ "pcmpeqb %%mm6, %%mm0 \n\t" // zeros->1s, v versa
+
+// preload "movl len, %%ecx \n\t" // load length of line
+// preload "movl srcptr, %%esi \n\t" // load source
+// preload "movl dstptr, %%edi \n\t" // load dest
+
+ "cmpl $0, %%ecx \n\t" // len == 0 ?
+ "je mainloop8end \n\t"
+
+ "mainloop8: \n\t"
+ "movq (%%esi), %%mm4 \n\t" // *srcptr
+ "pand %%mm0, %%mm4 \n\t"
+ "movq %%mm0, %%mm6 \n\t"
+ "pandn (%%edi), %%mm6 \n\t" // *dstptr
+ "por %%mm6, %%mm4 \n\t"
+ "movq %%mm4, (%%edi) \n\t"
+ "addl $8, %%esi \n\t" // inc by 8 bytes processed
+ "addl $8, %%edi \n\t"
+ "subl $8, %%ecx \n\t" // dec by 8 pixels processed
+ "ja mainloop8 \n\t"
+
+ "mainloop8end: \n\t"
+// preload "movl diff, %%ecx \n\t" // (diff is in eax)
+ "movl %%eax, %%ecx \n\t"
+ "cmpl $0, %%ecx \n\t"
+ "jz end8 \n\t"
+// preload "movl mask, %%edx \n\t"
+ "sall $24, %%edx \n\t" // make low byte, high byte
+
+ "secondloop8: \n\t"
+ "sall %%edx \n\t" // move high bit to CF
+ "jnc skip8 \n\t" // if CF = 0
+ "movb (%%esi), %%al \n\t"
+ "movb %%al, (%%edi) \n\t"
+
+ "skip8: \n\t"
+ "incl %%esi \n\t"
+ "incl %%edi \n\t"
+ "decl %%ecx \n\t"
+ "jnz secondloop8 \n\t"
+
+ "end8: \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=a" (dummy_value_a), // output regs (dummy)
+ "=d" (dummy_value_d),
+ "=c" (dummy_value_c),
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "3" (srcptr), // esi // input regs
+ "4" (dstptr), // edi
+ "0" (diff), // eax
+// was (unmask) "b" RESERVED // ebx // Global Offset Table idx
+ "2" (len), // ecx
+ "1" (mask) // edx
+
+#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
+ : "%mm0", "%mm4", "%mm6", "%mm7" // clobber list
+#endif
+ );
+ }
+ else /* mmx _not supported - Use modified C routine */
+#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
+ {
+ register png_uint_32 i;
+ png_uint_32 initial_val = png_pass_start[png_ptr->pass];
+ /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
+ register int stride = png_pass_inc[png_ptr->pass];
+ /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
+ register int rep_bytes = png_pass_width[png_ptr->pass];
+ /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
+ png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */
+ int diff = (int) (png_ptr->width & 7); /* amount lost */
+ register png_uint_32 final_val = len; /* GRR bugfix */
+
+ srcptr = png_ptr->row_buf + 1 + initial_val;
+ dstptr = row + initial_val;
+
+ for (i = initial_val; i < final_val; i += stride)
+ {
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ if (diff) /* number of leftover pixels: 3 for pngtest */
+ {
+ final_val+=diff /* *BPP1 */ ;
+ for (; i < final_val; i += stride)
+ {
+ if (rep_bytes > (int)(final_val-i))
+ rep_bytes = (int)(final_val-i);
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ }
+
+ } /* end of else (_mmx_supported) */
+
+ break;
+ } /* end 8 bpp */
+
+ case 16: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
+ /* && _mmx_supported */ )
+ {
+ png_uint_32 len;
+ int diff;
+ int dummy_value_a; // fix 'forbidden register spilled' error
+ int dummy_value_d;
+ int dummy_value_c;
+ int dummy_value_S;
+ int dummy_value_D;
+ _unmask = ~mask; // global variable for -fPIC version
+ srcptr = png_ptr->row_buf + 1;
+ dstptr = row;
+ len = png_ptr->width &~7; // reduce to multiple of 8
+ diff = (int) (png_ptr->width & 7); // amount lost //
+
+ __asm__ __volatile__ (
+ "movd _unmask, %%mm7 \n\t" // load bit pattern
+ "psubb %%mm6, %%mm6 \n\t" // zero mm6
+ "punpcklbw %%mm7, %%mm7 \n\t"
+ "punpcklwd %%mm7, %%mm7 \n\t"
+ "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks
+
+ "movq _mask16_0, %%mm0 \n\t"
+ "movq _mask16_1, %%mm1 \n\t"
+
+ "pand %%mm7, %%mm0 \n\t"
+ "pand %%mm7, %%mm1 \n\t"
+
+ "pcmpeqb %%mm6, %%mm0 \n\t"
+ "pcmpeqb %%mm6, %%mm1 \n\t"
+
+// preload "movl len, %%ecx \n\t" // load length of line
+// preload "movl srcptr, %%esi \n\t" // load source
+// preload "movl dstptr, %%edi \n\t" // load dest
+
+ "cmpl $0, %%ecx \n\t"
+ "jz mainloop16end \n\t"
+
+ "mainloop16: \n\t"
+ "movq (%%esi), %%mm4 \n\t"
+ "pand %%mm0, %%mm4 \n\t"
+ "movq %%mm0, %%mm6 \n\t"
+ "movq (%%edi), %%mm7 \n\t"
+ "pandn %%mm7, %%mm6 \n\t"
+ "por %%mm6, %%mm4 \n\t"
+ "movq %%mm4, (%%edi) \n\t"
+
+ "movq 8(%%esi), %%mm5 \n\t"
+ "pand %%mm1, %%mm5 \n\t"
+ "movq %%mm1, %%mm7 \n\t"
+ "movq 8(%%edi), %%mm6 \n\t"
+ "pandn %%mm6, %%mm7 \n\t"
+ "por %%mm7, %%mm5 \n\t"
+ "movq %%mm5, 8(%%edi) \n\t"
+
+ "addl $16, %%esi \n\t" // inc by 16 bytes processed
+ "addl $16, %%edi \n\t"
+ "subl $8, %%ecx \n\t" // dec by 8 pixels processed
+ "ja mainloop16 \n\t"
+
+ "mainloop16end: \n\t"
+// preload "movl diff, %%ecx \n\t" // (diff is in eax)
+ "movl %%eax, %%ecx \n\t"
+ "cmpl $0, %%ecx \n\t"
+ "jz end16 \n\t"
+// preload "movl mask, %%edx \n\t"
+ "sall $24, %%edx \n\t" // make low byte, high byte
+
+ "secondloop16: \n\t"
+ "sall %%edx \n\t" // move high bit to CF
+ "jnc skip16 \n\t" // if CF = 0
+ "movw (%%esi), %%ax \n\t"
+ "movw %%ax, (%%edi) \n\t"
+
+ "skip16: \n\t"
+ "addl $2, %%esi \n\t"
+ "addl $2, %%edi \n\t"
+ "decl %%ecx \n\t"
+ "jnz secondloop16 \n\t"
+
+ "end16: \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=a" (dummy_value_a), // output regs (dummy)
+ "=c" (dummy_value_c),
+ "=d" (dummy_value_d),
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (diff), // eax // input regs
+// was (unmask) " " RESERVED // ebx // Global Offset Table idx
+ "1" (len), // ecx
+ "2" (mask), // edx
+ "3" (srcptr), // esi
+ "4" (dstptr) // edi
+
+#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
+ : "%mm0", "%mm1", "%mm4" // clobber list
+ , "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ else /* mmx _not supported - Use modified C routine */
+#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
+ {
+ register png_uint_32 i;
+ png_uint_32 initial_val = BPP2 * png_pass_start[png_ptr->pass];
+ /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
+ register int stride = BPP2 * png_pass_inc[png_ptr->pass];
+ /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
+ register int rep_bytes = BPP2 * png_pass_width[png_ptr->pass];
+ /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
+ png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */
+ int diff = (int) (png_ptr->width & 7); /* amount lost */
+ register png_uint_32 final_val = BPP2 * len; /* GRR bugfix */
+
+ srcptr = png_ptr->row_buf + 1 + initial_val;
+ dstptr = row + initial_val;
+
+ for (i = initial_val; i < final_val; i += stride)
+ {
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ if (diff) /* number of leftover pixels: 3 for pngtest */
+ {
+ final_val+=diff*BPP2;
+ for (; i < final_val; i += stride)
+ {
+ if (rep_bytes > (int)(final_val-i))
+ rep_bytes = (int)(final_val-i);
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ }
+ } /* end of else (_mmx_supported) */
+
+ break;
+ } /* end 16 bpp */
+
+ case 24: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
+ /* && _mmx_supported */ )
+ {
+ png_uint_32 len;
+ int diff;
+ int dummy_value_a; // fix 'forbidden register spilled' error
+ int dummy_value_d;
+ int dummy_value_c;
+ int dummy_value_S;
+ int dummy_value_D;
+ _unmask = ~mask; // global variable for -fPIC version
+ srcptr = png_ptr->row_buf + 1;
+ dstptr = row;
+ len = png_ptr->width &~7; // reduce to multiple of 8
+ diff = (int) (png_ptr->width & 7); // amount lost //
+
+ __asm__ __volatile__ (
+ "movd _unmask, %%mm7 \n\t" // load bit pattern
+ "psubb %%mm6, %%mm6 \n\t" // zero mm6
+ "punpcklbw %%mm7, %%mm7 \n\t"
+ "punpcklwd %%mm7, %%mm7 \n\t"
+ "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks
+
+ "movq _mask24_0, %%mm0 \n\t"
+ "movq _mask24_1, %%mm1 \n\t"
+ "movq _mask24_2, %%mm2 \n\t"
+
+ "pand %%mm7, %%mm0 \n\t"
+ "pand %%mm7, %%mm1 \n\t"
+ "pand %%mm7, %%mm2 \n\t"
+
+ "pcmpeqb %%mm6, %%mm0 \n\t"
+ "pcmpeqb %%mm6, %%mm1 \n\t"
+ "pcmpeqb %%mm6, %%mm2 \n\t"
+
+// preload "movl len, %%ecx \n\t" // load length of line
+// preload "movl srcptr, %%esi \n\t" // load source
+// preload "movl dstptr, %%edi \n\t" // load dest
+
+ "cmpl $0, %%ecx \n\t"
+ "jz mainloop24end \n\t"
+
+ "mainloop24: \n\t"
+ "movq (%%esi), %%mm4 \n\t"
+ "pand %%mm0, %%mm4 \n\t"
+ "movq %%mm0, %%mm6 \n\t"
+ "movq (%%edi), %%mm7 \n\t"
+ "pandn %%mm7, %%mm6 \n\t"
+ "por %%mm6, %%mm4 \n\t"
+ "movq %%mm4, (%%edi) \n\t"
+
+ "movq 8(%%esi), %%mm5 \n\t"
+ "pand %%mm1, %%mm5 \n\t"
+ "movq %%mm1, %%mm7 \n\t"
+ "movq 8(%%edi), %%mm6 \n\t"
+ "pandn %%mm6, %%mm7 \n\t"
+ "por %%mm7, %%mm5 \n\t"
+ "movq %%mm5, 8(%%edi) \n\t"
+
+ "movq 16(%%esi), %%mm6 \n\t"
+ "pand %%mm2, %%mm6 \n\t"
+ "movq %%mm2, %%mm4 \n\t"
+ "movq 16(%%edi), %%mm7 \n\t"
+ "pandn %%mm7, %%mm4 \n\t"
+ "por %%mm4, %%mm6 \n\t"
+ "movq %%mm6, 16(%%edi) \n\t"
+
+ "addl $24, %%esi \n\t" // inc by 24 bytes processed
+ "addl $24, %%edi \n\t"
+ "subl $8, %%ecx \n\t" // dec by 8 pixels processed
+
+ "ja mainloop24 \n\t"
+
+ "mainloop24end: \n\t"
+// preload "movl diff, %%ecx \n\t" // (diff is in eax)
+ "movl %%eax, %%ecx \n\t"
+ "cmpl $0, %%ecx \n\t"
+ "jz end24 \n\t"
+// preload "movl mask, %%edx \n\t"
+ "sall $24, %%edx \n\t" // make low byte, high byte
+
+ "secondloop24: \n\t"
+ "sall %%edx \n\t" // move high bit to CF
+ "jnc skip24 \n\t" // if CF = 0
+ "movw (%%esi), %%ax \n\t"
+ "movw %%ax, (%%edi) \n\t"
+ "xorl %%eax, %%eax \n\t"
+ "movb 2(%%esi), %%al \n\t"
+ "movb %%al, 2(%%edi) \n\t"
+
+ "skip24: \n\t"
+ "addl $3, %%esi \n\t"
+ "addl $3, %%edi \n\t"
+ "decl %%ecx \n\t"
+ "jnz secondloop24 \n\t"
+
+ "end24: \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=a" (dummy_value_a), // output regs (dummy)
+ "=d" (dummy_value_d),
+ "=c" (dummy_value_c),
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "3" (srcptr), // esi // input regs
+ "4" (dstptr), // edi
+ "0" (diff), // eax
+// was (unmask) "b" RESERVED // ebx // Global Offset Table idx
+ "2" (len), // ecx
+ "1" (mask) // edx
+
+#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
+ : "%mm0", "%mm1", "%mm2" // clobber list
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ else /* mmx _not supported - Use modified C routine */
+#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
+ {
+ register png_uint_32 i;
+ png_uint_32 initial_val = BPP3 * png_pass_start[png_ptr->pass];
+ /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
+ register int stride = BPP3 * png_pass_inc[png_ptr->pass];
+ /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
+ register int rep_bytes = BPP3 * png_pass_width[png_ptr->pass];
+ /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
+ png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */
+ int diff = (int) (png_ptr->width & 7); /* amount lost */
+ register png_uint_32 final_val = BPP3 * len; /* GRR bugfix */
+
+ srcptr = png_ptr->row_buf + 1 + initial_val;
+ dstptr = row + initial_val;
+
+ for (i = initial_val; i < final_val; i += stride)
+ {
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ if (diff) /* number of leftover pixels: 3 for pngtest */
+ {
+ final_val+=diff*BPP3;
+ for (; i < final_val; i += stride)
+ {
+ if (rep_bytes > (int)(final_val-i))
+ rep_bytes = (int)(final_val-i);
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ }
+ } /* end of else (_mmx_supported) */
+
+ break;
+ } /* end 24 bpp */
+
+ case 32: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
+ /* && _mmx_supported */ )
+ {
+ png_uint_32 len;
+ int diff;
+ int dummy_value_a; // fix 'forbidden register spilled' error
+ int dummy_value_d;
+ int dummy_value_c;
+ int dummy_value_S;
+ int dummy_value_D;
+ _unmask = ~mask; // global variable for -fPIC version
+ srcptr = png_ptr->row_buf + 1;
+ dstptr = row;
+ len = png_ptr->width &~7; // reduce to multiple of 8
+ diff = (int) (png_ptr->width & 7); // amount lost //
+
+ __asm__ __volatile__ (
+ "movd _unmask, %%mm7 \n\t" // load bit pattern
+ "psubb %%mm6, %%mm6 \n\t" // zero mm6
+ "punpcklbw %%mm7, %%mm7 \n\t"
+ "punpcklwd %%mm7, %%mm7 \n\t"
+ "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks
+
+ "movq _mask32_0, %%mm0 \n\t"
+ "movq _mask32_1, %%mm1 \n\t"
+ "movq _mask32_2, %%mm2 \n\t"
+ "movq _mask32_3, %%mm3 \n\t"
+
+ "pand %%mm7, %%mm0 \n\t"
+ "pand %%mm7, %%mm1 \n\t"
+ "pand %%mm7, %%mm2 \n\t"
+ "pand %%mm7, %%mm3 \n\t"
+
+ "pcmpeqb %%mm6, %%mm0 \n\t"
+ "pcmpeqb %%mm6, %%mm1 \n\t"
+ "pcmpeqb %%mm6, %%mm2 \n\t"
+ "pcmpeqb %%mm6, %%mm3 \n\t"
+
+// preload "movl len, %%ecx \n\t" // load length of line
+// preload "movl srcptr, %%esi \n\t" // load source
+// preload "movl dstptr, %%edi \n\t" // load dest
+
+ "cmpl $0, %%ecx \n\t" // lcr
+ "jz mainloop32end \n\t"
+
+ "mainloop32: \n\t"
+ "movq (%%esi), %%mm4 \n\t"
+ "pand %%mm0, %%mm4 \n\t"
+ "movq %%mm0, %%mm6 \n\t"
+ "movq (%%edi), %%mm7 \n\t"
+ "pandn %%mm7, %%mm6 \n\t"
+ "por %%mm6, %%mm4 \n\t"
+ "movq %%mm4, (%%edi) \n\t"
+
+ "movq 8(%%esi), %%mm5 \n\t"
+ "pand %%mm1, %%mm5 \n\t"
+ "movq %%mm1, %%mm7 \n\t"
+ "movq 8(%%edi), %%mm6 \n\t"
+ "pandn %%mm6, %%mm7 \n\t"
+ "por %%mm7, %%mm5 \n\t"
+ "movq %%mm5, 8(%%edi) \n\t"
+
+ "movq 16(%%esi), %%mm6 \n\t"
+ "pand %%mm2, %%mm6 \n\t"
+ "movq %%mm2, %%mm4 \n\t"
+ "movq 16(%%edi), %%mm7 \n\t"
+ "pandn %%mm7, %%mm4 \n\t"
+ "por %%mm4, %%mm6 \n\t"
+ "movq %%mm6, 16(%%edi) \n\t"
+
+ "movq 24(%%esi), %%mm7 \n\t"
+ "pand %%mm3, %%mm7 \n\t"
+ "movq %%mm3, %%mm5 \n\t"
+ "movq 24(%%edi), %%mm4 \n\t"
+ "pandn %%mm4, %%mm5 \n\t"
+ "por %%mm5, %%mm7 \n\t"
+ "movq %%mm7, 24(%%edi) \n\t"
+
+ "addl $32, %%esi \n\t" // inc by 32 bytes processed
+ "addl $32, %%edi \n\t"
+ "subl $8, %%ecx \n\t" // dec by 8 pixels processed
+ "ja mainloop32 \n\t"
+
+ "mainloop32end: \n\t"
+// preload "movl diff, %%ecx \n\t" // (diff is in eax)
+ "movl %%eax, %%ecx \n\t"
+ "cmpl $0, %%ecx \n\t"
+ "jz end32 \n\t"
+// preload "movl mask, %%edx \n\t"
+ "sall $24, %%edx \n\t" // low byte => high byte
+
+ "secondloop32: \n\t"
+ "sall %%edx \n\t" // move high bit to CF
+ "jnc skip32 \n\t" // if CF = 0
+ "movl (%%esi), %%eax \n\t"
+ "movl %%eax, (%%edi) \n\t"
+
+ "skip32: \n\t"
+ "addl $4, %%esi \n\t"
+ "addl $4, %%edi \n\t"
+ "decl %%ecx \n\t"
+ "jnz secondloop32 \n\t"
+
+ "end32: \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=a" (dummy_value_a), // output regs (dummy)
+ "=d" (dummy_value_d),
+ "=c" (dummy_value_c),
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "3" (srcptr), // esi // input regs
+ "4" (dstptr), // edi
+ "0" (diff), // eax
+// was (unmask) "b" RESERVED // ebx // Global Offset Table idx
+ "2" (len), // ecx
+ "1" (mask) // edx
+
+#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
+ : "%mm0", "%mm1", "%mm2", "%mm3" // clobber list
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ else /* mmx _not supported - Use modified C routine */
+#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
+ {
+ register png_uint_32 i;
+ png_uint_32 initial_val = BPP4 * png_pass_start[png_ptr->pass];
+ /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
+ register int stride = BPP4 * png_pass_inc[png_ptr->pass];
+ /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
+ register int rep_bytes = BPP4 * png_pass_width[png_ptr->pass];
+ /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
+ png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */
+ int diff = (int) (png_ptr->width & 7); /* amount lost */
+ register png_uint_32 final_val = BPP4 * len; /* GRR bugfix */
+
+ srcptr = png_ptr->row_buf + 1 + initial_val;
+ dstptr = row + initial_val;
+
+ for (i = initial_val; i < final_val; i += stride)
+ {
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ if (diff) /* number of leftover pixels: 3 for pngtest */
+ {
+ final_val+=diff*BPP4;
+ for (; i < final_val; i += stride)
+ {
+ if (rep_bytes > (int)(final_val-i))
+ rep_bytes = (int)(final_val-i);
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ }
+ } /* end of else (_mmx_supported) */
+
+ break;
+ } /* end 32 bpp */
+
+ case 48: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
+ /* && _mmx_supported */ )
+ {
+ png_uint_32 len;
+ int diff;
+ int dummy_value_a; // fix 'forbidden register spilled' error
+ int dummy_value_d;
+ int dummy_value_c;
+ int dummy_value_S;
+ int dummy_value_D;
+ _unmask = ~mask; // global variable for -fPIC version
+ srcptr = png_ptr->row_buf + 1;
+ dstptr = row;
+ len = png_ptr->width &~7; // reduce to multiple of 8
+ diff = (int) (png_ptr->width & 7); // amount lost //
+
+ __asm__ __volatile__ (
+ "movd _unmask, %%mm7 \n\t" // load bit pattern
+ "psubb %%mm6, %%mm6 \n\t" // zero mm6
+ "punpcklbw %%mm7, %%mm7 \n\t"
+ "punpcklwd %%mm7, %%mm7 \n\t"
+ "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks
+
+ "movq _mask48_0, %%mm0 \n\t"
+ "movq _mask48_1, %%mm1 \n\t"
+ "movq _mask48_2, %%mm2 \n\t"
+ "movq _mask48_3, %%mm3 \n\t"
+ "movq _mask48_4, %%mm4 \n\t"
+ "movq _mask48_5, %%mm5 \n\t"
+
+ "pand %%mm7, %%mm0 \n\t"
+ "pand %%mm7, %%mm1 \n\t"
+ "pand %%mm7, %%mm2 \n\t"
+ "pand %%mm7, %%mm3 \n\t"
+ "pand %%mm7, %%mm4 \n\t"
+ "pand %%mm7, %%mm5 \n\t"
+
+ "pcmpeqb %%mm6, %%mm0 \n\t"
+ "pcmpeqb %%mm6, %%mm1 \n\t"
+ "pcmpeqb %%mm6, %%mm2 \n\t"
+ "pcmpeqb %%mm6, %%mm3 \n\t"
+ "pcmpeqb %%mm6, %%mm4 \n\t"
+ "pcmpeqb %%mm6, %%mm5 \n\t"
+
+// preload "movl len, %%ecx \n\t" // load length of line
+// preload "movl srcptr, %%esi \n\t" // load source
+// preload "movl dstptr, %%edi \n\t" // load dest
+
+ "cmpl $0, %%ecx \n\t"
+ "jz mainloop48end \n\t"
+
+ "mainloop48: \n\t"
+ "movq (%%esi), %%mm7 \n\t"
+ "pand %%mm0, %%mm7 \n\t"
+ "movq %%mm0, %%mm6 \n\t"
+ "pandn (%%edi), %%mm6 \n\t"
+ "por %%mm6, %%mm7 \n\t"
+ "movq %%mm7, (%%edi) \n\t"
+
+ "movq 8(%%esi), %%mm6 \n\t"
+ "pand %%mm1, %%mm6 \n\t"
+ "movq %%mm1, %%mm7 \n\t"
+ "pandn 8(%%edi), %%mm7 \n\t"
+ "por %%mm7, %%mm6 \n\t"
+ "movq %%mm6, 8(%%edi) \n\t"
+
+ "movq 16(%%esi), %%mm6 \n\t"
+ "pand %%mm2, %%mm6 \n\t"
+ "movq %%mm2, %%mm7 \n\t"
+ "pandn 16(%%edi), %%mm7 \n\t"
+ "por %%mm7, %%mm6 \n\t"
+ "movq %%mm6, 16(%%edi) \n\t"
+
+ "movq 24(%%esi), %%mm7 \n\t"
+ "pand %%mm3, %%mm7 \n\t"
+ "movq %%mm3, %%mm6 \n\t"
+ "pandn 24(%%edi), %%mm6 \n\t"
+ "por %%mm6, %%mm7 \n\t"
+ "movq %%mm7, 24(%%edi) \n\t"
+
+ "movq 32(%%esi), %%mm6 \n\t"
+ "pand %%mm4, %%mm6 \n\t"
+ "movq %%mm4, %%mm7 \n\t"
+ "pandn 32(%%edi), %%mm7 \n\t"
+ "por %%mm7, %%mm6 \n\t"
+ "movq %%mm6, 32(%%edi) \n\t"
+
+ "movq 40(%%esi), %%mm7 \n\t"
+ "pand %%mm5, %%mm7 \n\t"
+ "movq %%mm5, %%mm6 \n\t"
+ "pandn 40(%%edi), %%mm6 \n\t"
+ "por %%mm6, %%mm7 \n\t"
+ "movq %%mm7, 40(%%edi) \n\t"
+
+ "addl $48, %%esi \n\t" // inc by 48 bytes processed
+ "addl $48, %%edi \n\t"
+ "subl $8, %%ecx \n\t" // dec by 8 pixels processed
+
+ "ja mainloop48 \n\t"
+
+ "mainloop48end: \n\t"
+// preload "movl diff, %%ecx \n\t" // (diff is in eax)
+ "movl %%eax, %%ecx \n\t"
+ "cmpl $0, %%ecx \n\t"
+ "jz end48 \n\t"
+// preload "movl mask, %%edx \n\t"
+ "sall $24, %%edx \n\t" // make low byte, high byte
+
+ "secondloop48: \n\t"
+ "sall %%edx \n\t" // move high bit to CF
+ "jnc skip48 \n\t" // if CF = 0
+ "movl (%%esi), %%eax \n\t"
+ "movl %%eax, (%%edi) \n\t"
+
+ "skip48: \n\t"
+ "addl $4, %%esi \n\t"
+ "addl $4, %%edi \n\t"
+ "decl %%ecx \n\t"
+ "jnz secondloop48 \n\t"
+
+ "end48: \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=a" (dummy_value_a), // output regs (dummy)
+ "=d" (dummy_value_d),
+ "=c" (dummy_value_c),
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "3" (srcptr), // esi // input regs
+ "4" (dstptr), // edi
+ "0" (diff), // eax
+// was (unmask) "b" RESERVED // ebx // Global Offset Table idx
+ "2" (len), // ecx
+ "1" (mask) // edx
+
+#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
+ : "%mm0", "%mm1", "%mm2", "%mm3" // clobber list
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ else /* mmx _not supported - Use modified C routine */
+#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
+ {
+ register png_uint_32 i;
+ png_uint_32 initial_val = BPP6 * png_pass_start[png_ptr->pass];
+ /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
+ register int stride = BPP6 * png_pass_inc[png_ptr->pass];
+ /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
+ register int rep_bytes = BPP6 * png_pass_width[png_ptr->pass];
+ /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
+ png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */
+ int diff = (int) (png_ptr->width & 7); /* amount lost */
+ register png_uint_32 final_val = BPP6 * len; /* GRR bugfix */
+
+ srcptr = png_ptr->row_buf + 1 + initial_val;
+ dstptr = row + initial_val;
+
+ for (i = initial_val; i < final_val; i += stride)
+ {
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ if (diff) /* number of leftover pixels: 3 for pngtest */
+ {
+ final_val+=diff*BPP6;
+ for (; i < final_val; i += stride)
+ {
+ if (rep_bytes > (int)(final_val-i))
+ rep_bytes = (int)(final_val-i);
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ }
+ } /* end of else (_mmx_supported) */
+
+ break;
+ } /* end 48 bpp */
+
+ case 64: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+ register png_uint_32 i;
+ png_uint_32 initial_val = BPP8 * png_pass_start[png_ptr->pass];
+ /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
+ register int stride = BPP8 * png_pass_inc[png_ptr->pass];
+ /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
+ register int rep_bytes = BPP8 * png_pass_width[png_ptr->pass];
+ /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
+ png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */
+ int diff = (int) (png_ptr->width & 7); /* amount lost */
+ register png_uint_32 final_val = BPP8 * len; /* GRR bugfix */
+
+ srcptr = png_ptr->row_buf + 1 + initial_val;
+ dstptr = row + initial_val;
+
+ for (i = initial_val; i < final_val; i += stride)
+ {
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ if (diff) /* number of leftover pixels: 3 for pngtest */
+ {
+ final_val+=diff*BPP8;
+ for (; i < final_val; i += stride)
+ {
+ if (rep_bytes > (int)(final_val-i))
+ rep_bytes = (int)(final_val-i);
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ }
+
+ break;
+ } /* end 64 bpp */
+
+ default: /* png_ptr->row_info.pixel_depth != 1,2,4,8,16,24,32,48,64 */
+ {
+ /* this should never happen */
+ png_warning(png_ptr, "Invalid row_info.pixel_depth in pnggccrd");
+ break;
+ }
+ } /* end switch (png_ptr->row_info.pixel_depth) */
+
+ } /* end if (non-trivial mask) */
+
+} /* end png_combine_row() */
+
+#endif /* PNG_HAVE_ASSEMBLER_COMBINE_ROW */
+
+
+
+
+/*===========================================================================*/
+/* */
+/* P N G _ D O _ R E A D _ I N T E R L A C E */
+/* */
+/*===========================================================================*/
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+#if defined(PNG_HAVE_ASSEMBLER_READ_INTERLACE)
+
+/* png_do_read_interlace() is called after any 16-bit to 8-bit conversion
+ * has taken place. [GRR: what other steps come before and/or after?]
+ */
+
+void /* PRIVATE */
+png_do_read_interlace(png_structp png_ptr)
+{
+ png_row_infop row_info = &(png_ptr->row_info);
+ png_bytep row = png_ptr->row_buf + 1;
+ int pass = png_ptr->pass;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ png_uint_32 transformations = png_ptr->transformations;
+#endif
+
+ png_debug(1, "in png_do_read_interlace (pnggccrd.c)\n");
+
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
+ if (_mmx_supported == 2) {
+ /* this should have happened in png_init_mmx_flags() already */
+ png_warning(png_ptr, "asm_flags may not have been initialized");
+ png_mmx_support();
+ }
+#endif
+
+ if (row != NULL && row_info != NULL)
+ {
+ png_uint_32 final_width;
+
+ final_width = row_info->width * png_pass_inc[pass];
+
+ switch (row_info->pixel_depth)
+ {
+ case 1:
+ {
+ png_bytep sp, dp;
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ png_byte v;
+ png_uint_32 i;
+ int j;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 3);
+ dp = row + (png_size_t)((final_width - 1) >> 3);
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (int)((row_info->width + 7) & 7);
+ dshift = (int)((final_width + 7) & 7);
+ s_start = 7;
+ s_end = 0;
+ s_inc = -1;
+ }
+ else
+#endif
+ {
+ sshift = 7 - (int)((row_info->width + 7) & 7);
+ dshift = 7 - (int)((final_width + 7) & 7);
+ s_start = 0;
+ s_end = 7;
+ s_inc = 1;
+ }
+
+ for (i = row_info->width; i; i--)
+ {
+ v = (png_byte)((*sp >> sshift) & 0x1);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+
+ case 2:
+ {
+ png_bytep sp, dp;
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 2);
+ dp = row + (png_size_t)((final_width - 1) >> 2);
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (png_size_t)(((row_info->width + 3) & 3) << 1);
+ dshift = (png_size_t)(((final_width + 3) & 3) << 1);
+ s_start = 6;
+ s_end = 0;
+ s_inc = -2;
+ }
+ else
+#endif
+ {
+ sshift = (png_size_t)((3 - ((row_info->width + 3) & 3)) << 1);
+ dshift = (png_size_t)((3 - ((final_width + 3) & 3)) << 1);
+ s_start = 0;
+ s_end = 6;
+ s_inc = 2;
+ }
+
+ for (i = row_info->width; i; i--)
+ {
+ png_byte v;
+ int j;
+
+ v = (png_byte)((*sp >> sshift) & 0x3);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+
+ case 4:
+ {
+ png_bytep sp, dp;
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 1);
+ dp = row + (png_size_t)((final_width - 1) >> 1);
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (png_size_t)(((row_info->width + 1) & 1) << 2);
+ dshift = (png_size_t)(((final_width + 1) & 1) << 2);
+ s_start = 4;
+ s_end = 0;
+ s_inc = -4;
+ }
+ else
+#endif
+ {
+ sshift = (png_size_t)((1 - ((row_info->width + 1) & 1)) << 2);
+ dshift = (png_size_t)((1 - ((final_width + 1) & 1)) << 2);
+ s_start = 0;
+ s_end = 4;
+ s_inc = 4;
+ }
+
+ for (i = row_info->width; i; i--)
+ {
+ png_byte v;
+ int j;
+
+ v = (png_byte)((*sp >> sshift) & 0xf);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+
+ /*====================================================================*/
+
+ default: /* 8-bit or larger (this is where the routine is modified) */
+ {
+#if 0
+// static unsigned long long _const4 = 0x0000000000FFFFFFLL; no good
+// static unsigned long long const4 = 0x0000000000FFFFFFLL; no good
+// unsigned long long _const4 = 0x0000000000FFFFFFLL; no good
+// unsigned long long const4 = 0x0000000000FFFFFFLL; no good
+#endif
+ png_bytep sptr, dp;
+ png_uint_32 i;
+ png_size_t pixel_bytes;
+ int width = (int)row_info->width;
+
+ pixel_bytes = (row_info->pixel_depth >> 3);
+
+ /* point sptr at the last pixel in the pre-expanded row: */
+ sptr = row + (width - 1) * pixel_bytes;
+
+ /* point dp at the last pixel position in the expanded row: */
+ dp = row + (final_width - 1) * pixel_bytes;
+
+ /* New code by Nirav Chhatrapati - Intel Corporation */
+
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_INTERLACE)
+ /* && _mmx_supported */ )
+ {
+ //--------------------------------------------------------------
+ if (pixel_bytes == 3)
+ {
+ if (((pass == 0) || (pass == 1)) && width)
+ {
+ int dummy_value_c; // fix 'forbidden register spilled'
+ int dummy_value_S;
+ int dummy_value_D;
+
+ __asm__ __volatile__ (
+ "subl $21, %%edi \n\t"
+ // (png_pass_inc[pass] - 1)*pixel_bytes
+
+ ".loop3_pass0: \n\t"
+ "movd (%%esi), %%mm0 \n\t" // x x x x x 2 1 0
+ "pand _const4, %%mm0 \n\t" // z z z z z 2 1 0
+ "movq %%mm0, %%mm1 \n\t" // z z z z z 2 1 0
+ "psllq $16, %%mm0 \n\t" // z z z 2 1 0 z z
+ "movq %%mm0, %%mm2 \n\t" // z z z 2 1 0 z z
+ "psllq $24, %%mm0 \n\t" // 2 1 0 z z z z z
+ "psrlq $8, %%mm1 \n\t" // z z z z z z 2 1
+ "por %%mm2, %%mm0 \n\t" // 2 1 0 2 1 0 z z
+ "por %%mm1, %%mm0 \n\t" // 2 1 0 2 1 0 2 1
+ "movq %%mm0, %%mm3 \n\t" // 2 1 0 2 1 0 2 1
+ "psllq $16, %%mm0 \n\t" // 0 2 1 0 2 1 z z
+ "movq %%mm3, %%mm4 \n\t" // 2 1 0 2 1 0 2 1
+ "punpckhdq %%mm0, %%mm3 \n\t" // 0 2 1 0 2 1 0 2
+ "movq %%mm4, 16(%%edi) \n\t"
+ "psrlq $32, %%mm0 \n\t" // z z z z 0 2 1 0
+ "movq %%mm3, 8(%%edi) \n\t"
+ "punpckldq %%mm4, %%mm0 \n\t" // 1 0 2 1 0 2 1 0
+ "subl $3, %%esi \n\t"
+ "movq %%mm0, (%%edi) \n\t"
+ "subl $24, %%edi \n\t"
+ "decl %%ecx \n\t"
+ "jnz .loop3_pass0 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "1" (sptr), // esi // input regs
+ "2" (dp), // edi
+ "0" (width) // ecx
+// doesn't work "i" (0x0000000000FFFFFFLL) // %1 (a.k.a. _const4)
+
+#if 0 /* %mm0, ..., %mm4 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ : "%mm0", "%mm1", "%mm2" // clobber list
+ , "%mm3", "%mm4"
+#endif
+ );
+ }
+ else if (((pass == 2) || (pass == 3)) && width)
+ {
+ int dummy_value_c; // fix 'forbidden register spilled'
+ int dummy_value_S;
+ int dummy_value_D;
+
+ __asm__ __volatile__ (
+ "subl $9, %%edi \n\t"
+ // (png_pass_inc[pass] - 1)*pixel_bytes
+
+ ".loop3_pass2: \n\t"
+ "movd (%%esi), %%mm0 \n\t" // x x x x x 2 1 0
+ "pand _const4, %%mm0 \n\t" // z z z z z 2 1 0
+ "movq %%mm0, %%mm1 \n\t" // z z z z z 2 1 0
+ "psllq $16, %%mm0 \n\t" // z z z 2 1 0 z z
+ "movq %%mm0, %%mm2 \n\t" // z z z 2 1 0 z z
+ "psllq $24, %%mm0 \n\t" // 2 1 0 z z z z z
+ "psrlq $8, %%mm1 \n\t" // z z z z z z 2 1
+ "por %%mm2, %%mm0 \n\t" // 2 1 0 2 1 0 z z
+ "por %%mm1, %%mm0 \n\t" // 2 1 0 2 1 0 2 1
+ "movq %%mm0, 4(%%edi) \n\t"
+ "psrlq $16, %%mm0 \n\t" // z z 2 1 0 2 1 0
+ "subl $3, %%esi \n\t"
+ "movd %%mm0, (%%edi) \n\t"
+ "subl $12, %%edi \n\t"
+ "decl %%ecx \n\t"
+ "jnz .loop3_pass2 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "1" (sptr), // esi // input regs
+ "2" (dp), // edi
+ "0" (width) // ecx
+
+#if 0 /* %mm0, ..., %mm2 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ : "%mm0", "%mm1", "%mm2" // clobber list
+#endif
+ );
+ }
+ else if (width) /* && ((pass == 4) || (pass == 5)) */
+ {
+ int width_mmx = ((width >> 1) << 1) - 8; // GRR: huh?
+ if (width_mmx < 0)
+ width_mmx = 0;
+ width -= width_mmx; // 8 or 9 pix, 24 or 27 bytes
+ if (width_mmx)
+ {
+ // png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
+ // sptr points at last pixel in pre-expanded row
+ // dp points at last pixel position in expanded row
+ int dummy_value_c; // fix 'forbidden register spilled'
+ int dummy_value_S;
+ int dummy_value_D;
+
+ __asm__ __volatile__ (
+ "subl $3, %%esi \n\t"
+ "subl $9, %%edi \n\t"
+ // (png_pass_inc[pass] + 1)*pixel_bytes
+
+ ".loop3_pass4: \n\t"
+ "movq (%%esi), %%mm0 \n\t" // x x 5 4 3 2 1 0
+ "movq %%mm0, %%mm1 \n\t" // x x 5 4 3 2 1 0
+ "movq %%mm0, %%mm2 \n\t" // x x 5 4 3 2 1 0
+ "psllq $24, %%mm0 \n\t" // 4 3 2 1 0 z z z
+ "pand _const4, %%mm1 \n\t" // z z z z z 2 1 0
+ "psrlq $24, %%mm2 \n\t" // z z z x x 5 4 3
+ "por %%mm1, %%mm0 \n\t" // 4 3 2 1 0 2 1 0
+ "movq %%mm2, %%mm3 \n\t" // z z z x x 5 4 3
+ "psllq $8, %%mm2 \n\t" // z z x x 5 4 3 z
+ "movq %%mm0, (%%edi) \n\t"
+ "psrlq $16, %%mm3 \n\t" // z z z z z x x 5
+ "pand _const6, %%mm3 \n\t" // z z z z z z z 5
+ "por %%mm3, %%mm2 \n\t" // z z x x 5 4 3 5
+ "subl $6, %%esi \n\t"
+ "movd %%mm2, 8(%%edi) \n\t"
+ "subl $12, %%edi \n\t"
+ "subl $2, %%ecx \n\t"
+ "jnz .loop3_pass4 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "1" (sptr), // esi // input regs
+ "2" (dp), // edi
+ "0" (width_mmx) // ecx
+
+#if 0 /* %mm0, ..., %mm3 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ : "%mm0", "%mm1" // clobber list
+ , "%mm2", "%mm3"
+#endif
+ );
+ }
+
+ sptr -= width_mmx*3;
+ dp -= width_mmx*6;
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+
+ png_memcpy(v, sptr, 3);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, 3);
+ dp -= 3;
+ }
+ sptr -= 3;
+ }
+ }
+ } /* end of pixel_bytes == 3 */
+
+ //--------------------------------------------------------------
+ else if (pixel_bytes == 1)
+ {
+ if (((pass == 0) || (pass == 1)) && width)
+ {
+ int width_mmx = ((width >> 2) << 2);
+ width -= width_mmx; // 0-3 pixels => 0-3 bytes
+ if (width_mmx)
+ {
+ int dummy_value_c; // fix 'forbidden register spilled'
+ int dummy_value_S;
+ int dummy_value_D;
+
+ __asm__ __volatile__ (
+ "subl $3, %%esi \n\t"
+ "subl $31, %%edi \n\t"
+
+ ".loop1_pass0: \n\t"
+ "movd (%%esi), %%mm0 \n\t" // x x x x 3 2 1 0
+ "movq %%mm0, %%mm1 \n\t" // x x x x 3 2 1 0
+ "punpcklbw %%mm0, %%mm0 \n\t" // 3 3 2 2 1 1 0 0
+ "movq %%mm0, %%mm2 \n\t" // 3 3 2 2 1 1 0 0
+ "punpcklwd %%mm0, %%mm0 \n\t" // 1 1 1 1 0 0 0 0
+ "movq %%mm0, %%mm3 \n\t" // 1 1 1 1 0 0 0 0
+ "punpckldq %%mm0, %%mm0 \n\t" // 0 0 0 0 0 0 0 0
+ "punpckhdq %%mm3, %%mm3 \n\t" // 1 1 1 1 1 1 1 1
+ "movq %%mm0, (%%edi) \n\t"
+ "punpckhwd %%mm2, %%mm2 \n\t" // 3 3 3 3 2 2 2 2
+ "movq %%mm3, 8(%%edi) \n\t"
+ "movq %%mm2, %%mm4 \n\t" // 3 3 3 3 2 2 2 2
+ "punpckldq %%mm2, %%mm2 \n\t" // 2 2 2 2 2 2 2 2
+ "punpckhdq %%mm4, %%mm4 \n\t" // 3 3 3 3 3 3 3 3
+ "movq %%mm2, 16(%%edi) \n\t"
+ "subl $4, %%esi \n\t"
+ "movq %%mm4, 24(%%edi) \n\t"
+ "subl $32, %%edi \n\t"
+ "subl $4, %%ecx \n\t"
+ "jnz .loop1_pass0 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "1" (sptr), // esi // input regs
+ "2" (dp), // edi
+ "0" (width_mmx) // ecx
+
+#if 0 /* %mm0, ..., %mm4 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ : "%mm0", "%mm1", "%mm2" // clobber list
+ , "%mm3", "%mm4"
+#endif
+ );
+ }
+
+ sptr -= width_mmx;
+ dp -= width_mmx*8;
+ for (i = width; i; i--)
+ {
+ int j;
+
+ /* I simplified this part in version 1.0.4e
+ * here and in several other instances where
+ * pixel_bytes == 1 -- GR-P
+ *
+ * Original code:
+ *
+ * png_byte v[8];
+ * png_memcpy(v, sptr, pixel_bytes);
+ * for (j = 0; j < png_pass_inc[pass]; j++)
+ * {
+ * png_memcpy(dp, v, pixel_bytes);
+ * dp -= pixel_bytes;
+ * }
+ * sptr -= pixel_bytes;
+ *
+ * Replacement code is in the next three lines:
+ */
+
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp-- = *sptr;
+ }
+ --sptr;
+ }
+ }
+ else if (((pass == 2) || (pass == 3)) && width)
+ {
+ int width_mmx = ((width >> 2) << 2);
+ width -= width_mmx; // 0-3 pixels => 0-3 bytes
+ if (width_mmx)
+ {
+ int dummy_value_c; // fix 'forbidden register spilled'
+ int dummy_value_S;
+ int dummy_value_D;
+
+ __asm__ __volatile__ (
+ "subl $3, %%esi \n\t"
+ "subl $15, %%edi \n\t"
+
+ ".loop1_pass2: \n\t"
+ "movd (%%esi), %%mm0 \n\t" // x x x x 3 2 1 0
+ "punpcklbw %%mm0, %%mm0 \n\t" // 3 3 2 2 1 1 0 0
+ "movq %%mm0, %%mm1 \n\t" // 3 3 2 2 1 1 0 0
+ "punpcklwd %%mm0, %%mm0 \n\t" // 1 1 1 1 0 0 0 0
+ "punpckhwd %%mm1, %%mm1 \n\t" // 3 3 3 3 2 2 2 2
+ "movq %%mm0, (%%edi) \n\t"
+ "subl $4, %%esi \n\t"
+ "movq %%mm1, 8(%%edi) \n\t"
+ "subl $16, %%edi \n\t"
+ "subl $4, %%ecx \n\t"
+ "jnz .loop1_pass2 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "1" (sptr), // esi // input regs
+ "2" (dp), // edi
+ "0" (width_mmx) // ecx
+
+#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ : "%mm0", "%mm1" // clobber list
+#endif
+ );
+ }
+
+ sptr -= width_mmx;
+ dp -= width_mmx*4;
+ for (i = width; i; i--)
+ {
+ int j;
+
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp-- = *sptr;
+ }
+ --sptr;
+ }
+ }
+ else if (width) /* && ((pass == 4) || (pass == 5)) */
+ {
+ int width_mmx = ((width >> 3) << 3);
+ width -= width_mmx; // 0-3 pixels => 0-3 bytes
+ if (width_mmx)
+ {
+ int dummy_value_c; // fix 'forbidden register spilled'
+ int dummy_value_S;
+ int dummy_value_D;
+
+ __asm__ __volatile__ (
+ "subl $7, %%esi \n\t"
+ "subl $15, %%edi \n\t"
+
+ ".loop1_pass4: \n\t"
+ "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0
+ "movq %%mm0, %%mm1 \n\t" // 7 6 5 4 3 2 1 0
+ "punpcklbw %%mm0, %%mm0 \n\t" // 3 3 2 2 1 1 0 0
+ "punpckhbw %%mm1, %%mm1 \n\t" // 7 7 6 6 5 5 4 4
+ "movq %%mm1, 8(%%edi) \n\t"
+ "subl $8, %%esi \n\t"
+ "movq %%mm0, (%%edi) \n\t"
+ "subl $16, %%edi \n\t"
+ "subl $8, %%ecx \n\t"
+ "jnz .loop1_pass4 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (none)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "1" (sptr), // esi // input regs
+ "2" (dp), // edi
+ "0" (width_mmx) // ecx
+
+#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ : "%mm0", "%mm1" // clobber list
+#endif
+ );
+ }
+
+ sptr -= width_mmx;
+ dp -= width_mmx*2;
+ for (i = width; i; i--)
+ {
+ int j;
+
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp-- = *sptr;
+ }
+ --sptr;
+ }
+ }
+ } /* end of pixel_bytes == 1 */
+
+ //--------------------------------------------------------------
+ else if (pixel_bytes == 2)
+ {
+ if (((pass == 0) || (pass == 1)) && width)
+ {
+ int width_mmx = ((width >> 1) << 1);
+ width -= width_mmx; // 0,1 pixels => 0,2 bytes
+ if (width_mmx)
+ {
+ int dummy_value_c; // fix 'forbidden register spilled'
+ int dummy_value_S;
+ int dummy_value_D;
+
+ __asm__ __volatile__ (
+ "subl $2, %%esi \n\t"
+ "subl $30, %%edi \n\t"
+
+ ".loop2_pass0: \n\t"
+ "movd (%%esi), %%mm0 \n\t" // x x x x 3 2 1 0
+ "punpcklwd %%mm0, %%mm0 \n\t" // 3 2 3 2 1 0 1 0
+ "movq %%mm0, %%mm1 \n\t" // 3 2 3 2 1 0 1 0
+ "punpckldq %%mm0, %%mm0 \n\t" // 1 0 1 0 1 0 1 0
+ "punpckhdq %%mm1, %%mm1 \n\t" // 3 2 3 2 3 2 3 2
+ "movq %%mm0, (%%edi) \n\t"
+ "movq %%mm0, 8(%%edi) \n\t"
+ "movq %%mm1, 16(%%edi) \n\t"
+ "subl $4, %%esi \n\t"
+ "movq %%mm1, 24(%%edi) \n\t"
+ "subl $32, %%edi \n\t"
+ "subl $2, %%ecx \n\t"
+ "jnz .loop2_pass0 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "1" (sptr), // esi // input regs
+ "2" (dp), // edi
+ "0" (width_mmx) // ecx
+
+#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ : "%mm0", "%mm1" // clobber list
+#endif
+ );
+ }
+
+ sptr -= (width_mmx*2 - 2); // sign fixed
+ dp -= (width_mmx*16 - 2); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 2;
+ png_memcpy(v, sptr, 2);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 2;
+ png_memcpy(dp, v, 2);
+ }
+ }
+ }
+ else if (((pass == 2) || (pass == 3)) && width)
+ {
+ int width_mmx = ((width >> 1) << 1) ;
+ width -= width_mmx; // 0,1 pixels => 0,2 bytes
+ if (width_mmx)
+ {
+ int dummy_value_c; // fix 'forbidden register spilled'
+ int dummy_value_S;
+ int dummy_value_D;
+
+ __asm__ __volatile__ (
+ "subl $2, %%esi \n\t"
+ "subl $14, %%edi \n\t"
+
+ ".loop2_pass2: \n\t"
+ "movd (%%esi), %%mm0 \n\t" // x x x x 3 2 1 0
+ "punpcklwd %%mm0, %%mm0 \n\t" // 3 2 3 2 1 0 1 0
+ "movq %%mm0, %%mm1 \n\t" // 3 2 3 2 1 0 1 0
+ "punpckldq %%mm0, %%mm0 \n\t" // 1 0 1 0 1 0 1 0
+ "punpckhdq %%mm1, %%mm1 \n\t" // 3 2 3 2 3 2 3 2
+ "movq %%mm0, (%%edi) \n\t"
+ "subl $4, %%esi \n\t"
+ "movq %%mm1, 8(%%edi) \n\t"
+ "subl $16, %%edi \n\t"
+ "subl $2, %%ecx \n\t"
+ "jnz .loop2_pass2 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "1" (sptr), // esi // input regs
+ "2" (dp), // edi
+ "0" (width_mmx) // ecx
+
+#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ : "%mm0", "%mm1" // clobber list
+#endif
+ );
+ }
+
+ sptr -= (width_mmx*2 - 2); // sign fixed
+ dp -= (width_mmx*8 - 2); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 2;
+ png_memcpy(v, sptr, 2);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 2;
+ png_memcpy(dp, v, 2);
+ }
+ }
+ }
+ else if (width) // pass == 4 or 5
+ {
+ int width_mmx = ((width >> 1) << 1) ;
+ width -= width_mmx; // 0,1 pixels => 0,2 bytes
+ if (width_mmx)
+ {
+ int dummy_value_c; // fix 'forbidden register spilled'
+ int dummy_value_S;
+ int dummy_value_D;
+
+ __asm__ __volatile__ (
+ "subl $2, %%esi \n\t"
+ "subl $6, %%edi \n\t"
+
+ ".loop2_pass4: \n\t"
+ "movd (%%esi), %%mm0 \n\t" // x x x x 3 2 1 0
+ "punpcklwd %%mm0, %%mm0 \n\t" // 3 2 3 2 1 0 1 0
+ "subl $4, %%esi \n\t"
+ "movq %%mm0, (%%edi) \n\t"
+ "subl $8, %%edi \n\t"
+ "subl $2, %%ecx \n\t"
+ "jnz .loop2_pass4 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "1" (sptr), // esi // input regs
+ "2" (dp), // edi
+ "0" (width_mmx) // ecx
+
+#if 0 /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ : "%mm0" // clobber list
+#endif
+ );
+ }
+
+ sptr -= (width_mmx*2 - 2); // sign fixed
+ dp -= (width_mmx*4 - 2); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 2;
+ png_memcpy(v, sptr, 2);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 2;
+ png_memcpy(dp, v, 2);
+ }
+ }
+ }
+ } /* end of pixel_bytes == 2 */
+
+ //--------------------------------------------------------------
+ else if (pixel_bytes == 4)
+ {
+ if (((pass == 0) || (pass == 1)) && width)
+ {
+ int width_mmx = ((width >> 1) << 1);
+ width -= width_mmx; // 0,1 pixels => 0,4 bytes
+ if (width_mmx)
+ {
+ int dummy_value_c; // fix 'forbidden register spilled'
+ int dummy_value_S;
+ int dummy_value_D;
+
+ __asm__ __volatile__ (
+ "subl $4, %%esi \n\t"
+ "subl $60, %%edi \n\t"
+
+ ".loop4_pass0: \n\t"
+ "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0
+ "movq %%mm0, %%mm1 \n\t" // 7 6 5 4 3 2 1 0
+ "punpckldq %%mm0, %%mm0 \n\t" // 3 2 1 0 3 2 1 0
+ "punpckhdq %%mm1, %%mm1 \n\t" // 7 6 5 4 7 6 5 4
+ "movq %%mm0, (%%edi) \n\t"
+ "movq %%mm0, 8(%%edi) \n\t"
+ "movq %%mm0, 16(%%edi) \n\t"
+ "movq %%mm0, 24(%%edi) \n\t"
+ "movq %%mm1, 32(%%edi) \n\t"
+ "movq %%mm1, 40(%%edi) \n\t"
+ "movq %%mm1, 48(%%edi) \n\t"
+ "subl $8, %%esi \n\t"
+ "movq %%mm1, 56(%%edi) \n\t"
+ "subl $64, %%edi \n\t"
+ "subl $2, %%ecx \n\t"
+ "jnz .loop4_pass0 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "1" (sptr), // esi // input regs
+ "2" (dp), // edi
+ "0" (width_mmx) // ecx
+
+#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ : "%mm0", "%mm1" // clobber list
+#endif
+ );
+ }
+
+ sptr -= (width_mmx*4 - 4); // sign fixed
+ dp -= (width_mmx*32 - 4); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 4;
+ png_memcpy(v, sptr, 4);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 4;
+ png_memcpy(dp, v, 4);
+ }
+ }
+ }
+ else if (((pass == 2) || (pass == 3)) && width)
+ {
+ int width_mmx = ((width >> 1) << 1);
+ width -= width_mmx; // 0,1 pixels => 0,4 bytes
+ if (width_mmx)
+ {
+ int dummy_value_c; // fix 'forbidden register spilled'
+ int dummy_value_S;
+ int dummy_value_D;
+
+ __asm__ __volatile__ (
+ "subl $4, %%esi \n\t"
+ "subl $28, %%edi \n\t"
+
+ ".loop4_pass2: \n\t"
+ "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0
+ "movq %%mm0, %%mm1 \n\t" // 7 6 5 4 3 2 1 0
+ "punpckldq %%mm0, %%mm0 \n\t" // 3 2 1 0 3 2 1 0
+ "punpckhdq %%mm1, %%mm1 \n\t" // 7 6 5 4 7 6 5 4
+ "movq %%mm0, (%%edi) \n\t"
+ "movq %%mm0, 8(%%edi) \n\t"
+ "movq %%mm1, 16(%%edi) \n\t"
+ "movq %%mm1, 24(%%edi) \n\t"
+ "subl $8, %%esi \n\t"
+ "subl $32, %%edi \n\t"
+ "subl $2, %%ecx \n\t"
+ "jnz .loop4_pass2 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "1" (sptr), // esi // input regs
+ "2" (dp), // edi
+ "0" (width_mmx) // ecx
+
+#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ : "%mm0", "%mm1" // clobber list
+#endif
+ );
+ }
+
+ sptr -= (width_mmx*4 - 4); // sign fixed
+ dp -= (width_mmx*16 - 4); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 4;
+ png_memcpy(v, sptr, 4);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 4;
+ png_memcpy(dp, v, 4);
+ }
+ }
+ }
+ else if (width) // pass == 4 or 5
+ {
+ int width_mmx = ((width >> 1) << 1) ;
+ width -= width_mmx; // 0,1 pixels => 0,4 bytes
+ if (width_mmx)
+ {
+ int dummy_value_c; // fix 'forbidden register spilled'
+ int dummy_value_S;
+ int dummy_value_D;
+
+ __asm__ __volatile__ (
+ "subl $4, %%esi \n\t"
+ "subl $12, %%edi \n\t"
+
+ ".loop4_pass4: \n\t"
+ "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0
+ "movq %%mm0, %%mm1 \n\t" // 7 6 5 4 3 2 1 0
+ "punpckldq %%mm0, %%mm0 \n\t" // 3 2 1 0 3 2 1 0
+ "punpckhdq %%mm1, %%mm1 \n\t" // 7 6 5 4 7 6 5 4
+ "movq %%mm0, (%%edi) \n\t"
+ "subl $8, %%esi \n\t"
+ "movq %%mm1, 8(%%edi) \n\t"
+ "subl $16, %%edi \n\t"
+ "subl $2, %%ecx \n\t"
+ "jnz .loop4_pass4 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "1" (sptr), // esi // input regs
+ "2" (dp), // edi
+ "0" (width_mmx) // ecx
+
+#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ : "%mm0", "%mm1" // clobber list
+#endif
+ );
+ }
+
+ sptr -= (width_mmx*4 - 4); // sign fixed
+ dp -= (width_mmx*8 - 4); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 4;
+ png_memcpy(v, sptr, 4);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 4;
+ png_memcpy(dp, v, 4);
+ }
+ }
+ }
+ } /* end of pixel_bytes == 4 */
+
+ //--------------------------------------------------------------
+ else if (pixel_bytes == 8)
+ {
+// GRR TEST: should work, but needs testing (special 64-bit version of rpng2?)
+ // GRR NOTE: no need to combine passes here!
+ if (((pass == 0) || (pass == 1)) && width)
+ {
+ int dummy_value_c; // fix 'forbidden register spilled'
+ int dummy_value_S;
+ int dummy_value_D;
+
+ // source is 8-byte RRGGBBAA
+ // dest is 64-byte RRGGBBAA RRGGBBAA RRGGBBAA RRGGBBAA ...
+ __asm__ __volatile__ (
+ "subl $56, %%edi \n\t" // start of last block
+
+ ".loop8_pass0: \n\t"
+ "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0
+ "movq %%mm0, (%%edi) \n\t"
+ "movq %%mm0, 8(%%edi) \n\t"
+ "movq %%mm0, 16(%%edi) \n\t"
+ "movq %%mm0, 24(%%edi) \n\t"
+ "movq %%mm0, 32(%%edi) \n\t"
+ "movq %%mm0, 40(%%edi) \n\t"
+ "movq %%mm0, 48(%%edi) \n\t"
+ "subl $8, %%esi \n\t"
+ "movq %%mm0, 56(%%edi) \n\t"
+ "subl $64, %%edi \n\t"
+ "decl %%ecx \n\t"
+ "jnz .loop8_pass0 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "1" (sptr), // esi // input regs
+ "2" (dp), // edi
+ "0" (width) // ecx
+
+#if 0 /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ : "%mm0" // clobber list
+#endif
+ );
+ }
+ else if (((pass == 2) || (pass == 3)) && width)
+ {
+ // source is 8-byte RRGGBBAA
+ // dest is 32-byte RRGGBBAA RRGGBBAA RRGGBBAA RRGGBBAA
+ int width_mmx = ((width >> 1) << 1) ;
+ width -= width_mmx;
+ if (width_mmx)
+ {
+ int dummy_value_c; // fix 'forbidden register spilled'
+ int dummy_value_S;
+ int dummy_value_D;
+
+ __asm__ __volatile__ (
+ "subl $24, %%edi \n\t" // start of last block
+
+ ".loop8_pass2: \n\t"
+ "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0
+ "movq %%mm0, (%%edi) \n\t"
+ "movq %%mm0, 8(%%edi) \n\t"
+ "movq %%mm0, 16(%%edi) \n\t"
+ "subl $8, %%esi \n\t"
+ "movq %%mm0, 24(%%edi) \n\t"
+ "subl $32, %%edi \n\t"
+ "decl %%ecx \n\t"
+ "jnz .loop8_pass2 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "1" (sptr), // esi // input regs
+ "2" (dp), // edi
+ "0" (width) // ecx
+
+#if 0 /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ : "%mm0" // clobber list
+#endif
+ );
+ }
+ }
+ else if (width) // pass == 4 or 5
+ {
+ // source is 8-byte RRGGBBAA
+ // dest is 16-byte RRGGBBAA RRGGBBAA
+ int width_mmx = ((width >> 1) << 1) ;
+ width -= width_mmx;
+ if (width_mmx)
+ {
+ int dummy_value_c; // fix 'forbidden register spilled'
+ int dummy_value_S;
+ int dummy_value_D;
+
+ __asm__ __volatile__ (
+ "subl $8, %%edi \n\t" // start of last block
+
+ ".loop8_pass4: \n\t"
+ "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0
+ "movq %%mm0, (%%edi) \n\t"
+ "subl $8, %%esi \n\t"
+ "movq %%mm0, 8(%%edi) \n\t"
+ "subl $16, %%edi \n\t"
+ "decl %%ecx \n\t"
+ "jnz .loop8_pass4 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "1" (sptr), // esi // input regs
+ "2" (dp), // edi
+ "0" (width) // ecx
+
+#if 0 /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ : "%mm0" // clobber list
+#endif
+ );
+ }
+ }
+
+ } /* end of pixel_bytes == 8 */
+
+ //--------------------------------------------------------------
+ else if (pixel_bytes == 6)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, 6);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, 6);
+ dp -= 6;
+ }
+ sptr -= 6;
+ }
+ } /* end of pixel_bytes == 6 */
+
+ //--------------------------------------------------------------
+ else
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, pixel_bytes);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, pixel_bytes);
+ dp -= pixel_bytes;
+ }
+ sptr-= pixel_bytes;
+ }
+ }
+ } // end of _mmx_supported ========================================
+
+ else /* MMX not supported: use modified C code - takes advantage
+ * of inlining of png_memcpy for a constant */
+ /* GRR 19991007: does it? or should pixel_bytes in each
+ * block be replaced with immediate value (e.g., 1)? */
+ /* GRR 19991017: replaced with constants in each case */
+#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
+ {
+ if (pixel_bytes == 1)
+ {
+ for (i = width; i; i--)
+ {
+ int j;
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp-- = *sptr;
+ }
+ --sptr;
+ }
+ }
+ else if (pixel_bytes == 3)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, 3);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, 3);
+ dp -= 3;
+ }
+ sptr -= 3;
+ }
+ }
+ else if (pixel_bytes == 2)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, 2);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, 2);
+ dp -= 2;
+ }
+ sptr -= 2;
+ }
+ }
+ else if (pixel_bytes == 4)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, 4);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+#ifdef PNG_DEBUG
+ if (dp < row || dp+3 > row+png_ptr->row_buf_size)
+ {
+ printf("dp out of bounds: row=%d, dp=%d, rp=%d\n",
+ row, dp, row+png_ptr->row_buf_size);
+ printf("row_buf=%d\n",png_ptr->row_buf_size);
+ }
+#endif
+ png_memcpy(dp, v, 4);
+ dp -= 4;
+ }
+ sptr -= 4;
+ }
+ }
+ else if (pixel_bytes == 6)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, 6);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, 6);
+ dp -= 6;
+ }
+ sptr -= 6;
+ }
+ }
+ else if (pixel_bytes == 8)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, 8);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, 8);
+ dp -= 8;
+ }
+ sptr -= 8;
+ }
+ }
+ else /* GRR: should never be reached */
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, pixel_bytes);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, pixel_bytes);
+ dp -= pixel_bytes;
+ }
+ sptr -= pixel_bytes;
+ }
+ }
+
+ } /* end if (MMX not supported) */
+ break;
+ }
+ } /* end switch (row_info->pixel_depth) */
+
+ row_info->width = final_width;
+ row_info->rowbytes = ((final_width *
+ (png_uint_32)row_info->pixel_depth + 7) >> 3);
+ }
+
+} /* end png_do_read_interlace() */
+
+#endif /* PNG_HAVE_ASSEMBLER_READ_INTERLACE */
+#endif /* PNG_READ_INTERLACING_SUPPORTED */
+
+
+
+#if defined(PNG_HAVE_ASSEMBLER_READ_FILTER_ROW)
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
+
+// These variables are utilized in the functions below. They are declared
+// globally here to ensure alignment on 8-byte boundaries.
+
+union uAll {
+ long long use;
+ double align;
+} _LBCarryMask = {0x0101010101010101LL},
+ _HBClearMask = {0x7f7f7f7f7f7f7f7fLL},
+ _ActiveMask, _ActiveMask2, _ActiveMaskEnd, _ShiftBpp, _ShiftRem;
+
+#ifdef PNG_THREAD_UNSAFE_OK
+//===========================================================================//
+// //
+// P N G _ R E A D _ F I L T E R _ R O W _ M M X _ A V G //
+// //
+//===========================================================================//
+
+// Optimized code for PNG Average filter decoder
+
+static void /* PRIVATE */
+png_read_filter_row_mmx_avg(png_row_infop row_info, png_bytep row,
+ png_bytep prev_row)
+{
+ int bpp;
+ int dummy_value_c; // fix 'forbidden register 2 (cx) was spilled' error
+ int dummy_value_S;
+ int dummy_value_D;
+
+ bpp = (row_info->pixel_depth + 7) >> 3; // get # bytes per pixel
+ _FullLength = row_info->rowbytes; // # of bytes to filter
+
+ __asm__ __volatile__ (
+ // initialize address pointers and offset
+#ifdef __PIC__
+ "pushl %%ebx \n\t" // save index to Global Offset Table
+#endif
+//pre "movl row, %%edi \n\t" // edi: Avg(x)
+ "xorl %%ebx, %%ebx \n\t" // ebx: x
+ "movl %%edi, %%edx \n\t"
+//pre "movl prev_row, %%esi \n\t" // esi: Prior(x)
+//pre "subl bpp, %%edx \n\t" // (bpp is preloaded into ecx)
+ "subl %%ecx, %%edx \n\t" // edx: Raw(x-bpp)
+
+ "xorl %%eax,%%eax \n\t"
+
+ // Compute the Raw value for the first bpp bytes
+ // Raw(x) = Avg(x) + (Prior(x)/2)
+ "avg_rlp: \n\t"
+ "movb (%%esi,%%ebx,),%%al \n\t" // load al with Prior(x)
+ "incl %%ebx \n\t"
+ "shrb %%al \n\t" // divide by 2
+ "addb -1(%%edi,%%ebx,),%%al \n\t" // add Avg(x); -1 to offset inc ebx
+//pre "cmpl bpp, %%ebx \n\t" // (bpp is preloaded into ecx)
+ "cmpl %%ecx, %%ebx \n\t"
+ "movb %%al,-1(%%edi,%%ebx,) \n\t" // write Raw(x); -1 to offset inc ebx
+ "jb avg_rlp \n\t" // mov does not affect flags
+
+ // get # of bytes to alignment
+ "movl %%edi, _dif \n\t" // take start of row
+ "addl %%ebx, _dif \n\t" // add bpp
+ "addl $0xf, _dif \n\t" // add 7+8 to incr past alignment bdry
+ "andl $0xfffffff8, _dif \n\t" // mask to alignment boundary
+ "subl %%edi, _dif \n\t" // subtract from start => value ebx at
+ "jz avg_go \n\t" // alignment
+
+ // fix alignment
+ // Compute the Raw value for the bytes up to the alignment boundary
+ // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
+ "xorl %%ecx, %%ecx \n\t"
+
+ "avg_lp1: \n\t"
+ "xorl %%eax, %%eax \n\t"
+ "movb (%%esi,%%ebx,), %%cl \n\t" // load cl with Prior(x)
+ "movb (%%edx,%%ebx,), %%al \n\t" // load al with Raw(x-bpp)
+ "addw %%cx, %%ax \n\t"
+ "incl %%ebx \n\t"
+ "shrw %%ax \n\t" // divide by 2
+ "addb -1(%%edi,%%ebx,), %%al \n\t" // add Avg(x); -1 to offset inc ebx
+ "cmpl _dif, %%ebx \n\t" // check if at alignment boundary
+ "movb %%al, -1(%%edi,%%ebx,) \n\t" // write Raw(x); -1 to offset inc ebx
+ "jb avg_lp1 \n\t" // repeat until at alignment boundary
+
+ "avg_go: \n\t"
+ "movl _FullLength, %%eax \n\t"
+ "movl %%eax, %%ecx \n\t"
+ "subl %%ebx, %%eax \n\t" // subtract alignment fix
+ "andl $0x00000007, %%eax \n\t" // calc bytes over mult of 8
+ "subl %%eax, %%ecx \n\t" // drop over bytes from original length
+ "movl %%ecx, _MMXLength \n\t"
+#ifdef __PIC__
+ "popl %%ebx \n\t" // restore index to Global Offset Table
+#endif
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (bpp), // ecx // input regs
+ "1" (prev_row), // esi
+ "2" (row) // edi
+
+ : "%eax", "%edx" // clobber list
+#ifndef __PIC__
+ , "%ebx"
+#endif
+ // GRR: INCLUDE "memory" as clobbered? (_dif, _MMXLength)
+ // (seems to work fine without...)
+ );
+
+ // now do the math for the rest of the row
+ switch (bpp)
+ {
+ case 3:
+ {
+ _ActiveMask.use = 0x0000000000ffffffLL;
+ _ShiftBpp.use = 24; // == 3 * 8
+ _ShiftRem.use = 40; // == 64 - 24
+
+ __asm__ __volatile__ (
+ // re-init address pointers and offset
+ "movq _ActiveMask, %%mm7 \n\t"
+ "movl _dif, %%ecx \n\t" // ecx: x = offset to
+ "movq _LBCarryMask, %%mm5 \n\t" // alignment boundary
+// preload "movl row, %%edi \n\t" // edi: Avg(x)
+ "movq _HBClearMask, %%mm4 \n\t"
+// preload "movl prev_row, %%esi \n\t" // esi: Prior(x)
+
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%%edi,%%ecx,), %%mm2 \n\t" // load previous aligned 8 bytes
+ // (correct pos. in loop below)
+ "avg_3lp: \n\t"
+ "movq (%%edi,%%ecx,), %%mm0 \n\t" // load mm0 with Avg(x)
+ "movq %%mm5, %%mm3 \n\t"
+ "psrlq _ShiftRem, %%mm2 \n\t" // correct position Raw(x-bpp)
+ // data
+ "movq (%%esi,%%ecx,), %%mm1 \n\t" // load mm1 with Prior(x)
+ "movq %%mm7, %%mm6 \n\t"
+ "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte
+ "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2
+ "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg for
+ // each byte
+ // add 1st active group (Raw(x-bpp)/2) to average with LBCarry
+ "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting
+ // LBCarrys
+ "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte
+ // where both
+ // lsb's were == 1 (only valid for active group)
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2)
+ // for each byte
+ "pand %%mm6, %%mm2 \n\t" // leave only Active Group 1
+ // bytes to add to Avg
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to
+ // Avg for each Active
+ // byte
+ // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry
+ "psllq _ShiftBpp, %%mm6 \n\t" // shift the mm6 mask to cover
+ // bytes 3-5
+ "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2
+ "psllq _ShiftBpp, %%mm2 \n\t" // shift data to pos. correctly
+ "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting
+ // LBCarrys
+ "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte
+ // where both
+ // lsb's were == 1 (only valid for active group)
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2)
+ // for each byte
+ "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2
+ // bytes to add to Avg
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to
+ // Avg for each Active
+ // byte
+
+ // add 3rd active group (Raw(x-bpp)/2) to average with _LBCarry
+ "psllq _ShiftBpp, %%mm6 \n\t" // shift mm6 mask to cover last
+ // two
+ // bytes
+ "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2
+ "psllq _ShiftBpp, %%mm2 \n\t" // shift data to pos. correctly
+ // Data only needs to be shifted once here to
+ // get the correct x-bpp offset.
+ "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting
+ // LBCarrys
+ "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte
+ // where both
+ // lsb's were == 1 (only valid for active group)
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2)
+ // for each byte
+ "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2
+ // bytes to add to Avg
+ "addl $8, %%ecx \n\t"
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to
+ // Avg for each Active
+ // byte
+ // now ready to write back to memory
+ "movq %%mm0, -8(%%edi,%%ecx,) \n\t"
+ // move updated Raw(x) to use as Raw(x-bpp) for next loop
+ "cmpl _MMXLength, %%ecx \n\t"
+ "movq %%mm0, %%mm2 \n\t" // mov updated Raw(x) to mm2
+ "jb avg_3lp \n\t"
+
+ : "=S" (dummy_value_S), // output regs (dummy)
+ "=D" (dummy_value_D)
+
+ : "0" (prev_row), // esi // input regs
+ "1" (row) // edi
+
+ : "%ecx" // clobber list
+#if 0 /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ , "%mm0", "%mm1", "%mm2", "%mm3"
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ break; // end 3 bpp
+
+ case 6:
+ case 4:
+ //case 7: // who wrote this? PNG doesn't support 5 or 7 bytes/pixel
+ //case 5: // GRR BOGUS
+ {
+ _ActiveMask.use = 0xffffffffffffffffLL; // use shift below to clear
+ // appropriate inactive bytes
+ _ShiftBpp.use = bpp << 3;
+ _ShiftRem.use = 64 - _ShiftBpp.use;
+
+ __asm__ __volatile__ (
+ "movq _HBClearMask, %%mm4 \n\t"
+
+ // re-init address pointers and offset
+ "movl _dif, %%ecx \n\t" // ecx: x = offset to
+ // alignment boundary
+
+ // load _ActiveMask and clear all bytes except for 1st active group
+ "movq _ActiveMask, %%mm7 \n\t"
+// preload "movl row, %%edi \n\t" // edi: Avg(x)
+ "psrlq _ShiftRem, %%mm7 \n\t"
+// preload "movl prev_row, %%esi \n\t" // esi: Prior(x)
+ "movq %%mm7, %%mm6 \n\t"
+ "movq _LBCarryMask, %%mm5 \n\t"
+ "psllq _ShiftBpp, %%mm6 \n\t" // create mask for 2nd active
+ // group
+
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%%edi,%%ecx,), %%mm2 \n\t" // load previous aligned 8 bytes
+ // (we correct pos. in loop below)
+ "avg_4lp: \n\t"
+ "movq (%%edi,%%ecx,), %%mm0 \n\t"
+ "psrlq _ShiftRem, %%mm2 \n\t" // shift data to pos. correctly
+ "movq (%%esi,%%ecx,), %%mm1 \n\t"
+ // add (Prev_row/2) to average
+ "movq %%mm5, %%mm3 \n\t"
+ "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte
+ "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2
+ "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg for
+ // each byte
+ // add 1st active group (Raw(x-bpp)/2) to average with _LBCarry
+ "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting
+ // LBCarrys
+ "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte
+ // where both
+ // lsb's were == 1 (only valid for active group)
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2)
+ // for each byte
+ "pand %%mm7, %%mm2 \n\t" // leave only Active Group 1
+ // bytes to add to Avg
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg
+ // for each Active
+ // byte
+ // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry
+ "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2
+ "psllq _ShiftBpp, %%mm2 \n\t" // shift data to pos. correctly
+ "addl $8, %%ecx \n\t"
+ "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting
+ // LBCarrys
+ "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte
+ // where both
+ // lsb's were == 1 (only valid for active group)
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2)
+ // for each byte
+ "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2
+ // bytes to add to Avg
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to
+ // Avg for each Active
+ // byte
+ "cmpl _MMXLength, %%ecx \n\t"
+ // now ready to write back to memory
+ "movq %%mm0, -8(%%edi,%%ecx,) \n\t"
+ // prep Raw(x-bpp) for next loop
+ "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2
+ "jb avg_4lp \n\t"
+
+ : "=S" (dummy_value_S), // output regs (dummy)
+ "=D" (dummy_value_D)
+
+ : "0" (prev_row), // esi // input regs
+ "1" (row) // edi
+
+ : "%ecx" // clobber list
+#if 0 /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ , "%mm0", "%mm1", "%mm2", "%mm3"
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ break; // end 4,6 bpp
+
+ case 2:
+ {
+ _ActiveMask.use = 0x000000000000ffffLL;
+ _ShiftBpp.use = 16; // == 2 * 8
+ _ShiftRem.use = 48; // == 64 - 16
+
+ __asm__ __volatile__ (
+ // load _ActiveMask
+ "movq _ActiveMask, %%mm7 \n\t"
+ // re-init address pointers and offset
+ "movl _dif, %%ecx \n\t" // ecx: x = offset to alignment
+ // boundary
+ "movq _LBCarryMask, %%mm5 \n\t"
+// preload "movl row, %%edi \n\t" // edi: Avg(x)
+ "movq _HBClearMask, %%mm4 \n\t"
+// preload "movl prev_row, %%esi \n\t" // esi: Prior(x)
+
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%%edi,%%ecx,), %%mm2 \n\t" // load previous aligned 8 bytes
+ // (we correct pos. in loop below)
+ "avg_2lp: \n\t"
+ "movq (%%edi,%%ecx,), %%mm0 \n\t"
+ "psrlq _ShiftRem, %%mm2 \n\t" // shift data to pos. correctly
+ "movq (%%esi,%%ecx,), %%mm1 \n\t" // (GRR BUGFIX: was psllq)
+ // add (Prev_row/2) to average
+ "movq %%mm5, %%mm3 \n\t"
+ "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte
+ "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2
+ "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7 of each
+ // byte
+ "movq %%mm7, %%mm6 \n\t"
+ "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg for
+ // each byte
+
+ // add 1st active group (Raw(x-bpp)/2) to average with _LBCarry
+ "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting
+ // LBCarrys
+ "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte
+ // where both
+ // lsb's were == 1 (only valid
+ // for active group)
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2)
+ // for each byte
+ "pand %%mm6, %%mm2 \n\t" // leave only Active Group 1
+ // bytes to add to Avg
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg
+ // for each Active byte
+
+ // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry
+ "psllq _ShiftBpp, %%mm6 \n\t" // shift the mm6 mask to cover
+ // bytes 2 & 3
+ "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2
+ "psllq _ShiftBpp, %%mm2 \n\t" // shift data to pos. correctly
+ "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting
+ // LBCarrys
+ "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte
+ // where both
+ // lsb's were == 1 (only valid
+ // for active group)
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2)
+ // for each byte
+ "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2
+ // bytes to add to Avg
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to
+ // Avg for each Active byte
+
+ // add 3rd active group (Raw(x-bpp)/2) to average with _LBCarry
+ "psllq _ShiftBpp, %%mm6 \n\t" // shift the mm6 mask to cover
+ // bytes 4 & 5
+ "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2
+ "psllq _ShiftBpp, %%mm2 \n\t" // shift data to pos. correctly
+ "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting
+ // LBCarrys
+ "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte
+ // where both lsb's were == 1
+ // (only valid for active group)
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2)
+ // for each byte
+ "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2
+ // bytes to add to Avg
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to
+ // Avg for each Active byte
+
+ // add 4th active group (Raw(x-bpp)/2) to average with _LBCarry
+ "psllq _ShiftBpp, %%mm6 \n\t" // shift the mm6 mask to cover
+ // bytes 6 & 7
+ "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2
+ "psllq _ShiftBpp, %%mm2 \n\t" // shift data to pos. correctly
+ "addl $8, %%ecx \n\t"
+ "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting
+ // LBCarrys
+ "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte
+ // where both
+ // lsb's were == 1 (only valid
+ // for active group)
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2)
+ // for each byte
+ "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2
+ // bytes to add to Avg
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to
+ // Avg for each Active byte
+
+ "cmpl _MMXLength, %%ecx \n\t"
+ // now ready to write back to memory
+ "movq %%mm0, -8(%%edi,%%ecx,) \n\t"
+ // prep Raw(x-bpp) for next loop
+ "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2
+ "jb avg_2lp \n\t"
+
+ : "=S" (dummy_value_S), // output regs (dummy)
+ "=D" (dummy_value_D)
+
+ : "0" (prev_row), // esi // input regs
+ "1" (row) // edi
+
+ : "%ecx" // clobber list
+#if 0 /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ , "%mm0", "%mm1", "%mm2", "%mm3"
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ break; // end 2 bpp
+
+ case 1:
+ {
+ __asm__ __volatile__ (
+ // re-init address pointers and offset
+#ifdef __PIC__
+ "pushl %%ebx \n\t" // save Global Offset Table index
+#endif
+ "movl _dif, %%ebx \n\t" // ebx: x = offset to alignment
+ // boundary
+// preload "movl row, %%edi \n\t" // edi: Avg(x)
+ "cmpl _FullLength, %%ebx \n\t" // test if offset at end of array
+ "jnb avg_1end \n\t"
+ // do Paeth decode for remaining bytes
+// preload "movl prev_row, %%esi \n\t" // esi: Prior(x)
+ "movl %%edi, %%edx \n\t"
+// preload "subl bpp, %%edx \n\t" // (bpp is preloaded into ecx)
+ "subl %%ecx, %%edx \n\t" // edx: Raw(x-bpp)
+ "xorl %%ecx, %%ecx \n\t" // zero ecx before using cl & cx
+ // in loop below
+ "avg_1lp: \n\t"
+ // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
+ "xorl %%eax, %%eax \n\t"
+ "movb (%%esi,%%ebx,), %%cl \n\t" // load cl with Prior(x)
+ "movb (%%edx,%%ebx,), %%al \n\t" // load al with Raw(x-bpp)
+ "addw %%cx, %%ax \n\t"
+ "incl %%ebx \n\t"
+ "shrw %%ax \n\t" // divide by 2
+ "addb -1(%%edi,%%ebx,), %%al \n\t" // add Avg(x); -1 to offset
+ // inc ebx
+ "cmpl _FullLength, %%ebx \n\t" // check if at end of array
+ "movb %%al, -1(%%edi,%%ebx,) \n\t" // write back Raw(x);
+ // mov does not affect flags; -1 to offset inc ebx
+ "jb avg_1lp \n\t"
+
+ "avg_1end: \n\t"
+#ifdef __PIC__
+ "popl %%ebx \n\t" // Global Offset Table index
+#endif
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (bpp), // ecx // input regs
+ "1" (prev_row), // esi
+ "2" (row) // edi
+
+ : "%eax", "%edx" // clobber list
+#ifndef __PIC__
+ , "%ebx"
+#endif
+ );
+ }
+ return; // end 1 bpp
+
+ case 8:
+ {
+ __asm__ __volatile__ (
+ // re-init address pointers and offset
+ "movl _dif, %%ecx \n\t" // ecx: x == offset to alignment
+ "movq _LBCarryMask, %%mm5 \n\t" // boundary
+// preload "movl row, %%edi \n\t" // edi: Avg(x)
+ "movq _HBClearMask, %%mm4 \n\t"
+// preload "movl prev_row, %%esi \n\t" // esi: Prior(x)
+
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%%edi,%%ecx,), %%mm2 \n\t" // load previous aligned 8 bytes
+ // (NO NEED to correct pos. in loop below)
+
+ "avg_8lp: \n\t"
+ "movq (%%edi,%%ecx,), %%mm0 \n\t"
+ "movq %%mm5, %%mm3 \n\t"
+ "movq (%%esi,%%ecx,), %%mm1 \n\t"
+ "addl $8, %%ecx \n\t"
+ "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte
+ "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2
+ "pand %%mm2, %%mm3 \n\t" // get LBCarrys for each byte
+ // where both lsb's were == 1
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7, each byte
+ "paddb %%mm3, %%mm0 \n\t" // add LBCarrys to Avg, each byte
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7, each byte
+ "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg, each
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) to Avg for each
+ "cmpl _MMXLength, %%ecx \n\t"
+ "movq %%mm0, -8(%%edi,%%ecx,) \n\t"
+ "movq %%mm0, %%mm2 \n\t" // reuse as Raw(x-bpp)
+ "jb avg_8lp \n\t"
+
+ : "=S" (dummy_value_S), // output regs (dummy)
+ "=D" (dummy_value_D)
+
+ : "0" (prev_row), // esi // input regs
+ "1" (row) // edi
+
+ : "%ecx" // clobber list
+#if 0 /* %mm0, ..., %mm5 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ , "%mm0", "%mm1", "%mm2"
+ , "%mm3", "%mm4", "%mm5"
+#endif
+ );
+ }
+ break; // end 8 bpp
+
+ default: // bpp greater than 8 (!= 1,2,3,4,[5],6,[7],8)
+ {
+
+#ifdef PNG_DEBUG
+ // GRR: PRINT ERROR HERE: SHOULD NEVER BE REACHED
+ png_debug(1,
+ "Internal logic error in pnggccrd (png_read_filter_row_mmx_avg())\n");
+#endif
+
+#if 0
+ __asm__ __volatile__ (
+ "movq _LBCarryMask, %%mm5 \n\t"
+ // re-init address pointers and offset
+ "movl _dif, %%ebx \n\t" // ebx: x = offset to
+ // alignment boundary
+ "movl row, %%edi \n\t" // edi: Avg(x)
+ "movq _HBClearMask, %%mm4 \n\t"
+ "movl %%edi, %%edx \n\t"
+ "movl prev_row, %%esi \n\t" // esi: Prior(x)
+ "subl bpp, %%edx \n\t" // edx: Raw(x-bpp)
+ "avg_Alp: \n\t"
+ "movq (%%edi,%%ebx,), %%mm0 \n\t"
+ "movq %%mm5, %%mm3 \n\t"
+ "movq (%%esi,%%ebx,), %%mm1 \n\t"
+ "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte
+ "movq (%%edx,%%ebx,), %%mm2 \n\t"
+ "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2
+ "pand %%mm2, %%mm3 \n\t" // get LBCarrys for each byte
+ // where both lsb's were == 1
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm3, %%mm0 \n\t" // add LBCarrys to Avg for each
+ // byte
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg for
+ // each byte
+ "addl $8, %%ebx \n\t"
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) to Avg for each
+ // byte
+ "cmpl _MMXLength, %%ebx \n\t"
+ "movq %%mm0, -8(%%edi,%%ebx,) \n\t"
+ "jb avg_Alp \n\t"
+
+ : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var)
+
+ : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest)
+
+ : "%ebx", "%edx", "%edi", "%esi" // CHECKASM: clobber list
+ );
+#endif /* 0 - NEVER REACHED */
+ }
+ break;
+
+ } // end switch (bpp)
+
+ __asm__ __volatile__ (
+ // MMX acceleration complete; now do clean-up
+ // check if any remaining bytes left to decode
+#ifdef __PIC__
+ "pushl %%ebx \n\t" // save index to Global Offset Table
+#endif
+ "movl _MMXLength, %%ebx \n\t" // ebx: x == offset bytes after MMX
+//pre "movl row, %%edi \n\t" // edi: Avg(x)
+ "cmpl _FullLength, %%ebx \n\t" // test if offset at end of array
+ "jnb avg_end \n\t"
+
+ // do Avg decode for remaining bytes
+//pre "movl prev_row, %%esi \n\t" // esi: Prior(x)
+ "movl %%edi, %%edx \n\t"
+//pre "subl bpp, %%edx \n\t" // (bpp is preloaded into ecx)
+ "subl %%ecx, %%edx \n\t" // edx: Raw(x-bpp)
+ "xorl %%ecx, %%ecx \n\t" // zero ecx before using cl & cx below
+
+ "avg_lp2: \n\t"
+ // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
+ "xorl %%eax, %%eax \n\t"
+ "movb (%%esi,%%ebx,), %%cl \n\t" // load cl with Prior(x)
+ "movb (%%edx,%%ebx,), %%al \n\t" // load al with Raw(x-bpp)
+ "addw %%cx, %%ax \n\t"
+ "incl %%ebx \n\t"
+ "shrw %%ax \n\t" // divide by 2
+ "addb -1(%%edi,%%ebx,), %%al \n\t" // add Avg(x); -1 to offset inc ebx
+ "cmpl _FullLength, %%ebx \n\t" // check if at end of array
+ "movb %%al, -1(%%edi,%%ebx,) \n\t" // write back Raw(x) [mov does not
+ "jb avg_lp2 \n\t" // affect flags; -1 to offset inc ebx]
+
+ "avg_end: \n\t"
+ "EMMS \n\t" // end MMX; prep for poss. FP instrs.
+#ifdef __PIC__
+ "popl %%ebx \n\t" // restore index to Global Offset Table
+#endif
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (bpp), // ecx // input regs
+ "1" (prev_row), // esi
+ "2" (row) // edi
+
+ : "%eax", "%edx" // clobber list
+#ifndef __PIC__
+ , "%ebx"
+#endif
+ );
+
+} /* end png_read_filter_row_mmx_avg() */
+#endif
+
+
+
+#ifdef PNG_THREAD_UNSAFE_OK
+//===========================================================================//
+// //
+// P N G _ R E A D _ F I L T E R _ R O W _ M M X _ P A E T H //
+// //
+//===========================================================================//
+
+// Optimized code for PNG Paeth filter decoder
+
+static void /* PRIVATE */
+png_read_filter_row_mmx_paeth(png_row_infop row_info, png_bytep row,
+ png_bytep prev_row)
+{
+ int bpp;
+ int dummy_value_c; // fix 'forbidden register 2 (cx) was spilled' error
+ int dummy_value_S;
+ int dummy_value_D;
+
+ bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel
+ _FullLength = row_info->rowbytes; // # of bytes to filter
+
+ __asm__ __volatile__ (
+#ifdef __PIC__
+ "pushl %%ebx \n\t" // save index to Global Offset Table
+#endif
+ "xorl %%ebx, %%ebx \n\t" // ebx: x offset
+//pre "movl row, %%edi \n\t"
+ "xorl %%edx, %%edx \n\t" // edx: x-bpp offset
+//pre "movl prev_row, %%esi \n\t"
+ "xorl %%eax, %%eax \n\t"
+
+ // Compute the Raw value for the first bpp bytes
+ // Note: the formula works out to be always
+ // Paeth(x) = Raw(x) + Prior(x) where x < bpp
+ "paeth_rlp: \n\t"
+ "movb (%%edi,%%ebx,), %%al \n\t"
+ "addb (%%esi,%%ebx,), %%al \n\t"
+ "incl %%ebx \n\t"
+//pre "cmpl bpp, %%ebx \n\t" (bpp is preloaded into ecx)
+ "cmpl %%ecx, %%ebx \n\t"
+ "movb %%al, -1(%%edi,%%ebx,) \n\t"
+ "jb paeth_rlp \n\t"
+ // get # of bytes to alignment
+ "movl %%edi, _dif \n\t" // take start of row
+ "addl %%ebx, _dif \n\t" // add bpp
+ "xorl %%ecx, %%ecx \n\t"
+ "addl $0xf, _dif \n\t" // add 7 + 8 to incr past alignment
+ // boundary
+ "andl $0xfffffff8, _dif \n\t" // mask to alignment boundary
+ "subl %%edi, _dif \n\t" // subtract from start ==> value ebx
+ // at alignment
+ "jz paeth_go \n\t"
+ // fix alignment
+
+ "paeth_lp1: \n\t"
+ "xorl %%eax, %%eax \n\t"
+ // pav = p - a = (a + b - c) - a = b - c
+ "movb (%%esi,%%ebx,), %%al \n\t" // load Prior(x) into al
+ "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl
+ "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp)
+ "movl %%eax, _patemp \n\t" // Save pav for later use
+ "xorl %%eax, %%eax \n\t"
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movb (%%edi,%%edx,), %%al \n\t" // load Raw(x-bpp) into al
+ "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp)
+ "movl %%eax, %%ecx \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ "addl _patemp, %%eax \n\t" // pcv = pav + pbv
+ // pc = abs(pcv)
+ "testl $0x80000000, %%eax \n\t"
+ "jz paeth_pca \n\t"
+ "negl %%eax \n\t" // reverse sign of neg values
+
+ "paeth_pca: \n\t"
+ "movl %%eax, _pctemp \n\t" // save pc for later use
+ // pb = abs(pbv)
+ "testl $0x80000000, %%ecx \n\t"
+ "jz paeth_pba \n\t"
+ "negl %%ecx \n\t" // reverse sign of neg values
+
+ "paeth_pba: \n\t"
+ "movl %%ecx, _pbtemp \n\t" // save pb for later use
+ // pa = abs(pav)
+ "movl _patemp, %%eax \n\t"
+ "testl $0x80000000, %%eax \n\t"
+ "jz paeth_paa \n\t"
+ "negl %%eax \n\t" // reverse sign of neg values
+
+ "paeth_paa: \n\t"
+ "movl %%eax, _patemp \n\t" // save pa for later use
+ // test if pa <= pb
+ "cmpl %%ecx, %%eax \n\t"
+ "jna paeth_abb \n\t"
+ // pa > pb; now test if pb <= pc
+ "cmpl _pctemp, %%ecx \n\t"
+ "jna paeth_bbc \n\t"
+ // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl
+ "jmp paeth_paeth \n\t"
+
+ "paeth_bbc: \n\t"
+ // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
+ "movb (%%esi,%%ebx,), %%cl \n\t" // load Prior(x) into cl
+ "jmp paeth_paeth \n\t"
+
+ "paeth_abb: \n\t"
+ // pa <= pb; now test if pa <= pc
+ "cmpl _pctemp, %%eax \n\t"
+ "jna paeth_abc \n\t"
+ // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl
+ "jmp paeth_paeth \n\t"
+
+ "paeth_abc: \n\t"
+ // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
+ "movb (%%edi,%%edx,), %%cl \n\t" // load Raw(x-bpp) into cl
+
+ "paeth_paeth: \n\t"
+ "incl %%ebx \n\t"
+ "incl %%edx \n\t"
+ // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
+ "addb %%cl, -1(%%edi,%%ebx,) \n\t"
+ "cmpl _dif, %%ebx \n\t"
+ "jb paeth_lp1 \n\t"
+
+ "paeth_go: \n\t"
+ "movl _FullLength, %%ecx \n\t"
+ "movl %%ecx, %%eax \n\t"
+ "subl %%ebx, %%eax \n\t" // subtract alignment fix
+ "andl $0x00000007, %%eax \n\t" // calc bytes over mult of 8
+ "subl %%eax, %%ecx \n\t" // drop over bytes from original length
+ "movl %%ecx, _MMXLength \n\t"
+#ifdef __PIC__
+ "popl %%ebx \n\t" // restore index to Global Offset Table
+#endif
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (bpp), // ecx // input regs
+ "1" (prev_row), // esi
+ "2" (row) // edi
+
+ : "%eax", "%edx" // clobber list
+#ifndef __PIC__
+ , "%ebx"
+#endif
+ );
+
+ // now do the math for the rest of the row
+ switch (bpp)
+ {
+ case 3:
+ {
+ _ActiveMask.use = 0x0000000000ffffffLL;
+ _ActiveMaskEnd.use = 0xffff000000000000LL;
+ _ShiftBpp.use = 24; // == bpp(3) * 8
+ _ShiftRem.use = 40; // == 64 - 24
+
+ __asm__ __volatile__ (
+ "movl _dif, %%ecx \n\t"
+// preload "movl row, %%edi \n\t"
+// preload "movl prev_row, %%esi \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%%edi,%%ecx,), %%mm1 \n\t"
+ "paeth_3lp: \n\t"
+ "psrlq _ShiftRem, %%mm1 \n\t" // shift last 3 bytes to 1st
+ // 3 bytes
+ "movq (%%esi,%%ecx,), %%mm2 \n\t" // load b=Prior(x)
+ "punpcklbw %%mm0, %%mm1 \n\t" // unpack High bytes of a
+ "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // prep c=Prior(x-bpp) bytes
+ "punpcklbw %%mm0, %%mm2 \n\t" // unpack High bytes of b
+ "psrlq _ShiftRem, %%mm3 \n\t" // shift last 3 bytes to 1st
+ // 3 bytes
+ // pav = p - a = (a + b - c) - a = b - c
+ "movq %%mm2, %%mm4 \n\t"
+ "punpcklbw %%mm0, %%mm3 \n\t" // unpack High bytes of c
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movq %%mm1, %%mm5 \n\t"
+ "psubw %%mm3, %%mm4 \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ "movq %%mm4, %%mm6 \n\t"
+ "psubw %%mm3, %%mm5 \n\t"
+
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0
+ "paddw %%mm5, %%mm6 \n\t"
+ "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0
+ "psubw %%mm0, %%mm4 \n\t"
+ "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0
+ "psubw %%mm0, %%mm4 \n\t"
+ "psubw %%mm7, %%mm5 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0
+ "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "psubw %%mm7, %%mm5 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ // test pa <= pb
+ "movq %%mm4, %%mm7 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb?
+ "movq %%mm7, %%mm0 \n\t"
+ // use mm7 mask to merge pa & pb
+ "pand %%mm7, %%mm5 \n\t"
+ // use mm0 mask copy to merge a & b
+ "pand %%mm0, %%mm2 \n\t"
+ "pandn %%mm4, %%mm7 \n\t"
+ "pandn %%mm1, %%mm0 \n\t"
+ "paddw %%mm5, %%mm7 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+ // test ((pa <= pb)? pa:pb) <= pc
+ "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc?
+ "pxor %%mm1, %%mm1 \n\t"
+ "pand %%mm7, %%mm3 \n\t"
+ "pandn %%mm0, %%mm7 \n\t"
+ "paddw %%mm3, %%mm7 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "packuswb %%mm1, %%mm7 \n\t"
+ "movq (%%esi,%%ecx,), %%mm3 \n\t" // load c=Prior(x-bpp)
+ "pand _ActiveMask, %%mm7 \n\t"
+ "movq %%mm3, %%mm2 \n\t" // load b=Prior(x) step 1
+ "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor with Raw(x)
+ "punpcklbw %%mm0, %%mm3 \n\t" // unpack High bytes of c
+ "movq %%mm7, (%%edi,%%ecx,) \n\t" // write back updated value
+ "movq %%mm7, %%mm1 \n\t" // now mm1 will be used as
+ // Raw(x-bpp)
+ // now do Paeth for 2nd set of bytes (3-5)
+ "psrlq _ShiftBpp, %%mm2 \n\t" // load b=Prior(x) step 2
+ "punpcklbw %%mm0, %%mm1 \n\t" // unpack High bytes of a
+ "pxor %%mm7, %%mm7 \n\t"
+ "punpcklbw %%mm0, %%mm2 \n\t" // unpack High bytes of b
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movq %%mm1, %%mm5 \n\t"
+ // pav = p - a = (a + b - c) - a = b - c
+ "movq %%mm2, %%mm4 \n\t"
+ "psubw %%mm3, %%mm5 \n\t"
+ "psubw %%mm3, %%mm4 \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) =
+ // pav + pbv = pbv + pav
+ "movq %%mm5, %%mm6 \n\t"
+ "paddw %%mm4, %%mm6 \n\t"
+
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ "pcmpgtw %%mm5, %%mm0 \n\t" // create mask pbv bytes < 0
+ "pcmpgtw %%mm4, %%mm7 \n\t" // create mask pav bytes < 0
+ "pand %%mm5, %%mm0 \n\t" // only pbv bytes < 0 in mm0
+ "pand %%mm4, %%mm7 \n\t" // only pav bytes < 0 in mm7
+ "psubw %%mm0, %%mm5 \n\t"
+ "psubw %%mm7, %%mm4 \n\t"
+ "psubw %%mm0, %%mm5 \n\t"
+ "psubw %%mm7, %%mm4 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0
+ "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "psubw %%mm0, %%mm6 \n\t"
+ // test pa <= pb
+ "movq %%mm4, %%mm7 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb?
+ "movq %%mm7, %%mm0 \n\t"
+ // use mm7 mask to merge pa & pb
+ "pand %%mm7, %%mm5 \n\t"
+ // use mm0 mask copy to merge a & b
+ "pand %%mm0, %%mm2 \n\t"
+ "pandn %%mm4, %%mm7 \n\t"
+ "pandn %%mm1, %%mm0 \n\t"
+ "paddw %%mm5, %%mm7 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+ // test ((pa <= pb)? pa:pb) <= pc
+ "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc?
+ "movq (%%esi,%%ecx,), %%mm2 \n\t" // load b=Prior(x)
+ "pand %%mm7, %%mm3 \n\t"
+ "pandn %%mm0, %%mm7 \n\t"
+ "pxor %%mm1, %%mm1 \n\t"
+ "paddw %%mm3, %%mm7 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "packuswb %%mm1, %%mm7 \n\t"
+ "movq %%mm2, %%mm3 \n\t" // load c=Prior(x-bpp) step 1
+ "pand _ActiveMask, %%mm7 \n\t"
+ "punpckhbw %%mm0, %%mm2 \n\t" // unpack High bytes of b
+ "psllq _ShiftBpp, %%mm7 \n\t" // shift bytes to 2nd group of
+ // 3 bytes
+ // pav = p - a = (a + b - c) - a = b - c
+ "movq %%mm2, %%mm4 \n\t"
+ "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor with Raw(x)
+ "psllq _ShiftBpp, %%mm3 \n\t" // load c=Prior(x-bpp) step 2
+ "movq %%mm7, (%%edi,%%ecx,) \n\t" // write back updated value
+ "movq %%mm7, %%mm1 \n\t"
+ "punpckhbw %%mm0, %%mm3 \n\t" // unpack High bytes of c
+ "psllq _ShiftBpp, %%mm1 \n\t" // shift bytes
+ // now mm1 will be used as Raw(x-bpp)
+ // now do Paeth for 3rd, and final, set of bytes (6-7)
+ "pxor %%mm7, %%mm7 \n\t"
+ "punpckhbw %%mm0, %%mm1 \n\t" // unpack High bytes of a
+ "psubw %%mm3, %%mm4 \n\t"
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movq %%mm1, %%mm5 \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ "movq %%mm4, %%mm6 \n\t"
+ "psubw %%mm3, %%mm5 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0
+ "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0
+ "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0
+ "psubw %%mm0, %%mm4 \n\t"
+ "psubw %%mm7, %%mm5 \n\t"
+ "psubw %%mm0, %%mm4 \n\t"
+ "psubw %%mm7, %%mm5 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0
+ "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "psubw %%mm0, %%mm6 \n\t"
+ // test pa <= pb
+ "movq %%mm4, %%mm7 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb?
+ "movq %%mm7, %%mm0 \n\t"
+ // use mm0 mask copy to merge a & b
+ "pand %%mm0, %%mm2 \n\t"
+ // use mm7 mask to merge pa & pb
+ "pand %%mm7, %%mm5 \n\t"
+ "pandn %%mm1, %%mm0 \n\t"
+ "pandn %%mm4, %%mm7 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+ "paddw %%mm5, %%mm7 \n\t"
+ // test ((pa <= pb)? pa:pb) <= pc
+ "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc?
+ "pand %%mm7, %%mm3 \n\t"
+ "pandn %%mm0, %%mm7 \n\t"
+ "paddw %%mm3, %%mm7 \n\t"
+ "pxor %%mm1, %%mm1 \n\t"
+ "packuswb %%mm7, %%mm1 \n\t"
+ // step ecx to next set of 8 bytes and repeat loop til done
+ "addl $8, %%ecx \n\t"
+ "pand _ActiveMaskEnd, %%mm1 \n\t"
+ "paddb -8(%%edi,%%ecx,), %%mm1 \n\t" // add Paeth predictor with
+ // Raw(x)
+
+ "cmpl _MMXLength, %%ecx \n\t"
+ "pxor %%mm0, %%mm0 \n\t" // pxor does not affect flags
+ "movq %%mm1, -8(%%edi,%%ecx,) \n\t" // write back updated value
+ // mm1 will be used as Raw(x-bpp) next loop
+ // mm3 ready to be used as Prior(x-bpp) next loop
+ "jb paeth_3lp \n\t"
+
+ : "=S" (dummy_value_S), // output regs (dummy)
+ "=D" (dummy_value_D)
+
+ : "0" (prev_row), // esi // input regs
+ "1" (row) // edi
+
+ : "%ecx" // clobber list
+#if 0 /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ , "%mm0", "%mm1", "%mm2", "%mm3"
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ break; // end 3 bpp
+
+ case 6:
+ //case 7: // GRR BOGUS
+ //case 5: // GRR BOGUS
+ {
+ _ActiveMask.use = 0x00000000ffffffffLL;
+ _ActiveMask2.use = 0xffffffff00000000LL;
+ _ShiftBpp.use = bpp << 3; // == bpp * 8
+ _ShiftRem.use = 64 - _ShiftBpp.use;
+
+ __asm__ __volatile__ (
+ "movl _dif, %%ecx \n\t"
+// preload "movl row, %%edi \n\t"
+// preload "movl prev_row, %%esi \n\t"
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%%edi,%%ecx,), %%mm1 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+
+ "paeth_6lp: \n\t"
+ // must shift to position Raw(x-bpp) data
+ "psrlq _ShiftRem, %%mm1 \n\t"
+ // do first set of 4 bytes
+ "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes
+ "punpcklbw %%mm0, %%mm1 \n\t" // unpack Low bytes of a
+ "movq (%%esi,%%ecx,), %%mm2 \n\t" // load b=Prior(x)
+ "punpcklbw %%mm0, %%mm2 \n\t" // unpack Low bytes of b
+ // must shift to position Prior(x-bpp) data
+ "psrlq _ShiftRem, %%mm3 \n\t"
+ // pav = p - a = (a + b - c) - a = b - c
+ "movq %%mm2, %%mm4 \n\t"
+ "punpcklbw %%mm0, %%mm3 \n\t" // unpack Low bytes of c
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movq %%mm1, %%mm5 \n\t"
+ "psubw %%mm3, %%mm4 \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ "movq %%mm4, %%mm6 \n\t"
+ "psubw %%mm3, %%mm5 \n\t"
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0
+ "paddw %%mm5, %%mm6 \n\t"
+ "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0
+ "psubw %%mm0, %%mm4 \n\t"
+ "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0
+ "psubw %%mm0, %%mm4 \n\t"
+ "psubw %%mm7, %%mm5 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0
+ "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "psubw %%mm7, %%mm5 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ // test pa <= pb
+ "movq %%mm4, %%mm7 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb?
+ "movq %%mm7, %%mm0 \n\t"
+ // use mm7 mask to merge pa & pb
+ "pand %%mm7, %%mm5 \n\t"
+ // use mm0 mask copy to merge a & b
+ "pand %%mm0, %%mm2 \n\t"
+ "pandn %%mm4, %%mm7 \n\t"
+ "pandn %%mm1, %%mm0 \n\t"
+ "paddw %%mm5, %%mm7 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+ // test ((pa <= pb)? pa:pb) <= pc
+ "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc?
+ "pxor %%mm1, %%mm1 \n\t"
+ "pand %%mm7, %%mm3 \n\t"
+ "pandn %%mm0, %%mm7 \n\t"
+ "paddw %%mm3, %%mm7 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "packuswb %%mm1, %%mm7 \n\t"
+ "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // load c=Prior(x-bpp)
+ "pand _ActiveMask, %%mm7 \n\t"
+ "psrlq _ShiftRem, %%mm3 \n\t"
+ "movq (%%esi,%%ecx,), %%mm2 \n\t" // load b=Prior(x) step 1
+ "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor and Raw(x)
+ "movq %%mm2, %%mm6 \n\t"
+ "movq %%mm7, (%%edi,%%ecx,) \n\t" // write back updated value
+ "movq -8(%%edi,%%ecx,), %%mm1 \n\t"
+ "psllq _ShiftBpp, %%mm6 \n\t"
+ "movq %%mm7, %%mm5 \n\t"
+ "psrlq _ShiftRem, %%mm1 \n\t"
+ "por %%mm6, %%mm3 \n\t"
+ "psllq _ShiftBpp, %%mm5 \n\t"
+ "punpckhbw %%mm0, %%mm3 \n\t" // unpack High bytes of c
+ "por %%mm5, %%mm1 \n\t"
+ // do second set of 4 bytes
+ "punpckhbw %%mm0, %%mm2 \n\t" // unpack High bytes of b
+ "punpckhbw %%mm0, %%mm1 \n\t" // unpack High bytes of a
+ // pav = p - a = (a + b - c) - a = b - c
+ "movq %%mm2, %%mm4 \n\t"
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movq %%mm1, %%mm5 \n\t"
+ "psubw %%mm3, %%mm4 \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ "movq %%mm4, %%mm6 \n\t"
+ "psubw %%mm3, %%mm5 \n\t"
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0
+ "paddw %%mm5, %%mm6 \n\t"
+ "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0
+ "psubw %%mm0, %%mm4 \n\t"
+ "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0
+ "psubw %%mm0, %%mm4 \n\t"
+ "psubw %%mm7, %%mm5 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0
+ "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "psubw %%mm7, %%mm5 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ // test pa <= pb
+ "movq %%mm4, %%mm7 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb?
+ "movq %%mm7, %%mm0 \n\t"
+ // use mm7 mask to merge pa & pb
+ "pand %%mm7, %%mm5 \n\t"
+ // use mm0 mask copy to merge a & b
+ "pand %%mm0, %%mm2 \n\t"
+ "pandn %%mm4, %%mm7 \n\t"
+ "pandn %%mm1, %%mm0 \n\t"
+ "paddw %%mm5, %%mm7 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+ // test ((pa <= pb)? pa:pb) <= pc
+ "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc?
+ "pxor %%mm1, %%mm1 \n\t"
+ "pand %%mm7, %%mm3 \n\t"
+ "pandn %%mm0, %%mm7 \n\t"
+ "pxor %%mm1, %%mm1 \n\t"
+ "paddw %%mm3, %%mm7 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ // step ecx to next set of 8 bytes and repeat loop til done
+ "addl $8, %%ecx \n\t"
+ "packuswb %%mm7, %%mm1 \n\t"
+ "paddb -8(%%edi,%%ecx,), %%mm1 \n\t" // add Paeth predictor with Raw(x)
+ "cmpl _MMXLength, %%ecx \n\t"
+ "movq %%mm1, -8(%%edi,%%ecx,) \n\t" // write back updated value
+ // mm1 will be used as Raw(x-bpp) next loop
+ "jb paeth_6lp \n\t"
+
+ : "=S" (dummy_value_S), // output regs (dummy)
+ "=D" (dummy_value_D)
+
+ : "0" (prev_row), // esi // input regs
+ "1" (row) // edi
+
+ : "%ecx" // clobber list
+#if 0 /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ , "%mm0", "%mm1", "%mm2", "%mm3"
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ break; // end 6 bpp
+
+ case 4:
+ {
+ _ActiveMask.use = 0x00000000ffffffffLL;
+
+ __asm__ __volatile__ (
+ "movl _dif, %%ecx \n\t"
+// preload "movl row, %%edi \n\t"
+// preload "movl prev_row, %%esi \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%%edi,%%ecx,), %%mm1 \n\t" // only time should need to read
+ // a=Raw(x-bpp) bytes
+ "paeth_4lp: \n\t"
+ // do first set of 4 bytes
+ "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes
+ "punpckhbw %%mm0, %%mm1 \n\t" // unpack Low bytes of a
+ "movq (%%esi,%%ecx,), %%mm2 \n\t" // load b=Prior(x)
+ "punpcklbw %%mm0, %%mm2 \n\t" // unpack High bytes of b
+ // pav = p - a = (a + b - c) - a = b - c
+ "movq %%mm2, %%mm4 \n\t"
+ "punpckhbw %%mm0, %%mm3 \n\t" // unpack High bytes of c
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movq %%mm1, %%mm5 \n\t"
+ "psubw %%mm3, %%mm4 \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ "movq %%mm4, %%mm6 \n\t"
+ "psubw %%mm3, %%mm5 \n\t"
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0
+ "paddw %%mm5, %%mm6 \n\t"
+ "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0
+ "psubw %%mm0, %%mm4 \n\t"
+ "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0
+ "psubw %%mm0, %%mm4 \n\t"
+ "psubw %%mm7, %%mm5 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0
+ "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "psubw %%mm7, %%mm5 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ // test pa <= pb
+ "movq %%mm4, %%mm7 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb?
+ "movq %%mm7, %%mm0 \n\t"
+ // use mm7 mask to merge pa & pb
+ "pand %%mm7, %%mm5 \n\t"
+ // use mm0 mask copy to merge a & b
+ "pand %%mm0, %%mm2 \n\t"
+ "pandn %%mm4, %%mm7 \n\t"
+ "pandn %%mm1, %%mm0 \n\t"
+ "paddw %%mm5, %%mm7 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+ // test ((pa <= pb)? pa:pb) <= pc
+ "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc?
+ "pxor %%mm1, %%mm1 \n\t"
+ "pand %%mm7, %%mm3 \n\t"
+ "pandn %%mm0, %%mm7 \n\t"
+ "paddw %%mm3, %%mm7 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "packuswb %%mm1, %%mm7 \n\t"
+ "movq (%%esi,%%ecx,), %%mm3 \n\t" // load c=Prior(x-bpp)
+ "pand _ActiveMask, %%mm7 \n\t"
+ "movq %%mm3, %%mm2 \n\t" // load b=Prior(x) step 1
+ "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor with Raw(x)
+ "punpcklbw %%mm0, %%mm3 \n\t" // unpack High bytes of c
+ "movq %%mm7, (%%edi,%%ecx,) \n\t" // write back updated value
+ "movq %%mm7, %%mm1 \n\t" // now mm1 will be used as Raw(x-bpp)
+ // do second set of 4 bytes
+ "punpckhbw %%mm0, %%mm2 \n\t" // unpack Low bytes of b
+ "punpcklbw %%mm0, %%mm1 \n\t" // unpack Low bytes of a
+ // pav = p - a = (a + b - c) - a = b - c
+ "movq %%mm2, %%mm4 \n\t"
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movq %%mm1, %%mm5 \n\t"
+ "psubw %%mm3, %%mm4 \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ "movq %%mm4, %%mm6 \n\t"
+ "psubw %%mm3, %%mm5 \n\t"
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0
+ "paddw %%mm5, %%mm6 \n\t"
+ "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0
+ "psubw %%mm0, %%mm4 \n\t"
+ "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0
+ "psubw %%mm0, %%mm4 \n\t"
+ "psubw %%mm7, %%mm5 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0
+ "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "psubw %%mm7, %%mm5 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ // test pa <= pb
+ "movq %%mm4, %%mm7 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb?
+ "movq %%mm7, %%mm0 \n\t"
+ // use mm7 mask to merge pa & pb
+ "pand %%mm7, %%mm5 \n\t"
+ // use mm0 mask copy to merge a & b
+ "pand %%mm0, %%mm2 \n\t"
+ "pandn %%mm4, %%mm7 \n\t"
+ "pandn %%mm1, %%mm0 \n\t"
+ "paddw %%mm5, %%mm7 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+ // test ((pa <= pb)? pa:pb) <= pc
+ "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc?
+ "pxor %%mm1, %%mm1 \n\t"
+ "pand %%mm7, %%mm3 \n\t"
+ "pandn %%mm0, %%mm7 \n\t"
+ "pxor %%mm1, %%mm1 \n\t"
+ "paddw %%mm3, %%mm7 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ // step ecx to next set of 8 bytes and repeat loop til done
+ "addl $8, %%ecx \n\t"
+ "packuswb %%mm7, %%mm1 \n\t"
+ "paddb -8(%%edi,%%ecx,), %%mm1 \n\t" // add predictor with Raw(x)
+ "cmpl _MMXLength, %%ecx \n\t"
+ "movq %%mm1, -8(%%edi,%%ecx,) \n\t" // write back updated value
+ // mm1 will be used as Raw(x-bpp) next loop
+ "jb paeth_4lp \n\t"
+
+ : "=S" (dummy_value_S), // output regs (dummy)
+ "=D" (dummy_value_D)
+
+ : "0" (prev_row), // esi // input regs
+ "1" (row) // edi
+
+ : "%ecx" // clobber list
+#if 0 /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ , "%mm0", "%mm1", "%mm2", "%mm3"
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ break; // end 4 bpp
+
+ case 8: // bpp == 8
+ {
+ _ActiveMask.use = 0x00000000ffffffffLL;
+
+ __asm__ __volatile__ (
+ "movl _dif, %%ecx \n\t"
+// preload "movl row, %%edi \n\t"
+// preload "movl prev_row, %%esi \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%%edi,%%ecx,), %%mm1 \n\t" // only time should need to read
+ // a=Raw(x-bpp) bytes
+ "paeth_8lp: \n\t"
+ // do first set of 4 bytes
+ "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes
+ "punpcklbw %%mm0, %%mm1 \n\t" // unpack Low bytes of a
+ "movq (%%esi,%%ecx,), %%mm2 \n\t" // load b=Prior(x)
+ "punpcklbw %%mm0, %%mm2 \n\t" // unpack Low bytes of b
+ // pav = p - a = (a + b - c) - a = b - c
+ "movq %%mm2, %%mm4 \n\t"
+ "punpcklbw %%mm0, %%mm3 \n\t" // unpack Low bytes of c
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movq %%mm1, %%mm5 \n\t"
+ "psubw %%mm3, %%mm4 \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ "movq %%mm4, %%mm6 \n\t"
+ "psubw %%mm3, %%mm5 \n\t"
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0
+ "paddw %%mm5, %%mm6 \n\t"
+ "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0
+ "psubw %%mm0, %%mm4 \n\t"
+ "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0
+ "psubw %%mm0, %%mm4 \n\t"
+ "psubw %%mm7, %%mm5 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0
+ "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "psubw %%mm7, %%mm5 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ // test pa <= pb
+ "movq %%mm4, %%mm7 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb?
+ "movq %%mm7, %%mm0 \n\t"
+ // use mm7 mask to merge pa & pb
+ "pand %%mm7, %%mm5 \n\t"
+ // use mm0 mask copy to merge a & b
+ "pand %%mm0, %%mm2 \n\t"
+ "pandn %%mm4, %%mm7 \n\t"
+ "pandn %%mm1, %%mm0 \n\t"
+ "paddw %%mm5, %%mm7 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+ // test ((pa <= pb)? pa:pb) <= pc
+ "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc?
+ "pxor %%mm1, %%mm1 \n\t"
+ "pand %%mm7, %%mm3 \n\t"
+ "pandn %%mm0, %%mm7 \n\t"
+ "paddw %%mm3, %%mm7 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "packuswb %%mm1, %%mm7 \n\t"
+ "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes
+ "pand _ActiveMask, %%mm7 \n\t"
+ "movq (%%esi,%%ecx,), %%mm2 \n\t" // load b=Prior(x)
+ "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor with Raw(x)
+ "punpckhbw %%mm0, %%mm3 \n\t" // unpack High bytes of c
+ "movq %%mm7, (%%edi,%%ecx,) \n\t" // write back updated value
+ "movq -8(%%edi,%%ecx,), %%mm1 \n\t" // read a=Raw(x-bpp) bytes
+
+ // do second set of 4 bytes
+ "punpckhbw %%mm0, %%mm2 \n\t" // unpack High bytes of b
+ "punpckhbw %%mm0, %%mm1 \n\t" // unpack High bytes of a
+ // pav = p - a = (a + b - c) - a = b - c
+ "movq %%mm2, %%mm4 \n\t"
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movq %%mm1, %%mm5 \n\t"
+ "psubw %%mm3, %%mm4 \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ "movq %%mm4, %%mm6 \n\t"
+ "psubw %%mm3, %%mm5 \n\t"
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0
+ "paddw %%mm5, %%mm6 \n\t"
+ "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0
+ "psubw %%mm0, %%mm4 \n\t"
+ "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0
+ "psubw %%mm0, %%mm4 \n\t"
+ "psubw %%mm7, %%mm5 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0
+ "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "psubw %%mm7, %%mm5 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ // test pa <= pb
+ "movq %%mm4, %%mm7 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb?
+ "movq %%mm7, %%mm0 \n\t"
+ // use mm7 mask to merge pa & pb
+ "pand %%mm7, %%mm5 \n\t"
+ // use mm0 mask copy to merge a & b
+ "pand %%mm0, %%mm2 \n\t"
+ "pandn %%mm4, %%mm7 \n\t"
+ "pandn %%mm1, %%mm0 \n\t"
+ "paddw %%mm5, %%mm7 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+ // test ((pa <= pb)? pa:pb) <= pc
+ "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc?
+ "pxor %%mm1, %%mm1 \n\t"
+ "pand %%mm7, %%mm3 \n\t"
+ "pandn %%mm0, %%mm7 \n\t"
+ "pxor %%mm1, %%mm1 \n\t"
+ "paddw %%mm3, %%mm7 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ // step ecx to next set of 8 bytes and repeat loop til done
+ "addl $8, %%ecx \n\t"
+ "packuswb %%mm7, %%mm1 \n\t"
+ "paddb -8(%%edi,%%ecx,), %%mm1 \n\t" // add Paeth predictor with Raw(x)
+ "cmpl _MMXLength, %%ecx \n\t"
+ "movq %%mm1, -8(%%edi,%%ecx,) \n\t" // write back updated value
+ // mm1 will be used as Raw(x-bpp) next loop
+ "jb paeth_8lp \n\t"
+
+ : "=S" (dummy_value_S), // output regs (dummy)
+ "=D" (dummy_value_D)
+
+ : "0" (prev_row), // esi // input regs
+ "1" (row) // edi
+
+ : "%ecx" // clobber list
+#if 0 /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
+ , "%mm0", "%mm1", "%mm2", "%mm3"
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ break; // end 8 bpp
+
+ case 1: // bpp = 1
+ case 2: // bpp = 2
+ default: // bpp > 8
+ {
+ __asm__ __volatile__ (
+#ifdef __PIC__
+ "pushl %%ebx \n\t" // save Global Offset Table index
+#endif
+ "movl _dif, %%ebx \n\t"
+ "cmpl _FullLength, %%ebx \n\t"
+ "jnb paeth_dend \n\t"
+
+// preload "movl row, %%edi \n\t"
+// preload "movl prev_row, %%esi \n\t"
+ // do Paeth decode for remaining bytes
+ "movl %%ebx, %%edx \n\t"
+// preload "subl bpp, %%edx \n\t" // (bpp is preloaded into ecx)
+ "subl %%ecx, %%edx \n\t" // edx = ebx - bpp
+ "xorl %%ecx, %%ecx \n\t" // zero ecx before using cl & cx
+
+ "paeth_dlp: \n\t"
+ "xorl %%eax, %%eax \n\t"
+ // pav = p - a = (a + b - c) - a = b - c
+ "movb (%%esi,%%ebx,), %%al \n\t" // load Prior(x) into al
+ "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl
+ "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp)
+ "movl %%eax, _patemp \n\t" // Save pav for later use
+ "xorl %%eax, %%eax \n\t"
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movb (%%edi,%%edx,), %%al \n\t" // load Raw(x-bpp) into al
+ "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp)
+ "movl %%eax, %%ecx \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ "addl _patemp, %%eax \n\t" // pcv = pav + pbv
+ // pc = abs(pcv)
+ "testl $0x80000000, %%eax \n\t"
+ "jz paeth_dpca \n\t"
+ "negl %%eax \n\t" // reverse sign of neg values
+
+ "paeth_dpca: \n\t"
+ "movl %%eax, _pctemp \n\t" // save pc for later use
+ // pb = abs(pbv)
+ "testl $0x80000000, %%ecx \n\t"
+ "jz paeth_dpba \n\t"
+ "negl %%ecx \n\t" // reverse sign of neg values
+
+ "paeth_dpba: \n\t"
+ "movl %%ecx, _pbtemp \n\t" // save pb for later use
+ // pa = abs(pav)
+ "movl _patemp, %%eax \n\t"
+ "testl $0x80000000, %%eax \n\t"
+ "jz paeth_dpaa \n\t"
+ "negl %%eax \n\t" // reverse sign of neg values
+
+ "paeth_dpaa: \n\t"
+ "movl %%eax, _patemp \n\t" // save pa for later use
+ // test if pa <= pb
+ "cmpl %%ecx, %%eax \n\t"
+ "jna paeth_dabb \n\t"
+ // pa > pb; now test if pb <= pc
+ "cmpl _pctemp, %%ecx \n\t"
+ "jna paeth_dbbc \n\t"
+ // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl
+ "jmp paeth_dpaeth \n\t"
+
+ "paeth_dbbc: \n\t"
+ // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
+ "movb (%%esi,%%ebx,), %%cl \n\t" // load Prior(x) into cl
+ "jmp paeth_dpaeth \n\t"
+
+ "paeth_dabb: \n\t"
+ // pa <= pb; now test if pa <= pc
+ "cmpl _pctemp, %%eax \n\t"
+ "jna paeth_dabc \n\t"
+ // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl
+ "jmp paeth_dpaeth \n\t"
+
+ "paeth_dabc: \n\t"
+ // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
+ "movb (%%edi,%%edx,), %%cl \n\t" // load Raw(x-bpp) into cl
+
+ "paeth_dpaeth: \n\t"
+ "incl %%ebx \n\t"
+ "incl %%edx \n\t"
+ // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
+ "addb %%cl, -1(%%edi,%%ebx,) \n\t"
+ "cmpl _FullLength, %%ebx \n\t"
+ "jb paeth_dlp \n\t"
+
+ "paeth_dend: \n\t"
+#ifdef __PIC__
+ "popl %%ebx \n\t" // index to Global Offset Table
+#endif
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (bpp), // ecx // input regs
+ "1" (prev_row), // esi
+ "2" (row) // edi
+
+ : "%eax", "%edx" // clobber list
+#ifndef __PIC__
+ , "%ebx"
+#endif
+ );
+ }
+ return; // No need to go further with this one
+
+ } // end switch (bpp)
+
+ __asm__ __volatile__ (
+ // MMX acceleration complete; now do clean-up
+ // check if any remaining bytes left to decode
+#ifdef __PIC__
+ "pushl %%ebx \n\t" // save index to Global Offset Table
+#endif
+ "movl _MMXLength, %%ebx \n\t"
+ "cmpl _FullLength, %%ebx \n\t"
+ "jnb paeth_end \n\t"
+//pre "movl row, %%edi \n\t"
+//pre "movl prev_row, %%esi \n\t"
+ // do Paeth decode for remaining bytes
+ "movl %%ebx, %%edx \n\t"
+//pre "subl bpp, %%edx \n\t" // (bpp is preloaded into ecx)
+ "subl %%ecx, %%edx \n\t" // edx = ebx - bpp
+ "xorl %%ecx, %%ecx \n\t" // zero ecx before using cl & cx below
+
+ "paeth_lp2: \n\t"
+ "xorl %%eax, %%eax \n\t"
+ // pav = p - a = (a + b - c) - a = b - c
+ "movb (%%esi,%%ebx,), %%al \n\t" // load Prior(x) into al
+ "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl
+ "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp)
+ "movl %%eax, _patemp \n\t" // Save pav for later use
+ "xorl %%eax, %%eax \n\t"
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movb (%%edi,%%edx,), %%al \n\t" // load Raw(x-bpp) into al
+ "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp)
+ "movl %%eax, %%ecx \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ "addl _patemp, %%eax \n\t" // pcv = pav + pbv
+ // pc = abs(pcv)
+ "testl $0x80000000, %%eax \n\t"
+ "jz paeth_pca2 \n\t"
+ "negl %%eax \n\t" // reverse sign of neg values
+
+ "paeth_pca2: \n\t"
+ "movl %%eax, _pctemp \n\t" // save pc for later use
+ // pb = abs(pbv)
+ "testl $0x80000000, %%ecx \n\t"
+ "jz paeth_pba2 \n\t"
+ "negl %%ecx \n\t" // reverse sign of neg values
+
+ "paeth_pba2: \n\t"
+ "movl %%ecx, _pbtemp \n\t" // save pb for later use
+ // pa = abs(pav)
+ "movl _patemp, %%eax \n\t"
+ "testl $0x80000000, %%eax \n\t"
+ "jz paeth_paa2 \n\t"
+ "negl %%eax \n\t" // reverse sign of neg values
+
+ "paeth_paa2: \n\t"
+ "movl %%eax, _patemp \n\t" // save pa for later use
+ // test if pa <= pb
+ "cmpl %%ecx, %%eax \n\t"
+ "jna paeth_abb2 \n\t"
+ // pa > pb; now test if pb <= pc
+ "cmpl _pctemp, %%ecx \n\t"
+ "jna paeth_bbc2 \n\t"
+ // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl
+ "jmp paeth_paeth2 \n\t"
+
+ "paeth_bbc2: \n\t"
+ // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
+ "movb (%%esi,%%ebx,), %%cl \n\t" // load Prior(x) into cl
+ "jmp paeth_paeth2 \n\t"
+
+ "paeth_abb2: \n\t"
+ // pa <= pb; now test if pa <= pc
+ "cmpl _pctemp, %%eax \n\t"
+ "jna paeth_abc2 \n\t"
+ // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl
+ "jmp paeth_paeth2 \n\t"
+
+ "paeth_abc2: \n\t"
+ // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
+ "movb (%%edi,%%edx,), %%cl \n\t" // load Raw(x-bpp) into cl
+
+ "paeth_paeth2: \n\t"
+ "incl %%ebx \n\t"
+ "incl %%edx \n\t"
+ // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
+ "addb %%cl, -1(%%edi,%%ebx,) \n\t"
+ "cmpl _FullLength, %%ebx \n\t"
+ "jb paeth_lp2 \n\t"
+
+ "paeth_end: \n\t"
+ "EMMS \n\t" // end MMX; prep for poss. FP instrs.
+#ifdef __PIC__
+ "popl %%ebx \n\t" // restore index to Global Offset Table
+#endif
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (bpp), // ecx // input regs
+ "1" (prev_row), // esi
+ "2" (row) // edi
+
+ : "%eax", "%edx" // clobber list (no input regs!)
+#ifndef __PIC__
+ , "%ebx"
+#endif
+ );
+
+} /* end png_read_filter_row_mmx_paeth() */
+#endif
+
+
+
+
+#ifdef PNG_THREAD_UNSAFE_OK
+//===========================================================================//
+// //
+// P N G _ R E A D _ F I L T E R _ R O W _ M M X _ S U B //
+// //
+//===========================================================================//
+
+// Optimized code for PNG Sub filter decoder
+
+static void /* PRIVATE */
+png_read_filter_row_mmx_sub(png_row_infop row_info, png_bytep row)
+{
+ int bpp;
+ int dummy_value_a;
+ int dummy_value_D;
+
+ bpp = (row_info->pixel_depth + 7) >> 3; // calc number of bytes per pixel
+ _FullLength = row_info->rowbytes - bpp; // number of bytes to filter
+
+ __asm__ __volatile__ (
+//pre "movl row, %%edi \n\t"
+ "movl %%edi, %%esi \n\t" // lp = row
+//pre "movl bpp, %%eax \n\t"
+ "addl %%eax, %%edi \n\t" // rp = row + bpp
+//irr "xorl %%eax, %%eax \n\t"
+ // get # of bytes to alignment
+ "movl %%edi, _dif \n\t" // take start of row
+ "addl $0xf, _dif \n\t" // add 7 + 8 to incr past
+ // alignment boundary
+ "xorl %%ecx, %%ecx \n\t"
+ "andl $0xfffffff8, _dif \n\t" // mask to alignment boundary
+ "subl %%edi, _dif \n\t" // subtract from start ==> value
+ "jz sub_go \n\t" // ecx at alignment
+
+ "sub_lp1: \n\t" // fix alignment
+ "movb (%%esi,%%ecx,), %%al \n\t"
+ "addb %%al, (%%edi,%%ecx,) \n\t"
+ "incl %%ecx \n\t"
+ "cmpl _dif, %%ecx \n\t"
+ "jb sub_lp1 \n\t"
+
+ "sub_go: \n\t"
+ "movl _FullLength, %%eax \n\t"
+ "movl %%eax, %%edx \n\t"
+ "subl %%ecx, %%edx \n\t" // subtract alignment fix
+ "andl $0x00000007, %%edx \n\t" // calc bytes over mult of 8
+ "subl %%edx, %%eax \n\t" // drop over bytes from length
+ "movl %%eax, _MMXLength \n\t"
+
+ : "=a" (dummy_value_a), // 0 // output regs (dummy)
+ "=D" (dummy_value_D) // 1
+
+ : "0" (bpp), // eax // input regs
+ "1" (row) // edi
+
+ : "%ebx", "%ecx", "%edx" // clobber list
+ , "%esi"
+
+#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
+ , "%mm0", "%mm1", "%mm2", "%mm3"
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+
+ // now do the math for the rest of the row
+ switch (bpp)
+ {
+ case 3:
+ {
+ _ActiveMask.use = 0x0000ffffff000000LL;
+ _ShiftBpp.use = 24; // == 3 * 8
+ _ShiftRem.use = 40; // == 64 - 24
+
+ __asm__ __volatile__ (
+// preload "movl row, %%edi \n\t"
+ "movq _ActiveMask, %%mm7 \n\t" // load _ActiveMask for 2nd
+ // active byte group
+ "movl %%edi, %%esi \n\t" // lp = row
+// preload "movl bpp, %%eax \n\t"
+ "addl %%eax, %%edi \n\t" // rp = row + bpp
+ "movq %%mm7, %%mm6 \n\t"
+ "movl _dif, %%edx \n\t"
+ "psllq _ShiftBpp, %%mm6 \n\t" // move mask in mm6 to cover
+ // 3rd active byte group
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%%edi,%%edx,), %%mm1 \n\t"
+
+ "sub_3lp: \n\t" // shift data for adding first
+ "psrlq _ShiftRem, %%mm1 \n\t" // bpp bytes (no need for mask;
+ // shift clears inactive bytes)
+ // add 1st active group
+ "movq (%%edi,%%edx,), %%mm0 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+
+ // add 2nd active group
+ "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1
+ "psllq _ShiftBpp, %%mm1 \n\t" // shift data to pos. correctly
+ "pand %%mm7, %%mm1 \n\t" // mask to use 2nd active group
+ "paddb %%mm1, %%mm0 \n\t"
+
+ // add 3rd active group
+ "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1
+ "psllq _ShiftBpp, %%mm1 \n\t" // shift data to pos. correctly
+ "pand %%mm6, %%mm1 \n\t" // mask to use 3rd active group
+ "addl $8, %%edx \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+
+ "cmpl _MMXLength, %%edx \n\t"
+ "movq %%mm0, -8(%%edi,%%edx,) \n\t" // write updated Raws to array
+ "movq %%mm0, %%mm1 \n\t" // prep 1st add at top of loop
+ "jb sub_3lp \n\t"
+
+ : "=a" (dummy_value_a), // 0 // output regs (dummy)
+ "=D" (dummy_value_D) // 1
+
+ : "0" (bpp), // eax // input regs
+ "1" (row) // edi
+
+ : "%edx", "%esi" // clobber list
+#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
+ , "%mm0", "%mm1", "%mm6", "%mm7"
+#endif
+ );
+ }
+ break;
+
+ case 1:
+ {
+ __asm__ __volatile__ (
+ "movl _dif, %%edx \n\t"
+// preload "movl row, %%edi \n\t"
+ "cmpl _FullLength, %%edx \n\t"
+ "jnb sub_1end \n\t"
+ "movl %%edi, %%esi \n\t" // lp = row
+ "xorl %%eax, %%eax \n\t"
+// preload "movl bpp, %%eax \n\t"
+ "addl %%eax, %%edi \n\t" // rp = row + bpp
+
+ "sub_1lp: \n\t"
+ "movb (%%esi,%%edx,), %%al \n\t"
+ "addb %%al, (%%edi,%%edx,) \n\t"
+ "incl %%edx \n\t"
+ "cmpl _FullLength, %%edx \n\t"
+ "jb sub_1lp \n\t"
+
+ "sub_1end: \n\t"
+
+ : "=a" (dummy_value_a), // 0 // output regs (dummy)
+ "=D" (dummy_value_D) // 1
+
+ : "0" (bpp), // eax // input regs
+ "1" (row) // edi
+
+ : "%edx", "%esi" // clobber list
+ );
+ }
+ return;
+
+ case 6:
+ case 4:
+ //case 7: // GRR BOGUS
+ //case 5: // GRR BOGUS
+ {
+ _ShiftBpp.use = bpp << 3;
+ _ShiftRem.use = 64 - _ShiftBpp.use;
+
+ __asm__ __volatile__ (
+// preload "movl row, %%edi \n\t"
+ "movl _dif, %%edx \n\t"
+ "movl %%edi, %%esi \n\t" // lp = row
+// preload "movl bpp, %%eax \n\t"
+ "addl %%eax, %%edi \n\t" // rp = row + bpp
+
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%%edi,%%edx,), %%mm1 \n\t"
+
+ "sub_4lp: \n\t" // shift data for adding first
+ "psrlq _ShiftRem, %%mm1 \n\t" // bpp bytes (no need for mask;
+ // shift clears inactive bytes)
+ "movq (%%edi,%%edx,), %%mm0 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+
+ // add 2nd active group
+ "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1
+ "psllq _ShiftBpp, %%mm1 \n\t" // shift data to pos. correctly
+ "addl $8, %%edx \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+
+ "cmpl _MMXLength, %%edx \n\t"
+ "movq %%mm0, -8(%%edi,%%edx,) \n\t"
+ "movq %%mm0, %%mm1 \n\t" // prep 1st add at top of loop
+ "jb sub_4lp \n\t"
+
+ : "=a" (dummy_value_a), // 0 // output regs (dummy)
+ "=D" (dummy_value_D) // 1
+
+ : "0" (bpp), // eax // input regs
+ "1" (row) // edi
+
+ : "%edx", "%esi" // clobber list
+#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
+ , "%mm0", "%mm1"
+#endif
+ );
+ }
+ break;
+
+ case 2:
+ {
+ _ActiveMask.use = 0x00000000ffff0000LL;
+ _ShiftBpp.use = 16; // == 2 * 8
+ _ShiftRem.use = 48; // == 64 - 16
+
+ __asm__ __volatile__ (
+ "movq _ActiveMask, %%mm7 \n\t" // load _ActiveMask for 2nd
+ // active byte group
+ "movl _dif, %%edx \n\t"
+ "movq %%mm7, %%mm6 \n\t"
+// preload "movl row, %%edi \n\t"
+ "psllq _ShiftBpp, %%mm6 \n\t" // move mask in mm6 to cover
+ // 3rd active byte group
+ "movl %%edi, %%esi \n\t" // lp = row
+ "movq %%mm6, %%mm5 \n\t"
+// preload "movl bpp, %%eax \n\t"
+ "addl %%eax, %%edi \n\t" // rp = row + bpp
+ "psllq _ShiftBpp, %%mm5 \n\t" // move mask in mm5 to cover
+ // 4th active byte group
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%%edi,%%edx,), %%mm1 \n\t"
+
+ "sub_2lp: \n\t" // shift data for adding first
+ "psrlq _ShiftRem, %%mm1 \n\t" // bpp bytes (no need for mask;
+ // shift clears inactive bytes)
+ // add 1st active group
+ "movq (%%edi,%%edx,), %%mm0 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+
+ // add 2nd active group
+ "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1
+ "psllq _ShiftBpp, %%mm1 \n\t" // shift data to pos. correctly
+ "pand %%mm7, %%mm1 \n\t" // mask to use 2nd active group
+ "paddb %%mm1, %%mm0 \n\t"
+
+ // add 3rd active group
+ "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1
+ "psllq _ShiftBpp, %%mm1 \n\t" // shift data to pos. correctly
+ "pand %%mm6, %%mm1 \n\t" // mask to use 3rd active group
+ "paddb %%mm1, %%mm0 \n\t"
+
+ // add 4th active group
+ "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1
+ "psllq _ShiftBpp, %%mm1 \n\t" // shift data to pos. correctly
+ "pand %%mm5, %%mm1 \n\t" // mask to use 4th active group
+ "addl $8, %%edx \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+ "cmpl _MMXLength, %%edx \n\t"
+ "movq %%mm0, -8(%%edi,%%edx,) \n\t" // write updated Raws to array
+ "movq %%mm0, %%mm1 \n\t" // prep 1st add at top of loop
+ "jb sub_2lp \n\t"
+
+ : "=a" (dummy_value_a), // 0 // output regs (dummy)
+ "=D" (dummy_value_D) // 1
+
+ : "0" (bpp), // eax // input regs
+ "1" (row) // edi
+
+ : "%edx", "%esi" // clobber list
+#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
+ , "%mm0", "%mm1", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ break;
+
+ case 8:
+ {
+ __asm__ __volatile__ (
+// preload "movl row, %%edi \n\t"
+ "movl _dif, %%edx \n\t"
+ "movl %%edi, %%esi \n\t" // lp = row
+// preload "movl bpp, %%eax \n\t"
+ "addl %%eax, %%edi \n\t" // rp = row + bpp
+ "movl _MMXLength, %%ecx \n\t"
+
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%%edi,%%edx,), %%mm7 \n\t"
+ "andl $0x0000003f, %%ecx \n\t" // calc bytes over mult of 64
+
+ "sub_8lp: \n\t"
+ "movq (%%edi,%%edx,), %%mm0 \n\t" // load Sub(x) for 1st 8 bytes
+ "paddb %%mm7, %%mm0 \n\t"
+ "movq 8(%%edi,%%edx,), %%mm1 \n\t" // load Sub(x) for 2nd 8 bytes
+ "movq %%mm0, (%%edi,%%edx,) \n\t" // write Raw(x) for 1st 8 bytes
+
+ // Now mm0 will be used as Raw(x-bpp) for the 2nd group of 8 bytes.
+ // This will be repeated for each group of 8 bytes with the 8th
+ // group being used as the Raw(x-bpp) for the 1st group of the
+ // next loop.
+
+ "paddb %%mm0, %%mm1 \n\t"
+ "movq 16(%%edi,%%edx,), %%mm2 \n\t" // load Sub(x) for 3rd 8 bytes
+ "movq %%mm1, 8(%%edi,%%edx,) \n\t" // write Raw(x) for 2nd 8 bytes
+ "paddb %%mm1, %%mm2 \n\t"
+ "movq 24(%%edi,%%edx,), %%mm3 \n\t" // load Sub(x) for 4th 8 bytes
+ "movq %%mm2, 16(%%edi,%%edx,) \n\t" // write Raw(x) for 3rd 8 bytes
+ "paddb %%mm2, %%mm3 \n\t"
+ "movq 32(%%edi,%%edx,), %%mm4 \n\t" // load Sub(x) for 5th 8 bytes
+ "movq %%mm3, 24(%%edi,%%edx,) \n\t" // write Raw(x) for 4th 8 bytes
+ "paddb %%mm3, %%mm4 \n\t"
+ "movq 40(%%edi,%%edx,), %%mm5 \n\t" // load Sub(x) for 6th 8 bytes
+ "movq %%mm4, 32(%%edi,%%edx,) \n\t" // write Raw(x) for 5th 8 bytes
+ "paddb %%mm4, %%mm5 \n\t"
+ "movq 48(%%edi,%%edx,), %%mm6 \n\t" // load Sub(x) for 7th 8 bytes
+ "movq %%mm5, 40(%%edi,%%edx,) \n\t" // write Raw(x) for 6th 8 bytes
+ "paddb %%mm5, %%mm6 \n\t"
+ "movq 56(%%edi,%%edx,), %%mm7 \n\t" // load Sub(x) for 8th 8 bytes
+ "movq %%mm6, 48(%%edi,%%edx,) \n\t" // write Raw(x) for 7th 8 bytes
+ "addl $64, %%edx \n\t"
+ "paddb %%mm6, %%mm7 \n\t"
+ "cmpl %%ecx, %%edx \n\t"
+ "movq %%mm7, -8(%%edi,%%edx,) \n\t" // write Raw(x) for 8th 8 bytes
+ "jb sub_8lp \n\t"
+
+ "cmpl _MMXLength, %%edx \n\t"
+ "jnb sub_8lt8 \n\t"
+
+ "sub_8lpA: \n\t"
+ "movq (%%edi,%%edx,), %%mm0 \n\t"
+ "addl $8, %%edx \n\t"
+ "paddb %%mm7, %%mm0 \n\t"
+ "cmpl _MMXLength, %%edx \n\t"
+ "movq %%mm0, -8(%%edi,%%edx,) \n\t" // -8 to offset early addl edx
+ "movq %%mm0, %%mm7 \n\t" // move calculated Raw(x) data
+ // to mm1 to be new Raw(x-bpp)
+ // for next loop
+ "jb sub_8lpA \n\t"
+
+ "sub_8lt8: \n\t"
+
+ : "=a" (dummy_value_a), // 0 // output regs (dummy)
+ "=D" (dummy_value_D) // 1
+
+ : "0" (bpp), // eax // input regs
+ "1" (row) // edi
+
+ : "%ecx", "%edx", "%esi" // clobber list
+#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
+ , "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ break;
+
+ default: // bpp greater than 8 bytes GRR BOGUS
+ {
+ __asm__ __volatile__ (
+ "movl _dif, %%edx \n\t"
+// preload "movl row, %%edi \n\t"
+ "movl %%edi, %%esi \n\t" // lp = row
+// preload "movl bpp, %%eax \n\t"
+ "addl %%eax, %%edi \n\t" // rp = row + bpp
+
+ "sub_Alp: \n\t"
+ "movq (%%edi,%%edx,), %%mm0 \n\t"
+ "movq (%%esi,%%edx,), %%mm1 \n\t"
+ "addl $8, %%edx \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+ "cmpl _MMXLength, %%edx \n\t"
+ "movq %%mm0, -8(%%edi,%%edx,) \n\t" // mov does not affect flags;
+ // -8 to offset addl edx
+ "jb sub_Alp \n\t"
+
+ : "=a" (dummy_value_a), // 0 // output regs (dummy)
+ "=D" (dummy_value_D) // 1
+
+ : "0" (bpp), // eax // input regs
+ "1" (row) // edi
+
+ : "%edx", "%esi" // clobber list
+#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
+ , "%mm0", "%mm1"
+#endif
+ );
+ }
+ break;
+
+ } // end switch (bpp)
+
+ __asm__ __volatile__ (
+ "movl _MMXLength, %%edx \n\t"
+//pre "movl row, %%edi \n\t"
+ "cmpl _FullLength, %%edx \n\t"
+ "jnb sub_end \n\t"
+
+ "movl %%edi, %%esi \n\t" // lp = row
+//pre "movl bpp, %%eax \n\t"
+ "addl %%eax, %%edi \n\t" // rp = row + bpp
+ "xorl %%eax, %%eax \n\t"
+
+ "sub_lp2: \n\t"
+ "movb (%%esi,%%edx,), %%al \n\t"
+ "addb %%al, (%%edi,%%edx,) \n\t"
+ "incl %%edx \n\t"
+ "cmpl _FullLength, %%edx \n\t"
+ "jb sub_lp2 \n\t"
+
+ "sub_end: \n\t"
+ "EMMS \n\t" // end MMX instructions
+
+ : "=a" (dummy_value_a), // 0 // output regs (dummy)
+ "=D" (dummy_value_D) // 1
+
+ : "0" (bpp), // eax // input regs
+ "1" (row) // edi
+
+ : "%edx", "%esi" // clobber list
+ );
+
+} // end of png_read_filter_row_mmx_sub()
+#endif
+
+
+
+
+//===========================================================================//
+// //
+// P N G _ R E A D _ F I L T E R _ R O W _ M M X _ U P //
+// //
+//===========================================================================//
+
+// Optimized code for PNG Up filter decoder
+
+static void /* PRIVATE */
+png_read_filter_row_mmx_up(png_row_infop row_info, png_bytep row,
+ png_bytep prev_row)
+{
+ png_uint_32 len;
+ int dummy_value_d; // fix 'forbidden register 3 (dx) was spilled' error
+ int dummy_value_S;
+ int dummy_value_D;
+
+ len = row_info->rowbytes; // number of bytes to filter
+
+ __asm__ __volatile__ (
+//pre "movl row, %%edi \n\t"
+ // get # of bytes to alignment
+ "movl %%edi, %%ecx \n\t"
+ "xorl %%ebx, %%ebx \n\t"
+ "addl $0x7, %%ecx \n\t"
+ "xorl %%eax, %%eax \n\t"
+ "andl $0xfffffff8, %%ecx \n\t"
+//pre "movl prev_row, %%esi \n\t"
+ "subl %%edi, %%ecx \n\t"
+ "jz up_go \n\t"
+
+ "up_lp1: \n\t" // fix alignment
+ "movb (%%edi,%%ebx,), %%al \n\t"
+ "addb (%%esi,%%ebx,), %%al \n\t"
+ "incl %%ebx \n\t"
+ "cmpl %%ecx, %%ebx \n\t"
+ "movb %%al, -1(%%edi,%%ebx,) \n\t" // mov does not affect flags; -1 to
+ "jb up_lp1 \n\t" // offset incl ebx
+
+ "up_go: \n\t"
+//pre "movl len, %%edx \n\t"
+ "movl %%edx, %%ecx \n\t"
+ "subl %%ebx, %%edx \n\t" // subtract alignment fix
+ "andl $0x0000003f, %%edx \n\t" // calc bytes over mult of 64
+ "subl %%edx, %%ecx \n\t" // drop over bytes from length
+
+ // unrolled loop - use all MMX registers and interleave to reduce
+ // number of branch instructions (loops) and reduce partial stalls
+ "up_loop: \n\t"
+ "movq (%%esi,%%ebx,), %%mm1 \n\t"
+ "movq (%%edi,%%ebx,), %%mm0 \n\t"
+ "movq 8(%%esi,%%ebx,), %%mm3 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+ "movq 8(%%edi,%%ebx,), %%mm2 \n\t"
+ "movq %%mm0, (%%edi,%%ebx,) \n\t"
+ "paddb %%mm3, %%mm2 \n\t"
+ "movq 16(%%esi,%%ebx,), %%mm5 \n\t"
+ "movq %%mm2, 8(%%edi,%%ebx,) \n\t"
+ "movq 16(%%edi,%%ebx,), %%mm4 \n\t"
+ "movq 24(%%esi,%%ebx,), %%mm7 \n\t"
+ "paddb %%mm5, %%mm4 \n\t"
+ "movq 24(%%edi,%%ebx,), %%mm6 \n\t"
+ "movq %%mm4, 16(%%edi,%%ebx,) \n\t"
+ "paddb %%mm7, %%mm6 \n\t"
+ "movq 32(%%esi,%%ebx,), %%mm1 \n\t"
+ "movq %%mm6, 24(%%edi,%%ebx,) \n\t"
+ "movq 32(%%edi,%%ebx,), %%mm0 \n\t"
+ "movq 40(%%esi,%%ebx,), %%mm3 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+ "movq 40(%%edi,%%ebx,), %%mm2 \n\t"
+ "movq %%mm0, 32(%%edi,%%ebx,) \n\t"
+ "paddb %%mm3, %%mm2 \n\t"
+ "movq 48(%%esi,%%ebx,), %%mm5 \n\t"
+ "movq %%mm2, 40(%%edi,%%ebx,) \n\t"
+ "movq 48(%%edi,%%ebx,), %%mm4 \n\t"
+ "movq 56(%%esi,%%ebx,), %%mm7 \n\t"
+ "paddb %%mm5, %%mm4 \n\t"
+ "movq 56(%%edi,%%ebx,), %%mm6 \n\t"
+ "movq %%mm4, 48(%%edi,%%ebx,) \n\t"
+ "addl $64, %%ebx \n\t"
+ "paddb %%mm7, %%mm6 \n\t"
+ "cmpl %%ecx, %%ebx \n\t"
+ "movq %%mm6, -8(%%edi,%%ebx,) \n\t" // (+56)movq does not affect flags;
+ "jb up_loop \n\t" // -8 to offset addl ebx
+
+ "cmpl $0, %%edx \n\t" // test for bytes over mult of 64
+ "jz up_end \n\t"
+
+ "cmpl $8, %%edx \n\t" // test for less than 8 bytes
+ "jb up_lt8 \n\t" // [added by lcreeve@netins.net]
+
+ "addl %%edx, %%ecx \n\t"
+ "andl $0x00000007, %%edx \n\t" // calc bytes over mult of 8
+ "subl %%edx, %%ecx \n\t" // drop over bytes from length
+ "jz up_lt8 \n\t"
+
+ "up_lpA: \n\t" // use MMX regs to update 8 bytes sim.
+ "movq (%%esi,%%ebx,), %%mm1 \n\t"
+ "movq (%%edi,%%ebx,), %%mm0 \n\t"
+ "addl $8, %%ebx \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+ "cmpl %%ecx, %%ebx \n\t"
+ "movq %%mm0, -8(%%edi,%%ebx,) \n\t" // movq does not affect flags; -8 to
+ "jb up_lpA \n\t" // offset add ebx
+ "cmpl $0, %%edx \n\t" // test for bytes over mult of 8
+ "jz up_end \n\t"
+
+ "up_lt8: \n\t"
+ "xorl %%eax, %%eax \n\t"
+ "addl %%edx, %%ecx \n\t" // move over byte count into counter
+
+ "up_lp2: \n\t" // use x86 regs for remaining bytes
+ "movb (%%edi,%%ebx,), %%al \n\t"
+ "addb (%%esi,%%ebx,), %%al \n\t"
+ "incl %%ebx \n\t"
+ "cmpl %%ecx, %%ebx \n\t"
+ "movb %%al, -1(%%edi,%%ebx,) \n\t" // mov does not affect flags; -1 to
+ "jb up_lp2 \n\t" // offset inc ebx
+
+ "up_end: \n\t"
+ "EMMS \n\t" // conversion of filtered row complete
+
+ : "=d" (dummy_value_d), // 0 // output regs (dummy)
+ "=S" (dummy_value_S), // 1
+ "=D" (dummy_value_D) // 2
+
+ : "0" (len), // edx // input regs
+ "1" (prev_row), // esi
+ "2" (row) // edi
+
+ : "%eax", "%ebx", "%ecx" // clobber list (no input regs!)
+
+#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
+ , "%mm0", "%mm1", "%mm2", "%mm3"
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+
+} // end of png_read_filter_row_mmx_up()
+
+#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
+
+
+
+
+/*===========================================================================*/
+/* */
+/* P N G _ R E A D _ F I L T E R _ R O W */
+/* */
+/*===========================================================================*/
+
+
+/* Optimized png_read_filter_row routines */
+
+void /* PRIVATE */
+png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep
+ row, png_bytep prev_row, int filter)
+{
+#ifdef PNG_DEBUG
+ char filnm[10];
+#endif
+
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
+/* GRR: these are superseded by png_ptr->asm_flags: */
+#define UseMMX_sub 1 // GRR: converted 20000730
+#define UseMMX_up 1 // GRR: converted 20000729
+#define UseMMX_avg 1 // GRR: converted 20000828 (+ 16-bit bugfix 20000916)
+#define UseMMX_paeth 1 // GRR: converted 20000828
+
+ if (_mmx_supported == 2) {
+ /* this should have happened in png_init_mmx_flags() already */
+ png_warning(png_ptr, "asm_flags may not have been initialized");
+ png_mmx_support();
+ }
+#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
+
+#ifdef PNG_DEBUG
+ png_debug(1, "in png_read_filter_row (pnggccrd.c)\n");
+ switch (filter)
+ {
+ case 0: sprintf(filnm, "none");
+ break;
+ case 1: sprintf(filnm, "sub-%s",
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
+ (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB)? "MMX" :
+#endif
+"x86");
+ break;
+ case 2: sprintf(filnm, "up-%s",
+#ifdef PNG_ASSEMBLER_CODE_SUPPORTED
+ (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP)? "MMX" :
+#endif
+ "x86");
+ break;
+ case 3: sprintf(filnm, "avg-%s",
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
+ (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG)? "MMX" :
+#endif
+ "x86");
+ break;
+ case 4: sprintf(filnm, "Paeth-%s",
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
+ (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH)? "MMX":
+#endif
+"x86");
+ break;
+ default: sprintf(filnm, "unknw");
+ break;
+ }
+ png_debug2(0, "row_number=%5ld, %5s, ", png_ptr->row_number, filnm);
+ png_debug1(0, "row=0x%08lx, ", (unsigned long)row);
+ png_debug2(0, "pixdepth=%2d, bytes=%d, ", (int)row_info->pixel_depth,
+ (int)((row_info->pixel_depth + 7) >> 3));
+ png_debug1(0,"rowbytes=%8ld\n", row_info->rowbytes);
+#endif /* PNG_DEBUG */
+
+ switch (filter)
+ {
+ case PNG_FILTER_VALUE_NONE:
+ break;
+
+ case PNG_FILTER_VALUE_SUB:
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB) &&
+ (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
+ (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
+ {
+ png_read_filter_row_mmx_sub(row_info, row);
+ }
+ else
+#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
+ {
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
+ png_bytep rp = row + bpp;
+ png_bytep lp = row;
+
+ for (i = bpp; i < istop; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
+ rp++;
+ }
+ } /* end !UseMMX_sub */
+ break;
+
+ case PNG_FILTER_VALUE_UP:
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP) &&
+ (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
+ (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
+ {
+ png_read_filter_row_mmx_up(row_info, row, prev_row);
+ }
+ else
+#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
+ {
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+
+ for (i = 0; i < istop; ++i)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
+ rp++;
+ }
+ } /* end !UseMMX_up */
+ break;
+
+ case PNG_FILTER_VALUE_AVG:
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG) &&
+ (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
+ (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
+ {
+ png_read_filter_row_mmx_avg(row_info, row, prev_row);
+ }
+ else
+#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
+ {
+ png_uint_32 i;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+ png_bytep lp = row;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
+ png_uint_32 istop = row_info->rowbytes - bpp;
+
+ for (i = 0; i < bpp; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ ((int)(*pp++) >> 1)) & 0xff);
+ rp++;
+ }
+
+ for (i = 0; i < istop; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ ((int)(*pp++ + *lp++) >> 1)) & 0xff);
+ rp++;
+ }
+ } /* end !UseMMX_avg */
+ break;
+
+ case PNG_FILTER_VALUE_PAETH:
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH) &&
+ (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
+ (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
+ {
+ png_read_filter_row_mmx_paeth(row_info, row, prev_row);
+ }
+ else
+#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
+ {
+ png_uint_32 i;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+ png_bytep lp = row;
+ png_bytep cp = prev_row;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
+ png_uint_32 istop = row_info->rowbytes - bpp;
+
+ for (i = 0; i < bpp; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
+ rp++;
+ }
+
+ for (i = 0; i < istop; i++) /* use leftover rp,pp */
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ a = *lp++;
+ b = *pp++;
+ c = *cp++;
+
+ p = b - c;
+ pc = a - c;
+
+#ifdef PNG_USE_ABS
+ pa = abs(p);
+ pb = abs(pc);
+ pc = abs(p + pc);
+#else
+ pa = p < 0 ? -p : p;
+ pb = pc < 0 ? -pc : pc;
+ pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+#endif
+
+ /*
+ if (pa <= pb && pa <= pc)
+ p = a;
+ else if (pb <= pc)
+ p = b;
+ else
+ p = c;
+ */
+
+ p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
+
+ *rp = (png_byte)(((int)(*rp) + p) & 0xff);
+ rp++;
+ }
+ } /* end !UseMMX_paeth */
+ break;
+
+ default:
+ png_warning(png_ptr, "Ignoring bad row-filter type");
+ *row=0;
+ break;
+ }
+}
+
+#endif /* PNG_HAVE_ASSEMBLER_READ_FILTER_ROW */
+
+
+/*===========================================================================*/
+/* */
+/* P N G _ M M X _ S U P P O R T */
+/* */
+/*===========================================================================*/
+
+/* GRR NOTES: (1) the following code assumes 386 or better (pushfl/popfl)
+ * (2) all instructions compile with gcc 2.7.2.3 and later
+ * (3) the function is moved down here to prevent gcc from
+ * inlining it in multiple places and then barfing be-
+ * cause the ".NOT_SUPPORTED" label is multiply defined
+ * [is there a way to signal that a *single* function should
+ * not be inlined? is there a way to modify the label for
+ * each inlined instance, e.g., by appending _1, _2, etc.?
+ * maybe if don't use leading "." in label name? (nope...sigh)]
+ */
+
+int PNGAPI
+png_mmx_support(void)
+{
+#if defined(PNG_MMX_CODE_SUPPORTED)
+ __asm__ __volatile__ (
+ "pushl %%ebx \n\t" // ebx gets clobbered by CPUID instruction
+ "pushl %%ecx \n\t" // so does ecx...
+ "pushl %%edx \n\t" // ...and edx (but ecx & edx safe on Linux)
+// ".byte 0x66 \n\t" // convert 16-bit pushf to 32-bit pushfd
+// "pushf \n\t" // 16-bit pushf
+ "pushfl \n\t" // save Eflag to stack
+ "popl %%eax \n\t" // get Eflag from stack into eax
+ "movl %%eax, %%ecx \n\t" // make another copy of Eflag in ecx
+ "xorl $0x200000, %%eax \n\t" // toggle ID bit in Eflag (i.e., bit 21)
+ "pushl %%eax \n\t" // save modified Eflag back to stack
+// ".byte 0x66 \n\t" // convert 16-bit popf to 32-bit popfd
+// "popf \n\t" // 16-bit popf
+ "popfl \n\t" // restore modified value to Eflag reg
+ "pushfl \n\t" // save Eflag to stack
+ "popl %%eax \n\t" // get Eflag from stack
+ "xorl %%ecx, %%eax \n\t" // compare new Eflag with original Eflag
+ "jz .NOT_SUPPORTED \n\t" // if same, CPUID instr. is not supported
+
+ "xorl %%eax, %%eax \n\t" // set eax to zero
+// ".byte 0x0f, 0xa2 \n\t" // CPUID instruction (two-byte opcode)
+ "cpuid \n\t" // get the CPU identification info
+ "cmpl $1, %%eax \n\t" // make sure eax return non-zero value
+ "jl .NOT_SUPPORTED \n\t" // if eax is zero, MMX is not supported
+
+ "xorl %%eax, %%eax \n\t" // set eax to zero and...
+ "incl %%eax \n\t" // ...increment eax to 1. This pair is
+ // faster than the instruction "mov eax, 1"
+ "cpuid \n\t" // get the CPU identification info again
+ "andl $0x800000, %%edx \n\t" // mask out all bits but MMX bit (23)
+ "cmpl $0, %%edx \n\t" // 0 = MMX not supported
+ "jz .NOT_SUPPORTED \n\t" // non-zero = yes, MMX IS supported
+
+ "movl $1, %%eax \n\t" // set return value to 1
+ "jmp .RETURN \n\t" // DONE: have MMX support
+
+ ".NOT_SUPPORTED: \n\t" // target label for jump instructions
+ "movl $0, %%eax \n\t" // set return value to 0
+ ".RETURN: \n\t" // target label for jump instructions
+ "movl %%eax, _mmx_supported \n\t" // save in global static variable, too
+ "popl %%edx \n\t" // restore edx
+ "popl %%ecx \n\t" // restore ecx
+ "popl %%ebx \n\t" // restore ebx
+
+// "ret \n\t" // DONE: no MMX support
+ // (fall through to standard C "ret")
+
+ : // output list (none)
+
+ : // any variables used on input (none)
+
+ : "%eax" // clobber list
+// , "%ebx", "%ecx", "%edx" // GRR: we handle these manually
+// , "memory" // if write to a variable gcc thought was in a reg
+// , "cc" // "condition codes" (flag bits)
+ );
+#else
+ _mmx_supported = 0;
+#endif /* PNG_MMX_CODE_SUPPORTED */
+
+ return _mmx_supported;
+}
+
+
+#endif /* PNG_USE_PNGGCCRD */
--- /dev/null
+
+/* pngget.c - retrieval of values from info struct
+ *
+ * libpng 1.2.0 - September 1, 2001
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+png_uint_32 PNGAPI
+png_get_valid(png_structp png_ptr, png_infop info_ptr, png_uint_32 flag)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ return(info_ptr->valid & flag);
+ else
+ return(0);
+}
+
+png_uint_32 PNGAPI
+png_get_rowbytes(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ return(info_ptr->rowbytes);
+ else
+ return(0);
+}
+
+#if defined(PNG_INFO_IMAGE_SUPPORTED)
+png_bytepp PNGAPI
+png_get_rows(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ return(info_ptr->row_pointers);
+ else
+ return(0);
+}
+#endif
+
+#ifdef PNG_EASY_ACCESS_SUPPORTED
+/* easy access to info, added in libpng-0.99 */
+png_uint_32 PNGAPI
+png_get_image_width(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ {
+ return info_ptr->width;
+ }
+ return (0);
+}
+
+png_uint_32 PNGAPI
+png_get_image_height(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ {
+ return info_ptr->height;
+ }
+ return (0);
+}
+
+png_byte PNGAPI
+png_get_bit_depth(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ {
+ return info_ptr->bit_depth;
+ }
+ return (0);
+}
+
+png_byte PNGAPI
+png_get_color_type(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ {
+ return info_ptr->color_type;
+ }
+ return (0);
+}
+
+png_byte PNGAPI
+png_get_filter_type(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ {
+ return info_ptr->filter_type;
+ }
+ return (0);
+}
+
+png_byte PNGAPI
+png_get_interlace_type(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ {
+ return info_ptr->interlace_type;
+ }
+ return (0);
+}
+
+png_byte PNGAPI
+png_get_compression_type(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ {
+ return info_ptr->compression_type;
+ }
+ return (0);
+}
+
+png_uint_32 PNGAPI
+png_get_x_pixels_per_meter(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+#if defined(PNG_pHYs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_pHYs)
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_x_pixels_per_meter");
+ if(info_ptr->phys_unit_type != PNG_RESOLUTION_METER)
+ return (0);
+ else return (info_ptr->x_pixels_per_unit);
+ }
+#else
+ return (0);
+#endif
+ return (0);
+}
+
+png_uint_32 PNGAPI
+png_get_y_pixels_per_meter(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+#if defined(PNG_pHYs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_pHYs)
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_y_pixels_per_meter");
+ if(info_ptr->phys_unit_type != PNG_RESOLUTION_METER)
+ return (0);
+ else return (info_ptr->y_pixels_per_unit);
+ }
+#else
+ return (0);
+#endif
+ return (0);
+}
+
+png_uint_32 PNGAPI
+png_get_pixels_per_meter(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+#if defined(PNG_pHYs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_pHYs)
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_pixels_per_meter");
+ if(info_ptr->phys_unit_type != PNG_RESOLUTION_METER ||
+ info_ptr->x_pixels_per_unit != info_ptr->y_pixels_per_unit)
+ return (0);
+ else return (info_ptr->x_pixels_per_unit);
+ }
+#else
+ return (0);
+#endif
+ return (0);
+}
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+float PNGAPI
+png_get_pixel_aspect_ratio(png_structp png_ptr, png_infop info_ptr)
+ {
+ if (png_ptr != NULL && info_ptr != NULL)
+#if defined(PNG_pHYs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_pHYs)
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_aspect_ratio");
+ if (info_ptr->x_pixels_per_unit == 0)
+ return ((float)0.0);
+ else
+ return ((float)((float)info_ptr->y_pixels_per_unit
+ /(float)info_ptr->x_pixels_per_unit));
+ }
+#else
+ return (0.0);
+#endif
+ return ((float)0.0);
+}
+#endif
+
+png_int_32 PNGAPI
+png_get_x_offset_microns(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+#if defined(PNG_oFFs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_oFFs)
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_x_offset_microns");
+ if(info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER)
+ return (0);
+ else return (info_ptr->x_offset);
+ }
+#else
+ return (0);
+#endif
+ return (0);
+}
+
+png_int_32 PNGAPI
+png_get_y_offset_microns(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+#if defined(PNG_oFFs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_oFFs)
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_y_offset_microns");
+ if(info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER)
+ return (0);
+ else return (info_ptr->y_offset);
+ }
+#else
+ return (0);
+#endif
+ return (0);
+}
+
+png_int_32 PNGAPI
+png_get_x_offset_pixels(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+#if defined(PNG_oFFs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_oFFs)
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_x_offset_microns");
+ if(info_ptr->offset_unit_type != PNG_OFFSET_PIXEL)
+ return (0);
+ else return (info_ptr->x_offset);
+ }
+#else
+ return (0);
+#endif
+ return (0);
+}
+
+png_int_32 PNGAPI
+png_get_y_offset_pixels(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+#if defined(PNG_oFFs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_oFFs)
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_y_offset_microns");
+ if(info_ptr->offset_unit_type != PNG_OFFSET_PIXEL)
+ return (0);
+ else return (info_ptr->y_offset);
+ }
+#else
+ return (0);
+#endif
+ return (0);
+}
+
+#if defined(PNG_INCH_CONVERSIONS) && defined(PNG_FLOATING_POINT_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_pixels_per_inch(png_structp png_ptr, png_infop info_ptr)
+{
+ return ((png_uint_32)((float)png_get_pixels_per_meter(png_ptr, info_ptr)
+ *.0254 +.5));
+}
+
+png_uint_32 PNGAPI
+png_get_x_pixels_per_inch(png_structp png_ptr, png_infop info_ptr)
+{
+ return ((png_uint_32)((float)png_get_x_pixels_per_meter(png_ptr, info_ptr)
+ *.0254 +.5));
+}
+
+png_uint_32 PNGAPI
+png_get_y_pixels_per_inch(png_structp png_ptr, png_infop info_ptr)
+{
+ return ((png_uint_32)((float)png_get_y_pixels_per_meter(png_ptr, info_ptr)
+ *.0254 +.5));
+}
+
+float PNGAPI
+png_get_x_offset_inches(png_structp png_ptr, png_infop info_ptr)
+{
+ return ((float)png_get_x_offset_microns(png_ptr, info_ptr)
+ *.00003937);
+}
+
+float PNGAPI
+png_get_y_offset_inches(png_structp png_ptr, png_infop info_ptr)
+{
+ return ((float)png_get_y_offset_microns(png_ptr, info_ptr)
+ *.00003937);
+}
+
+#if defined(PNG_pHYs_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_pHYs_dpi(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)
+{
+ png_uint_32 retval = 0;
+
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
+ {
+ png_debug1(1, "in %s retrieval function\n", "pHYs");
+ if (res_x != NULL)
+ {
+ *res_x = info_ptr->x_pixels_per_unit;
+ retval |= PNG_INFO_pHYs;
+ }
+ if (res_y != NULL)
+ {
+ *res_y = info_ptr->y_pixels_per_unit;
+ retval |= PNG_INFO_pHYs;
+ }
+ if (unit_type != NULL)
+ {
+ *unit_type = (int)info_ptr->phys_unit_type;
+ retval |= PNG_INFO_pHYs;
+ if(*unit_type == 1)
+ {
+ if (res_x != NULL) *res_x = (png_uint_32)(*res_x * .0254 + .50);
+ if (res_y != NULL) *res_y = (png_uint_32)(*res_y * .0254 + .50);
+ }
+ }
+ }
+ return (retval);
+}
+#endif /* PNG_pHYs_SUPPORTED */
+#endif /* PNG_INCH_CONVERSIONS && PNG_FLOATING_POINT_SUPPORTED */
+
+/* png_get_channels really belongs in here, too, but it's been around longer */
+
+#endif /* PNG_EASY_ACCESS_SUPPORTED */
+
+png_byte PNGAPI
+png_get_channels(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ return(info_ptr->channels);
+ else
+ return (0);
+}
+
+png_bytep PNGAPI
+png_get_signature(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ return(info_ptr->signature);
+ else
+ return (NULL);
+}
+
+#if defined(PNG_bKGD_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_bKGD(png_structp png_ptr, png_infop info_ptr,
+ png_color_16p *background)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD)
+ && background != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "bKGD");
+ *background = &(info_ptr->background);
+ return (PNG_INFO_bKGD);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_cHRM_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+png_uint_32 PNGAPI
+png_get_cHRM(png_structp png_ptr, png_infop info_ptr,
+ double *white_x, double *white_y, double *red_x, double *red_y,
+ double *green_x, double *green_y, double *blue_x, double *blue_y)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
+ {
+ png_debug1(1, "in %s retrieval function\n", "cHRM");
+ if (white_x != NULL)
+ *white_x = (double)info_ptr->x_white;
+ if (white_y != NULL)
+ *white_y = (double)info_ptr->y_white;
+ if (red_x != NULL)
+ *red_x = (double)info_ptr->x_red;
+ if (red_y != NULL)
+ *red_y = (double)info_ptr->y_red;
+ if (green_x != NULL)
+ *green_x = (double)info_ptr->x_green;
+ if (green_y != NULL)
+ *green_y = (double)info_ptr->y_green;
+ if (blue_x != NULL)
+ *blue_x = (double)info_ptr->x_blue;
+ if (blue_y != NULL)
+ *blue_y = (double)info_ptr->y_blue;
+ return (PNG_INFO_cHRM);
+ }
+ return (0);
+}
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+png_uint_32 PNGAPI
+png_get_cHRM_fixed(png_structp png_ptr, png_infop info_ptr,
+ png_fixed_point *white_x, png_fixed_point *white_y, png_fixed_point *red_x,
+ png_fixed_point *red_y, png_fixed_point *green_x, png_fixed_point *green_y,
+ png_fixed_point *blue_x, png_fixed_point *blue_y)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
+ {
+ png_debug1(1, "in %s retrieval function\n", "cHRM");
+ if (white_x != NULL)
+ *white_x = info_ptr->int_x_white;
+ if (white_y != NULL)
+ *white_y = info_ptr->int_y_white;
+ if (red_x != NULL)
+ *red_x = info_ptr->int_x_red;
+ if (red_y != NULL)
+ *red_y = info_ptr->int_y_red;
+ if (green_x != NULL)
+ *green_x = info_ptr->int_x_green;
+ if (green_y != NULL)
+ *green_y = info_ptr->int_y_green;
+ if (blue_x != NULL)
+ *blue_x = info_ptr->int_x_blue;
+ if (blue_y != NULL)
+ *blue_y = info_ptr->int_y_blue;
+ return (PNG_INFO_cHRM);
+ }
+ return (0);
+}
+#endif
+#endif
+
+#if defined(PNG_gAMA_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+png_uint_32 PNGAPI
+png_get_gAMA(png_structp png_ptr, png_infop info_ptr, double *file_gamma)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
+ && file_gamma != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "gAMA");
+ *file_gamma = (double)info_ptr->gamma;
+ return (PNG_INFO_gAMA);
+ }
+ return (0);
+}
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+png_uint_32 PNGAPI
+png_get_gAMA_fixed(png_structp png_ptr, png_infop info_ptr,
+ png_fixed_point *int_file_gamma)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
+ && int_file_gamma != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "gAMA");
+ *int_file_gamma = info_ptr->int_gamma;
+ return (PNG_INFO_gAMA);
+ }
+ return (0);
+}
+#endif
+#endif
+
+#if defined(PNG_sRGB_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_sRGB(png_structp png_ptr, png_infop info_ptr, int *file_srgb_intent)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)
+ && file_srgb_intent != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "sRGB");
+ *file_srgb_intent = (int)info_ptr->srgb_intent;
+ return (PNG_INFO_sRGB);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_iCCP_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_iCCP(png_structp png_ptr, png_infop info_ptr,
+ png_charpp name, int *compression_type,
+ png_charpp profile, png_uint_32 *proflen)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP)
+ && name != NULL && profile != NULL && proflen != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "iCCP");
+ *name = info_ptr->iccp_name;
+ *profile = info_ptr->iccp_profile;
+ /* compression_type is a dummy so the API won't have to change
+ if we introduce multiple compression types later. */
+ *proflen = (int)info_ptr->iccp_proflen;
+ *compression_type = (int)info_ptr->iccp_compression;
+ return (PNG_INFO_iCCP);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_sPLT_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_sPLT(png_structp png_ptr, png_infop info_ptr,
+ png_sPLT_tpp spalettes)
+{
+ if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL)
+ *spalettes = info_ptr->splt_palettes;
+ return ((png_uint_32)info_ptr->splt_palettes_num);
+}
+#endif
+
+#if defined(PNG_hIST_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p *hist)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST)
+ && hist != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "hIST");
+ *hist = info_ptr->hist;
+ return (PNG_INFO_hIST);
+ }
+ return (0);
+}
+#endif
+
+png_uint_32 PNGAPI
+png_get_IHDR(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 *width, png_uint_32 *height, int *bit_depth,
+ int *color_type, int *interlace_type, int *compression_type,
+ int *filter_type)
+
+{
+ if (png_ptr != NULL && info_ptr != NULL && width != NULL && height != NULL &&
+ bit_depth != NULL && color_type != NULL)
+ {
+ int pixel_depth, channels;
+ png_uint_32 rowbytes_per_pixel;
+
+ png_debug1(1, "in %s retrieval function\n", "IHDR");
+ *width = info_ptr->width;
+ *height = info_ptr->height;
+ *bit_depth = info_ptr->bit_depth;
+ *color_type = info_ptr->color_type;
+ if (compression_type != NULL)
+ *compression_type = info_ptr->compression_type;
+ if (filter_type != NULL)
+ *filter_type = info_ptr->filter_type;
+ if (interlace_type != NULL)
+ *interlace_type = info_ptr->interlace_type;
+
+ /* check for potential overflow of rowbytes */
+ if (*color_type == PNG_COLOR_TYPE_PALETTE)
+ channels = 1;
+ else if (*color_type & PNG_COLOR_MASK_COLOR)
+ channels = 3;
+ else
+ channels = 1;
+ if (*color_type & PNG_COLOR_MASK_ALPHA)
+ channels++;
+ pixel_depth = *bit_depth * channels;
+ rowbytes_per_pixel = (pixel_depth + 7) >> 3;
+ if ((*width > PNG_MAX_UINT/rowbytes_per_pixel))
+ {
+ png_warning(png_ptr,
+ "Width too large for libpng to process image data.");
+ }
+ return (1);
+ }
+ return (0);
+}
+
+#if defined(PNG_oFFs_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_oFFs(png_structp png_ptr, png_infop info_ptr,
+ png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)
+ && offset_x != NULL && offset_y != NULL && unit_type != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "oFFs");
+ *offset_x = info_ptr->x_offset;
+ *offset_y = info_ptr->y_offset;
+ *unit_type = (int)info_ptr->offset_unit_type;
+ return (PNG_INFO_oFFs);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_pCAL_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_pCAL(png_structp png_ptr, png_infop info_ptr,
+ png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams,
+ png_charp *units, png_charpp *params)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL)
+ && purpose != NULL && X0 != NULL && X1 != NULL && type != NULL &&
+ nparams != NULL && units != NULL && params != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "pCAL");
+ *purpose = info_ptr->pcal_purpose;
+ *X0 = info_ptr->pcal_X0;
+ *X1 = info_ptr->pcal_X1;
+ *type = (int)info_ptr->pcal_type;
+ *nparams = (int)info_ptr->pcal_nparams;
+ *units = info_ptr->pcal_units;
+ *params = info_ptr->pcal_params;
+ return (PNG_INFO_pCAL);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_sCAL_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+png_uint_32 PNGAPI
+png_get_sCAL(png_structp png_ptr, png_infop info_ptr,
+ int *unit, double *width, double *height)
+{
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_sCAL))
+ {
+ *unit = info_ptr->scal_unit;
+ *width = info_ptr->scal_pixel_width;
+ *height = info_ptr->scal_pixel_height;
+ return (PNG_INFO_sCAL);
+ }
+ return(0);
+}
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+png_uint_32 PNGAPI
+png_get_sCAL_s(png_structp png_ptr, png_infop info_ptr,
+ int *unit, png_charpp width, png_charpp height)
+{
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_sCAL))
+ {
+ *unit = info_ptr->scal_unit;
+ *width = info_ptr->scal_s_width;
+ *height = info_ptr->scal_s_height;
+ return (PNG_INFO_sCAL);
+ }
+ return(0);
+}
+#endif
+#endif
+#endif
+
+#if defined(PNG_pHYs_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_pHYs(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)
+{
+ png_uint_32 retval = 0;
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_pHYs))
+ {
+ png_debug1(1, "in %s retrieval function\n", "pHYs");
+ if (res_x != NULL)
+ {
+ *res_x = info_ptr->x_pixels_per_unit;
+ retval |= PNG_INFO_pHYs;
+ }
+ if (res_y != NULL)
+ {
+ *res_y = info_ptr->y_pixels_per_unit;
+ retval |= PNG_INFO_pHYs;
+ }
+ if (unit_type != NULL)
+ {
+ *unit_type = (int)info_ptr->phys_unit_type;
+ retval |= PNG_INFO_pHYs;
+ }
+ }
+ return (retval);
+}
+#endif
+
+png_uint_32 PNGAPI
+png_get_PLTE(png_structp png_ptr, png_infop info_ptr, png_colorp *palette,
+ int *num_palette)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_PLTE)
+ && palette != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "PLTE");
+ *palette = info_ptr->palette;
+ *num_palette = info_ptr->num_palette;
+ png_debug1(3, "num_palette = %d\n", *num_palette);
+ return (PNG_INFO_PLTE);
+ }
+ return (0);
+}
+
+#if defined(PNG_sBIT_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_sBIT(png_structp png_ptr, png_infop info_ptr, png_color_8p *sig_bit)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT)
+ && sig_bit != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "sBIT");
+ *sig_bit = &(info_ptr->sig_bit);
+ return (PNG_INFO_sBIT);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_TEXT_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_text(png_structp png_ptr, png_infop info_ptr, png_textp *text_ptr,
+ int *num_text)
+{
+ if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0)
+ {
+ png_debug1(1, "in %s retrieval function\n",
+ (png_ptr->chunk_name[0] == '\0' ? "text"
+ : (png_const_charp)png_ptr->chunk_name));
+ if (text_ptr != NULL)
+ *text_ptr = info_ptr->text;
+ if (num_text != NULL)
+ *num_text = info_ptr->num_text;
+ return ((png_uint_32)info_ptr->num_text);
+ }
+ if (num_text != NULL)
+ *num_text = 0;
+ return(0);
+}
+#endif
+
+#if defined(PNG_tIME_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_tIME(png_structp png_ptr, png_infop info_ptr, png_timep *mod_time)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME)
+ && mod_time != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "tIME");
+ *mod_time = &(info_ptr->mod_time);
+ return (PNG_INFO_tIME);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_tRNS_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_tRNS(png_structp png_ptr, png_infop info_ptr,
+ png_bytep *trans, int *num_trans, png_color_16p *trans_values)
+{
+ png_uint_32 retval = 0;
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
+ {
+ png_debug1(1, "in %s retrieval function\n", "tRNS");
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (trans != NULL)
+ {
+ *trans = info_ptr->trans;
+ retval |= PNG_INFO_tRNS;
+ }
+ if (trans_values != NULL)
+ *trans_values = &(info_ptr->trans_values);
+ }
+ else /* if (info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) */
+ {
+ if (trans_values != NULL)
+ {
+ *trans_values = &(info_ptr->trans_values);
+ retval |= PNG_INFO_tRNS;
+ }
+ if(trans != NULL)
+ *trans = NULL;
+ }
+ if(num_trans != NULL)
+ {
+ *num_trans = info_ptr->num_trans;
+ retval |= PNG_INFO_tRNS;
+ }
+ }
+ return (retval);
+}
+#endif
+
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_unknown_chunks(png_structp png_ptr, png_infop info_ptr,
+ png_unknown_chunkpp unknowns)
+{
+ if (png_ptr != NULL && info_ptr != NULL && unknowns != NULL)
+ *unknowns = info_ptr->unknown_chunks;
+ return ((png_uint_32)info_ptr->unknown_chunks_num);
+}
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+png_byte PNGAPI
+png_get_rgb_to_gray_status (png_structp png_ptr)
+{
+ return (png_byte)(png_ptr? png_ptr->rgb_to_gray_status : 0);
+}
+#endif
+
+#if defined(PNG_USER_CHUNKS_SUPPORTED)
+png_voidp PNGAPI
+png_get_user_chunk_ptr(png_structp png_ptr)
+{
+ return (png_ptr? png_ptr->user_chunk_ptr : NULL);
+}
+#endif
+
+
+png_uint_32 PNGAPI
+png_get_compression_buffer_size(png_structp png_ptr)
+{
+ return (png_uint_32)(png_ptr? png_ptr->zbuf_size : 0L);
+}
+
+
+#ifdef PNG_ASSEMBLER_CODE_SUPPORTED
+/* this function was added to libpng 1.2.0 and should exist by default*/
+png_uint_32 PNGAPI
+png_get_asm_flags (png_structp png_ptr)
+{
+ return (png_uint_32)(png_ptr? png_ptr->asm_flags : 0L);
+}
+
+/* this function was added to libpng 1.2.0 and should exist by default */
+png_uint_32 PNGAPI
+png_get_asm_flagmask (int flag_select)
+{
+ png_uint_32 settable_asm_flags = 0;
+
+ if (flag_select & PNG_SELECT_READ)
+ settable_asm_flags |=
+ PNG_ASM_FLAG_MMX_READ_COMBINE_ROW |
+ PNG_ASM_FLAG_MMX_READ_INTERLACE |
+ PNG_ASM_FLAG_MMX_READ_FILTER_SUB |
+ PNG_ASM_FLAG_MMX_READ_FILTER_UP |
+ PNG_ASM_FLAG_MMX_READ_FILTER_AVG |
+ PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ;
+ /* no non-MMX flags yet */
+
+#if 0
+ /* GRR: no write-flags yet, either, but someday... */
+ if (flag_select & PNG_SELECT_WRITE)
+ settable_asm_flags |=
+ PNG_ASM_FLAG_MMX_WRITE_ [whatever] ;
+#endif /* 0 */
+
+ return settable_asm_flags; /* _theoretically_ settable capabilities only */
+}
+#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
+
+
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
+ /* GRR: could add this: && defined(PNG_MMX_CODE_SUPPORTED) */
+/* this function was added to libpng 1.2.0 */
+png_uint_32 PNGAPI
+png_get_mmx_flagmask (int flag_select, int *compilerID)
+{
+ png_uint_32 settable_mmx_flags = 0;
+
+ if (flag_select & PNG_SELECT_READ)
+ settable_mmx_flags |=
+ PNG_ASM_FLAG_MMX_READ_COMBINE_ROW |
+ PNG_ASM_FLAG_MMX_READ_INTERLACE |
+ PNG_ASM_FLAG_MMX_READ_FILTER_SUB |
+ PNG_ASM_FLAG_MMX_READ_FILTER_UP |
+ PNG_ASM_FLAG_MMX_READ_FILTER_AVG |
+ PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ;
+#if 0
+ /* GRR: no MMX write support yet, but someday... */
+ if (flag_select & PNG_SELECT_WRITE)
+ settable_mmx_flags |=
+ PNG_ASM_FLAG_MMX_WRITE_ [whatever] ;
+#endif /* 0 */
+
+ if (compilerID != NULL) {
+#ifdef PNG_USE_PNGVCRD
+ *compilerID = 1; /* MSVC */
+#else
+#ifdef PNG_USE_PNGGCCRD
+ *compilerID = 2; /* gcc/gas */
+#else
+ *compilerID = -1; /* unknown (i.e., no asm/MMX code compiled) */
+#endif
+#endif
+ }
+
+ return settable_mmx_flags; /* _theoretically_ settable capabilities only */
+}
+
+/* this function was added to libpng 1.2.0 */
+png_byte PNGAPI
+png_get_mmx_bitdepth_threshold (png_structp png_ptr)
+{
+ return (png_byte)(png_ptr? png_ptr->mmx_bitdepth_threshold : 0);
+}
+
+/* this function was added to libpng 1.2.0 */
+png_uint_32 PNGAPI
+png_get_mmx_rowbytes_threshold (png_structp png_ptr)
+{
+ return (png_uint_32)(png_ptr? png_ptr->mmx_rowbytes_threshold : 0L);
+}
+#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
--- /dev/null
+
+/* pngmem.c - stub functions for memory allocation
+ *
+ * libpng 1.2.0 - September 1, 2001
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ *
+ * This file provides a location for all memory allocation. Users who
+ * need special memory handling are expected to supply replacement
+ * functions for png_malloc() and png_free(), and to use
+ * png_create_read_struct_2() and png_create_write_struct_2() to
+ * identify the replacement functions.
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* Borland DOS special memory handler */
+#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__)
+/* if you change this, be sure to change the one in png.h also */
+
+/* Allocate memory for a png_struct. The malloc and memset can be replaced
+ by a single call to calloc() if this is thought to improve performance. */
+png_voidp /* PRIVATE */
+png_create_struct(int type)
+{
+#ifdef PNG_USER_MEM_SUPPORTED
+ return (png_create_struct_2(type, NULL, NULL));
+}
+
+/* Alternate version of png_create_struct, for use with user-defined malloc. */
+png_voidp /* PRIVATE */
+png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr)
+{
+#endif /* PNG_USER_MEM_SUPPORTED */
+ png_size_t size;
+ png_voidp struct_ptr;
+
+ if (type == PNG_STRUCT_INFO)
+ size = sizeof(png_info);
+ else if (type == PNG_STRUCT_PNG)
+ size = sizeof(png_struct);
+ else
+ return ((png_voidp)NULL);
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ if(malloc_fn != NULL)
+ {
+ if (mem_ptr != NULL)
+ {
+ png_struct dummy_struct;
+ png_structp png_ptr = &dummy_struct;
+ png_ptr->mem_ptr=mem_ptr;
+ struct_ptr = (*(malloc_fn))(png_ptr, size);
+ }
+ else
+ struct_ptr = (*(malloc_fn))(NULL, size);
+ if (struct_ptr != NULL)
+ png_memset(struct_ptr, 0, size);
+ return (struct_ptr);
+ }
+#endif /* PNG_USER_MEM_SUPPORTED */
+ if ((struct_ptr = (png_voidp)farmalloc(size)) != NULL)
+ {
+ png_memset(struct_ptr, 0, size);
+ }
+ return (struct_ptr);
+}
+
+
+/* Free memory allocated by a png_create_struct() call */
+void /* PRIVATE */
+png_destroy_struct(png_voidp struct_ptr)
+{
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2(struct_ptr, (png_free_ptr)NULL, (png_voidp)NULL);
+}
+
+/* Free memory allocated by a png_create_struct() call */
+void /* PRIVATE */
+png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn,
+ png_voidp mem_ptr)
+{
+#endif
+ if (struct_ptr != NULL)
+ {
+#ifdef PNG_USER_MEM_SUPPORTED
+ if(free_fn != NULL)
+ {
+ png_struct dummy_struct;
+ png_structp png_ptr = &dummy_struct;
+ png_ptr->mem_ptr=mem_ptr;
+ (*(free_fn))(png_ptr, struct_ptr);
+ return;
+ }
+#endif /* PNG_USER_MEM_SUPPORTED */
+ farfree (struct_ptr);
+ }
+}
+
+/* Allocate memory. For reasonable files, size should never exceed
+ * 64K. However, zlib may allocate more then 64K if you don't tell
+ * it not to. See zconf.h and png.h for more information. zlib does
+ * need to allocate exactly 64K, so whatever you call here must
+ * have the ability to do that.
+ *
+ * Borland seems to have a problem in DOS mode for exactly 64K.
+ * It gives you a segment with an offset of 8 (perhaps to store its
+ * memory stuff). zlib doesn't like this at all, so we have to
+ * detect and deal with it. This code should not be needed in
+ * Windows or OS/2 modes, and only in 16 bit mode. This code has
+ * been updated by Alexander Lehmann for version 0.89 to waste less
+ * memory.
+ *
+ * Note that we can't use png_size_t for the "size" declaration,
+ * since on some systems a png_size_t is a 16-bit quantity, and as a
+ * result, we would be truncating potentially larger memory requests
+ * (which should cause a fatal error) and introducing major problems.
+ */
+png_voidp PNGAPI
+png_malloc(png_structp png_ptr, png_uint_32 size)
+{
+#ifndef PNG_USER_MEM_SUPPORTED
+ png_voidp ret;
+#endif
+ if (png_ptr == NULL || size == 0)
+ return ((png_voidp)NULL);
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ if(png_ptr->malloc_fn != NULL)
+ {
+ ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, size));
+ if (ret == NULL)
+ png_error(png_ptr, "Out of memory!");
+ return (ret);
+ }
+ else
+ return png_malloc_default(png_ptr, size);
+}
+
+png_voidp PNGAPI
+png_malloc_default(png_structp png_ptr, png_uint_32 size)
+{
+ png_voidp ret;
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (size > (png_uint_32)65536L)
+ png_error(png_ptr, "Cannot Allocate > 64K");
+#endif
+
+ if (size == (png_uint_32)65536L)
+ {
+ if (png_ptr->offset_table == NULL)
+ {
+ /* try to see if we need to do any of this fancy stuff */
+ ret = farmalloc(size);
+ if (ret == NULL || ((png_size_t)ret & 0xffff))
+ {
+ int num_blocks;
+ png_uint_32 total_size;
+ png_bytep table;
+ int i;
+ png_byte huge * hptr;
+
+ if (ret != NULL)
+ {
+ farfree(ret);
+ ret = NULL;
+ }
+
+ if(png_ptr->zlib_window_bits > 14)
+ num_blocks = (int)(1 << (png_ptr->zlib_window_bits - 14));
+ else
+ num_blocks = 1;
+ if (png_ptr->zlib_mem_level >= 7)
+ num_blocks += (int)(1 << (png_ptr->zlib_mem_level - 7));
+ else
+ num_blocks++;
+
+ total_size = ((png_uint_32)65536L) * (png_uint_32)num_blocks+16;
+
+ table = farmalloc(total_size);
+
+ if (table == NULL)
+ {
+ png_error(png_ptr, "Out Of Memory."); /* Note "O" and "M" */
+ }
+
+ if ((png_size_t)table & 0xfff0)
+ {
+ png_error(png_ptr, "Farmalloc didn't return normalized pointer");
+ }
+
+ png_ptr->offset_table = table;
+ png_ptr->offset_table_ptr = farmalloc(num_blocks *
+ sizeof (png_bytep));
+
+ if (png_ptr->offset_table_ptr == NULL)
+ {
+ png_error(png_ptr, "Out Of memory.");
+ }
+
+ hptr = (png_byte huge *)table;
+ if ((png_size_t)hptr & 0xf)
+ {
+ hptr = (png_byte huge *)((long)(hptr) & 0xfffffff0L);
+ hptr = hptr + 16L; /* "hptr += 16L" fails on Turbo C++ 3.0 */
+ }
+ for (i = 0; i < num_blocks; i++)
+ {
+ png_ptr->offset_table_ptr[i] = (png_bytep)hptr;
+ hptr = hptr + (png_uint_32)65536L; /* "+=" fails on TC++3.0 */
+ }
+
+ png_ptr->offset_table_number = num_blocks;
+ png_ptr->offset_table_count = 0;
+ png_ptr->offset_table_count_free = 0;
+ }
+ }
+
+ if (png_ptr->offset_table_count >= png_ptr->offset_table_number)
+ png_error(png_ptr, "Out of Memory.");
+
+ ret = png_ptr->offset_table_ptr[png_ptr->offset_table_count++];
+ }
+ else
+ ret = farmalloc(size);
+
+ if (ret == NULL)
+ {
+ png_error(png_ptr, "Out of memory."); /* Note "o" and "m" */
+ }
+
+ return (ret);
+}
+
+/* free a pointer allocated by png_malloc(). In the default
+ configuration, png_ptr is not used, but is passed in case it
+ is needed. If ptr is NULL, return without taking any action. */
+void PNGAPI
+png_free(png_structp png_ptr, png_voidp ptr)
+{
+ if (png_ptr == NULL || ptr == NULL)
+ return;
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ if (png_ptr->free_fn != NULL)
+ {
+ (*(png_ptr->free_fn))(png_ptr, ptr);
+ return;
+ }
+ else png_free_default(png_ptr, ptr);
+}
+
+void PNGAPI
+png_free_default(png_structp png_ptr, png_voidp ptr)
+{
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+ if (png_ptr->offset_table != NULL)
+ {
+ int i;
+
+ for (i = 0; i < png_ptr->offset_table_count; i++)
+ {
+ if (ptr == png_ptr->offset_table_ptr[i])
+ {
+ ptr = NULL;
+ png_ptr->offset_table_count_free++;
+ break;
+ }
+ }
+ if (png_ptr->offset_table_count_free == png_ptr->offset_table_count)
+ {
+ farfree(png_ptr->offset_table);
+ farfree(png_ptr->offset_table_ptr);
+ png_ptr->offset_table = NULL;
+ png_ptr->offset_table_ptr = NULL;
+ }
+ }
+
+ if (ptr != NULL)
+ {
+ farfree(ptr);
+ }
+}
+
+#else /* Not the Borland DOS special memory handler */
+
+/* Allocate memory for a png_struct or a png_info. The malloc and
+ memset can be replaced by a single call to calloc() if this is thought
+ to improve performance noticably.*/
+png_voidp /* PRIVATE */
+png_create_struct(int type)
+{
+#ifdef PNG_USER_MEM_SUPPORTED
+ return (png_create_struct_2(type, NULL, NULL));
+}
+
+/* Allocate memory for a png_struct or a png_info. The malloc and
+ memset can be replaced by a single call to calloc() if this is thought
+ to improve performance noticably.*/
+png_voidp /* PRIVATE */
+png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr)
+{
+#endif /* PNG_USER_MEM_SUPPORTED */
+ png_size_t size;
+ png_voidp struct_ptr;
+
+ if (type == PNG_STRUCT_INFO)
+ size = sizeof(png_info);
+ else if (type == PNG_STRUCT_PNG)
+ size = sizeof(png_struct);
+ else
+ return ((png_voidp)NULL);
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ if(malloc_fn != NULL)
+ {
+ if (mem_ptr != NULL)
+ {
+ png_struct dummy_struct;
+ png_structp png_ptr = &dummy_struct;
+ png_ptr->mem_ptr=mem_ptr;
+ struct_ptr = (*(malloc_fn))(png_ptr, size);
+ }
+ else
+ struct_ptr = (*(malloc_fn))(NULL, size);
+ if (struct_ptr != NULL)
+ png_memset(struct_ptr, 0, size);
+ return (struct_ptr);
+ }
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+#if defined(__TURBOC__) && !defined(__FLAT__)
+ if ((struct_ptr = (png_voidp)farmalloc(size)) != NULL)
+#else
+# if defined(_MSC_VER) && defined(MAXSEG_64K)
+ if ((struct_ptr = (png_voidp)halloc(size,1)) != NULL)
+# else
+ if ((struct_ptr = (png_voidp)malloc(size)) != NULL)
+# endif
+#endif
+ {
+ png_memset(struct_ptr, 0, size);
+ }
+
+ return (struct_ptr);
+}
+
+
+/* Free memory allocated by a png_create_struct() call */
+void /* PRIVATE */
+png_destroy_struct(png_voidp struct_ptr)
+{
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2(struct_ptr, (png_free_ptr)NULL, (png_voidp)NULL);
+}
+
+/* Free memory allocated by a png_create_struct() call */
+void /* PRIVATE */
+png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn,
+ png_voidp mem_ptr)
+{
+#endif /* PNG_USER_MEM_SUPPORTED */
+ if (struct_ptr != NULL)
+ {
+#ifdef PNG_USER_MEM_SUPPORTED
+ if(free_fn != NULL)
+ {
+ png_struct dummy_struct;
+ png_structp png_ptr = &dummy_struct;
+ png_ptr->mem_ptr=mem_ptr;
+ (*(free_fn))(png_ptr, struct_ptr);
+ return;
+ }
+#endif /* PNG_USER_MEM_SUPPORTED */
+#if defined(__TURBOC__) && !defined(__FLAT__)
+ farfree(struct_ptr);
+#else
+# if defined(_MSC_VER) && defined(MAXSEG_64K)
+ hfree(struct_ptr);
+# else
+ free(struct_ptr);
+# endif
+#endif
+ }
+}
+
+
+/* Allocate memory. For reasonable files, size should never exceed
+ 64K. However, zlib may allocate more then 64K if you don't tell
+ it not to. See zconf.h and png.h for more information. zlib does
+ need to allocate exactly 64K, so whatever you call here must
+ have the ability to do that. */
+
+png_voidp PNGAPI
+png_malloc(png_structp png_ptr, png_uint_32 size)
+{
+ png_voidp ret;
+ if (png_ptr == NULL || size == 0)
+ return ((png_voidp)NULL);
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ if(png_ptr->malloc_fn != NULL)
+ {
+ ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, size));
+ if (ret == NULL)
+ png_error(png_ptr, "Out of Memory!");
+ return (ret);
+ }
+ else
+ return (png_malloc_default(png_ptr, size));
+}
+png_voidp /* PRIVATE */
+png_malloc_default(png_structp png_ptr, png_uint_32 size)
+{
+ png_voidp ret;
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (size > (png_uint_32)65536L)
+ png_error(png_ptr, "Cannot Allocate > 64K");
+#endif
+
+#if defined(__TURBOC__) && !defined(__FLAT__)
+ ret = farmalloc(size);
+#else
+# if defined(_MSC_VER) && defined(MAXSEG_64K)
+ ret = halloc(size, 1);
+# else
+ ret = malloc((size_t)size);
+# endif
+#endif
+
+ if (ret == NULL)
+ png_error(png_ptr, "Out of Memory");
+
+ return (ret);
+}
+
+/* Free a pointer allocated by png_malloc(). If ptr is NULL, return
+ without taking any action. */
+void PNGAPI
+png_free(png_structp png_ptr, png_voidp ptr)
+{
+ if (png_ptr == NULL || ptr == NULL)
+ return;
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ if (png_ptr->free_fn != NULL)
+ {
+ (*(png_ptr->free_fn))(png_ptr, ptr);
+ return;
+ }
+ else png_free_default(png_ptr, ptr);
+}
+void /* PRIVATE */
+png_free_default(png_structp png_ptr, png_voidp ptr)
+{
+ if (png_ptr == NULL || ptr == NULL)
+ return;
+
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+#if defined(__TURBOC__) && !defined(__FLAT__)
+ farfree(ptr);
+#else
+# if defined(_MSC_VER) && defined(MAXSEG_64K)
+ hfree(ptr);
+# else
+ free(ptr);
+# endif
+#endif
+}
+
+#endif /* Not Borland DOS special memory handler */
+
+png_voidp /* PRIVATE */
+png_memcpy_check (png_structp png_ptr, png_voidp s1, png_voidp s2,
+ png_uint_32 length)
+{
+ png_size_t size;
+
+ size = (png_size_t)length;
+ if ((png_uint_32)size != length)
+ png_error(png_ptr,"Overflow in png_memcpy_check.");
+
+ return(png_memcpy (s1, s2, size));
+}
+
+png_voidp /* PRIVATE */
+png_memset_check (png_structp png_ptr, png_voidp s1, int value,
+ png_uint_32 length)
+{
+ png_size_t size;
+
+ size = (png_size_t)length;
+ if ((png_uint_32)size != length)
+ png_error(png_ptr,"Overflow in png_memset_check.");
+
+ return (png_memset (s1, value, size));
+
+}
+
+#ifdef PNG_USER_MEM_SUPPORTED
+/* This function is called when the application wants to use another method
+ * of allocating and freeing memory.
+ */
+void PNGAPI
+png_set_mem_fn(png_structp png_ptr, png_voidp mem_ptr, png_malloc_ptr
+ malloc_fn, png_free_ptr free_fn)
+{
+ png_ptr->mem_ptr = mem_ptr;
+ png_ptr->malloc_fn = malloc_fn;
+ png_ptr->free_fn = free_fn;
+}
+
+/* This function returns a pointer to the mem_ptr associated with the user
+ * functions. The application should free any memory associated with this
+ * pointer before png_write_destroy and png_read_destroy are called.
+ */
+png_voidp PNGAPI
+png_get_mem_ptr(png_structp png_ptr)
+{
+ return ((png_voidp)png_ptr->mem_ptr);
+}
+#endif /* PNG_USER_MEM_SUPPORTED */
--- /dev/null
+
+/* pngpread.c - read a png file in push mode
+ *
+ * libpng 1.2.0 - September 1, 2001
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+
+/* push model modes */
+#define PNG_READ_SIG_MODE 0
+#define PNG_READ_CHUNK_MODE 1
+#define PNG_READ_IDAT_MODE 2
+#define PNG_SKIP_MODE 3
+#define PNG_READ_tEXt_MODE 4
+#define PNG_READ_zTXt_MODE 5
+#define PNG_READ_DONE_MODE 6
+#define PNG_READ_iTXt_MODE 7
+#define PNG_ERROR_MODE 8
+
+void PNGAPI
+png_process_data(png_structp png_ptr, png_infop info_ptr,
+ png_bytep buffer, png_size_t buffer_size)
+{
+ png_push_restore_buffer(png_ptr, buffer, buffer_size);
+
+ while (png_ptr->buffer_size)
+ {
+ png_process_some_data(png_ptr, info_ptr);
+ }
+}
+
+/* What we do with the incoming data depends on what we were previously
+ * doing before we ran out of data...
+ */
+void /* PRIVATE */
+png_process_some_data(png_structp png_ptr, png_infop info_ptr)
+{
+ switch (png_ptr->process_mode)
+ {
+ case PNG_READ_SIG_MODE:
+ {
+ png_push_read_sig(png_ptr, info_ptr);
+ break;
+ }
+ case PNG_READ_CHUNK_MODE:
+ {
+ png_push_read_chunk(png_ptr, info_ptr);
+ break;
+ }
+ case PNG_READ_IDAT_MODE:
+ {
+ png_push_read_IDAT(png_ptr);
+ break;
+ }
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ case PNG_READ_tEXt_MODE:
+ {
+ png_push_read_tEXt(png_ptr, info_ptr);
+ break;
+ }
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ case PNG_READ_zTXt_MODE:
+ {
+ png_push_read_zTXt(png_ptr, info_ptr);
+ break;
+ }
+#endif
+#if defined(PNG_READ_iTXt_SUPPORTED)
+ case PNG_READ_iTXt_MODE:
+ {
+ png_push_read_iTXt(png_ptr, info_ptr);
+ break;
+ }
+#endif
+ case PNG_SKIP_MODE:
+ {
+ png_push_crc_finish(png_ptr);
+ break;
+ }
+ default:
+ {
+ png_ptr->buffer_size = 0;
+ break;
+ }
+ }
+}
+
+/* Read any remaining signature bytes from the stream and compare them with
+ * the correct PNG signature. It is possible that this routine is called
+ * with bytes already read from the signature, either because they have been
+ * checked by the calling application, or because of multiple calls to this
+ * routine.
+ */
+void /* PRIVATE */
+png_push_read_sig(png_structp png_ptr, png_infop info_ptr)
+{
+ png_size_t num_checked = png_ptr->sig_bytes,
+ num_to_check = 8 - num_checked;
+
+ if (png_ptr->buffer_size < num_to_check)
+ {
+ num_to_check = png_ptr->buffer_size;
+ }
+
+ png_push_fill_buffer(png_ptr, &(info_ptr->signature[num_checked]),
+ num_to_check);
+ png_ptr->sig_bytes = (png_byte)(png_ptr->sig_bytes+num_to_check);
+
+ if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))
+ {
+ if (num_checked < 4 &&
+ png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))
+ png_error(png_ptr, "Not a PNG file");
+ else
+ png_error(png_ptr, "PNG file corrupted by ASCII conversion");
+ }
+ else
+ {
+ if (png_ptr->sig_bytes >= 8)
+ {
+ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+ }
+ }
+}
+
+void /* PRIVATE */
+png_push_read_chunk(png_structp png_ptr, png_infop info_ptr)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_IHDR;
+ PNG_IDAT;
+ PNG_IEND;
+ PNG_PLTE;
+#if defined(PNG_READ_bKGD_SUPPORTED)
+ PNG_bKGD;
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED)
+ PNG_cHRM;
+#endif
+#if defined(PNG_READ_gAMA_SUPPORTED)
+ PNG_gAMA;
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+ PNG_hIST;
+#endif
+#if defined(PNG_READ_iCCP_SUPPORTED)
+ PNG_iCCP;
+#endif
+#if defined(PNG_READ_iTXt_SUPPORTED)
+ PNG_iTXt;
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED)
+ PNG_oFFs;
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+ PNG_pCAL;
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED)
+ PNG_pHYs;
+#endif
+#if defined(PNG_READ_sBIT_SUPPORTED)
+ PNG_sBIT;
+#endif
+#if defined(PNG_READ_sCAL_SUPPORTED)
+ PNG_sCAL;
+#endif
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ PNG_sRGB;
+#endif
+#if defined(PNG_READ_sPLT_SUPPORTED)
+ PNG_sPLT;
+#endif
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ PNG_tEXt;
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED)
+ PNG_tIME;
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED)
+ PNG_tRNS;
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ PNG_zTXt;
+#endif
+#endif /* PNG_USE_LOCAL_ARRAYS */
+ /* First we make sure we have enough data for the 4 byte chunk name
+ * and the 4 byte chunk length before proceeding with decoding the
+ * chunk data. To fully decode each of these chunks, we also make
+ * sure we have enough data in the buffer for the 4 byte CRC at the
+ * end of every chunk (except IDAT, which is handled separately).
+ */
+ if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER))
+ {
+ png_byte chunk_length[4];
+
+ if (png_ptr->buffer_size < 8)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_push_fill_buffer(png_ptr, chunk_length, 4);
+ png_ptr->push_length = png_get_uint_32(chunk_length);
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+ png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
+ }
+
+ if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length);
+ }
+ else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length);
+ }
+ else if (!png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4))
+ {
+ /* If we reach an IDAT chunk, this means we have read all of the
+ * header chunks, and we can start reading the image (or if this
+ * is called after the image has been read - we have an error).
+ */
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ if (png_ptr->push_length == 0)
+ return;
+
+ if (png_ptr->mode & PNG_AFTER_IDAT)
+ png_error(png_ptr, "Too many IDAT's found");
+ }
+
+ png_ptr->idat_size = png_ptr->push_length;
+ png_ptr->mode |= PNG_HAVE_IDAT;
+ png_ptr->process_mode = PNG_READ_IDAT_MODE;
+ png_push_have_info(png_ptr, info_ptr);
+ png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes;
+ png_ptr->zstream.next_out = png_ptr->row_buf;
+ return;
+ }
+ else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length);
+ png_ptr->process_mode = PNG_READ_DONE_MODE;
+ png_push_have_end(png_ptr, info_ptr);
+ }
+#if defined(PNG_READ_gAMA_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_sBIT_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_iCCP_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_sPLT_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_bKGD_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_sCAL_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4))
+ {
+ png_push_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4))
+ {
+ png_push_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_iTXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4))
+ {
+ png_push_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+ else
+ {
+ png_push_handle_unknown(png_ptr, info_ptr, png_ptr->push_length);
+ }
+
+ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
+}
+
+void /* PRIVATE */
+png_push_crc_skip(png_structp png_ptr, png_uint_32 skip)
+{
+ png_ptr->process_mode = PNG_SKIP_MODE;
+ png_ptr->skip_length = skip;
+}
+
+void /* PRIVATE */
+png_push_crc_finish(png_structp png_ptr)
+{
+ if (png_ptr->skip_length && png_ptr->save_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (png_ptr->skip_length < (png_uint_32)png_ptr->save_buffer_size)
+ save_size = (png_size_t)png_ptr->skip_length;
+ else
+ save_size = png_ptr->save_buffer_size;
+
+ png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size);
+
+ png_ptr->skip_length -= save_size;
+ png_ptr->buffer_size -= save_size;
+ png_ptr->save_buffer_size -= save_size;
+ png_ptr->save_buffer_ptr += save_size;
+ }
+ if (png_ptr->skip_length && png_ptr->current_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (png_ptr->skip_length < (png_uint_32)png_ptr->current_buffer_size)
+ save_size = (png_size_t)png_ptr->skip_length;
+ else
+ save_size = png_ptr->current_buffer_size;
+
+ png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size);
+
+ png_ptr->skip_length -= save_size;
+ png_ptr->buffer_size -= save_size;
+ png_ptr->current_buffer_size -= save_size;
+ png_ptr->current_buffer_ptr += save_size;
+ }
+ if (!png_ptr->skip_length)
+ {
+ if (png_ptr->buffer_size < 4)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_crc_finish(png_ptr, 0);
+ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+ }
+}
+
+void /* PRIVATE */
+png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length)
+{
+ png_bytep ptr;
+
+ ptr = buffer;
+ if (png_ptr->save_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (length < png_ptr->save_buffer_size)
+ save_size = length;
+ else
+ save_size = png_ptr->save_buffer_size;
+
+ png_memcpy(ptr, png_ptr->save_buffer_ptr, save_size);
+ length -= save_size;
+ ptr += save_size;
+ png_ptr->buffer_size -= save_size;
+ png_ptr->save_buffer_size -= save_size;
+ png_ptr->save_buffer_ptr += save_size;
+ }
+ if (length && png_ptr->current_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (length < png_ptr->current_buffer_size)
+ save_size = length;
+ else
+ save_size = png_ptr->current_buffer_size;
+
+ png_memcpy(ptr, png_ptr->current_buffer_ptr, save_size);
+ png_ptr->buffer_size -= save_size;
+ png_ptr->current_buffer_size -= save_size;
+ png_ptr->current_buffer_ptr += save_size;
+ }
+}
+
+void /* PRIVATE */
+png_push_save_buffer(png_structp png_ptr)
+{
+ if (png_ptr->save_buffer_size)
+ {
+ if (png_ptr->save_buffer_ptr != png_ptr->save_buffer)
+ {
+ png_size_t i,istop;
+ png_bytep sp;
+ png_bytep dp;
+
+ istop = png_ptr->save_buffer_size;
+ for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer;
+ i < istop; i++, sp++, dp++)
+ {
+ *dp = *sp;
+ }
+ }
+ }
+ if (png_ptr->save_buffer_size + png_ptr->current_buffer_size >
+ png_ptr->save_buffer_max)
+ {
+ png_size_t new_max;
+ png_bytep old_buffer;
+
+ new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256;
+ old_buffer = png_ptr->save_buffer;
+ png_ptr->save_buffer = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)new_max);
+ png_memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size);
+ png_free(png_ptr, old_buffer);
+ png_ptr->save_buffer_max = new_max;
+ }
+ if (png_ptr->current_buffer_size)
+ {
+ png_memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size,
+ png_ptr->current_buffer_ptr, png_ptr->current_buffer_size);
+ png_ptr->save_buffer_size += png_ptr->current_buffer_size;
+ png_ptr->current_buffer_size = 0;
+ }
+ png_ptr->save_buffer_ptr = png_ptr->save_buffer;
+ png_ptr->buffer_size = 0;
+}
+
+void /* PRIVATE */
+png_push_restore_buffer(png_structp png_ptr, png_bytep buffer,
+ png_size_t buffer_length)
+{
+ png_ptr->current_buffer = buffer;
+ png_ptr->current_buffer_size = buffer_length;
+ png_ptr->buffer_size = buffer_length + png_ptr->save_buffer_size;
+ png_ptr->current_buffer_ptr = png_ptr->current_buffer;
+}
+
+void /* PRIVATE */
+png_push_read_IDAT(png_structp png_ptr)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_IDAT;
+#endif
+ if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER))
+ {
+ png_byte chunk_length[4];
+
+ if (png_ptr->buffer_size < 8)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_push_fill_buffer(png_ptr, chunk_length, 4);
+ png_ptr->push_length = png_get_uint_32(chunk_length);
+
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+ png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
+
+ if (png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4))
+ {
+ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
+ png_error(png_ptr, "Not enough compressed data");
+ return;
+ }
+
+ png_ptr->idat_size = png_ptr->push_length;
+ }
+ if (png_ptr->idat_size && png_ptr->save_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (png_ptr->idat_size < (png_uint_32)png_ptr->save_buffer_size)
+ {
+ save_size = (png_size_t)png_ptr->idat_size;
+ /* check for overflow */
+ if((png_uint_32)save_size != png_ptr->idat_size)
+ png_error(png_ptr, "save_size overflowed in pngpread");
+ }
+ else
+ save_size = png_ptr->save_buffer_size;
+
+ png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size);
+ png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size);
+
+ png_ptr->idat_size -= save_size;
+ png_ptr->buffer_size -= save_size;
+ png_ptr->save_buffer_size -= save_size;
+ png_ptr->save_buffer_ptr += save_size;
+ }
+ if (png_ptr->idat_size && png_ptr->current_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (png_ptr->idat_size < (png_uint_32)png_ptr->current_buffer_size)
+ {
+ save_size = (png_size_t)png_ptr->idat_size;
+ /* check for overflow */
+ if((png_uint_32)save_size != png_ptr->idat_size)
+ png_error(png_ptr, "save_size overflowed in pngpread");
+ }
+ else
+ save_size = png_ptr->current_buffer_size;
+
+ png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size);
+ png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size);
+
+ png_ptr->idat_size -= save_size;
+ png_ptr->buffer_size -= save_size;
+ png_ptr->current_buffer_size -= save_size;
+ png_ptr->current_buffer_ptr += save_size;
+ }
+ if (!png_ptr->idat_size)
+ {
+ if (png_ptr->buffer_size < 4)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_crc_finish(png_ptr, 0);
+ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
+ }
+}
+
+void /* PRIVATE */
+png_process_IDAT_data(png_structp png_ptr, png_bytep buffer,
+ png_size_t buffer_length)
+{
+ int ret;
+
+ if ((png_ptr->flags & PNG_FLAG_ZLIB_FINISHED) && buffer_length)
+ png_error(png_ptr, "Extra compression data");
+
+ png_ptr->zstream.next_in = buffer;
+ png_ptr->zstream.avail_in = (uInt)buffer_length;
+ for(;;)
+ {
+ ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
+ if (ret != Z_OK)
+ {
+ if (ret == Z_STREAM_END)
+ {
+ if (png_ptr->zstream.avail_in)
+ png_error(png_ptr, "Extra compressed data");
+ if (!(png_ptr->zstream.avail_out))
+ {
+ png_push_process_row(png_ptr);
+ }
+
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
+ break;
+ }
+ else if (ret == Z_BUF_ERROR)
+ break;
+ else
+ png_error(png_ptr, "Decompression Error");
+ }
+ if (!(png_ptr->zstream.avail_out))
+ {
+ png_push_process_row(png_ptr);
+ png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes;
+ png_ptr->zstream.next_out = png_ptr->row_buf;
+ }
+ else
+ break;
+ }
+}
+
+void /* PRIVATE */
+png_push_process_row(png_structp png_ptr)
+{
+ png_ptr->row_info.color_type = png_ptr->color_type;
+ png_ptr->row_info.width = png_ptr->iwidth;
+ png_ptr->row_info.channels = png_ptr->channels;
+ png_ptr->row_info.bit_depth = png_ptr->bit_depth;
+ png_ptr->row_info.pixel_depth = png_ptr->pixel_depth;
+
+ png_ptr->row_info.rowbytes = ((png_ptr->row_info.width *
+ (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3);
+
+ png_read_filter_row(png_ptr, &(png_ptr->row_info),
+ png_ptr->row_buf + 1, png_ptr->prev_row + 1,
+ (int)(png_ptr->row_buf[0]));
+
+ png_memcpy_check(png_ptr, png_ptr->prev_row, png_ptr->row_buf,
+ png_ptr->rowbytes + 1);
+
+ if (png_ptr->transformations)
+ png_do_read_transformations(png_ptr);
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+ /* blow up interlaced rows to full size */
+ if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
+ {
+ if (png_ptr->pass < 6)
+/* old interface (pre-1.0.9):
+ png_do_read_interlace(&(png_ptr->row_info),
+ png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations);
+ */
+ png_do_read_interlace(png_ptr);
+
+ switch (png_ptr->pass)
+ {
+ case 0:
+ {
+ int i;
+ for (i = 0; i < 8 && png_ptr->pass == 0; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr); /* updates png_ptr->pass */
+ }
+ if (png_ptr->pass == 2) /* pass 1 might be empty */
+ {
+ for (i = 0; i < 4 && png_ptr->pass == 2; i++)
+ {
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ }
+ if (png_ptr->pass == 4 && png_ptr->height <= 4)
+ {
+ for (i = 0; i < 2 && png_ptr->pass == 4; i++)
+ {
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ }
+ if (png_ptr->pass == 6 && png_ptr->height <= 4)
+ {
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ break;
+ }
+ case 1:
+ {
+ int i;
+ for (i = 0; i < 8 && png_ptr->pass == 1; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ if (png_ptr->pass == 2) /* skip top 4 generated rows */
+ {
+ for (i = 0; i < 4 && png_ptr->pass == 2; i++)
+ {
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ }
+ break;
+ }
+ case 2:
+ {
+ int i;
+ for (i = 0; i < 4 && png_ptr->pass == 2; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ for (i = 0; i < 4 && png_ptr->pass == 2; i++)
+ {
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ if (png_ptr->pass == 4) /* pass 3 might be empty */
+ {
+ for (i = 0; i < 2 && png_ptr->pass == 4; i++)
+ {
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ }
+ break;
+ }
+ case 3:
+ {
+ int i;
+ for (i = 0; i < 4 && png_ptr->pass == 3; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ if (png_ptr->pass == 4) /* skip top two generated rows */
+ {
+ for (i = 0; i < 2 && png_ptr->pass == 4; i++)
+ {
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ }
+ break;
+ }
+ case 4:
+ {
+ int i;
+ for (i = 0; i < 2 && png_ptr->pass == 4; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ for (i = 0; i < 2 && png_ptr->pass == 4; i++)
+ {
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ if (png_ptr->pass == 6) /* pass 5 might be empty */
+ {
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ break;
+ }
+ case 5:
+ {
+ int i;
+ for (i = 0; i < 2 && png_ptr->pass == 5; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ if (png_ptr->pass == 6) /* skip top generated row */
+ {
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ break;
+ }
+ case 6:
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ if (png_ptr->pass != 6)
+ break;
+ png_push_have_row(png_ptr, NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ }
+ }
+ else
+#endif
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+}
+
+void /* PRIVATE */
+png_read_push_finish_row(png_structp png_ptr)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+
+ /* start of interlace block */
+ const int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
+
+ /* offset to next interlace block */
+ const int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
+
+ /* start of interlace block in the y direction */
+ const int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
+
+ /* offset to next interlace block in the y direction */
+ const int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
+
+ /* Width of interlace block. This is not currently used - if you need
+ * it, uncomment it here and in png.h
+ const int FARDATA png_pass_width[] = {8, 4, 4, 2, 2, 1, 1};
+ */
+
+ /* Height of interlace block. This is not currently used - if you need
+ * it, uncomment it here and in png.h
+ const int FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1};
+ */
+#endif
+
+ png_ptr->row_number++;
+ if (png_ptr->row_number < png_ptr->num_rows)
+ return;
+
+ if (png_ptr->interlaced)
+ {
+ png_ptr->row_number = 0;
+ png_memset_check(png_ptr, png_ptr->prev_row, 0,
+ png_ptr->rowbytes + 1);
+ do
+ {
+ png_ptr->pass++;
+ if ((png_ptr->pass == 1 && png_ptr->width < 5) ||
+ (png_ptr->pass == 3 && png_ptr->width < 3) ||
+ (png_ptr->pass == 5 && png_ptr->width < 2))
+ png_ptr->pass++;
+
+ if (png_ptr->pass >= 7)
+ break;
+
+ png_ptr->iwidth = (png_ptr->width +
+ png_pass_inc[png_ptr->pass] - 1 -
+ png_pass_start[png_ptr->pass]) /
+ png_pass_inc[png_ptr->pass];
+
+ png_ptr->irowbytes = ((png_ptr->iwidth *
+ png_ptr->pixel_depth + 7) >> 3) + 1;
+
+ if (png_ptr->transformations & PNG_INTERLACE)
+ break;
+
+ png_ptr->num_rows = (png_ptr->height +
+ png_pass_yinc[png_ptr->pass] - 1 -
+ png_pass_ystart[png_ptr->pass]) /
+ png_pass_yinc[png_ptr->pass];
+
+ } while (png_ptr->iwidth == 0 || png_ptr->num_rows == 0);
+ }
+}
+
+#if defined(PNG_READ_tEXt_SUPPORTED)
+void /* PRIVATE */
+png_push_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32
+ length)
+{
+ if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND))
+ {
+ png_error(png_ptr, "Out of place tEXt");
+ /* to quiet some compiler warnings */
+ if(info_ptr == NULL) return;
+ }
+
+#ifdef PNG_MAX_MALLOC_64K
+ png_ptr->skip_length = 0; /* This may not be necessary */
+
+ if (length > (png_uint_32)65535L) /* Can't hold entire string in memory */
+ {
+ png_warning(png_ptr, "tEXt chunk too large to fit in memory");
+ png_ptr->skip_length = length - (png_uint_32)65535L;
+ length = (png_uint_32)65535L;
+ }
+#endif
+
+ png_ptr->current_text = (png_charp)png_malloc(png_ptr,
+ (png_uint_32)(length+1));
+ png_ptr->current_text[length] = '\0';
+ png_ptr->current_text_ptr = png_ptr->current_text;
+ png_ptr->current_text_size = (png_size_t)length;
+ png_ptr->current_text_left = (png_size_t)length;
+ png_ptr->process_mode = PNG_READ_tEXt_MODE;
+}
+
+void /* PRIVATE */
+png_push_read_tEXt(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr->buffer_size && png_ptr->current_text_left)
+ {
+ png_size_t text_size;
+
+ if (png_ptr->buffer_size < png_ptr->current_text_left)
+ text_size = png_ptr->buffer_size;
+ else
+ text_size = png_ptr->current_text_left;
+ png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size);
+ png_ptr->current_text_left -= text_size;
+ png_ptr->current_text_ptr += text_size;
+ }
+ if (!(png_ptr->current_text_left))
+ {
+ png_textp text_ptr;
+ png_charp text;
+ png_charp key;
+
+ if (png_ptr->buffer_size < 4)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_push_crc_finish(png_ptr);
+
+#if defined(PNG_MAX_MALLOC_64K)
+ if (png_ptr->skip_length)
+ return;
+#endif
+
+ key = png_ptr->current_text;
+ png_ptr->current_text = 0;
+
+ for (text = key; *text; text++)
+ /* empty loop */ ;
+
+ if (text != key + png_ptr->current_text_size)
+ text++;
+
+ text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text));
+ text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
+ text_ptr->key = key;
+#ifdef PNG_iTXt_SUPPORTED
+ text_ptr->lang = (char *)NULL;
+ text_ptr->lang_key = (char *)NULL;
+#endif
+ text_ptr->text = text;
+
+ png_set_text(png_ptr, info_ptr, text_ptr, 1);
+
+ png_free(png_ptr, key);
+ png_free(png_ptr, text_ptr);
+ }
+}
+#endif
+
+#if defined(PNG_READ_zTXt_SUPPORTED)
+void /* PRIVATE */
+png_push_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32
+ length)
+{
+ if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND))
+ {
+ png_error(png_ptr, "Out of place zTXt");
+ /* to quiet some compiler warnings */
+ if(info_ptr == NULL) return;
+ }
+
+#ifdef PNG_MAX_MALLOC_64K
+ /* We can't handle zTXt chunks > 64K, since we don't have enough space
+ * to be able to store the uncompressed data. Actually, the threshold
+ * is probably around 32K, but it isn't as definite as 64K is.
+ */
+ if (length > (png_uint_32)65535L)
+ {
+ png_warning(png_ptr, "zTXt chunk too large to fit in memory");
+ png_push_crc_skip(png_ptr, length);
+ return;
+ }
+#endif
+
+ png_ptr->current_text = (png_charp)png_malloc(png_ptr,
+ (png_uint_32)(length+1));
+ png_ptr->current_text[length] = '\0';
+ png_ptr->current_text_ptr = png_ptr->current_text;
+ png_ptr->current_text_size = (png_size_t)length;
+ png_ptr->current_text_left = (png_size_t)length;
+ png_ptr->process_mode = PNG_READ_zTXt_MODE;
+}
+
+void /* PRIVATE */
+png_push_read_zTXt(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr->buffer_size && png_ptr->current_text_left)
+ {
+ png_size_t text_size;
+
+ if (png_ptr->buffer_size < (png_uint_32)png_ptr->current_text_left)
+ text_size = png_ptr->buffer_size;
+ else
+ text_size = png_ptr->current_text_left;
+ png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size);
+ png_ptr->current_text_left -= text_size;
+ png_ptr->current_text_ptr += text_size;
+ }
+ if (!(png_ptr->current_text_left))
+ {
+ png_textp text_ptr;
+ png_charp text;
+ png_charp key;
+ int ret;
+ png_size_t text_size, key_size;
+
+ if (png_ptr->buffer_size < 4)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_push_crc_finish(png_ptr);
+
+ key = png_ptr->current_text;
+ png_ptr->current_text = 0;
+
+ for (text = key; *text; text++)
+ /* empty loop */ ;
+
+ /* zTXt can't have zero text */
+ if (text == key + png_ptr->current_text_size)
+ {
+ png_free(png_ptr, key);
+ return;
+ }
+
+ text++;
+
+ if (*text != PNG_TEXT_COMPRESSION_zTXt) /* check compression byte */
+ {
+ png_free(png_ptr, key);
+ return;
+ }
+
+ text++;
+
+ png_ptr->zstream.next_in = (png_bytep )text;
+ png_ptr->zstream.avail_in = (uInt)(png_ptr->current_text_size -
+ (text - key));
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+
+ key_size = text - key;
+ text_size = 0;
+ text = NULL;
+ ret = Z_STREAM_END;
+
+ while (png_ptr->zstream.avail_in)
+ {
+ ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
+ if (ret != Z_OK && ret != Z_STREAM_END)
+ {
+ inflateReset(&png_ptr->zstream);
+ png_ptr->zstream.avail_in = 0;
+ png_free(png_ptr, key);
+ png_free(png_ptr, text);
+ return;
+ }
+ if (!(png_ptr->zstream.avail_out) || ret == Z_STREAM_END)
+ {
+ if (text == NULL)
+ {
+ text = (png_charp)png_malloc(png_ptr,
+ (png_uint_32)(png_ptr->zbuf_size - png_ptr->zstream.avail_out
+ + key_size + 1));
+ png_memcpy(text + key_size, png_ptr->zbuf,
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out);
+ png_memcpy(text, key, key_size);
+ text_size = key_size + png_ptr->zbuf_size -
+ png_ptr->zstream.avail_out;
+ *(text + text_size) = '\0';
+ }
+ else
+ {
+ png_charp tmp;
+
+ tmp = text;
+ text = (png_charp)png_malloc(png_ptr, text_size +
+ (png_uint_32)(png_ptr->zbuf_size - png_ptr->zstream.avail_out
+ + 1));
+ png_memcpy(text, tmp, text_size);
+ png_free(png_ptr, tmp);
+ png_memcpy(text + text_size, png_ptr->zbuf,
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out);
+ text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
+ *(text + text_size) = '\0';
+ }
+ if (ret != Z_STREAM_END)
+ {
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ }
+ }
+ else
+ {
+ break;
+ }
+
+ if (ret == Z_STREAM_END)
+ break;
+ }
+
+ inflateReset(&png_ptr->zstream);
+ png_ptr->zstream.avail_in = 0;
+
+ if (ret != Z_STREAM_END)
+ {
+ png_free(png_ptr, key);
+ png_free(png_ptr, text);
+ return;
+ }
+
+ png_free(png_ptr, key);
+ key = text;
+ text += key_size;
+
+ text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text));
+ text_ptr->compression = PNG_TEXT_COMPRESSION_zTXt;
+ text_ptr->key = key;
+#ifdef PNG_iTXt_SUPPORTED
+ text_ptr->lang = (char *)NULL;
+ text_ptr->lang_key = (char *)NULL;
+#endif
+ text_ptr->text = text;
+
+ png_set_text(png_ptr, info_ptr, text_ptr, 1);
+
+ png_free(png_ptr, key);
+ png_free(png_ptr, text_ptr);
+ }
+}
+#endif
+
+#if defined(PNG_READ_iTXt_SUPPORTED)
+void /* PRIVATE */
+png_push_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32
+ length)
+{
+ if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND))
+ {
+ png_error(png_ptr, "Out of place iTXt");
+ /* to quiet some compiler warnings */
+ if(info_ptr == NULL) return;
+ }
+
+#ifdef PNG_MAX_MALLOC_64K
+ png_ptr->skip_length = 0; /* This may not be necessary */
+
+ if (length > (png_uint_32)65535L) /* Can't hold entire string in memory */
+ {
+ png_warning(png_ptr, "iTXt chunk too large to fit in memory");
+ png_ptr->skip_length = length - (png_uint_32)65535L;
+ length = (png_uint_32)65535L;
+ }
+#endif
+
+ png_ptr->current_text = (png_charp)png_malloc(png_ptr,
+ (png_uint_32)(length+1));
+ png_ptr->current_text[length] = '\0';
+ png_ptr->current_text_ptr = png_ptr->current_text;
+ png_ptr->current_text_size = (png_size_t)length;
+ png_ptr->current_text_left = (png_size_t)length;
+ png_ptr->process_mode = PNG_READ_iTXt_MODE;
+}
+
+void /* PRIVATE */
+png_push_read_iTXt(png_structp png_ptr, png_infop info_ptr)
+{
+
+ if (png_ptr->buffer_size && png_ptr->current_text_left)
+ {
+ png_size_t text_size;
+
+ if (png_ptr->buffer_size < png_ptr->current_text_left)
+ text_size = png_ptr->buffer_size;
+ else
+ text_size = png_ptr->current_text_left;
+ png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size);
+ png_ptr->current_text_left -= text_size;
+ png_ptr->current_text_ptr += text_size;
+ }
+ if (!(png_ptr->current_text_left))
+ {
+ png_textp text_ptr;
+ png_charp key;
+ int comp_flag;
+ png_charp lang;
+ png_charp lang_key;
+ png_charp text;
+
+ if (png_ptr->buffer_size < 4)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_push_crc_finish(png_ptr);
+
+#if defined(PNG_MAX_MALLOC_64K)
+ if (png_ptr->skip_length)
+ return;
+#endif
+
+ key = png_ptr->current_text;
+ png_ptr->current_text = 0;
+
+ for (lang = key; *lang; lang++)
+ /* empty loop */ ;
+
+ if (lang != key + png_ptr->current_text_size)
+ lang++;
+
+ comp_flag = *lang++;
+ lang++; /* skip comp_type, always zero */
+
+ for (lang_key = lang; *lang_key; lang_key++)
+ /* empty loop */ ;
+ lang_key++; /* skip NUL separator */
+
+ for (text = lang_key; *text; text++)
+ /* empty loop */ ;
+
+ if (text != key + png_ptr->current_text_size)
+ text++;
+
+ text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text));
+ text_ptr->compression = comp_flag + 2;
+ text_ptr->key = key;
+ text_ptr->lang = lang;
+ text_ptr->lang_key = lang_key;
+ text_ptr->text = text;
+ text_ptr->text_length = 0;
+ text_ptr->itxt_length = png_strlen(text);
+
+ png_set_text(png_ptr, info_ptr, text_ptr, 1);
+
+ png_free(png_ptr, text_ptr);
+ }
+}
+#endif
+
+/* This function is called when we haven't found a handler for this
+ * chunk. If there isn't a problem with the chunk itself (ie a bad chunk
+ * name or a critical chunk), the chunk is (currently) silently ignored.
+ */
+void /* PRIVATE */
+png_push_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32
+ length)
+{
+ png_uint_32 skip=0;
+ png_check_chunk_name(png_ptr, png_ptr->chunk_name);
+
+ if (!(png_ptr->chunk_name[0] & 0x20))
+ {
+#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
+ if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
+ HANDLE_CHUNK_ALWAYS
+#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
+ && png_ptr->read_user_chunk_fn == NULL
+#endif
+ )
+#endif
+ png_chunk_error(png_ptr, "unknown critical chunk");
+
+ /* to quiet compiler warnings about unused info_ptr */
+ if (info_ptr == NULL)
+ return;
+ }
+
+#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
+ if (png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS)
+ {
+ png_unknown_chunk chunk;
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (length > (png_uint_32)65535L)
+ {
+ png_warning(png_ptr, "unknown chunk too large to fit in memory");
+ skip = length - (png_uint_32)65535L;
+ length = (png_uint_32)65535L;
+ }
+#endif
+
+ png_strcpy((png_charp)chunk.name, (png_charp)png_ptr->chunk_name);
+ chunk.data = (png_bytep)png_malloc(png_ptr, length);
+ png_crc_read(png_ptr, chunk.data, length);
+ chunk.size = length;
+#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
+ if(png_ptr->read_user_chunk_fn != NULL)
+ {
+ /* callback to user unknown chunk handler */
+ if ((*(png_ptr->read_user_chunk_fn)) (png_ptr, &chunk) <= 0)
+ {
+ if (!(png_ptr->chunk_name[0] & 0x20))
+ if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
+ HANDLE_CHUNK_ALWAYS)
+ png_chunk_error(png_ptr, "unknown critical chunk");
+ }
+ png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1);
+ }
+ else
+#endif
+ png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1);
+ png_free(png_ptr, chunk.data);
+ }
+ else
+#endif
+ skip=length;
+ png_push_crc_skip(png_ptr, skip);
+}
+
+void /* PRIVATE */
+png_push_have_info(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr->info_fn != NULL)
+ (*(png_ptr->info_fn))(png_ptr, info_ptr);
+}
+
+void /* PRIVATE */
+png_push_have_end(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr->end_fn != NULL)
+ (*(png_ptr->end_fn))(png_ptr, info_ptr);
+}
+
+void /* PRIVATE */
+png_push_have_row(png_structp png_ptr, png_bytep row)
+{
+ if (png_ptr->row_fn != NULL)
+ (*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number,
+ (int)png_ptr->pass);
+}
+
+void PNGAPI
+png_progressive_combine_row (png_structp png_ptr,
+ png_bytep old_row, png_bytep new_row)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ const int FARDATA png_pass_dsp_mask[7] =
+ {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff};
+#endif
+ if (new_row != NULL) /* new_row must == png_ptr->row_buf here. */
+ png_combine_row(png_ptr, old_row, png_pass_dsp_mask[png_ptr->pass]);
+}
+
+void PNGAPI
+png_set_progressive_read_fn(png_structp png_ptr, png_voidp progressive_ptr,
+ png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn,
+ png_progressive_end_ptr end_fn)
+{
+ png_ptr->info_fn = info_fn;
+ png_ptr->row_fn = row_fn;
+ png_ptr->end_fn = end_fn;
+
+ png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
+}
+
+png_voidp PNGAPI
+png_get_progressive_ptr(png_structp png_ptr)
+{
+ return png_ptr->io_ptr;
+}
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
--- /dev/null
+
+/* pngread.c - read a PNG file
+ *
+ * libpng 1.2.0 - September 1, 2001
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ *
+ * This file contains routines that an application calls directly to
+ * read a PNG file or stream.
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* Create a PNG structure for reading, and allocate any memory needed. */
+png_structp PNGAPI
+png_create_read_struct(png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn)
+{
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ return (png_create_read_struct_2(user_png_ver, error_ptr, error_fn,
+ warn_fn, NULL, NULL, NULL));
+}
+
+/* Alternate create PNG structure for reading, and allocate any memory needed. */
+png_structp PNGAPI
+png_create_read_struct_2(png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
+ png_malloc_ptr malloc_fn, png_free_ptr free_fn)
+{
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+ png_structp png_ptr;
+
+#ifdef PNG_SETJMP_SUPPORTED
+#ifdef USE_FAR_KEYWORD
+ jmp_buf jmpbuf;
+#endif
+#endif
+
+ int i;
+
+ png_debug(1, "in png_create_read_struct\n");
+#ifdef PNG_USER_MEM_SUPPORTED
+ if ((png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG,
+ (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr)) == NULL)
+#else
+ if ((png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG)) == NULL)
+#endif
+ {
+ return (png_structp)NULL;
+ }
+
+#ifdef PNG_ASSEMBLER_CODE_SUPPORTED
+ png_init_mmx_flags(png_ptr); /* 1.2.0 addition */
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+#ifdef USE_FAR_KEYWORD
+ if (setjmp(jmpbuf))
+#else
+ if (setjmp(png_ptr->jmpbuf))
+#endif
+ {
+ png_free(png_ptr, png_ptr->zbuf);
+ png_ptr->zbuf=NULL;
+ png_destroy_struct(png_ptr);
+ return (png_structp)NULL;
+ }
+#ifdef USE_FAR_KEYWORD
+ png_memcpy(png_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
+#endif
+#endif
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn);
+#endif
+
+ png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
+
+ i=0;
+ do
+ {
+ if(user_png_ver[i] != png_libpng_ver[i])
+ png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
+ } while (png_libpng_ver[i++]);
+
+ if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)
+ {
+ /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
+ * we must recompile any applications that use any older library version.
+ * For versions after libpng 1.0, we will be compatible, so we need
+ * only check the first digit.
+ */
+ if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
+ (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) ||
+ (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
+ {
+#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
+ char msg[80];
+ if (user_png_ver)
+ {
+ sprintf(msg, "Application was compiled with png.h from libpng-%.20s",
+ user_png_ver);
+ png_warning(png_ptr, msg);
+ }
+ sprintf(msg, "Application is running with png.c from libpng-%.20s",
+ png_libpng_ver);
+ png_warning(png_ptr, msg);
+#endif
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+ png_ptr->flags=0;
+#endif
+ png_error(png_ptr,
+ "Incompatible libpng version in application and library");
+ }
+ }
+
+ /* initialize zbuf - compression buffer */
+ png_ptr->zbuf_size = PNG_ZBUF_SIZE;
+ png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)png_ptr->zbuf_size);
+ png_ptr->zstream.zalloc = png_zalloc;
+ png_ptr->zstream.zfree = png_zfree;
+ png_ptr->zstream.opaque = (voidpf)png_ptr;
+
+ switch (inflateInit(&png_ptr->zstream))
+ {
+ case Z_OK: /* Do nothing */ break;
+ case Z_MEM_ERROR:
+ case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory error"); break;
+ case Z_VERSION_ERROR: png_error(png_ptr, "zlib version error"); break;
+ default: png_error(png_ptr, "Unknown zlib error");
+ }
+
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+
+ png_set_read_fn(png_ptr, NULL, NULL);
+
+ return (png_ptr);
+}
+
+/* Initialize PNG structure for reading, and allocate any memory needed.
+ This interface is deprecated in favour of the png_create_read_struct(),
+ and it will eventually disappear. */
+#undef png_read_init
+void PNGAPI
+png_read_init(png_structp png_ptr)
+{
+ /* We only come here via pre-1.0.7-compiled applications */
+ png_read_init_2(png_ptr, "1.0.6 or earlier", 0, 0);
+}
+
+#undef png_read_init_2
+void PNGAPI
+png_read_init_2(png_structp png_ptr, png_const_charp user_png_ver,
+ png_size_t png_struct_size, png_size_t png_info_size)
+{
+ /* We only come here via pre-1.0.12-compiled applications */
+#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
+ if(sizeof(png_struct) > png_struct_size || sizeof(png_info) > png_info_size)
+ {
+ char msg[80];
+ png_ptr->warning_fn=(png_error_ptr)NULL;
+ if (user_png_ver)
+ {
+ sprintf(msg, "Application was compiled with png.h from libpng-%.20s",
+ user_png_ver);
+ png_warning(png_ptr, msg);
+ }
+ sprintf(msg, "Application is running with png.c from libpng-%.20s",
+ png_libpng_ver);
+ png_warning(png_ptr, msg);
+ }
+#endif
+ if(sizeof(png_struct) > png_struct_size)
+ {
+ png_ptr->error_fn=(png_error_ptr)NULL;
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+ png_ptr->flags=0;
+#endif
+ png_error(png_ptr,
+ "The png struct allocated by the application for reading is too small.");
+ }
+ if(sizeof(png_info) > png_info_size)
+ {
+ png_ptr->error_fn=(png_error_ptr)NULL;
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+ png_ptr->flags=0;
+#endif
+ png_error(png_ptr,
+ "The info struct allocated by application for reading is too small.");
+ }
+ png_read_init_3(&png_ptr, user_png_ver, png_struct_size);
+}
+
+void PNGAPI
+png_read_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver,
+ png_size_t png_struct_size)
+{
+#ifdef PNG_SETJMP_SUPPORTED
+ jmp_buf tmp_jmp; /* to save current jump buffer */
+#endif
+
+ int i=0;
+
+ png_structp png_ptr=*ptr_ptr;
+
+ do
+ {
+ if(user_png_ver[i] != png_libpng_ver[i])
+ {
+#ifdef PNG_LEGACY_SUPPORTED
+ png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
+#else
+ png_ptr->warning_fn=(png_error_ptr)NULL;
+ png_warning(png_ptr,
+ "Application uses deprecated png_read_init() and should be recompiled.");
+ break;
+#endif
+ }
+ } while (png_libpng_ver[i++]);
+
+ png_debug(1, "in png_read_init_3\n");
+
+#ifdef PNG_SETJMP_SUPPORTED
+ /* save jump buffer and error functions */
+ png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
+#endif
+
+ if(sizeof(png_struct) > png_struct_size)
+ {
+ png_destroy_struct(png_ptr);
+ *ptr_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
+ png_ptr = *ptr_ptr;
+ }
+
+ /* reset all variables to 0 */
+ png_memset(png_ptr, 0, sizeof (png_struct));
+
+#ifdef PNG_SETJMP_SUPPORTED
+ /* restore jump buffer */
+ png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
+#endif
+
+ /* initialize zbuf - compression buffer */
+ png_ptr->zbuf_size = PNG_ZBUF_SIZE;
+ png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)png_ptr->zbuf_size);
+ png_ptr->zstream.zalloc = png_zalloc;
+ png_ptr->zstream.zfree = png_zfree;
+ png_ptr->zstream.opaque = (voidpf)png_ptr;
+
+ switch (inflateInit(&png_ptr->zstream))
+ {
+ case Z_OK: /* Do nothing */ break;
+ case Z_MEM_ERROR:
+ case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory"); break;
+ case Z_VERSION_ERROR: png_error(png_ptr, "zlib version"); break;
+ default: png_error(png_ptr, "Unknown zlib error");
+ }
+
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+
+ png_set_read_fn(png_ptr, NULL, NULL);
+}
+
+/* Read the information before the actual image data. This has been
+ * changed in v0.90 to allow reading a file that already has the magic
+ * bytes read from the stream. You can tell libpng how many bytes have
+ * been read from the beginning of the stream (up to the maximum of 8)
+ * via png_set_sig_bytes(), and we will only check the remaining bytes
+ * here. The application can then have access to the signature bytes we
+ * read if it is determined that this isn't a valid PNG file.
+ */
+void PNGAPI
+png_read_info(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_read_info\n");
+ /* save jump buffer and error functions */
+ /* If we haven't checked all of the PNG signature bytes, do so now. */
+ if (png_ptr->sig_bytes < 8)
+ {
+ png_size_t num_checked = png_ptr->sig_bytes,
+ num_to_check = 8 - num_checked;
+
+ png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check);
+ png_ptr->sig_bytes = 8;
+
+ if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))
+ {
+ if (num_checked < 4 &&
+ png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))
+ png_error(png_ptr, "Not a PNG file");
+ else
+ png_error(png_ptr, "PNG file corrupted by ASCII conversion");
+ }
+ if (num_checked < 3)
+ png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
+ }
+
+ for(;;)
+ {
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_IHDR;
+ PNG_IDAT;
+ PNG_IEND;
+ PNG_PLTE;
+#if defined(PNG_READ_bKGD_SUPPORTED)
+ PNG_bKGD;
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED)
+ PNG_cHRM;
+#endif
+#if defined(PNG_READ_gAMA_SUPPORTED)
+ PNG_gAMA;
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+ PNG_hIST;
+#endif
+#if defined(PNG_READ_iCCP_SUPPORTED)
+ PNG_iCCP;
+#endif
+#if defined(PNG_READ_iTXt_SUPPORTED)
+ PNG_iTXt;
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED)
+ PNG_oFFs;
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+ PNG_pCAL;
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED)
+ PNG_pHYs;
+#endif
+#if defined(PNG_READ_sBIT_SUPPORTED)
+ PNG_sBIT;
+#endif
+#if defined(PNG_READ_sCAL_SUPPORTED)
+ PNG_sCAL;
+#endif
+#if defined(PNG_READ_sPLT_SUPPORTED)
+ PNG_sPLT;
+#endif
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ PNG_sRGB;
+#endif
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ PNG_tEXt;
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED)
+ PNG_tIME;
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED)
+ PNG_tRNS;
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ PNG_zTXt;
+#endif
+#endif /* PNG_GLOBAL_ARRAYS */
+ png_byte chunk_length[4];
+ png_uint_32 length;
+
+ png_read_data(png_ptr, chunk_length, 4);
+ length = png_get_uint_32(chunk_length);
+
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+
+ png_debug2(0, "Reading %s chunk, length=%lu.\n", png_ptr->chunk_name,
+ length);
+
+ /* This should be a binary subdivision search or a hash for
+ * matching the chunk name rather than a linear search.
+ */
+ if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4))
+ png_handle_IHDR(png_ptr, info_ptr, length);
+ else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
+ png_handle_IEND(png_ptr, info_ptr, length);
+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+ else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name))
+ {
+ if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ png_ptr->mode |= PNG_HAVE_IDAT;
+ png_handle_unknown(png_ptr, info_ptr, length);
+ if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ png_ptr->mode |= PNG_HAVE_PLTE;
+ else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ {
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before IDAT");
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+ !(png_ptr->mode & PNG_HAVE_PLTE))
+ png_error(png_ptr, "Missing PLTE before IDAT");
+ break;
+ }
+ }
+#endif
+ else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ png_handle_PLTE(png_ptr, info_ptr, length);
+ else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ {
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before IDAT");
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+ !(png_ptr->mode & PNG_HAVE_PLTE))
+ png_error(png_ptr, "Missing PLTE before IDAT");
+
+ png_ptr->idat_size = length;
+ png_ptr->mode |= PNG_HAVE_IDAT;
+ break;
+ }
+#if defined(PNG_READ_bKGD_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4))
+ png_handle_bKGD(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4))
+ png_handle_cHRM(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_gAMA_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4))
+ png_handle_gAMA(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4))
+ png_handle_hIST(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4))
+ png_handle_oFFs(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4))
+ png_handle_pCAL(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sCAL_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4))
+ png_handle_sCAL(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4))
+ png_handle_pHYs(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sBIT_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4))
+ png_handle_sBIT(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4))
+ png_handle_sRGB(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_iCCP_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4))
+ png_handle_iCCP(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sPLT_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4))
+ png_handle_sPLT(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4))
+ png_handle_tEXt(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
+ png_handle_tIME(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4))
+ png_handle_tRNS(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4))
+ png_handle_zTXt(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_iTXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4))
+ png_handle_iTXt(png_ptr, info_ptr, length);
+#endif
+ else
+ png_handle_unknown(png_ptr, info_ptr, length);
+ }
+}
+
+/* optional call to update the users info_ptr structure */
+void PNGAPI
+png_read_update_info(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_read_update_info\n");
+ /* save jump buffer and error functions */
+ if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
+ png_read_start_row(png_ptr);
+ else
+ png_warning(png_ptr,
+ "Ignoring extra png_read_update_info() call; row buffer not reallocated");
+ png_read_transform_info(png_ptr, info_ptr);
+}
+
+/* Initialize palette, background, etc, after transformations
+ * are set, but before any reading takes place. This allows
+ * the user to obtain a gamma-corrected palette, for example.
+ * If the user doesn't call this, we will do it ourselves.
+ */
+void PNGAPI
+png_start_read_image(png_structp png_ptr)
+{
+ png_debug(1, "in png_start_read_image\n");
+ /* save jump buffer and error functions */
+ if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
+ png_read_start_row(png_ptr);
+}
+
+void PNGAPI
+png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_IDAT;
+ const int png_pass_dsp_mask[7] = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff};
+ const int png_pass_mask[7] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff};
+#endif
+ int ret;
+ png_debug2(1, "in png_read_row (row %lu, pass %d)\n",
+ png_ptr->row_number, png_ptr->pass);
+ /* save jump buffer and error functions */
+ if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
+ png_read_start_row(png_ptr);
+ if (png_ptr->row_number == 0 && png_ptr->pass == 0)
+ {
+ /* check for transforms that have been set but were defined out */
+#if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_MONO)
+ png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined.");
+#endif
+#if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED)
+ if (png_ptr->transformations & PNG_FILLER)
+ png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined.");
+#endif
+#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && !defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined.");
+#endif
+#if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACK)
+ png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined.");
+#endif
+#if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED)
+ if (png_ptr->transformations & PNG_SHIFT)
+ png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined.");
+#endif
+#if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED)
+ if (png_ptr->transformations & PNG_BGR)
+ png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined.");
+#endif
+#if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_BYTES)
+ png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined.");
+#endif
+ }
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+ /* if interlaced and we do not need a new row, combine row and return */
+ if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
+ {
+ switch (png_ptr->pass)
+ {
+ case 0:
+ if (png_ptr->row_number & 0x07)
+ {
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 1:
+ if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)
+ {
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 2:
+ if ((png_ptr->row_number & 0x07) != 4)
+ {
+ if (dsp_row != NULL && (png_ptr->row_number & 4))
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 3:
+ if ((png_ptr->row_number & 3) || png_ptr->width < 3)
+ {
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 4:
+ if ((png_ptr->row_number & 3) != 2)
+ {
+ if (dsp_row != NULL && (png_ptr->row_number & 2))
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 5:
+ if ((png_ptr->row_number & 1) || png_ptr->width < 2)
+ {
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 6:
+ if (!(png_ptr->row_number & 1))
+ {
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ }
+ }
+#endif
+
+ if (!(png_ptr->mode & PNG_HAVE_IDAT))
+ png_error(png_ptr, "Invalid attempt to read row data");
+
+ png_ptr->zstream.next_out = png_ptr->row_buf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes;
+ do
+ {
+ if (!(png_ptr->zstream.avail_in))
+ {
+ while (!png_ptr->idat_size)
+ {
+ png_byte chunk_length[4];
+
+ png_crc_finish(png_ptr, 0);
+
+ png_read_data(png_ptr, chunk_length, 4);
+ png_ptr->idat_size = png_get_uint_32(chunk_length);
+
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+ if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ png_error(png_ptr, "Not enough image data");
+ }
+ png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_in = png_ptr->zbuf;
+ if (png_ptr->zbuf_size > png_ptr->idat_size)
+ png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
+ png_crc_read(png_ptr, png_ptr->zbuf,
+ (png_size_t)png_ptr->zstream.avail_in);
+ png_ptr->idat_size -= png_ptr->zstream.avail_in;
+ }
+ ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
+ if (ret == Z_STREAM_END)
+ {
+ if (png_ptr->zstream.avail_out || png_ptr->zstream.avail_in ||
+ png_ptr->idat_size)
+ png_error(png_ptr, "Extra compressed data");
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
+ break;
+ }
+ if (ret != Z_OK)
+ png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
+ "Decompression error");
+
+ } while (png_ptr->zstream.avail_out);
+
+ png_ptr->row_info.color_type = png_ptr->color_type;
+ png_ptr->row_info.width = png_ptr->iwidth;
+ png_ptr->row_info.channels = png_ptr->channels;
+ png_ptr->row_info.bit_depth = png_ptr->bit_depth;
+ png_ptr->row_info.pixel_depth = png_ptr->pixel_depth;
+ png_ptr->row_info.rowbytes = ((png_ptr->row_info.width *
+ (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3);
+
+ if(png_ptr->row_buf[0])
+ png_read_filter_row(png_ptr, &(png_ptr->row_info),
+ png_ptr->row_buf + 1, png_ptr->prev_row + 1,
+ (int)(png_ptr->row_buf[0]));
+
+ png_memcpy_check(png_ptr, png_ptr->prev_row, png_ptr->row_buf,
+ png_ptr->rowbytes + 1);
+
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
+ (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))
+ {
+ /* Intrapixel differencing */
+ png_do_read_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1);
+ }
+#endif
+
+ if (png_ptr->transformations)
+ png_do_read_transformations(png_ptr);
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+ /* blow up interlaced rows to full size */
+ if (png_ptr->interlaced &&
+ (png_ptr->transformations & PNG_INTERLACE))
+ {
+ if (png_ptr->pass < 6)
+/* old interface (pre-1.0.9):
+ png_do_read_interlace(&(png_ptr->row_info),
+ png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations);
+ */
+ png_do_read_interlace(png_ptr);
+
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ if (row != NULL)
+ png_combine_row(png_ptr, row,
+ png_pass_mask[png_ptr->pass]);
+ }
+ else
+#endif
+ {
+ if (row != NULL)
+ png_combine_row(png_ptr, row, 0xff);
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row, 0xff);
+ }
+ png_read_finish_row(png_ptr);
+
+ if (png_ptr->read_row_fn != NULL)
+ (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
+}
+
+/* Read one or more rows of image data. If the image is interlaced,
+ * and png_set_interlace_handling() has been called, the rows need to
+ * contain the contents of the rows from the previous pass. If the
+ * image has alpha or transparency, and png_handle_alpha()[*] has been
+ * called, the rows contents must be initialized to the contents of the
+ * screen.
+ *
+ * "row" holds the actual image, and pixels are placed in it
+ * as they arrive. If the image is displayed after each pass, it will
+ * appear to "sparkle" in. "display_row" can be used to display a
+ * "chunky" progressive image, with finer detail added as it becomes
+ * available. If you do not want this "chunky" display, you may pass
+ * NULL for display_row. If you do not want the sparkle display, and
+ * you have not called png_handle_alpha(), you may pass NULL for rows.
+ * If you have called png_handle_alpha(), and the image has either an
+ * alpha channel or a transparency chunk, you must provide a buffer for
+ * rows. In this case, you do not have to provide a display_row buffer
+ * also, but you may. If the image is not interlaced, or if you have
+ * not called png_set_interlace_handling(), the display_row buffer will
+ * be ignored, so pass NULL to it.
+ *
+ * [*] png_handle_alpha() does not exist yet, as of libpng version 1.2.0
+ */
+
+void PNGAPI
+png_read_rows(png_structp png_ptr, png_bytepp row,
+ png_bytepp display_row, png_uint_32 num_rows)
+{
+ png_uint_32 i;
+ png_bytepp rp;
+ png_bytepp dp;
+
+ png_debug(1, "in png_read_rows\n");
+ /* save jump buffer and error functions */
+ rp = row;
+ dp = display_row;
+ if (rp != NULL && dp != NULL)
+ for (i = 0; i < num_rows; i++)
+ {
+ png_bytep rptr = *rp++;
+ png_bytep dptr = *dp++;
+
+ png_read_row(png_ptr, rptr, dptr);
+ }
+ else if(rp != NULL)
+ for (i = 0; i < num_rows; i++)
+ {
+ png_bytep rptr = *rp;
+ png_read_row(png_ptr, rptr, NULL);
+ rp++;
+ }
+ else if(dp != NULL)
+ for (i = 0; i < num_rows; i++)
+ {
+ png_bytep dptr = *dp;
+ png_read_row(png_ptr, NULL, dptr);
+ dp++;
+ }
+}
+
+/* Read the entire image. If the image has an alpha channel or a tRNS
+ * chunk, and you have called png_handle_alpha()[*], you will need to
+ * initialize the image to the current image that PNG will be overlaying.
+ * We set the num_rows again here, in case it was incorrectly set in
+ * png_read_start_row() by a call to png_read_update_info() or
+ * png_start_read_image() if png_set_interlace_handling() wasn't called
+ * prior to either of these functions like it should have been. You can
+ * only call this function once. If you desire to have an image for
+ * each pass of a interlaced image, use png_read_rows() instead.
+ *
+ * [*] png_handle_alpha() does not exist yet, as of libpng version 1.2.0
+ */
+void PNGAPI
+png_read_image(png_structp png_ptr, png_bytepp image)
+{
+ png_uint_32 i,image_height;
+ int pass, j;
+ png_bytepp rp;
+
+ png_debug(1, "in png_read_image\n");
+ /* save jump buffer and error functions */
+
+#ifdef PNG_READ_INTERLACING_SUPPORTED
+ pass = png_set_interlace_handling(png_ptr);
+#else
+ if (png_ptr->interlaced)
+ png_error(png_ptr,
+ "Cannot read interlaced image -- interlace handler disabled.");
+ pass = 1;
+#endif
+
+
+ image_height=png_ptr->height;
+ png_ptr->num_rows = image_height; /* Make sure this is set correctly */
+
+ for (j = 0; j < pass; j++)
+ {
+ rp = image;
+ for (i = 0; i < image_height; i++)
+ {
+ png_read_row(png_ptr, *rp, NULL);
+ rp++;
+ }
+ }
+}
+
+/* Read the end of the PNG file. Will not read past the end of the
+ * file, will verify the end is accurate, and will read any comments
+ * or time information at the end of the file, if info is not NULL.
+ */
+void PNGAPI
+png_read_end(png_structp png_ptr, png_infop info_ptr)
+{
+ png_byte chunk_length[4];
+ png_uint_32 length;
+
+ png_debug(1, "in png_read_end\n");
+ /* save jump buffer and error functions */
+ png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */
+
+ do
+ {
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_IHDR;
+ PNG_IDAT;
+ PNG_IEND;
+ PNG_PLTE;
+#if defined(PNG_READ_bKGD_SUPPORTED)
+ PNG_bKGD;
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED)
+ PNG_cHRM;
+#endif
+#if defined(PNG_READ_gAMA_SUPPORTED)
+ PNG_gAMA;
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+ PNG_hIST;
+#endif
+#if defined(PNG_READ_iCCP_SUPPORTED)
+ PNG_iCCP;
+#endif
+#if defined(PNG_READ_iTXt_SUPPORTED)
+ PNG_iTXt;
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED)
+ PNG_oFFs;
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+ PNG_pCAL;
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED)
+ PNG_pHYs;
+#endif
+#if defined(PNG_READ_sBIT_SUPPORTED)
+ PNG_sBIT;
+#endif
+#if defined(PNG_READ_sCAL_SUPPORTED)
+ PNG_sCAL;
+#endif
+#if defined(PNG_READ_sPLT_SUPPORTED)
+ PNG_sPLT;
+#endif
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ PNG_sRGB;
+#endif
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ PNG_tEXt;
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED)
+ PNG_tIME;
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED)
+ PNG_tRNS;
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ PNG_zTXt;
+#endif
+#endif /* PNG_GLOBAL_ARRAYS */
+
+ png_read_data(png_ptr, chunk_length, 4);
+ length = png_get_uint_32(chunk_length);
+
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+
+ png_debug1(0, "Reading %s chunk.\n", png_ptr->chunk_name);
+
+ if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4))
+ png_handle_IHDR(png_ptr, info_ptr, length);
+ else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
+ png_handle_IEND(png_ptr, info_ptr, length);
+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+ else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name))
+ {
+ if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ {
+ if (length > 0 || png_ptr->mode & PNG_AFTER_IDAT)
+ png_error(png_ptr, "Too many IDAT's found");
+ }
+ else
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_handle_unknown(png_ptr, info_ptr, length);
+ if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ png_ptr->mode |= PNG_HAVE_PLTE;
+ }
+#endif
+ else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ {
+ /* Zero length IDATs are legal after the last IDAT has been
+ * read, but not after other chunks have been read.
+ */
+ if (length > 0 || png_ptr->mode & PNG_AFTER_IDAT)
+ png_error(png_ptr, "Too many IDAT's found");
+ png_crc_finish(png_ptr, length);
+ }
+ else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ png_handle_PLTE(png_ptr, info_ptr, length);
+#if defined(PNG_READ_bKGD_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4))
+ png_handle_bKGD(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4))
+ png_handle_cHRM(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_gAMA_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4))
+ png_handle_gAMA(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4))
+ png_handle_hIST(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4))
+ png_handle_oFFs(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4))
+ png_handle_pCAL(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sCAL_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4))
+ png_handle_sCAL(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4))
+ png_handle_pHYs(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sBIT_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4))
+ png_handle_sBIT(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4))
+ png_handle_sRGB(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_iCCP_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4))
+ png_handle_iCCP(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sPLT_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4))
+ png_handle_sPLT(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4))
+ png_handle_tEXt(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
+ png_handle_tIME(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4))
+ png_handle_tRNS(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4))
+ png_handle_zTXt(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_iTXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4))
+ png_handle_iTXt(png_ptr, info_ptr, length);
+#endif
+ else
+ png_handle_unknown(png_ptr, info_ptr, length);
+ } while (!(png_ptr->mode & PNG_HAVE_IEND));
+}
+
+/* free all memory used by the read */
+void PNGAPI
+png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr,
+ png_infopp end_info_ptr_ptr)
+{
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL, end_info_ptr = NULL;
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_free_ptr free_fn = NULL;
+ png_voidp mem_ptr = NULL;
+#endif
+
+ png_debug(1, "in png_destroy_read_struct\n");
+ /* save jump buffer and error functions */
+ if (png_ptr_ptr != NULL)
+ png_ptr = *png_ptr_ptr;
+
+ if (info_ptr_ptr != NULL)
+ info_ptr = *info_ptr_ptr;
+
+ if (end_info_ptr_ptr != NULL)
+ end_info_ptr = *end_info_ptr_ptr;
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ free_fn = png_ptr->free_fn;
+ mem_ptr = png_ptr->mem_ptr;
+#endif
+
+ png_read_destroy(png_ptr, info_ptr, end_info_ptr);
+
+ if (info_ptr != NULL)
+ {
+#if defined(PNG_TEXT_SUPPORTED)
+ png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, -1);
+#endif
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn,
+ (png_voidp)mem_ptr);
+#else
+ png_destroy_struct((png_voidp)info_ptr);
+#endif
+ *info_ptr_ptr = (png_infop)NULL;
+ }
+
+ if (end_info_ptr != NULL)
+ {
+#if defined(PNG_READ_TEXT_SUPPORTED)
+ png_free_data(png_ptr, end_info_ptr, PNG_FREE_TEXT, -1);
+#endif
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2((png_voidp)end_info_ptr, (png_free_ptr)free_fn,
+ (png_voidp)mem_ptr);
+#else
+ png_destroy_struct((png_voidp)end_info_ptr);
+#endif
+ *end_info_ptr_ptr = (png_infop)NULL;
+ }
+
+ if (png_ptr != NULL)
+ {
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn,
+ (png_voidp)mem_ptr);
+#else
+ png_destroy_struct((png_voidp)png_ptr);
+#endif
+ *png_ptr_ptr = (png_structp)NULL;
+ }
+}
+
+/* free all memory used by the read (old method) */
+void /* PRIVATE */
+png_read_destroy(png_structp png_ptr, png_infop info_ptr, png_infop end_info_ptr)
+{
+#ifdef PNG_SETJMP_SUPPORTED
+ jmp_buf tmp_jmp;
+#endif
+ png_error_ptr error_fn;
+ png_error_ptr warning_fn;
+ png_voidp error_ptr;
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_free_ptr free_fn;
+#endif
+
+ png_debug(1, "in png_read_destroy\n");
+ /* save jump buffer and error functions */
+ if (info_ptr != NULL)
+ png_info_destroy(png_ptr, info_ptr);
+
+ if (end_info_ptr != NULL)
+ png_info_destroy(png_ptr, end_info_ptr);
+
+ png_free(png_ptr, png_ptr->zbuf);
+ png_free(png_ptr, png_ptr->big_row_buf);
+ png_free(png_ptr, png_ptr->prev_row);
+#if defined(PNG_READ_DITHER_SUPPORTED)
+ png_free(png_ptr, png_ptr->palette_lookup);
+ png_free(png_ptr, png_ptr->dither_index);
+#endif
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ png_free(png_ptr, png_ptr->gamma_table);
+#endif
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ png_free(png_ptr, png_ptr->gamma_from_1);
+ png_free(png_ptr, png_ptr->gamma_to_1);
+#endif
+#ifdef PNG_FREE_ME_SUPPORTED
+ if (png_ptr->free_me & PNG_FREE_PLTE)
+ png_zfree(png_ptr, png_ptr->palette);
+ png_ptr->free_me &= ~PNG_FREE_PLTE;
+#else
+ if (png_ptr->flags & PNG_FLAG_FREE_PLTE)
+ png_zfree(png_ptr, png_ptr->palette);
+ png_ptr->flags &= ~PNG_FLAG_FREE_PLTE;
+#endif
+#if defined(PNG_tRNS_SUPPORTED) || \
+ defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+#ifdef PNG_FREE_ME_SUPPORTED
+ if (png_ptr->free_me & PNG_FREE_TRNS)
+ png_free(png_ptr, png_ptr->trans);
+ png_ptr->free_me &= ~PNG_FREE_TRNS;
+#else
+ if (png_ptr->flags & PNG_FLAG_FREE_TRNS)
+ png_free(png_ptr, png_ptr->trans);
+ png_ptr->flags &= ~PNG_FLAG_FREE_TRNS;
+#endif
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+#ifdef PNG_FREE_ME_SUPPORTED
+ if (png_ptr->free_me & PNG_FREE_HIST)
+ png_free(png_ptr, png_ptr->hist);
+ png_ptr->free_me &= ~PNG_FREE_HIST;
+#else
+ if (png_ptr->flags & PNG_FLAG_FREE_HIST)
+ png_free(png_ptr, png_ptr->hist);
+ png_ptr->flags &= ~PNG_FLAG_FREE_HIST;
+#endif
+#endif
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (png_ptr->gamma_16_table != NULL)
+ {
+ int i;
+ int istop = (1 << (8 - png_ptr->gamma_shift));
+ for (i = 0; i < istop; i++)
+ {
+ png_free(png_ptr, png_ptr->gamma_16_table[i]);
+ }
+ png_free(png_ptr, png_ptr->gamma_16_table);
+ }
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->gamma_16_from_1 != NULL)
+ {
+ int i;
+ int istop = (1 << (8 - png_ptr->gamma_shift));
+ for (i = 0; i < istop; i++)
+ {
+ png_free(png_ptr, png_ptr->gamma_16_from_1[i]);
+ }
+ png_free(png_ptr, png_ptr->gamma_16_from_1);
+ }
+ if (png_ptr->gamma_16_to_1 != NULL)
+ {
+ int i;
+ int istop = (1 << (8 - png_ptr->gamma_shift));
+ for (i = 0; i < istop; i++)
+ {
+ png_free(png_ptr, png_ptr->gamma_16_to_1[i]);
+ }
+ png_free(png_ptr, png_ptr->gamma_16_to_1);
+ }
+#endif
+#endif
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+ png_free(png_ptr, png_ptr->time_buffer);
+#endif
+
+ inflateEnd(&png_ptr->zstream);
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+ png_free(png_ptr, png_ptr->save_buffer);
+#endif
+
+ /* Save the important info out of the png_struct, in case it is
+ * being used again.
+ */
+#ifdef PNG_SETJMP_SUPPORTED
+ png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
+#endif
+
+ error_fn = png_ptr->error_fn;
+ warning_fn = png_ptr->warning_fn;
+ error_ptr = png_ptr->error_ptr;
+#ifdef PNG_USER_MEM_SUPPORTED
+ free_fn = png_ptr->free_fn;
+#endif
+
+ png_memset(png_ptr, 0, sizeof (png_struct));
+
+ png_ptr->error_fn = error_fn;
+ png_ptr->warning_fn = warning_fn;
+ png_ptr->error_ptr = error_ptr;
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_ptr->free_fn = free_fn;
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+ png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
+#endif
+
+}
+
+void PNGAPI
+png_set_read_status_fn(png_structp png_ptr, png_read_status_ptr read_row_fn)
+{
+ png_ptr->read_row_fn = read_row_fn;
+}
+
+#if defined(PNG_INFO_IMAGE_SUPPORTED)
+void PNGAPI
+png_read_png(png_structp png_ptr, png_infop info_ptr,
+ int transforms,
+ voidp params)
+{
+ int row;
+
+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
+ /* invert the alpha channel from opacity to transparency */
+ if (transforms & PNG_TRANSFORM_INVERT_ALPHA)
+ png_set_invert_alpha(png_ptr);
+#endif
+
+ /* The call to png_read_info() gives us all of the information from the
+ * PNG file before the first IDAT (image data chunk).
+ */
+ png_read_info(png_ptr, info_ptr);
+
+ /* -------------- image transformations start here ------------------- */
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+ /* tell libpng to strip 16 bit/color files down to 8 bits/color */
+ if (transforms & PNG_TRANSFORM_STRIP_16)
+ png_set_strip_16(png_ptr);
+#endif
+
+#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+ /* Strip alpha bytes from the input data without combining with the
+ * background (not recommended).
+ */
+ if (transforms & PNG_TRANSFORM_STRIP_ALPHA)
+ png_set_strip_alpha(png_ptr);
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED)
+ /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
+ * byte into separate bytes (useful for paletted and grayscale images).
+ */
+ if (transforms & PNG_TRANSFORM_PACKING)
+ png_set_packing(png_ptr);
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ /* Change the order of packed pixels to least significant bit first
+ * (not useful if you are using png_set_packing). */
+ if (transforms & PNG_TRANSFORM_PACKSWAP)
+ png_set_packswap(png_ptr);
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ /* Expand paletted colors into true RGB triplets
+ * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel
+ * Expand paletted or RGB images with transparency to full alpha
+ * channels so the data will be available as RGBA quartets.
+ */
+ if (transforms & PNG_TRANSFORM_EXPAND)
+ if ((png_ptr->bit_depth < 8) ||
+ (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ||
+ (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
+ png_set_expand(png_ptr);
+#endif
+
+ /* We don't handle background color or gamma transformation or dithering. */
+
+#if defined(PNG_READ_INVERT_SUPPORTED)
+ /* invert monochrome files to have 0 as white and 1 as black */
+ if (transforms & PNG_TRANSFORM_INVERT_MONO)
+ png_set_invert_mono(png_ptr);
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED)
+ /* If you want to shift the pixel values from the range [0,255] or
+ * [0,65535] to the original [0,7] or [0,31], or whatever range the
+ * colors were originally in:
+ */
+ if ((transforms & PNG_TRANSFORM_SHIFT)
+ && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
+ {
+ png_color_8p sig_bit;
+
+ png_get_sBIT(png_ptr, info_ptr, &sig_bit);
+ png_set_shift(png_ptr, sig_bit);
+ }
+#endif
+
+#if defined(PNG_READ_BGR_SUPPORTED)
+ /* flip the RGB pixels to BGR (or RGBA to BGRA) */
+ if (transforms & PNG_TRANSFORM_BGR)
+ png_set_bgr(png_ptr);
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
+ /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
+ if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
+ png_set_swap_alpha(png_ptr);
+#endif
+
+#if defined(PNG_READ_SWAP_SUPPORTED)
+ /* swap bytes of 16 bit files to least significant byte first */
+ if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
+ png_set_swap(png_ptr);
+#endif
+
+ /* We don't handle adding filler bytes */
+
+ /* Optional call to gamma correct and add the background to the palette
+ * and update info structure. REQUIRED if you are expecting libpng to
+ * update the palette for you (i.e., you selected such a transform above).
+ */
+ png_read_update_info(png_ptr, info_ptr);
+
+ /* -------------- image transformations end here ------------------- */
+
+#ifdef PNG_FREE_ME_SUPPORTED
+ png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
+#endif
+ if(info_ptr->row_pointers == NULL)
+ {
+ info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr,
+ info_ptr->height * sizeof(png_bytep));
+#ifdef PNG_FREE_ME_SUPPORTED
+ info_ptr->free_me |= PNG_FREE_ROWS;
+#endif
+ for (row = 0; row < (int)info_ptr->height; row++)
+ {
+ info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr,
+ png_get_rowbytes(png_ptr, info_ptr));
+ }
+ }
+
+ png_read_image(png_ptr, info_ptr->row_pointers);
+ info_ptr->valid |= PNG_INFO_IDAT;
+
+ /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
+ png_read_end(png_ptr, info_ptr);
+
+ if(transforms == 0 || params == NULL)
+ /* quiet compiler warnings */ return;
+
+}
+#endif
--- /dev/null
+
+/* pngrio.c - functions for data input
+ *
+ * libpng 1.2.0 - September 1, 2001
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ *
+ * This file provides a location for all input. Users who need
+ * special handling are expected to write a function that has the same
+ * arguments as this and performs a similar function, but that possibly
+ * has a different input method. Note that you shouldn't change this
+ * function, but rather write a replacement function and then make
+ * libpng use it at run time with png_set_read_fn(...).
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* Read the data from whatever input you are using. The default routine
+ reads from a file pointer. Note that this routine sometimes gets called
+ with very small lengths, so you should implement some kind of simple
+ buffering if you are using unbuffered reads. This should never be asked
+ to read more then 64K on a 16 bit machine. */
+void /* PRIVATE */
+png_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_debug1(4,"reading %d bytes\n", (int)length);
+ if (png_ptr->read_data_fn != NULL)
+ (*(png_ptr->read_data_fn))(png_ptr, data, length);
+ else
+ png_error(png_ptr, "Call to NULL read function");
+}
+
+#if !defined(PNG_NO_STDIO)
+/* This is the function that does the actual reading of data. If you are
+ not reading from a standard C stream, you should create a replacement
+ read_data function and use it at run time with png_set_read_fn(), rather
+ than changing the library. */
+#ifndef USE_FAR_KEYWORD
+static void /* PRIVATE */
+png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_size_t check;
+
+ /* fread() returns 0 on error, so it is OK to store this in a png_size_t
+ * instead of an int, which is what fread() actually returns.
+ */
+#if defined(_WIN32_WCE)
+ if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) )
+ check = 0;
+#else
+ check = (png_size_t)fread(data, (png_size_t)1, length,
+ (png_FILE_p)png_ptr->io_ptr);
+#endif
+
+ if (check != length)
+ png_error(png_ptr, "Read Error");
+}
+#else
+/* this is the model-independent version. Since the standard I/O library
+ can't handle far buffers in the medium and small models, we have to copy
+ the data.
+*/
+
+#define NEAR_BUF_SIZE 1024
+#define MIN(a,b) (a <= b ? a : b)
+
+static void /* PRIVATE */
+png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ int check;
+ png_byte *n_data;
+ png_FILE_p io_ptr;
+
+ /* Check if data really is near. If so, use usual code. */
+ n_data = (png_byte *)CVT_PTR_NOCHECK(data);
+ io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
+ if ((png_bytep)n_data == data)
+ {
+#if defined(_WIN32_WCE)
+ if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) )
+ check = 0;
+#else
+ check = fread(n_data, 1, length, io_ptr);
+#endif
+ }
+ else
+ {
+ png_byte buf[NEAR_BUF_SIZE];
+ png_size_t read, remaining, err;
+ check = 0;
+ remaining = length;
+ do
+ {
+ read = MIN(NEAR_BUF_SIZE, remaining);
+#if defined(_WIN32_WCE)
+ if ( !ReadFile((HANDLE)(io_ptr), buf, read, &err, NULL) )
+ err = 0;
+#else
+ err = fread(buf, (png_size_t)1, read, io_ptr);
+#endif
+ png_memcpy(data, buf, read); /* copy far buffer to near buffer */
+ if(err != read)
+ break;
+ else
+ check += err;
+ data += read;
+ remaining -= read;
+ }
+ while (remaining != 0);
+ }
+ if ((png_uint_32)check != (png_uint_32)length)
+ png_error(png_ptr, "read Error");
+}
+#endif
+#endif
+
+/* This function allows the application to supply a new input function
+ for libpng if standard C streams aren't being used.
+
+ This function takes as its arguments:
+ png_ptr - pointer to a png input data structure
+ io_ptr - pointer to user supplied structure containing info about
+ the input functions. May be NULL.
+ read_data_fn - pointer to a new input function that takes as its
+ arguments a pointer to a png_struct, a pointer to
+ a location where input data can be stored, and a 32-bit
+ unsigned int that is the number of bytes to be read.
+ To exit and output any fatal error messages the new write
+ function should call png_error(png_ptr, "Error msg"). */
+void PNGAPI
+png_set_read_fn(png_structp png_ptr, png_voidp io_ptr,
+ png_rw_ptr read_data_fn)
+{
+ png_ptr->io_ptr = io_ptr;
+
+#if !defined(PNG_NO_STDIO)
+ if (read_data_fn != NULL)
+ png_ptr->read_data_fn = read_data_fn;
+ else
+ png_ptr->read_data_fn = png_default_read_data;
+#else
+ png_ptr->read_data_fn = read_data_fn;
+#endif
+
+ /* It is an error to write to a read device */
+ if (png_ptr->write_data_fn != NULL)
+ {
+ png_ptr->write_data_fn = NULL;
+ png_warning(png_ptr,
+ "It's an error to set both read_data_fn and write_data_fn in the ");
+ png_warning(png_ptr,
+ "same structure. Resetting write_data_fn to NULL.");
+ }
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+ png_ptr->output_flush_fn = NULL;
+#endif
+}
--- /dev/null
+
+/* pngrtran.c - transforms the data in a row for PNG readers
+ *
+ * libpng 1.2.0 - September 1, 2001
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ *
+ * This file contains functions optionally called by an application
+ * in order to tell libpng how to handle data when reading a PNG.
+ * Transformations that are used in both reading and writing are
+ * in pngtrans.c.
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+/* Set the action on getting a CRC error for an ancillary or critical chunk. */
+void PNGAPI
+png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action)
+{
+ png_debug(1, "in png_set_crc_action\n");
+ /* Tell libpng how we react to CRC errors in critical chunks */
+ switch (crit_action)
+ {
+ case PNG_CRC_NO_CHANGE: /* leave setting as is */
+ break;
+ case PNG_CRC_WARN_USE: /* warn/use data */
+ png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
+ png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE;
+ break;
+ case PNG_CRC_QUIET_USE: /* quiet/use data */
+ png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
+ png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE |
+ PNG_FLAG_CRC_CRITICAL_IGNORE;
+ break;
+ case PNG_CRC_WARN_DISCARD: /* not a valid action for critical data */
+ png_warning(png_ptr, "Can't discard critical data on CRC error.");
+ case PNG_CRC_ERROR_QUIT: /* error/quit */
+ case PNG_CRC_DEFAULT:
+ default:
+ png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
+ break;
+ }
+
+ switch (ancil_action)
+ {
+ case PNG_CRC_NO_CHANGE: /* leave setting as is */
+ break;
+ case PNG_CRC_WARN_USE: /* warn/use data */
+ png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
+ png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE;
+ break;
+ case PNG_CRC_QUIET_USE: /* quiet/use data */
+ png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
+ png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE |
+ PNG_FLAG_CRC_ANCILLARY_NOWARN;
+ break;
+ case PNG_CRC_ERROR_QUIT: /* error/quit */
+ png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
+ png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN;
+ break;
+ case PNG_CRC_WARN_DISCARD: /* warn/discard data */
+ case PNG_CRC_DEFAULT:
+ default:
+ png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
+ break;
+ }
+}
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
+ defined(PNG_FLOATING_POINT_SUPPORTED)
+/* handle alpha and tRNS via a background color */
+void PNGAPI
+png_set_background(png_structp png_ptr,
+ png_color_16p background_color, int background_gamma_code,
+ int need_expand, double background_gamma)
+{
+ png_debug(1, "in png_set_background\n");
+ if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN)
+ {
+ png_warning(png_ptr, "Application must supply a known background gamma");
+ return;
+ }
+
+ png_ptr->transformations |= PNG_BACKGROUND;
+ png_memcpy(&(png_ptr->background), background_color, sizeof(png_color_16));
+ png_ptr->background_gamma = (float)background_gamma;
+ png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
+ png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0);
+
+ /* Note: if need_expand is set and color_type is either RGB or RGB_ALPHA
+ * (in which case need_expand is superfluous anyway), the background color
+ * might actually be gray yet not be flagged as such. This is not a problem
+ * for the current code, which uses PNG_BACKGROUND_IS_GRAY only to
+ * decide when to do the png_do_gray_to_rgb() transformation.
+ */
+ if ((need_expand && !(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) ||
+ (!need_expand && background_color->red == background_color->green &&
+ background_color->red == background_color->blue))
+ png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
+}
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+/* strip 16 bit depth files to 8 bit depth */
+void PNGAPI
+png_set_strip_16(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_strip_16\n");
+ png_ptr->transformations |= PNG_16_TO_8;
+}
+#endif
+
+#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+void PNGAPI
+png_set_strip_alpha(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_strip_alpha\n");
+ png_ptr->transformations |= PNG_STRIP_ALPHA;
+}
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+/* Dither file to 8 bit. Supply a palette, the current number
+ * of elements in the palette, the maximum number of elements
+ * allowed, and a histogram if possible. If the current number
+ * of colors is greater then the maximum number, the palette will be
+ * modified to fit in the maximum number. "full_dither" indicates
+ * whether we need a dithering cube set up for RGB images, or if we
+ * simply are reducing the number of colors in a paletted image.
+ */
+
+typedef struct png_dsort_struct
+{
+ struct png_dsort_struct FAR * next;
+ png_byte left;
+ png_byte right;
+} png_dsort;
+typedef png_dsort FAR * png_dsortp;
+typedef png_dsort FAR * FAR * png_dsortpp;
+
+void PNGAPI
+png_set_dither(png_structp png_ptr, png_colorp palette,
+ int num_palette, int maximum_colors, png_uint_16p histogram,
+ int full_dither)
+{
+ png_debug(1, "in png_set_dither\n");
+ png_ptr->transformations |= PNG_DITHER;
+
+ if (!full_dither)
+ {
+ int i;
+
+ png_ptr->dither_index = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)(num_palette * sizeof (png_byte)));
+ for (i = 0; i < num_palette; i++)
+ png_ptr->dither_index[i] = (png_byte)i;
+ }
+
+ if (num_palette > maximum_colors)
+ {
+ if (histogram != NULL)
+ {
+ /* This is easy enough, just throw out the least used colors.
+ Perhaps not the best solution, but good enough. */
+
+ int i;
+ png_bytep sort;
+
+ /* initialize an array to sort colors */
+ sort = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_palette
+ * sizeof (png_byte)));
+
+ /* initialize the sort array */
+ for (i = 0; i < num_palette; i++)
+ sort[i] = (png_byte)i;
+
+ /* Find the least used palette entries by starting a
+ bubble sort, and running it until we have sorted
+ out enough colors. Note that we don't care about
+ sorting all the colors, just finding which are
+ least used. */
+
+ for (i = num_palette - 1; i >= maximum_colors; i--)
+ {
+ int done; /* to stop early if the list is pre-sorted */
+ int j;
+
+ done = 1;
+ for (j = 0; j < i; j++)
+ {
+ if (histogram[sort[j]] < histogram[sort[j + 1]])
+ {
+ png_byte t;
+
+ t = sort[j];
+ sort[j] = sort[j + 1];
+ sort[j + 1] = t;
+ done = 0;
+ }
+ }
+ if (done)
+ break;
+ }
+
+ /* swap the palette around, and set up a table, if necessary */
+ if (full_dither)
+ {
+ int j = num_palette;
+
+ /* put all the useful colors within the max, but don't
+ move the others */
+ for (i = 0; i < maximum_colors; i++)
+ {
+ if ((int)sort[i] >= maximum_colors)
+ {
+ do
+ j--;
+ while ((int)sort[j] >= maximum_colors);
+ palette[i] = palette[j];
+ }
+ }
+ }
+ else
+ {
+ int j = num_palette;
+
+ /* move all the used colors inside the max limit, and
+ develop a translation table */
+ for (i = 0; i < maximum_colors; i++)
+ {
+ /* only move the colors we need to */
+ if ((int)sort[i] >= maximum_colors)
+ {
+ png_color tmp_color;
+
+ do
+ j--;
+ while ((int)sort[j] >= maximum_colors);
+
+ tmp_color = palette[j];
+ palette[j] = palette[i];
+ palette[i] = tmp_color;
+ /* indicate where the color went */
+ png_ptr->dither_index[j] = (png_byte)i;
+ png_ptr->dither_index[i] = (png_byte)j;
+ }
+ }
+
+ /* find closest color for those colors we are not using */
+ for (i = 0; i < num_palette; i++)
+ {
+ if ((int)png_ptr->dither_index[i] >= maximum_colors)
+ {
+ int min_d, k, min_k, d_index;
+
+ /* find the closest color to one we threw out */
+ d_index = png_ptr->dither_index[i];
+ min_d = PNG_COLOR_DIST(palette[d_index], palette[0]);
+ for (k = 1, min_k = 0; k < maximum_colors; k++)
+ {
+ int d;
+
+ d = PNG_COLOR_DIST(palette[d_index], palette[k]);
+
+ if (d < min_d)
+ {
+ min_d = d;
+ min_k = k;
+ }
+ }
+ /* point to closest color */
+ png_ptr->dither_index[i] = (png_byte)min_k;
+ }
+ }
+ }
+ png_free(png_ptr, sort);
+ }
+ else
+ {
+ /* This is much harder to do simply (and quickly). Perhaps
+ we need to go through a median cut routine, but those
+ don't always behave themselves with only a few colors
+ as input. So we will just find the closest two colors,
+ and throw out one of them (chosen somewhat randomly).
+ [We don't understand this at all, so if someone wants to
+ work on improving it, be our guest - AED, GRP]
+ */
+ int i;
+ int max_d;
+ int num_new_palette;
+ png_dsortpp hash;
+ png_bytep index_to_palette;
+ /* where the original index currently is in the palette */
+ png_bytep palette_to_index;
+ /* which original index points to this palette color */
+
+ /* initialize palette index arrays */
+ index_to_palette = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)(num_palette * sizeof (png_byte)));
+ palette_to_index = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)(num_palette * sizeof (png_byte)));
+
+ /* initialize the sort array */
+ for (i = 0; i < num_palette; i++)
+ {
+ index_to_palette[i] = (png_byte)i;
+ palette_to_index[i] = (png_byte)i;
+ }
+
+ hash = (png_dsortpp)png_malloc(png_ptr, (png_uint_32)(769 *
+ sizeof (png_dsortp)));
+ for (i = 0; i < 769; i++)
+ hash[i] = NULL;
+/* png_memset(hash, 0, 769 * sizeof (png_dsortp)); */
+
+ num_new_palette = num_palette;
+
+ /* initial wild guess at how far apart the farthest pixel
+ pair we will be eliminating will be. Larger
+ numbers mean more areas will be allocated, Smaller
+ numbers run the risk of not saving enough data, and
+ having to do this all over again.
+
+ I have not done extensive checking on this number.
+ */
+ max_d = 96;
+
+ while (num_new_palette > maximum_colors)
+ {
+ for (i = 0; i < num_new_palette - 1; i++)
+ {
+ int j;
+
+ for (j = i + 1; j < num_new_palette; j++)
+ {
+ int d;
+
+ d = PNG_COLOR_DIST(palette[i], palette[j]);
+
+ if (d <= max_d)
+ {
+ png_dsortp t;
+
+ t = (png_dsortp)png_malloc(png_ptr, (png_uint_32)(sizeof
+ (png_dsort)));
+ t->next = hash[d];
+ t->left = (png_byte)i;
+ t->right = (png_byte)j;
+ hash[d] = t;
+ }
+ }
+ }
+
+ for (i = 0; i <= max_d; i++)
+ {
+ if (hash[i] != NULL)
+ {
+ png_dsortp p;
+
+ for (p = hash[i]; p; p = p->next)
+ {
+ if ((int)index_to_palette[p->left] < num_new_palette &&
+ (int)index_to_palette[p->right] < num_new_palette)
+ {
+ int j, next_j;
+
+ if (num_new_palette & 0x01)
+ {
+ j = p->left;
+ next_j = p->right;
+ }
+ else
+ {
+ j = p->right;
+ next_j = p->left;
+ }
+
+ num_new_palette--;
+ palette[index_to_palette[j]] = palette[num_new_palette];
+ if (!full_dither)
+ {
+ int k;
+
+ for (k = 0; k < num_palette; k++)
+ {
+ if (png_ptr->dither_index[k] ==
+ index_to_palette[j])
+ png_ptr->dither_index[k] =
+ index_to_palette[next_j];
+ if ((int)png_ptr->dither_index[k] ==
+ num_new_palette)
+ png_ptr->dither_index[k] =
+ index_to_palette[j];
+ }
+ }
+
+ index_to_palette[palette_to_index[num_new_palette]] =
+ index_to_palette[j];
+ palette_to_index[index_to_palette[j]] =
+ palette_to_index[num_new_palette];
+
+ index_to_palette[j] = (png_byte)num_new_palette;
+ palette_to_index[num_new_palette] = (png_byte)j;
+ }
+ if (num_new_palette <= maximum_colors)
+ break;
+ }
+ if (num_new_palette <= maximum_colors)
+ break;
+ }
+ }
+
+ for (i = 0; i < 769; i++)
+ {
+ if (hash[i] != NULL)
+ {
+ png_dsortp p = hash[i];
+ while (p)
+ {
+ png_dsortp t;
+
+ t = p->next;
+ png_free(png_ptr, p);
+ p = t;
+ }
+ }
+ hash[i] = 0;
+ }
+ max_d += 96;
+ }
+ png_free(png_ptr, hash);
+ png_free(png_ptr, palette_to_index);
+ png_free(png_ptr, index_to_palette);
+ }
+ num_palette = maximum_colors;
+ }
+ if (png_ptr->palette == NULL)
+ {
+ png_ptr->palette = palette;
+ }
+ png_ptr->num_palette = (png_uint_16)num_palette;
+
+ if (full_dither)
+ {
+ int i;
+ png_bytep distance;
+ int total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS +
+ PNG_DITHER_BLUE_BITS;
+ int num_red = (1 << PNG_DITHER_RED_BITS);
+ int num_green = (1 << PNG_DITHER_GREEN_BITS);
+ int num_blue = (1 << PNG_DITHER_BLUE_BITS);
+ png_size_t num_entries = ((png_size_t)1 << total_bits);
+
+ png_ptr->palette_lookup = (png_bytep )png_malloc(png_ptr,
+ (png_uint_32)(num_entries * sizeof (png_byte)));
+
+ png_memset(png_ptr->palette_lookup, 0, num_entries * sizeof (png_byte));
+
+ distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries *
+ sizeof(png_byte)));
+
+ png_memset(distance, 0xff, num_entries * sizeof(png_byte));
+
+ for (i = 0; i < num_palette; i++)
+ {
+ int ir, ig, ib;
+ int r = (palette[i].red >> (8 - PNG_DITHER_RED_BITS));
+ int g = (palette[i].green >> (8 - PNG_DITHER_GREEN_BITS));
+ int b = (palette[i].blue >> (8 - PNG_DITHER_BLUE_BITS));
+
+ for (ir = 0; ir < num_red; ir++)
+ {
+ int dr = abs(ir - r);
+ int index_r = (ir << (PNG_DITHER_BLUE_BITS + PNG_DITHER_GREEN_BITS));
+
+ for (ig = 0; ig < num_green; ig++)
+ {
+ int dg = abs(ig - g);
+ int dt = dr + dg;
+ int dm = ((dr > dg) ? dr : dg);
+ int index_g = index_r | (ig << PNG_DITHER_BLUE_BITS);
+
+ for (ib = 0; ib < num_blue; ib++)
+ {
+ int d_index = index_g | ib;
+ int db = abs(ib - b);
+ int dmax = ((dm > db) ? dm : db);
+ int d = dmax + dt + db;
+
+ if (d < (int)distance[d_index])
+ {
+ distance[d_index] = (png_byte)d;
+ png_ptr->palette_lookup[d_index] = (png_byte)i;
+ }
+ }
+ }
+ }
+ }
+
+ png_free(png_ptr, distance);
+ }
+}
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
+/* Transform the image from the file_gamma to the screen_gamma. We
+ * only do transformations on images where the file_gamma and screen_gamma
+ * are not close reciprocals, otherwise it slows things down slightly, and
+ * also needlessly introduces small errors.
+ */
+void PNGAPI
+png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma)
+{
+ png_debug(1, "in png_set_gamma\n");
+ if (fabs(scrn_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD)
+ png_ptr->transformations |= PNG_GAMMA;
+ png_ptr->gamma = (float)file_gamma;
+ png_ptr->screen_gamma = (float)scrn_gamma;
+}
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+/* Expand paletted images to RGB, expand grayscale images of
+ * less than 8-bit depth to 8-bit depth, and expand tRNS chunks
+ * to alpha channels.
+ */
+void PNGAPI
+png_set_expand(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_expand\n");
+ png_ptr->transformations |= PNG_EXPAND;
+}
+
+/* GRR 19990627: the following three functions currently are identical
+ * to png_set_expand(). However, it is entirely reasonable that someone
+ * might wish to expand an indexed image to RGB but *not* expand a single,
+ * fully transparent palette entry to a full alpha channel--perhaps instead
+ * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace
+ * the transparent color with a particular RGB value, or drop tRNS entirely.
+ * IOW, a future version of the library may make the transformations flag
+ * a bit more fine-grained, with separate bits for each of these three
+ * functions.
+ *
+ * More to the point, these functions make it obvious what libpng will be
+ * doing, whereas "expand" can (and does) mean any number of things.
+ */
+
+/* Expand paletted images to RGB. */
+void PNGAPI
+png_set_palette_to_rgb(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_expand\n");
+ png_ptr->transformations |= PNG_EXPAND;
+}
+
+/* Expand grayscale images of less than 8-bit depth to 8 bits. */
+void PNGAPI
+png_set_gray_1_2_4_to_8(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_expand\n");
+ png_ptr->transformations |= PNG_EXPAND;
+}
+
+/* Expand tRNS chunks to alpha channels. */
+void PNGAPI
+png_set_tRNS_to_alpha(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_expand\n");
+ png_ptr->transformations |= PNG_EXPAND;
+}
+#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+void PNGAPI
+png_set_gray_to_rgb(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_gray_to_rgb\n");
+ png_ptr->transformations |= PNG_GRAY_TO_RGB;
+}
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+#if defined(PNG_FLOATING_POINT_SUPPORTED)
+/* Convert a RGB image to a grayscale of the same width. This allows us,
+ * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image.
+ */
+
+void PNGAPI
+png_set_rgb_to_gray(png_structp png_ptr, int error_action, double red,
+ double green)
+{
+ int red_fixed = (int)((float)red*100000.0 + 0.5);
+ int green_fixed = (int)((float)green*100000.0 + 0.5);
+ png_set_rgb_to_gray_fixed(png_ptr, error_action, red_fixed, green_fixed);
+}
+#endif
+
+void PNGAPI
+png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action,
+ png_fixed_point red, png_fixed_point green)
+{
+ png_debug(1, "in png_set_rgb_to_gray\n");
+ switch(error_action)
+ {
+ case 1: png_ptr->transformations |= PNG_RGB_TO_GRAY;
+ break;
+ case 2: png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN;
+ break;
+ case 3: png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR;
+ }
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ png_ptr->transformations |= PNG_EXPAND;
+#else
+ {
+ png_warning(png_ptr, "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED.");
+ png_ptr->transformations &= ~PNG_RGB_TO_GRAY;
+ }
+#endif
+ {
+ png_uint_16 red_int, green_int;
+ if(red < 0 || green < 0)
+ {
+ red_int = 6968; /* .212671 * 32768 + .5 */
+ green_int = 23434; /* .715160 * 32768 + .5 */
+ }
+ else if(red + green < 100000L)
+ {
+ red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L);
+ green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L);
+ }
+ else
+ {
+ png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients");
+ red_int = 6968;
+ green_int = 23434;
+ }
+ png_ptr->rgb_to_gray_red_coeff = red_int;
+ png_ptr->rgb_to_gray_green_coeff = green_int;
+ png_ptr->rgb_to_gray_blue_coeff = (png_uint_16)(32768-red_int-green_int);
+ }
+}
+#endif
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_LEGACY_SUPPORTED)
+void PNGAPI
+png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
+ read_user_transform_fn)
+{
+ png_debug(1, "in png_set_read_user_transform_fn\n");
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
+ png_ptr->transformations |= PNG_USER_TRANSFORM;
+ png_ptr->read_user_transform_fn = read_user_transform_fn;
+#endif
+#ifdef PNG_LEGACY_SUPPORTED
+ if(read_user_transform_fn)
+ png_warning(png_ptr,
+ "This version of libpng does not support user transforms");
+#endif
+}
+#endif
+
+/* Initialize everything needed for the read. This includes modifying
+ * the palette.
+ */
+void /* PRIVATE */
+png_init_read_transformations(png_structp png_ptr)
+{
+ png_debug(1, "in png_init_read_transformations\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if(png_ptr != NULL)
+#endif
+ {
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) || defined(PNG_READ_SHIFT_SUPPORTED) \
+ || defined(PNG_READ_GAMMA_SUPPORTED)
+ int color_type = png_ptr->color_type;
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
+ (png_ptr->transformations & PNG_EXPAND))
+ {
+ if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */
+ {
+ /* expand background chunk. */
+ switch (png_ptr->bit_depth)
+ {
+ case 1:
+ png_ptr->background.gray *= (png_uint_16)0xff;
+ png_ptr->background.red = png_ptr->background.green =
+ png_ptr->background.blue = png_ptr->background.gray;
+ break;
+ case 2:
+ png_ptr->background.gray *= (png_uint_16)0x55;
+ png_ptr->background.red = png_ptr->background.green =
+ png_ptr->background.blue = png_ptr->background.gray;
+ break;
+ case 4:
+ png_ptr->background.gray *= (png_uint_16)0x11;
+ png_ptr->background.red = png_ptr->background.green =
+ png_ptr->background.blue = png_ptr->background.gray;
+ break;
+ case 8:
+ case 16:
+ png_ptr->background.red = png_ptr->background.green =
+ png_ptr->background.blue = png_ptr->background.gray;
+ break;
+ }
+ }
+ else if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_ptr->background.red =
+ png_ptr->palette[png_ptr->background.index].red;
+ png_ptr->background.green =
+ png_ptr->palette[png_ptr->background.index].green;
+ png_ptr->background.blue =
+ png_ptr->palette[png_ptr->background.index].blue;
+
+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_ALPHA)
+ {
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ if (!(png_ptr->transformations & PNG_EXPAND))
+#endif
+ {
+ /* invert the alpha channel (in tRNS) unless the pixels are
+ going to be expanded, in which case leave it for later */
+ int i,istop;
+ istop=(int)png_ptr->num_trans;
+ for (i=0; i<istop; i++)
+ png_ptr->trans[i] = (png_byte)(255 - png_ptr->trans[i]);
+ }
+ }
+#endif
+
+ }
+ }
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ png_ptr->background_1 = png_ptr->background;
+#endif
+#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
+ if (png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY))
+ {
+ png_build_gamma_table(png_ptr);
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->transformations & PNG_BACKGROUND)
+ {
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_color back, back_1;
+ png_colorp palette = png_ptr->palette;
+ int num_palette = png_ptr->num_palette;
+ int i;
+ if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
+ {
+ back.red = png_ptr->gamma_table[png_ptr->background.red];
+ back.green = png_ptr->gamma_table[png_ptr->background.green];
+ back.blue = png_ptr->gamma_table[png_ptr->background.blue];
+
+ back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
+ back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
+ back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
+ }
+ else
+ {
+ double g, gs;
+
+ switch (png_ptr->background_gamma_type)
+ {
+ case PNG_BACKGROUND_GAMMA_SCREEN:
+ g = (png_ptr->screen_gamma);
+ gs = 1.0;
+ break;
+ case PNG_BACKGROUND_GAMMA_FILE:
+ g = 1.0 / (png_ptr->gamma);
+ gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
+ break;
+ case PNG_BACKGROUND_GAMMA_UNIQUE:
+ g = 1.0 / (png_ptr->background_gamma);
+ gs = 1.0 / (png_ptr->background_gamma *
+ png_ptr->screen_gamma);
+ break;
+ default:
+ g = 1.0; /* back_1 */
+ gs = 1.0; /* back */
+ }
+
+ if ( fabs(gs - 1.0) < PNG_GAMMA_THRESHOLD)
+ {
+ back.red = (png_byte)png_ptr->background.red;
+ back.green = (png_byte)png_ptr->background.green;
+ back.blue = (png_byte)png_ptr->background.blue;
+ }
+ else
+ {
+ back.red = (png_byte)(pow(
+ (double)png_ptr->background.red/255, gs) * 255.0 + .5);
+ back.green = (png_byte)(pow(
+ (double)png_ptr->background.green/255, gs) * 255.0 + .5);
+ back.blue = (png_byte)(pow(
+ (double)png_ptr->background.blue/255, gs) * 255.0 + .5);
+ }
+
+ back_1.red = (png_byte)(pow(
+ (double)png_ptr->background.red/255, g) * 255.0 + .5);
+ back_1.green = (png_byte)(pow(
+ (double)png_ptr->background.green/255, g) * 255.0 + .5);
+ back_1.blue = (png_byte)(pow(
+ (double)png_ptr->background.blue/255, g) * 255.0 + .5);
+ }
+ for (i = 0; i < num_palette; i++)
+ {
+ if (i < (int)png_ptr->num_trans && png_ptr->trans[i] != 0xff)
+ {
+ if (png_ptr->trans[i] == 0)
+ {
+ palette[i] = back;
+ }
+ else /* if (png_ptr->trans[i] != 0xff) */
+ {
+ png_byte v, w;
+
+ v = png_ptr->gamma_to_1[palette[i].red];
+ png_composite(w, v, png_ptr->trans[i], back_1.red);
+ palette[i].red = png_ptr->gamma_from_1[w];
+
+ v = png_ptr->gamma_to_1[palette[i].green];
+ png_composite(w, v, png_ptr->trans[i], back_1.green);
+ palette[i].green = png_ptr->gamma_from_1[w];
+
+ v = png_ptr->gamma_to_1[palette[i].blue];
+ png_composite(w, v, png_ptr->trans[i], back_1.blue);
+ palette[i].blue = png_ptr->gamma_from_1[w];
+ }
+ }
+ else
+ {
+ palette[i].red = png_ptr->gamma_table[palette[i].red];
+ palette[i].green = png_ptr->gamma_table[palette[i].green];
+ palette[i].blue = png_ptr->gamma_table[palette[i].blue];
+ }
+ }
+ }
+ /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN)*/
+ else
+ /* color_type != PNG_COLOR_TYPE_PALETTE */
+ {
+ double m = (double)(((png_uint_32)1 << png_ptr->bit_depth) - 1);
+ double g = 1.0;
+ double gs = 1.0;
+
+ switch (png_ptr->background_gamma_type)
+ {
+ case PNG_BACKGROUND_GAMMA_SCREEN:
+ g = (png_ptr->screen_gamma);
+ gs = 1.0;
+ break;
+ case PNG_BACKGROUND_GAMMA_FILE:
+ g = 1.0 / (png_ptr->gamma);
+ gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
+ break;
+ case PNG_BACKGROUND_GAMMA_UNIQUE:
+ g = 1.0 / (png_ptr->background_gamma);
+ gs = 1.0 / (png_ptr->background_gamma *
+ png_ptr->screen_gamma);
+ break;
+ }
+
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ /* RGB or RGBA */
+ png_ptr->background_1.red = (png_uint_16)(pow(
+ (double)png_ptr->background.red / m, g) * m + .5);
+ png_ptr->background_1.green = (png_uint_16)(pow(
+ (double)png_ptr->background.green / m, g) * m + .5);
+ png_ptr->background_1.blue = (png_uint_16)(pow(
+ (double)png_ptr->background.blue / m, g) * m + .5);
+ png_ptr->background.red = (png_uint_16)(pow(
+ (double)png_ptr->background.red / m, gs) * m + .5);
+ png_ptr->background.green = (png_uint_16)(pow(
+ (double)png_ptr->background.green / m, gs) * m + .5);
+ png_ptr->background.blue = (png_uint_16)(pow(
+ (double)png_ptr->background.blue / m, gs) * m + .5);
+ }
+ else
+ {
+ /* GRAY or GRAY ALPHA */
+ png_ptr->background_1.gray = (png_uint_16)(pow(
+ (double)png_ptr->background.gray / m, g) * m + .5);
+ png_ptr->background.gray = (png_uint_16)(pow(
+ (double)png_ptr->background.gray / m, gs) * m + .5);
+ }
+ }
+ }
+ else
+ /* transformation does not include PNG_BACKGROUND */
+#endif
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_colorp palette = png_ptr->palette;
+ int num_palette = png_ptr->num_palette;
+ int i;
+
+ for (i = 0; i < num_palette; i++)
+ {
+ palette[i].red = png_ptr->gamma_table[palette[i].red];
+ palette[i].green = png_ptr->gamma_table[palette[i].green];
+ palette[i].blue = png_ptr->gamma_table[palette[i].blue];
+ }
+ }
+ }
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ else
+#endif
+#endif
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ /* No GAMMA transformation */
+ if ((png_ptr->transformations & PNG_BACKGROUND) &&
+ (color_type == PNG_COLOR_TYPE_PALETTE))
+ {
+ int i;
+ int istop = (int)png_ptr->num_trans;
+ png_color back;
+ png_colorp palette = png_ptr->palette;
+
+ back.red = (png_byte)png_ptr->background.red;
+ back.green = (png_byte)png_ptr->background.green;
+ back.blue = (png_byte)png_ptr->background.blue;
+
+ for (i = 0; i < istop; i++)
+ {
+ if (png_ptr->trans[i] == 0)
+ {
+ palette[i] = back;
+ }
+ else if (png_ptr->trans[i] != 0xff)
+ {
+ /* The png_composite() macro is defined in png.h */
+ png_composite(palette[i].red, palette[i].red,
+ png_ptr->trans[i], back.red);
+ png_composite(palette[i].green, palette[i].green,
+ png_ptr->trans[i], back.green);
+ png_composite(palette[i].blue, palette[i].blue,
+ png_ptr->trans[i], back.blue);
+ }
+ }
+ }
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED)
+ if ((png_ptr->transformations & PNG_SHIFT) &&
+ (color_type == PNG_COLOR_TYPE_PALETTE))
+ {
+ png_uint_16 i;
+ png_uint_16 istop = png_ptr->num_palette;
+ int sr = 8 - png_ptr->sig_bit.red;
+ int sg = 8 - png_ptr->sig_bit.green;
+ int sb = 8 - png_ptr->sig_bit.blue;
+
+ if (sr < 0 || sr > 8)
+ sr = 0;
+ if (sg < 0 || sg > 8)
+ sg = 0;
+ if (sb < 0 || sb > 8)
+ sb = 0;
+ for (i = 0; i < istop; i++)
+ {
+ png_ptr->palette[i].red >>= sr;
+ png_ptr->palette[i].green >>= sg;
+ png_ptr->palette[i].blue >>= sb;
+ }
+ }
+#endif
+ }
+#if !defined(PNG_READ_GAMMA_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) \
+ && !defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if(png_ptr)
+ return;
+#endif
+}
+
+/* Modify the info structure to reflect the transformations. The
+ * info should be updated so a PNG file could be written with it,
+ * assuming the transformations result in valid PNG data.
+ */
+void /* PRIVATE */
+png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_read_transform_info\n");
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ if (png_ptr->transformations & PNG_EXPAND)
+ {
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (png_ptr->num_trans)
+ info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ else
+ info_ptr->color_type = PNG_COLOR_TYPE_RGB;
+ info_ptr->bit_depth = 8;
+ info_ptr->num_trans = 0;
+ }
+ else
+ {
+ if (png_ptr->num_trans)
+ info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
+ if (info_ptr->bit_depth < 8)
+ info_ptr->bit_depth = 8;
+ info_ptr->num_trans = 0;
+ }
+ }
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->transformations & PNG_BACKGROUND)
+ {
+ info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
+ info_ptr->num_trans = 0;
+ info_ptr->background = png_ptr->background;
+ }
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (png_ptr->transformations & PNG_GAMMA)
+ {
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ info_ptr->gamma = png_ptr->gamma;
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ info_ptr->int_gamma = png_ptr->int_gamma;
+#endif
+ }
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+ if ((png_ptr->transformations & PNG_16_TO_8) && (info_ptr->bit_depth == 16))
+ info_ptr->bit_depth = 8;
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+ if (png_ptr->transformations & PNG_DITHER)
+ {
+ if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
+ (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&
+ png_ptr->palette_lookup && info_ptr->bit_depth == 8)
+ {
+ info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
+ }
+ }
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED)
+ if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8))
+ info_ptr->bit_depth = 8;
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+ if (png_ptr->transformations & PNG_GRAY_TO_RGB)
+ info_ptr->color_type |= PNG_COLOR_MASK_COLOR;
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+ if (png_ptr->transformations & PNG_RGB_TO_GRAY)
+ info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR;
+#endif
+
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ info_ptr->channels = 1;
+ else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ info_ptr->channels = 3;
+ else
+ info_ptr->channels = 1;
+
+#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_STRIP_ALPHA)
+ info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
+#endif
+
+ if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
+ info_ptr->channels++;
+
+#if defined(PNG_READ_FILLER_SUPPORTED)
+ /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */
+ if ((png_ptr->transformations & PNG_FILLER) &&
+ ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
+ (info_ptr->color_type == PNG_COLOR_TYPE_GRAY)))
+ {
+ info_ptr->channels++;
+#if 0 /* if adding a true alpha channel not just filler */
+ info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
+#endif
+ }
+#endif
+
+#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \
+defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
+ if(png_ptr->transformations & PNG_USER_TRANSFORM)
+ {
+ if(info_ptr->bit_depth < png_ptr->user_transform_depth)
+ info_ptr->bit_depth = png_ptr->user_transform_depth;
+ if(info_ptr->channels < png_ptr->user_transform_channels)
+ info_ptr->channels = png_ptr->user_transform_channels;
+ }
+#endif
+
+ info_ptr->pixel_depth = (png_byte)(info_ptr->channels *
+ info_ptr->bit_depth);
+ info_ptr->rowbytes = ((info_ptr->width * info_ptr->pixel_depth + 7) >> 3);
+
+#if !defined(PNG_READ_EXPAND_SUPPORTED)
+ if(png_ptr)
+ return;
+#endif
+}
+
+/* Transform the row. The order of transformations is significant,
+ * and is very touchy. If you add a transformation, take care to
+ * decide how it fits in with the other transformations here.
+ */
+void /* PRIVATE */
+png_do_read_transformations(png_structp png_ptr)
+{
+ png_debug(1, "in png_do_read_transformations\n");
+#if !defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (png_ptr->row_buf == NULL)
+ {
+#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
+ char msg[50];
+
+ sprintf(msg, "NULL row buffer for row %ld, pass %d", png_ptr->row_number,
+ png_ptr->pass);
+ png_error(png_ptr, msg);
+#else
+ png_error(png_ptr, "NULL row buffer");
+#endif
+ }
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ if (png_ptr->transformations & PNG_EXPAND)
+ {
+ if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ png_ptr->palette, png_ptr->trans, png_ptr->num_trans);
+ }
+ else
+ {
+ if (png_ptr->num_trans)
+ png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ &(png_ptr->trans_values));
+ else
+ png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ NULL);
+ }
+ }
+#endif
+
+#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_STRIP_ALPHA)
+ png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ PNG_FLAG_FILLER_AFTER);
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+ if (png_ptr->transformations & PNG_RGB_TO_GRAY)
+ {
+ int rgb_error =
+ png_do_rgb_to_gray(png_ptr, &(png_ptr->row_info), png_ptr->row_buf + 1);
+ if(rgb_error)
+ {
+ png_ptr->rgb_to_gray_status=1;
+ if(png_ptr->transformations == PNG_RGB_TO_GRAY_WARN)
+ png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel");
+ if(png_ptr->transformations == PNG_RGB_TO_GRAY_ERR)
+ png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel");
+ }
+ }
+#endif
+
+/*
+From Andreas Dilger e-mail to png-implement, 26 March 1998:
+
+ In most cases, the "simple transparency" should be done prior to doing
+ gray-to-RGB, or you will have to test 3x as many bytes to check if a
+ pixel is transparent. You would also need to make sure that the
+ transparency information is upgraded to RGB.
+
+ To summarize, the current flow is:
+ - Gray + simple transparency -> compare 1 or 2 gray bytes and composite
+ with background "in place" if transparent,
+ convert to RGB if necessary
+ - Gray + alpha -> composite with gray background and remove alpha bytes,
+ convert to RGB if necessary
+
+ To support RGB backgrounds for gray images we need:
+ - Gray + simple transparency -> convert to RGB + simple transparency, compare
+ 3 or 6 bytes and composite with background
+ "in place" if transparent (3x compare/pixel
+ compared to doing composite with gray bkgrnd)
+ - Gray + alpha -> convert to RGB + alpha, composite with background and
+ remove alpha bytes (3x float operations/pixel
+ compared with composite on gray background)
+
+ Greg's change will do this. The reason it wasn't done before is for
+ performance, as this increases the per-pixel operations. If we would check
+ in advance if the background was gray or RGB, and position the gray-to-RGB
+ transform appropriately, then it would save a lot of work/time.
+ */
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+ /* if gray -> RGB, do so now only if background is non-gray; else do later
+ * for performance reasons */
+ if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
+ !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
+ png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if ((png_ptr->transformations & PNG_BACKGROUND) &&
+ ((png_ptr->num_trans != 0 ) ||
+ (png_ptr->color_type & PNG_COLOR_MASK_ALPHA)))
+ png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ &(png_ptr->trans_values), &(png_ptr->background),
+ &(png_ptr->background_1),
+ png_ptr->gamma_table, png_ptr->gamma_from_1,
+ png_ptr->gamma_to_1, png_ptr->gamma_16_table,
+ png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1,
+ png_ptr->gamma_shift);
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if ((png_ptr->transformations & PNG_GAMMA) &&
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ !((png_ptr->transformations & PNG_BACKGROUND) &&
+ ((png_ptr->num_trans != 0) ||
+ (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) &&
+#endif
+ (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
+ png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ png_ptr->gamma_table, png_ptr->gamma_16_table,
+ png_ptr->gamma_shift);
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+ if (png_ptr->transformations & PNG_16_TO_8)
+ png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+ if (png_ptr->transformations & PNG_DITHER)
+ {
+ png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1,
+ png_ptr->palette_lookup, png_ptr->dither_index);
+ if(png_ptr->row_info.rowbytes == (png_uint_32)0)
+ png_error(png_ptr, "png_do_dither returned rowbytes=0");
+ }
+#endif
+
+#if defined(PNG_READ_INVERT_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_MONO)
+ png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED)
+ if (png_ptr->transformations & PNG_SHIFT)
+ png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ &(png_ptr->shift));
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACK)
+ png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_BGR_SUPPORTED)
+ if (png_ptr->transformations & PNG_BGR)
+ png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+ /* if gray -> RGB, do so now only if we did not do so above */
+ if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
+ (png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
+ png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_FILLER_SUPPORTED)
+ if (png_ptr->transformations & PNG_FILLER)
+ png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ (png_uint_32)png_ptr->filler, png_ptr->flags);
+#endif
+
+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_ALPHA)
+ png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_ALPHA)
+ png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_SWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_BYTES)
+ png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
+ if (png_ptr->transformations & PNG_USER_TRANSFORM)
+ {
+ if(png_ptr->read_user_transform_fn != NULL)
+ (*(png_ptr->read_user_transform_fn)) /* user read transform function */
+ (png_ptr, /* png_ptr */
+ &(png_ptr->row_info), /* row_info: */
+ /* png_uint_32 width; width of row */
+ /* png_uint_32 rowbytes; number of bytes in row */
+ /* png_byte color_type; color type of pixels */
+ /* png_byte bit_depth; bit depth of samples */
+ /* png_byte channels; number of channels (1-4) */
+ /* png_byte pixel_depth; bits per pixel (depth*channels) */
+ png_ptr->row_buf + 1); /* start of pixel data for row */
+#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
+ if(png_ptr->user_transform_depth)
+ png_ptr->row_info.bit_depth = png_ptr->user_transform_depth;
+ if(png_ptr->user_transform_channels)
+ png_ptr->row_info.channels = png_ptr->user_transform_channels;
+#endif
+ png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
+ png_ptr->row_info.channels);
+ png_ptr->row_info.rowbytes = (png_ptr->row_info.width *
+ png_ptr->row_info.pixel_depth+7)>>3;
+ }
+#endif
+
+}
+
+#if defined(PNG_READ_PACK_SUPPORTED)
+/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,
+ * without changing the actual values. Thus, if you had a row with
+ * a bit depth of 1, you would end up with bytes that only contained
+ * the numbers 0 or 1. If you would rather they contain 0 and 255, use
+ * png_do_shift() after this.
+ */
+void /* PRIVATE */
+png_do_unpack(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_unpack\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL && row_info->bit_depth < 8)
+#else
+ if (row_info->bit_depth < 8)
+#endif
+ {
+ png_uint_32 i;
+ png_uint_32 row_width=row_info->width;
+
+ switch (row_info->bit_depth)
+ {
+ case 1:
+ {
+ png_bytep sp = row + (png_size_t)((row_width - 1) >> 3);
+ png_bytep dp = row + (png_size_t)row_width - 1;
+ png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07);
+ for (i = 0; i < row_width; i++)
+ {
+ *dp = (png_byte)((*sp >> shift) & 0x01);
+ if (shift == 7)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift++;
+
+ dp--;
+ }
+ break;
+ }
+ case 2:
+ {
+
+ png_bytep sp = row + (png_size_t)((row_width - 1) >> 2);
+ png_bytep dp = row + (png_size_t)row_width - 1;
+ png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
+ for (i = 0; i < row_width; i++)
+ {
+ *dp = (png_byte)((*sp >> shift) & 0x03);
+ if (shift == 6)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift += 2;
+
+ dp--;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_bytep sp = row + (png_size_t)((row_width - 1) >> 1);
+ png_bytep dp = row + (png_size_t)row_width - 1;
+ png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
+ for (i = 0; i < row_width; i++)
+ {
+ *dp = (png_byte)((*sp >> shift) & 0x0f);
+ if (shift == 4)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift = 4;
+
+ dp--;
+ }
+ break;
+ }
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = (png_byte)(8 * row_info->channels);
+ row_info->rowbytes = row_width * row_info->channels;
+ }
+}
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED)
+/* Reverse the effects of png_do_shift. This routine merely shifts the
+ * pixels back to their significant bits values. Thus, if you have
+ * a row of bit depth 8, but only 5 are significant, this will shift
+ * the values back to 0 through 31.
+ */
+void /* PRIVATE */
+png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits)
+{
+ png_debug(1, "in png_do_unshift\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL && sig_bits != NULL &&
+#endif
+ row_info->color_type != PNG_COLOR_TYPE_PALETTE)
+ {
+ int shift[4];
+ int channels = 0;
+ int c;
+ png_uint_16 value = 0;
+ png_uint_32 row_width = row_info->width;
+
+ if (row_info->color_type & PNG_COLOR_MASK_COLOR)
+ {
+ shift[channels++] = row_info->bit_depth - sig_bits->red;
+ shift[channels++] = row_info->bit_depth - sig_bits->green;
+ shift[channels++] = row_info->bit_depth - sig_bits->blue;
+ }
+ else
+ {
+ shift[channels++] = row_info->bit_depth - sig_bits->gray;
+ }
+ if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ shift[channels++] = row_info->bit_depth - sig_bits->alpha;
+ }
+
+ for (c = 0; c < channels; c++)
+ {
+ if (shift[c] <= 0)
+ shift[c] = 0;
+ else
+ value = 1;
+ }
+
+ if (!value)
+ return;
+
+ switch (row_info->bit_depth)
+ {
+ case 2:
+ {
+ png_bytep bp;
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+
+ for (bp = row, i = 0; i < istop; i++)
+ {
+ *bp >>= 1;
+ *bp++ &= 0x55;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_bytep bp = row;
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+ png_byte mask = (png_byte)((((int)0xf0 >> shift[0]) & (int)0xf0) |
+ (png_byte)((int)0xf >> shift[0]));
+
+ for (i = 0; i < istop; i++)
+ {
+ *bp >>= shift[0];
+ *bp++ &= mask;
+ }
+ break;
+ }
+ case 8:
+ {
+ png_bytep bp = row;
+ png_uint_32 i;
+ png_uint_32 istop = row_width * channels;
+
+ for (i = 0; i < istop; i++)
+ {
+ *bp++ >>= shift[i%channels];
+ }
+ break;
+ }
+ case 16:
+ {
+ png_bytep bp = row;
+ png_uint_32 i;
+ png_uint_32 istop = channels * row_width;
+
+ for (i = 0; i < istop; i++)
+ {
+ value = (png_uint_16)((*bp << 8) + *(bp + 1));
+ value >>= shift[i%channels];
+ *bp++ = (png_byte)(value >> 8);
+ *bp++ = (png_byte)(value & 0xff);
+ }
+ break;
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+/* chop rows of bit depth 16 down to 8 */
+void /* PRIVATE */
+png_do_chop(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_chop\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL && row_info->bit_depth == 16)
+#else
+ if (row_info->bit_depth == 16)
+#endif
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ png_uint_32 i;
+ png_uint_32 istop = row_info->width * row_info->channels;
+
+ for (i = 0; i<istop; i++, sp += 2, dp++)
+ {
+#if defined(PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED)
+ /* This does a more accurate scaling of the 16-bit color
+ * value, rather than a simple low-byte truncation.
+ *
+ * What the ideal calculation should be:
+ * *dp = (((((png_uint_32)(*sp) << 8) |
+ * (png_uint_32)(*(sp + 1))) * 255 + 127) / (png_uint_32)65535L;
+ *
+ * GRR: no, I think this is what it really should be:
+ * *dp = (((((png_uint_32)(*sp) << 8) |
+ * (png_uint_32)(*(sp + 1))) + 128L) / (png_uint_32)257L;
+ *
+ * GRR: here's the exact calculation with shifts:
+ * temp = (((png_uint_32)(*sp) << 8) | (png_uint_32)(*(sp + 1))) + 128L;
+ * *dp = (temp - (temp >> 8)) >> 8;
+ *
+ * Approximate calculation with shift/add instead of multiply/divide:
+ * *dp = ((((png_uint_32)(*sp) << 8) |
+ * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8;
+ *
+ * What we actually do to avoid extra shifting and conversion:
+ */
+
+ *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0);
+#else
+ /* Simply discard the low order byte */
+ *dp = *sp;
+#endif
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = (png_byte)(8 * row_info->channels);
+ row_info->rowbytes = row_info->width * row_info->channels;
+ }
+}
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
+void /* PRIVATE */
+png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_read_swap_alpha\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ png_uint_32 row_width = row_info->width;
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ /* This converts from RGBA to ARGB */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_byte save;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ save = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save;
+ }
+ }
+ /* This converts from RRGGBBAA to AARRGGBB */
+ else
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_byte save[2];
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ save[0] = *(--sp);
+ save[1] = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save[0];
+ *(--dp) = save[1];
+ }
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ /* This converts from GA to AG */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_byte save;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ save = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save;
+ }
+ }
+ /* This converts from GGAA to AAGG */
+ else
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_byte save[2];
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ save[0] = *(--sp);
+ save[1] = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save[0];
+ *(--dp) = save[1];
+ }
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
+void /* PRIVATE */
+png_do_read_invert_alpha(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_read_invert_alpha\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ png_uint_32 row_width = row_info->width;
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ /* This inverts the alpha channel in RGBA */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = (png_byte)(255 - *(--sp));
+
+/* This does nothing:
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ We can replace it with:
+*/
+ sp-=3;
+ dp=sp;
+ }
+ }
+ /* This inverts the alpha channel in RRGGBBAA */
+ else
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = (png_byte)(255 - *(--sp));
+ *(--dp) = (png_byte)(255 - *(--sp));
+
+/* This does nothing:
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ We can replace it with:
+*/
+ sp-=6;
+ dp=sp;
+ }
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ /* This inverts the alpha channel in GA */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = (png_byte)(255 - *(--sp));
+ *(--dp) = *(--sp);
+ }
+ }
+ /* This inverts the alpha channel in GGAA */
+ else
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = (png_byte)(255 - *(--sp));
+ *(--dp) = (png_byte)(255 - *(--sp));
+/*
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+*/
+ sp-=2;
+ dp=sp;
+ }
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_FILLER_SUPPORTED)
+/* Add filler channel if we have RGB color */
+void /* PRIVATE */
+png_do_read_filler(png_row_infop row_info, png_bytep row,
+ png_uint_32 filler, png_uint_32 flags)
+{
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ png_byte hi_filler = (png_byte)((filler>>8) & 0xff);
+ png_byte lo_filler = (png_byte)(filler & 0xff);
+
+ png_debug(1, "in png_do_read_filler\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ row_info->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ if(row_info->bit_depth == 8)
+ {
+ /* This changes the data from G to GX */
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ png_bytep sp = row + (png_size_t)row_width;
+ png_bytep dp = sp + (png_size_t)row_width;
+ for (i = 1; i < row_width; i++)
+ {
+ *(--dp) = lo_filler;
+ *(--dp) = *(--sp);
+ }
+ *(--dp) = lo_filler;
+ row_info->channels = 2;
+ row_info->pixel_depth = 16;
+ row_info->rowbytes = row_width * 2;
+ }
+ /* This changes the data from G to XG */
+ else
+ {
+ png_bytep sp = row + (png_size_t)row_width;
+ png_bytep dp = sp + (png_size_t)row_width;
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = *(--sp);
+ *(--dp) = lo_filler;
+ }
+ row_info->channels = 2;
+ row_info->pixel_depth = 16;
+ row_info->rowbytes = row_width * 2;
+ }
+ }
+ else if(row_info->bit_depth == 16)
+ {
+ /* This changes the data from GG to GGXX */
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ png_bytep sp = row + (png_size_t)row_width;
+ png_bytep dp = sp + (png_size_t)row_width;
+ for (i = 1; i < row_width; i++)
+ {
+ *(--dp) = hi_filler;
+ *(--dp) = lo_filler;
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ }
+ *(--dp) = hi_filler;
+ *(--dp) = lo_filler;
+ row_info->channels = 2;
+ row_info->pixel_depth = 32;
+ row_info->rowbytes = row_width * 4;
+ }
+ /* This changes the data from GG to XXGG */
+ else
+ {
+ png_bytep sp = row + (png_size_t)row_width;
+ png_bytep dp = sp + (png_size_t)row_width;
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = hi_filler;
+ *(--dp) = lo_filler;
+ }
+ row_info->channels = 2;
+ row_info->pixel_depth = 32;
+ row_info->rowbytes = row_width * 4;
+ }
+ }
+ } /* COLOR_TYPE == GRAY */
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ if(row_info->bit_depth == 8)
+ {
+ /* This changes the data from RGB to RGBX */
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ png_bytep sp = row + (png_size_t)row_width * 3;
+ png_bytep dp = sp + (png_size_t)row_width;
+ for (i = 1; i < row_width; i++)
+ {
+ *(--dp) = lo_filler;
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ }
+ *(--dp) = lo_filler;
+ row_info->channels = 4;
+ row_info->pixel_depth = 32;
+ row_info->rowbytes = row_width * 4;
+ }
+ /* This changes the data from RGB to XRGB */
+ else
+ {
+ png_bytep sp = row + (png_size_t)row_width * 3;
+ png_bytep dp = sp + (png_size_t)row_width;
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = lo_filler;
+ }
+ row_info->channels = 4;
+ row_info->pixel_depth = 32;
+ row_info->rowbytes = row_width * 4;
+ }
+ }
+ else if(row_info->bit_depth == 16)
+ {
+ /* This changes the data from RRGGBB to RRGGBBXX */
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ png_bytep sp = row + (png_size_t)row_width * 3;
+ png_bytep dp = sp + (png_size_t)row_width;
+ for (i = 1; i < row_width; i++)
+ {
+ *(--dp) = hi_filler;
+ *(--dp) = lo_filler;
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ }
+ *(--dp) = hi_filler;
+ *(--dp) = lo_filler;
+ row_info->channels = 4;
+ row_info->pixel_depth = 64;
+ row_info->rowbytes = row_width * 8;
+ }
+ /* This changes the data from RRGGBB to XXRRGGBB */
+ else
+ {
+ png_bytep sp = row + (png_size_t)row_width * 3;
+ png_bytep dp = sp + (png_size_t)row_width;
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = hi_filler;
+ *(--dp) = lo_filler;
+ }
+ row_info->channels = 4;
+ row_info->pixel_depth = 64;
+ row_info->rowbytes = row_width * 8;
+ }
+ }
+ } /* COLOR_TYPE == RGB */
+}
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+/* expand grayscale files to RGB, with or without alpha */
+void /* PRIVATE */
+png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
+{
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ png_debug(1, "in png_do_gray_to_rgb\n");
+ if (row_info->bit_depth >= 8 &&
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ !(row_info->color_type & PNG_COLOR_MASK_COLOR))
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp = row + (png_size_t)row_width - 1;
+ png_bytep dp = sp + (png_size_t)row_width * 2;
+ for (i = 0; i < row_width; i++)
+ {
+ *(dp--) = *sp;
+ *(dp--) = *sp;
+ *(dp--) = *(sp--);
+ }
+ }
+ else
+ {
+ png_bytep sp = row + (png_size_t)row_width * 2 - 1;
+ png_bytep dp = sp + (png_size_t)row_width * 4;
+ for (i = 0; i < row_width; i++)
+ {
+ *(dp--) = *sp;
+ *(dp--) = *(sp - 1);
+ *(dp--) = *sp;
+ *(dp--) = *(sp - 1);
+ *(dp--) = *(sp--);
+ *(dp--) = *(sp--);
+ }
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp = row + (png_size_t)row_width * 2 - 1;
+ png_bytep dp = sp + (png_size_t)row_width * 2;
+ for (i = 0; i < row_width; i++)
+ {
+ *(dp--) = *(sp--);
+ *(dp--) = *sp;
+ *(dp--) = *sp;
+ *(dp--) = *(sp--);
+ }
+ }
+ else
+ {
+ png_bytep sp = row + (png_size_t)row_width * 4 - 1;
+ png_bytep dp = sp + (png_size_t)row_width * 4;
+ for (i = 0; i < row_width; i++)
+ {
+ *(dp--) = *(sp--);
+ *(dp--) = *(sp--);
+ *(dp--) = *sp;
+ *(dp--) = *(sp - 1);
+ *(dp--) = *sp;
+ *(dp--) = *(sp - 1);
+ *(dp--) = *(sp--);
+ *(dp--) = *(sp--);
+ }
+ }
+ }
+ row_info->channels += (png_byte)2;
+ row_info->color_type |= PNG_COLOR_MASK_COLOR;
+ row_info->pixel_depth = (png_byte)(row_info->channels *
+ row_info->bit_depth);
+ row_info->rowbytes = ((row_width *
+ row_info->pixel_depth + 7) >> 3);
+ }
+}
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+/* reduce RGB files to grayscale, with or without alpha
+ * using the equation given in Poynton's ColorFAQ at
+ * <http://www.inforamp.net/~poynton/>
+ * Copyright (c) 1998-01-04 Charles Poynton poynton@inforamp.net
+ *
+ * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
+ *
+ * We approximate this with
+ *
+ * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B
+ *
+ * which can be expressed with integers as
+ *
+ * Y = (6969 * R + 23434 * G + 2365 * B)/32768
+ *
+ * The calculation is to be done in a linear colorspace.
+ *
+ * Other integer coefficents can be used via png_set_rgb_to_gray().
+ */
+int /* PRIVATE */
+png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
+
+{
+ png_uint_32 i;
+
+ png_uint_32 row_width = row_info->width;
+ int rgb_error = 0;
+
+ png_debug(1, "in png_do_rgb_to_gray\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ (row_info->color_type & PNG_COLOR_MASK_COLOR))
+ {
+ png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff;
+ png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff;
+ png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff;
+
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ if (row_info->bit_depth == 8)
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+
+ for (i = 0; i < row_width; i++)
+ {
+ png_byte red = png_ptr->gamma_to_1[*(sp++)];
+ png_byte green = png_ptr->gamma_to_1[*(sp++)];
+ png_byte blue = png_ptr->gamma_to_1[*(sp++)];
+ if(red != green || red != blue)
+ {
+ rgb_error |= 1;
+ *(dp++) = png_ptr->gamma_from_1[
+ (rc*red+gc*green+bc*blue)>>15];
+ }
+ else
+ *(dp++) = *(sp-1);
+ }
+ }
+ else
+#endif
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_byte red = *(sp++);
+ png_byte green = *(sp++);
+ png_byte blue = *(sp++);
+ if(red != green || red != blue)
+ {
+ rgb_error |= 1;
+ *(dp++) = (png_byte)((rc*red+gc*green+bc*blue)>>15);
+ }
+ else
+ *(dp++) = *(sp-1);
+ }
+ }
+ }
+
+ else /* RGB bit_depth == 16 */
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->gamma_16_to_1 != NULL &&
+ png_ptr->gamma_16_from_1 != NULL)
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 red, green, blue, w;
+
+ red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
+ green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
+ blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
+
+ if(red == green && red == blue)
+ w = red;
+ else
+ {
+ png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
+ png_ptr->gamma_shift][red>>8];
+ png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
+ png_ptr->gamma_shift][green>>8];
+ png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
+ png_ptr->gamma_shift][blue>>8];
+ png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1
+ + bc*blue_1)>>15);
+ w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
+ png_ptr->gamma_shift][gray16 >> 8];
+ rgb_error |= 1;
+ }
+
+ *(dp++) = (png_byte)((w>>8) & 0xff);
+ *(dp++) = (png_byte)(w & 0xff);
+ }
+ }
+ else
+#endif
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 red, green, blue, gray16;
+
+ red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
+ green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
+ blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
+
+ if(red != green || red != blue)
+ rgb_error |= 1;
+ gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
+ *(dp++) = (png_byte)((gray16>>8) & 0xff);
+ *(dp++) = (png_byte)(gray16 & 0xff);
+ }
+ }
+ }
+ }
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ if (row_info->bit_depth == 8)
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_byte red = png_ptr->gamma_to_1[*(sp++)];
+ png_byte green = png_ptr->gamma_to_1[*(sp++)];
+ png_byte blue = png_ptr->gamma_to_1[*(sp++)];
+ if(red != green || red != blue)
+ rgb_error |= 1;
+ *(dp++) = png_ptr->gamma_from_1
+ [(rc*red + gc*green + bc*blue)>>15];
+ *(dp++) = *(sp++); /* alpha */
+ }
+ }
+ else
+#endif
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_byte red = *(sp++);
+ png_byte green = *(sp++);
+ png_byte blue = *(sp++);
+ if(red != green || red != blue)
+ rgb_error |= 1;
+ *(dp++) = (png_byte)((gc*red + gc*green + bc*blue)>>8);
+ *(dp++) = *(sp++); /* alpha */
+ }
+ }
+ }
+ else /* RGBA bit_depth == 16 */
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->gamma_16_to_1 != NULL &&
+ png_ptr->gamma_16_from_1 != NULL)
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 red, green, blue, w;
+
+ red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
+ green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
+ blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
+
+ if(red == green && red == blue)
+ w = red;
+ else
+ {
+ png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
+ png_ptr->gamma_shift][red>>8];
+ png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
+ png_ptr->gamma_shift][green>>8];
+ png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
+ png_ptr->gamma_shift][blue>>8];
+ png_uint_16 gray16 = (png_uint_16)((rc * red_1
+ + gc * green_1 + bc * blue_1)>>15);
+ w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
+ png_ptr->gamma_shift][gray16 >> 8];
+ rgb_error |= 1;
+ }
+
+ *(dp++) = (png_byte)((w>>8) & 0xff);
+ *(dp++) = (png_byte)(w & 0xff);
+ *(dp++) = *(sp++); /* alpha */
+ *(dp++) = *(sp++);
+ }
+ }
+ else
+#endif
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 red, green, blue, gray16;
+ red = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
+ green = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
+ blue = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
+ if(red != green || red != blue)
+ rgb_error |= 1;
+ gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
+ *(dp++) = (png_byte)((gray16>>8) & 0xff);
+ *(dp++) = (png_byte)(gray16 & 0xff);
+ *(dp++) = *(sp++); /* alpha */
+ *(dp++) = *(sp++);
+ }
+ }
+ }
+ }
+ row_info->channels -= (png_byte)2;
+ row_info->color_type &= ~PNG_COLOR_MASK_COLOR;
+ row_info->pixel_depth = (png_byte)(row_info->channels *
+ row_info->bit_depth);
+ row_info->rowbytes = ((row_width *
+ row_info->pixel_depth + 7) >> 3);
+ }
+ return rgb_error;
+}
+#endif
+
+/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth
+ * large of png_color. This lets grayscale images be treated as
+ * paletted. Most useful for gamma correction and simplification
+ * of code.
+ */
+void /* PRIVATE */
+png_build_grayscale_palette(int bit_depth, png_colorp palette)
+{
+ int num_palette;
+ int color_inc;
+ int i;
+ int v;
+
+ png_debug(1, "in png_do_build_grayscale_palette\n");
+ if (palette == NULL)
+ return;
+
+ switch (bit_depth)
+ {
+ case 1:
+ num_palette = 2;
+ color_inc = 0xff;
+ break;
+ case 2:
+ num_palette = 4;
+ color_inc = 0x55;
+ break;
+ case 4:
+ num_palette = 16;
+ color_inc = 0x11;
+ break;
+ case 8:
+ num_palette = 256;
+ color_inc = 1;
+ break;
+ default:
+ num_palette = 0;
+ color_inc = 0;
+ break;
+ }
+
+ for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
+ {
+ palette[i].red = (png_byte)v;
+ palette[i].green = (png_byte)v;
+ palette[i].blue = (png_byte)v;
+ }
+}
+
+/* This function is currently unused. Do we really need it? */
+#if defined(PNG_READ_DITHER_SUPPORTED) && defined(PNG_CORRECT_PALETTE_SUPPORTED)
+void /* PRIVATE */
+png_correct_palette(png_structp png_ptr, png_colorp palette,
+ int num_palette)
+{
+ png_debug(1, "in png_correct_palette\n");
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
+ defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
+ if (png_ptr->transformations & (PNG_GAMMA | PNG_BACKGROUND))
+ {
+ png_color back, back_1;
+
+ if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
+ {
+ back.red = png_ptr->gamma_table[png_ptr->background.red];
+ back.green = png_ptr->gamma_table[png_ptr->background.green];
+ back.blue = png_ptr->gamma_table[png_ptr->background.blue];
+
+ back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
+ back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
+ back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
+ }
+ else
+ {
+ double g;
+
+ g = 1.0 / (png_ptr->background_gamma * png_ptr->screen_gamma);
+
+ if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_SCREEN ||
+ fabs(g - 1.0) < PNG_GAMMA_THRESHOLD)
+ {
+ back.red = png_ptr->background.red;
+ back.green = png_ptr->background.green;
+ back.blue = png_ptr->background.blue;
+ }
+ else
+ {
+ back.red =
+ (png_byte)(pow((double)png_ptr->background.red/255, g) *
+ 255.0 + 0.5);
+ back.green =
+ (png_byte)(pow((double)png_ptr->background.green/255, g) *
+ 255.0 + 0.5);
+ back.blue =
+ (png_byte)(pow((double)png_ptr->background.blue/255, g) *
+ 255.0 + 0.5);
+ }
+
+ g = 1.0 / png_ptr->background_gamma;
+
+ back_1.red =
+ (png_byte)(pow((double)png_ptr->background.red/255, g) *
+ 255.0 + 0.5);
+ back_1.green =
+ (png_byte)(pow((double)png_ptr->background.green/255, g) *
+ 255.0 + 0.5);
+ back_1.blue =
+ (png_byte)(pow((double)png_ptr->background.blue/255, g) *
+ 255.0 + 0.5);
+ }
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_uint_32 i;
+
+ for (i = 0; i < (png_uint_32)num_palette; i++)
+ {
+ if (i < png_ptr->num_trans && png_ptr->trans[i] == 0)
+ {
+ palette[i] = back;
+ }
+ else if (i < png_ptr->num_trans && png_ptr->trans[i] != 0xff)
+ {
+ png_byte v, w;
+
+ v = png_ptr->gamma_to_1[png_ptr->palette[i].red];
+ png_composite(w, v, png_ptr->trans[i], back_1.red);
+ palette[i].red = png_ptr->gamma_from_1[w];
+
+ v = png_ptr->gamma_to_1[png_ptr->palette[i].green];
+ png_composite(w, v, png_ptr->trans[i], back_1.green);
+ palette[i].green = png_ptr->gamma_from_1[w];
+
+ v = png_ptr->gamma_to_1[png_ptr->palette[i].blue];
+ png_composite(w, v, png_ptr->trans[i], back_1.blue);
+ palette[i].blue = png_ptr->gamma_from_1[w];
+ }
+ else
+ {
+ palette[i].red = png_ptr->gamma_table[palette[i].red];
+ palette[i].green = png_ptr->gamma_table[palette[i].green];
+ palette[i].blue = png_ptr->gamma_table[palette[i].blue];
+ }
+ }
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; i < num_palette; i++)
+ {
+ if (palette[i].red == (png_byte)png_ptr->trans_values.gray)
+ {
+ palette[i] = back;
+ }
+ else
+ {
+ palette[i].red = png_ptr->gamma_table[palette[i].red];
+ palette[i].green = png_ptr->gamma_table[palette[i].green];
+ palette[i].blue = png_ptr->gamma_table[palette[i].blue];
+ }
+ }
+ }
+ }
+ else
+#endif
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (png_ptr->transformations & PNG_GAMMA)
+ {
+ int i;
+
+ for (i = 0; i < num_palette; i++)
+ {
+ palette[i].red = png_ptr->gamma_table[palette[i].red];
+ palette[i].green = png_ptr->gamma_table[palette[i].green];
+ palette[i].blue = png_ptr->gamma_table[palette[i].blue];
+ }
+ }
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ else
+#endif
+#endif
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->transformations & PNG_BACKGROUND)
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_color back;
+
+ back.red = (png_byte)png_ptr->background.red;
+ back.green = (png_byte)png_ptr->background.green;
+ back.blue = (png_byte)png_ptr->background.blue;
+
+ for (i = 0; i < (int)png_ptr->num_trans; i++)
+ {
+ if (png_ptr->trans[i] == 0)
+ {
+ palette[i].red = back.red;
+ palette[i].green = back.green;
+ palette[i].blue = back.blue;
+ }
+ else if (png_ptr->trans[i] != 0xff)
+ {
+ png_composite(palette[i].red, png_ptr->palette[i].red,
+ png_ptr->trans[i], back.red);
+ png_composite(palette[i].green, png_ptr->palette[i].green,
+ png_ptr->trans[i], back.green);
+ png_composite(palette[i].blue, png_ptr->palette[i].blue,
+ png_ptr->trans[i], back.blue);
+ }
+ }
+ }
+ else /* assume grayscale palette (what else could it be?) */
+ {
+ int i;
+
+ for (i = 0; i < num_palette; i++)
+ {
+ if (i == (png_byte)png_ptr->trans_values.gray)
+ {
+ palette[i].red = (png_byte)png_ptr->background.red;
+ palette[i].green = (png_byte)png_ptr->background.green;
+ palette[i].blue = (png_byte)png_ptr->background.blue;
+ }
+ }
+ }
+ }
+#endif
+}
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+/* Replace any alpha or transparency with the supplied background color.
+ * "background" is already in the screen gamma, while "background_1" is
+ * at a gamma of 1.0. Paletted files have already been taken care of.
+ */
+void /* PRIVATE */
+png_do_background(png_row_infop row_info, png_bytep row,
+ png_color_16p trans_values, png_color_16p background,
+ png_color_16p background_1,
+ png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
+ png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
+ png_uint_16pp gamma_16_to_1, int gamma_shift)
+{
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width=row_info->width;
+ int shift;
+
+ png_debug(1, "in png_do_background\n");
+ if (background != NULL &&
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) ||
+ (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_values)))
+ {
+ switch (row_info->color_type)
+ {
+ case PNG_COLOR_TYPE_GRAY:
+ {
+ switch (row_info->bit_depth)
+ {
+ case 1:
+ {
+ sp = row;
+ shift = 7;
+ for (i = 0; i < row_width; i++)
+ {
+ if ((png_uint_16)((*sp >> shift) & 0x01)
+ == trans_values->gray)
+ {
+ *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
+ *sp |= (png_byte)(background->gray << shift);
+ }
+ if (!shift)
+ {
+ shift = 7;
+ sp++;
+ }
+ else
+ shift--;
+ }
+ break;
+ }
+ case 2:
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_table != NULL)
+ {
+ sp = row;
+ shift = 6;
+ for (i = 0; i < row_width; i++)
+ {
+ if ((png_uint_16)((*sp >> shift) & 0x03)
+ == trans_values->gray)
+ {
+ *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
+ *sp |= (png_byte)(background->gray << shift);
+ }
+ else
+ {
+ png_byte p = (png_byte)((*sp >> shift) & 0x03);
+ png_byte g = (png_byte)((gamma_table [p | (p << 2) |
+ (p << 4) | (p << 6)] >> 6) & 0x03);
+ *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
+ *sp |= (png_byte)(g << shift);
+ }
+ if (!shift)
+ {
+ shift = 6;
+ sp++;
+ }
+ else
+ shift -= 2;
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ shift = 6;
+ for (i = 0; i < row_width; i++)
+ {
+ if ((png_uint_16)((*sp >> shift) & 0x03)
+ == trans_values->gray)
+ {
+ *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
+ *sp |= (png_byte)(background->gray << shift);
+ }
+ if (!shift)
+ {
+ shift = 6;
+ sp++;
+ }
+ else
+ shift -= 2;
+ }
+ }
+ break;
+ }
+ case 4:
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_table != NULL)
+ {
+ sp = row;
+ shift = 4;
+ for (i = 0; i < row_width; i++)
+ {
+ if ((png_uint_16)((*sp >> shift) & 0x0f)
+ == trans_values->gray)
+ {
+ *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
+ *sp |= (png_byte)(background->gray << shift);
+ }
+ else
+ {
+ png_byte p = (png_byte)((*sp >> shift) & 0x0f);
+ png_byte g = (png_byte)((gamma_table[p |
+ (p << 4)] >> 4) & 0x0f);
+ *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
+ *sp |= (png_byte)(g << shift);
+ }
+ if (!shift)
+ {
+ shift = 4;
+ sp++;
+ }
+ else
+ shift -= 4;
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ shift = 4;
+ for (i = 0; i < row_width; i++)
+ {
+ if ((png_uint_16)((*sp >> shift) & 0x0f)
+ == trans_values->gray)
+ {
+ *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
+ *sp |= (png_byte)(background->gray << shift);
+ }
+ if (!shift)
+ {
+ shift = 4;
+ sp++;
+ }
+ else
+ shift -= 4;
+ }
+ }
+ break;
+ }
+ case 8:
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_table != NULL)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp++)
+ {
+ if (*sp == trans_values->gray)
+ {
+ *sp = (png_byte)background->gray;
+ }
+ else
+ {
+ *sp = gamma_table[*sp];
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp++)
+ {
+ if (*sp == trans_values->gray)
+ {
+ *sp = (png_byte)background->gray;
+ }
+ }
+ }
+ break;
+ }
+ case 16:
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_16 != NULL)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 2)
+ {
+ png_uint_16 v;
+
+ v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
+ if (v == trans_values->gray)
+ {
+ /* background is already in screen gamma */
+ *sp = (png_byte)((background->gray >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(background->gray & 0xff);
+ }
+ else
+ {
+ v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 2)
+ {
+ png_uint_16 v;
+
+ v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
+ if (v == trans_values->gray)
+ {
+ *sp = (png_byte)((background->gray >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(background->gray & 0xff);
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_RGB:
+ {
+ if (row_info->bit_depth == 8)
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_table != NULL)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 3)
+ {
+ if (*sp == trans_values->red &&
+ *(sp + 1) == trans_values->green &&
+ *(sp + 2) == trans_values->blue)
+ {
+ *sp = (png_byte)background->red;
+ *(sp + 1) = (png_byte)background->green;
+ *(sp + 2) = (png_byte)background->blue;
+ }
+ else
+ {
+ *sp = gamma_table[*sp];
+ *(sp + 1) = gamma_table[*(sp + 1)];
+ *(sp + 2) = gamma_table[*(sp + 2)];
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 3)
+ {
+ if (*sp == trans_values->red &&
+ *(sp + 1) == trans_values->green &&
+ *(sp + 2) == trans_values->blue)
+ {
+ *sp = (png_byte)background->red;
+ *(sp + 1) = (png_byte)background->green;
+ *(sp + 2) = (png_byte)background->blue;
+ }
+ }
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_16 != NULL)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 6)
+ {
+ png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
+ png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
+ png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
+ if (r == trans_values->red && g == trans_values->green &&
+ b == trans_values->blue)
+ {
+ /* background is already in screen gamma */
+ *sp = (png_byte)((background->red >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(background->red & 0xff);
+ *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
+ *(sp + 3) = (png_byte)(background->green & 0xff);
+ *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
+ *(sp + 5) = (png_byte)(background->blue & 0xff);
+ }
+ else
+ {
+ png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
+ *(sp + 2) = (png_byte)((v >> 8) & 0xff);
+ *(sp + 3) = (png_byte)(v & 0xff);
+ v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
+ *(sp + 4) = (png_byte)((v >> 8) & 0xff);
+ *(sp + 5) = (png_byte)(v & 0xff);
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 6)
+ {
+ png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp+1));
+ png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
+ png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
+
+ if (r == trans_values->red && g == trans_values->green &&
+ b == trans_values->blue)
+ {
+ *sp = (png_byte)((background->red >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(background->red & 0xff);
+ *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
+ *(sp + 3) = (png_byte)(background->green & 0xff);
+ *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
+ *(sp + 5) = (png_byte)(background->blue & 0xff);
+ }
+ }
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ {
+ if (row_info->bit_depth == 8)
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
+ gamma_table != NULL)
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 2, dp++)
+ {
+ png_uint_16 a = *(sp + 1);
+
+ if (a == 0xff)
+ {
+ *dp = gamma_table[*sp];
+ }
+ else if (a == 0)
+ {
+ /* background is already in screen gamma */
+ *dp = (png_byte)background->gray;
+ }
+ else
+ {
+ png_byte v, w;
+
+ v = gamma_to_1[*sp];
+ png_composite(w, v, a, background_1->gray);
+ *dp = gamma_from_1[w];
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 2, dp++)
+ {
+ png_byte a = *(sp + 1);
+
+ if (a == 0xff)
+ {
+ *dp = *sp;
+ }
+ else if (a == 0)
+ {
+ *dp = (png_byte)background->gray;
+ }
+ else
+ {
+ png_composite(*dp, *sp, a, background_1->gray);
+ }
+ }
+ }
+ }
+ else /* if (png_ptr->bit_depth == 16) */
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
+ gamma_16_to_1 != NULL)
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 4, dp += 2)
+ {
+ png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
+
+ if (a == (png_uint_16)0xffff)
+ {
+ png_uint_16 v;
+
+ v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
+ *dp = (png_byte)((v >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(v & 0xff);
+ }
+ else if (a == 0)
+ {
+ /* background is already in screen gamma */
+ *dp = (png_byte)((background->gray >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(background->gray & 0xff);
+ }
+ else
+ {
+ png_uint_16 g, v, w;
+
+ g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
+ png_composite_16(v, g, a, background_1->gray);
+ w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
+ *dp = (png_byte)((w >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(w & 0xff);
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 4, dp += 2)
+ {
+ png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
+ if (a == (png_uint_16)0xffff)
+ {
+ png_memcpy(dp, sp, 2);
+ }
+ else if (a == 0)
+ {
+ *dp = (png_byte)((background->gray >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(background->gray & 0xff);
+ }
+ else
+ {
+ png_uint_16 g, v;
+
+ g = (png_uint_16)(((*sp) << 8) + *(sp + 1));
+ png_composite_16(v, g, a, background_1->gray);
+ *dp = (png_byte)((v >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(v & 0xff);
+ }
+ }
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ {
+ if (row_info->bit_depth == 8)
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
+ gamma_table != NULL)
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 4, dp += 3)
+ {
+ png_byte a = *(sp + 3);
+
+ if (a == 0xff)
+ {
+ *dp = gamma_table[*sp];
+ *(dp + 1) = gamma_table[*(sp + 1)];
+ *(dp + 2) = gamma_table[*(sp + 2)];
+ }
+ else if (a == 0)
+ {
+ /* background is already in screen gamma */
+ *dp = (png_byte)background->red;
+ *(dp + 1) = (png_byte)background->green;
+ *(dp + 2) = (png_byte)background->blue;
+ }
+ else
+ {
+ png_byte v, w;
+
+ v = gamma_to_1[*sp];
+ png_composite(w, v, a, background_1->red);
+ *dp = gamma_from_1[w];
+ v = gamma_to_1[*(sp + 1)];
+ png_composite(w, v, a, background_1->green);
+ *(dp + 1) = gamma_from_1[w];
+ v = gamma_to_1[*(sp + 2)];
+ png_composite(w, v, a, background_1->blue);
+ *(dp + 2) = gamma_from_1[w];
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 4, dp += 3)
+ {
+ png_byte a = *(sp + 3);
+
+ if (a == 0xff)
+ {
+ *dp = *sp;
+ *(dp + 1) = *(sp + 1);
+ *(dp + 2) = *(sp + 2);
+ }
+ else if (a == 0)
+ {
+ *dp = (png_byte)background->red;
+ *(dp + 1) = (png_byte)background->green;
+ *(dp + 2) = (png_byte)background->blue;
+ }
+ else
+ {
+ png_composite(*dp, *sp, a, background->red);
+ png_composite(*(dp + 1), *(sp + 1), a,
+ background->green);
+ png_composite(*(dp + 2), *(sp + 2), a,
+ background->blue);
+ }
+ }
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
+ gamma_16_to_1 != NULL)
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 8, dp += 6)
+ {
+ png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
+ << 8) + (png_uint_16)(*(sp + 7)));
+ if (a == (png_uint_16)0xffff)
+ {
+ png_uint_16 v;
+
+ v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
+ *dp = (png_byte)((v >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(v & 0xff);
+ v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
+ *(dp + 2) = (png_byte)((v >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(v & 0xff);
+ v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
+ *(dp + 4) = (png_byte)((v >> 8) & 0xff);
+ *(dp + 5) = (png_byte)(v & 0xff);
+ }
+ else if (a == 0)
+ {
+ /* background is already in screen gamma */
+ *dp = (png_byte)((background->red >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(background->red & 0xff);
+ *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(background->green & 0xff);
+ *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
+ *(dp + 5) = (png_byte)(background->blue & 0xff);
+ }
+ else
+ {
+ png_uint_16 v, w, x;
+
+ v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
+ png_composite_16(w, v, a, background->red);
+ x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
+ *dp = (png_byte)((x >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(x & 0xff);
+ v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
+ png_composite_16(w, v, a, background->green);
+ x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
+ *(dp + 2) = (png_byte)((x >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(x & 0xff);
+ v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
+ png_composite_16(w, v, a, background->blue);
+ x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8];
+ *(dp + 4) = (png_byte)((x >> 8) & 0xff);
+ *(dp + 5) = (png_byte)(x & 0xff);
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 8, dp += 6)
+ {
+ png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
+ << 8) + (png_uint_16)(*(sp + 7)));
+ if (a == (png_uint_16)0xffff)
+ {
+ png_memcpy(dp, sp, 6);
+ }
+ else if (a == 0)
+ {
+ *dp = (png_byte)((background->red >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(background->red & 0xff);
+ *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(background->green & 0xff);
+ *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
+ *(dp + 5) = (png_byte)(background->blue & 0xff);
+ }
+ else
+ {
+ png_uint_16 v;
+
+ png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
+ png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
+ + *(sp + 3));
+ png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
+ + *(sp + 5));
+
+ png_composite_16(v, r, a, background->red);
+ *dp = (png_byte)((v >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(v & 0xff);
+ png_composite_16(v, g, a, background->green);
+ *(dp + 2) = (png_byte)((v >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(v & 0xff);
+ png_composite_16(v, b, a, background->blue);
+ *(dp + 4) = (png_byte)((v >> 8) & 0xff);
+ *(dp + 5) = (png_byte)(v & 0xff);
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
+ row_info->channels--;
+ row_info->pixel_depth = (png_byte)(row_info->channels *
+ row_info->bit_depth);
+ row_info->rowbytes = ((row_width *
+ row_info->pixel_depth + 7) >> 3);
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+/* Gamma correct the image, avoiding the alpha channel. Make sure
+ * you do this after you deal with the transparency issue on grayscale
+ * or RGB images. If your bit depth is 8, use gamma_table, if it
+ * is 16, use gamma_16_table and gamma_shift. Build these with
+ * build_gamma_table().
+ */
+void /* PRIVATE */
+png_do_gamma(png_row_infop row_info, png_bytep row,
+ png_bytep gamma_table, png_uint_16pp gamma_16_table,
+ int gamma_shift)
+{
+ png_bytep sp;
+ png_uint_32 i;
+ png_uint_32 row_width=row_info->width;
+
+ png_debug(1, "in png_do_gamma\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ ((row_info->bit_depth <= 8 && gamma_table != NULL) ||
+ (row_info->bit_depth == 16 && gamma_16_table != NULL)))
+ {
+ switch (row_info->color_type)
+ {
+ case PNG_COLOR_TYPE_RGB:
+ {
+ if (row_info->bit_depth == 8)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ *sp = gamma_table[*sp];
+ sp++;
+ *sp = gamma_table[*sp];
+ sp++;
+ *sp = gamma_table[*sp];
+ sp++;
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 v;
+
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ {
+ if (row_info->bit_depth == 8)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ *sp = gamma_table[*sp];
+ sp++;
+ *sp = gamma_table[*sp];
+ sp++;
+ *sp = gamma_table[*sp];
+ sp++;
+ sp++;
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 4;
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ {
+ if (row_info->bit_depth == 8)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ *sp = gamma_table[*sp];
+ sp += 2;
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 4;
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_GRAY:
+ {
+ if (row_info->bit_depth == 2)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i += 4)
+ {
+ int a = *sp & 0xc0;
+ int b = *sp & 0x30;
+ int c = *sp & 0x0c;
+ int d = *sp & 0x03;
+
+ *sp = (png_byte)(
+ ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)|
+ ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|
+ ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|
+ ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) ));
+ sp++;
+ }
+ }
+ if (row_info->bit_depth == 4)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i += 2)
+ {
+ int msb = *sp & 0xf0;
+ int lsb = *sp & 0x0f;
+
+ *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0)
+ | (((int)gamma_table[(lsb << 4) | lsb]) >> 4));
+ sp++;
+ }
+ }
+ else if (row_info->bit_depth == 8)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ *sp = gamma_table[*sp];
+ sp++;
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+/* Expands a palette row to an RGB or RGBA row depending
+ * upon whether you supply trans and num_trans.
+ */
+void /* PRIVATE */
+png_do_expand_palette(png_row_infop row_info, png_bytep row,
+ png_colorp palette, png_bytep trans, int num_trans)
+{
+ int shift, value;
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width=row_info->width;
+
+ png_debug(1, "in png_do_expand_palette\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ row_info->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (row_info->bit_depth < 8)
+ {
+ switch (row_info->bit_depth)
+ {
+ case 1:
+ {
+ sp = row + (png_size_t)((row_width - 1) >> 3);
+ dp = row + (png_size_t)row_width - 1;
+ shift = 7 - (int)((row_width + 7) & 0x07);
+ for (i = 0; i < row_width; i++)
+ {
+ if ((*sp >> shift) & 0x01)
+ *dp = 1;
+ else
+ *dp = 0;
+ if (shift == 7)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift++;
+
+ dp--;
+ }
+ break;
+ }
+ case 2:
+ {
+ sp = row + (png_size_t)((row_width - 1) >> 2);
+ dp = row + (png_size_t)row_width - 1;
+ shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
+ for (i = 0; i < row_width; i++)
+ {
+ value = (*sp >> shift) & 0x03;
+ *dp = (png_byte)value;
+ if (shift == 6)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift += 2;
+
+ dp--;
+ }
+ break;
+ }
+ case 4:
+ {
+ sp = row + (png_size_t)((row_width - 1) >> 1);
+ dp = row + (png_size_t)row_width - 1;
+ shift = (int)((row_width & 0x01) << 2);
+ for (i = 0; i < row_width; i++)
+ {
+ value = (*sp >> shift) & 0x0f;
+ *dp = (png_byte)value;
+ if (shift == 4)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift += 4;
+
+ dp--;
+ }
+ break;
+ }
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = 8;
+ row_info->rowbytes = row_width;
+ }
+ switch (row_info->bit_depth)
+ {
+ case 8:
+ {
+ if (trans != NULL)
+ {
+ sp = row + (png_size_t)row_width - 1;
+ dp = row + (png_size_t)(row_width << 2) - 1;
+
+ for (i = 0; i < row_width; i++)
+ {
+ if ((int)(*sp) >= num_trans)
+ *dp-- = 0xff;
+ else
+ *dp-- = trans[*sp];
+ *dp-- = palette[*sp].blue;
+ *dp-- = palette[*sp].green;
+ *dp-- = palette[*sp].red;
+ sp--;
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = 32;
+ row_info->rowbytes = row_width * 4;
+ row_info->color_type = 6;
+ row_info->channels = 4;
+ }
+ else
+ {
+ sp = row + (png_size_t)row_width - 1;
+ dp = row + (png_size_t)(row_width * 3) - 1;
+
+ for (i = 0; i < row_width; i++)
+ {
+ *dp-- = palette[*sp].blue;
+ *dp-- = palette[*sp].green;
+ *dp-- = palette[*sp].red;
+ sp--;
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = 24;
+ row_info->rowbytes = row_width * 3;
+ row_info->color_type = 2;
+ row_info->channels = 3;
+ }
+ break;
+ }
+ }
+ }
+}
+
+/* If the bit depth < 8, it is expanded to 8. Also, if the
+ * transparency value is supplied, an alpha channel is built.
+ */
+void /* PRIVATE */
+png_do_expand(png_row_infop row_info, png_bytep row,
+ png_color_16p trans_value)
+{
+ int shift, value;
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width=row_info->width;
+
+ png_debug(1, "in png_do_expand\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0);
+
+ if (row_info->bit_depth < 8)
+ {
+ switch (row_info->bit_depth)
+ {
+ case 1:
+ {
+ gray = (png_uint_16)(gray*0xff);
+ sp = row + (png_size_t)((row_width - 1) >> 3);
+ dp = row + (png_size_t)row_width - 1;
+ shift = 7 - (int)((row_width + 7) & 0x07);
+ for (i = 0; i < row_width; i++)
+ {
+ if ((*sp >> shift) & 0x01)
+ *dp = 0xff;
+ else
+ *dp = 0;
+ if (shift == 7)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift++;
+
+ dp--;
+ }
+ break;
+ }
+ case 2:
+ {
+ gray = (png_uint_16)(gray*0x55);
+ sp = row + (png_size_t)((row_width - 1) >> 2);
+ dp = row + (png_size_t)row_width - 1;
+ shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
+ for (i = 0; i < row_width; i++)
+ {
+ value = (*sp >> shift) & 0x03;
+ *dp = (png_byte)(value | (value << 2) | (value << 4) |
+ (value << 6));
+ if (shift == 6)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift += 2;
+
+ dp--;
+ }
+ break;
+ }
+ case 4:
+ {
+ gray = (png_uint_16)(gray*0x11);
+ sp = row + (png_size_t)((row_width - 1) >> 1);
+ dp = row + (png_size_t)row_width - 1;
+ shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
+ for (i = 0; i < row_width; i++)
+ {
+ value = (*sp >> shift) & 0x0f;
+ *dp = (png_byte)(value | (value << 4));
+ if (shift == 4)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift = 4;
+
+ dp--;
+ }
+ break;
+ }
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = 8;
+ row_info->rowbytes = row_width;
+ }
+
+ if (trans_value != NULL)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ sp = row + (png_size_t)row_width - 1;
+ dp = row + (png_size_t)(row_width << 1) - 1;
+ for (i = 0; i < row_width; i++)
+ {
+ if (*sp == gray)
+ *dp-- = 0;
+ else
+ *dp-- = 0xff;
+ *dp-- = *sp--;
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ sp = row + row_info->rowbytes - 1;
+ dp = row + (row_info->rowbytes << 1) - 1;
+ for (i = 0; i < row_width; i++)
+ {
+ if (((png_uint_16)*(sp) |
+ ((png_uint_16)*(sp - 1) << 8)) == gray)
+ {
+ *dp-- = 0;
+ *dp-- = 0;
+ }
+ else
+ {
+ *dp-- = 0xff;
+ *dp-- = 0xff;
+ }
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ }
+ }
+ row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
+ row_info->channels = 2;
+ row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
+ row_info->rowbytes =
+ ((row_width * row_info->pixel_depth) >> 3);
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ sp = row + (png_size_t)row_info->rowbytes - 1;
+ dp = row + (png_size_t)(row_width << 2) - 1;
+ for (i = 0; i < row_width; i++)
+ {
+ if (*(sp - 2) == trans_value->red &&
+ *(sp - 1) == trans_value->green &&
+ *(sp - 0) == trans_value->blue)
+ *dp-- = 0;
+ else
+ *dp-- = 0xff;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ sp = row + row_info->rowbytes - 1;
+ dp = row + (png_size_t)(row_width << 3) - 1;
+ for (i = 0; i < row_width; i++)
+ {
+ if ((((png_uint_16)*(sp - 4) |
+ ((png_uint_16)*(sp - 5) << 8)) == trans_value->red) &&
+ (((png_uint_16)*(sp - 2) |
+ ((png_uint_16)*(sp - 3) << 8)) == trans_value->green) &&
+ (((png_uint_16)*(sp - 0) |
+ ((png_uint_16)*(sp - 1) << 8)) == trans_value->blue))
+ {
+ *dp-- = 0;
+ *dp-- = 0;
+ }
+ else
+ {
+ *dp-- = 0xff;
+ *dp-- = 0xff;
+ }
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ }
+ }
+ row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ row_info->channels = 4;
+ row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
+ row_info->rowbytes =
+ ((row_width * row_info->pixel_depth) >> 3);
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+void /* PRIVATE */
+png_do_dither(png_row_infop row_info, png_bytep row,
+ png_bytep palette_lookup, png_bytep dither_lookup)
+{
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width=row_info->width;
+
+ png_debug(1, "in png_do_dither\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
+ palette_lookup && row_info->bit_depth == 8)
+ {
+ int r, g, b, p;
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ r = *sp++;
+ g = *sp++;
+ b = *sp++;
+
+ /* this looks real messy, but the compiler will reduce
+ it down to a reasonable formula. For example, with
+ 5 bits per color, we get:
+ p = (((r >> 3) & 0x1f) << 10) |
+ (((g >> 3) & 0x1f) << 5) |
+ ((b >> 3) & 0x1f);
+ */
+ p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
+ ((1 << PNG_DITHER_RED_BITS) - 1)) <<
+ (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
+ (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
+ ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
+ (PNG_DITHER_BLUE_BITS)) |
+ ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
+ ((1 << PNG_DITHER_BLUE_BITS) - 1));
+
+ *dp++ = palette_lookup[p];
+ }
+ row_info->color_type = PNG_COLOR_TYPE_PALETTE;
+ row_info->channels = 1;
+ row_info->pixel_depth = row_info->bit_depth;
+ row_info->rowbytes =
+ ((row_width * row_info->pixel_depth + 7) >> 3);
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
+ palette_lookup != NULL && row_info->bit_depth == 8)
+ {
+ int r, g, b, p;
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ r = *sp++;
+ g = *sp++;
+ b = *sp++;
+ sp++;
+
+ p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
+ ((1 << PNG_DITHER_RED_BITS) - 1)) <<
+ (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
+ (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
+ ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
+ (PNG_DITHER_BLUE_BITS)) |
+ ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
+ ((1 << PNG_DITHER_BLUE_BITS) - 1));
+
+ *dp++ = palette_lookup[p];
+ }
+ row_info->color_type = PNG_COLOR_TYPE_PALETTE;
+ row_info->channels = 1;
+ row_info->pixel_depth = row_info->bit_depth;
+ row_info->rowbytes =
+ ((row_width * row_info->pixel_depth + 7) >> 3);
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
+ dither_lookup && row_info->bit_depth == 8)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp++)
+ {
+ *sp = dither_lookup[*sp];
+ }
+ }
+ }
+}
+#endif
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+static int png_gamma_shift[] =
+ {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0};
+
+/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
+ * tables, we don't make a full table if we are reducing to 8-bit in
+ * the future. Note also how the gamma_16 tables are segmented so that
+ * we don't need to allocate > 64K chunks for a full 16-bit table.
+ */
+void /* PRIVATE */
+png_build_gamma_table(png_structp png_ptr)
+{
+ png_debug(1, "in png_build_gamma_table\n");
+ if(png_ptr->gamma != 0.0)
+ {
+ if (png_ptr->bit_depth <= 8)
+ {
+ int i;
+ double g;
+
+ if (png_ptr->screen_gamma > .000001)
+ g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
+ else
+ g = 1.0;
+
+ png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)256);
+
+ for (i = 0; i < 256; i++)
+ {
+ png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0,
+ g) * 255.0 + .5);
+ }
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
+ defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+ if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY))
+ {
+
+ g = 1.0 / (png_ptr->gamma);
+
+ png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)256);
+
+ for (i = 0; i < 256; i++)
+ {
+ png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0,
+ g) * 255.0 + .5);
+ }
+
+
+ png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)256);
+
+ if(png_ptr->screen_gamma > 0.000001)
+ g = 1.0 / png_ptr->screen_gamma;
+ else
+ g = png_ptr->gamma; /* probably doing rgb_to_gray */
+
+ for (i = 0; i < 256; i++)
+ {
+ png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0,
+ g) * 255.0 + .5);
+
+ }
+ }
+#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
+ }
+ else
+ {
+ double g;
+ int i, j, shift, num;
+ int sig_bit;
+ png_uint_32 ig;
+
+ if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ {
+ sig_bit = (int)png_ptr->sig_bit.red;
+ if ((int)png_ptr->sig_bit.green > sig_bit)
+ sig_bit = png_ptr->sig_bit.green;
+ if ((int)png_ptr->sig_bit.blue > sig_bit)
+ sig_bit = png_ptr->sig_bit.blue;
+ }
+ else
+ {
+ sig_bit = (int)png_ptr->sig_bit.gray;
+ }
+
+ if (sig_bit > 0)
+ shift = 16 - sig_bit;
+ else
+ shift = 0;
+
+ if (png_ptr->transformations & PNG_16_TO_8)
+ {
+ if (shift < (16 - PNG_MAX_GAMMA_8))
+ shift = (16 - PNG_MAX_GAMMA_8);
+ }
+
+ if (shift > 8)
+ shift = 8;
+ if (shift < 0)
+ shift = 0;
+
+ png_ptr->gamma_shift = (png_byte)shift;
+
+ num = (1 << (8 - shift));
+
+ if (png_ptr->screen_gamma > .000001)
+ g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
+ else
+ g = 1.0;
+
+ png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr,
+ (png_uint_32)(num * sizeof (png_uint_16p)));
+
+ if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND))
+ {
+ double fin, fout;
+ png_uint_32 last, max;
+
+ for (i = 0; i < num; i++)
+ {
+ png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(256 * sizeof (png_uint_16)));
+ }
+
+ g = 1.0 / g;
+ last = 0;
+ for (i = 0; i < 256; i++)
+ {
+ fout = ((double)i + 0.5) / 256.0;
+ fin = pow(fout, g);
+ max = (png_uint_32)(fin * (double)((png_uint_32)num << 8));
+ while (last <= max)
+ {
+ png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
+ [(int)(last >> (8 - shift))] = (png_uint_16)(
+ (png_uint_16)i | ((png_uint_16)i << 8));
+ last++;
+ }
+ }
+ while (last < ((png_uint_32)num << 8))
+ {
+ png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
+ [(int)(last >> (8 - shift))] = (png_uint_16)65535L;
+ last++;
+ }
+ }
+ else
+ {
+ for (i = 0; i < num; i++)
+ {
+ png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(256 * sizeof (png_uint_16)));
+
+ ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4);
+ for (j = 0; j < 256; j++)
+ {
+ png_ptr->gamma_16_table[i][j] =
+ (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
+ 65535.0, g) * 65535.0 + .5);
+ }
+ }
+ }
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
+ defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+ if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY))
+ {
+
+ g = 1.0 / (png_ptr->gamma);
+
+ png_ptr->gamma_16_to_1 = (png_uint_16pp)png_malloc(png_ptr,
+ (png_uint_32)(num * sizeof (png_uint_16p )));
+
+ for (i = 0; i < num; i++)
+ {
+ png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(256 * sizeof (png_uint_16)));
+
+ ig = (((png_uint_32)i *
+ (png_uint_32)png_gamma_shift[shift]) >> 4);
+ for (j = 0; j < 256; j++)
+ {
+ png_ptr->gamma_16_to_1[i][j] =
+ (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
+ 65535.0, g) * 65535.0 + .5);
+ }
+ }
+
+ if(png_ptr->screen_gamma > 0.000001)
+ g = 1.0 / png_ptr->screen_gamma;
+ else
+ g = png_ptr->gamma; /* probably doing rgb_to_gray */
+
+ png_ptr->gamma_16_from_1 = (png_uint_16pp)png_malloc(png_ptr,
+ (png_uint_32)(num * sizeof (png_uint_16p)));
+
+ for (i = 0; i < num; i++)
+ {
+ png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(256 * sizeof (png_uint_16)));
+
+ ig = (((png_uint_32)i *
+ (png_uint_32)png_gamma_shift[shift]) >> 4);
+ for (j = 0; j < 256; j++)
+ {
+ png_ptr->gamma_16_from_1[i][j] =
+ (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
+ 65535.0, g) * 65535.0 + .5);
+ }
+ }
+ }
+#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
+ }
+ }
+}
+#endif
+/* To do: install integer version of png_build_gamma_table here */
+#endif
+
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+/* undoes intrapixel differencing */
+void /* PRIVATE */
+png_do_read_intrapixel(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_read_intrapixel\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ (row_info->color_type & PNG_COLOR_MASK_COLOR))
+ {
+ int bytes_per_pixel;
+ png_uint_32 row_width = row_info->width;
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ bytes_per_pixel = 3;
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ bytes_per_pixel = 4;
+ else
+ return;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
+ {
+ *(rp) = (png_byte)((256 + *rp + *(rp+1))&0xff);
+ *(rp+2) = (png_byte)((256 + *(rp+2) + *(rp+1))&0xff);
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ bytes_per_pixel = 6;
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ bytes_per_pixel = 8;
+ else
+ return;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
+ {
+ png_uint_32 s0=*(rp )<<8 | *(rp+1);
+ png_uint_32 s1=*(rp+2)<<8 | *(rp+3);
+ png_uint_32 s2=*(rp+4)<<8 | *(rp+5);
+ png_uint_32 red=(65536+s0+s1)&0xffff;
+ png_uint_32 blue=(65536+s2+s1)&0xffff;
+ *(rp ) = (png_byte)((red>>8)&0xff);
+ *(rp+1) = (png_byte)(red&0xff);
+ *(rp+4) = (png_byte)((blue>>8)&0xff);
+ *(rp+5) = (png_byte)(blue&0xff);
+ }
+ }
+ }
+}
+#endif /* PNG_MNG_FEATURES_SUPPORTED */
--- /dev/null
+
+/* pngrutil.c - utilities to read a PNG file
+ *
+ * libpng 1.2.0 - September 1, 2001
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ *
+ * This file contains routines that are only called from within
+ * libpng itself during the course of reading an image.
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#if defined(_WIN32_WCE)
+/* strtod() function is not supported on WindowsCE */
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+__inline double strtod(const char *nptr, char **endptr)
+{
+ double result = 0;
+ int len;
+ wchar_t *str, *end;
+
+ len = MultiByteToWideChar(CP_ACP, 0, nptr, -1, NULL, 0);
+ str = (wchar_t *)malloc(len * sizeof(wchar_t));
+ if ( NULL != str )
+ {
+ MultiByteToWideChar(CP_ACP, 0, nptr, -1, str, len);
+ result = wcstod(str, &end);
+ len = WideCharToMultiByte(CP_ACP, 0, end, -1, NULL, 0, NULL, NULL);
+ *endptr = (char *)nptr + (png_strlen(nptr) - len + 1);
+ free(str);
+ }
+ return result;
+}
+# endif
+#endif
+
+#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED
+/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */
+png_uint_32 /* PRIVATE */
+png_get_uint_32(png_bytep buf)
+{
+ png_uint_32 i = ((png_uint_32)(*buf) << 24) +
+ ((png_uint_32)(*(buf + 1)) << 16) +
+ ((png_uint_32)(*(buf + 2)) << 8) +
+ (png_uint_32)(*(buf + 3));
+
+ return (i);
+}
+
+#if defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_READ_oFFs_SUPPORTED)
+/* Grab a signed 32-bit integer from a buffer in big-endian format. The
+ * data is stored in the PNG file in two's complement format, and it is
+ * assumed that the machine format for signed integers is the same. */
+png_int_32 /* PRIVATE */
+png_get_int_32(png_bytep buf)
+{
+ png_int_32 i = ((png_int_32)(*buf) << 24) +
+ ((png_int_32)(*(buf + 1)) << 16) +
+ ((png_int_32)(*(buf + 2)) << 8) +
+ (png_int_32)(*(buf + 3));
+
+ return (i);
+}
+#endif /* PNG_READ_pCAL_SUPPORTED */
+
+/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */
+png_uint_16 /* PRIVATE */
+png_get_uint_16(png_bytep buf)
+{
+ png_uint_16 i = (png_uint_16)(((png_uint_16)(*buf) << 8) +
+ (png_uint_16)(*(buf + 1)));
+
+ return (i);
+}
+#endif /* PNG_READ_BIG_ENDIAN_SUPPORTED */
+
+/* Read data, and (optionally) run it through the CRC. */
+void /* PRIVATE */
+png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length)
+{
+ png_read_data(png_ptr, buf, length);
+ png_calculate_crc(png_ptr, buf, length);
+}
+
+/* Optionally skip data and then check the CRC. Depending on whether we
+ are reading a ancillary or critical chunk, and how the program has set
+ things up, we may calculate the CRC on the data and print a message.
+ Returns '1' if there was a CRC error, '0' otherwise. */
+int /* PRIVATE */
+png_crc_finish(png_structp png_ptr, png_uint_32 skip)
+{
+ png_size_t i;
+ png_size_t istop = png_ptr->zbuf_size;
+
+ for (i = (png_size_t)skip; i > istop; i -= istop)
+ {
+ png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
+ }
+ if (i)
+ {
+ png_crc_read(png_ptr, png_ptr->zbuf, i);
+ }
+
+ if (png_crc_error(png_ptr))
+ {
+ if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */
+ !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) ||
+ (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */
+ (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE)))
+ {
+ png_chunk_warning(png_ptr, "CRC error");
+ }
+ else
+ {
+ png_chunk_error(png_ptr, "CRC error");
+ }
+ return (1);
+ }
+
+ return (0);
+}
+
+/* Compare the CRC stored in the PNG file with that calculated by libpng from
+ the data it has read thus far. */
+int /* PRIVATE */
+png_crc_error(png_structp png_ptr)
+{
+ png_byte crc_bytes[4];
+ png_uint_32 crc;
+ int need_crc = 1;
+
+ if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
+ {
+ if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
+ (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
+ need_crc = 0;
+ }
+ else /* critical */
+ {
+ if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
+ need_crc = 0;
+ }
+
+ png_read_data(png_ptr, crc_bytes, 4);
+
+ if (need_crc)
+ {
+ crc = png_get_uint_32(crc_bytes);
+ return ((int)(crc != png_ptr->crc));
+ }
+ else
+ return (0);
+}
+
+#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \
+ defined(PNG_READ_iCCP_SUPPORTED)
+/*
+ * Decompress trailing data in a chunk. The assumption is that chunkdata
+ * points at an allocated area holding the contents of a chunk with a
+ * trailing compressed part. What we get back is an allocated area
+ * holding the original prefix part and an uncompressed version of the
+ * trailing part (the malloc area passed in is freed).
+ */
+png_charp /* PRIVATE */
+png_decompress_chunk(png_structp png_ptr, int comp_type,
+ png_charp chunkdata, png_size_t chunklength,
+ png_size_t prefix_size, png_size_t *newlength)
+{
+ static char msg[] = "Error decoding compressed text";
+ png_charp text = NULL;
+ png_size_t text_size;
+
+ if (comp_type == PNG_COMPRESSION_TYPE_BASE)
+ {
+ int ret = Z_OK;
+ png_ptr->zstream.next_in = (png_bytep)(chunkdata + prefix_size);
+ png_ptr->zstream.avail_in = (uInt)(chunklength - prefix_size);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+
+ text_size = 0;
+ text = NULL;
+
+ while (png_ptr->zstream.avail_in)
+ {
+ ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
+ if (ret != Z_OK && ret != Z_STREAM_END)
+ {
+ if (png_ptr->zstream.msg != NULL)
+ png_warning(png_ptr, png_ptr->zstream.msg);
+ else
+ png_warning(png_ptr, msg);
+ inflateReset(&png_ptr->zstream);
+ png_ptr->zstream.avail_in = 0;
+
+ if (text == NULL)
+ {
+ text_size = prefix_size + sizeof(msg) + 1;
+ text = (png_charp)png_malloc(png_ptr, text_size);
+ png_memcpy(text, chunkdata, prefix_size);
+ }
+
+ text[text_size - 1] = 0x00;
+
+ /* Copy what we can of the error message into the text chunk */
+ text_size = (png_size_t)(chunklength - (text - chunkdata) - 1);
+ text_size = sizeof(msg) > text_size ? text_size : sizeof(msg);
+ png_memcpy(text + prefix_size, msg, text_size + 1);
+ break;
+ }
+ if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END)
+ {
+ if (text == NULL)
+ {
+ text_size = prefix_size +
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out;
+ text = (png_charp)png_malloc(png_ptr, text_size + 1);
+ png_memcpy(text + prefix_size, png_ptr->zbuf,
+ text_size - prefix_size);
+ png_memcpy(text, chunkdata, prefix_size);
+ *(text + text_size) = 0x00;
+ }
+ else
+ {
+ png_charp tmp;
+
+ tmp = text;
+ text = (png_charp)png_malloc(png_ptr, (png_uint_32)(text_size +
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out + 1));
+ png_memcpy(text, tmp, text_size);
+ png_free(png_ptr, tmp);
+ png_memcpy(text + text_size, png_ptr->zbuf,
+ (png_ptr->zbuf_size - png_ptr->zstream.avail_out));
+ text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
+ *(text + text_size) = 0x00;
+ }
+ if (ret == Z_STREAM_END)
+ break;
+ else
+ {
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ }
+ }
+ }
+ if (ret != Z_STREAM_END)
+ {
+#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
+ char umsg[50];
+
+ if (ret == Z_BUF_ERROR)
+ sprintf(umsg,"Buffer error in compressed datastream in %s chunk",
+ png_ptr->chunk_name);
+ else if (ret == Z_DATA_ERROR)
+ sprintf(umsg,"Data error in compressed datastream in %s chunk",
+ png_ptr->chunk_name);
+ else
+ sprintf(umsg,"Incomplete compressed datastream in %s chunk",
+ png_ptr->chunk_name);
+ png_warning(png_ptr, umsg);
+#else
+ png_warning(png_ptr,
+ "Incomplete compressed datastream in chunk other than IDAT");
+#endif
+ text_size=prefix_size;
+ if (text == NULL)
+ {
+ text = (png_charp)png_malloc(png_ptr, text_size+1);
+ png_memcpy(text, chunkdata, prefix_size);
+ }
+ *(text + text_size) = 0x00;
+ }
+
+ inflateReset(&png_ptr->zstream);
+ png_ptr->zstream.avail_in = 0;
+
+ png_free(png_ptr, chunkdata);
+ chunkdata = text;
+ *newlength=text_size;
+ }
+ else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */
+ {
+#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
+ char umsg[50];
+
+ sprintf(umsg, "Unknown zTXt compression type %d", comp_type);
+ png_warning(png_ptr, umsg);
+#else
+ png_warning(png_ptr, "Unknown zTXt compression type");
+#endif
+
+ *(chunkdata + prefix_size) = 0x00;
+ *newlength=prefix_size;
+ }
+
+ return chunkdata;
+}
+#endif
+
+/* read and check the IDHR chunk */
+void /* PRIVATE */
+png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte buf[13];
+ png_uint_32 width, height;
+ int bit_depth, color_type, compression_type, filter_type;
+ int interlace_type;
+
+ png_debug(1, "in png_handle_IHDR\n");
+
+ if (png_ptr->mode & PNG_HAVE_IHDR)
+ png_error(png_ptr, "Out of place IHDR");
+
+ /* check the length */
+ if (length != 13)
+ png_error(png_ptr, "Invalid IHDR chunk");
+
+ png_ptr->mode |= PNG_HAVE_IHDR;
+
+ png_crc_read(png_ptr, buf, 13);
+ png_crc_finish(png_ptr, 0);
+
+ width = png_get_uint_32(buf);
+ height = png_get_uint_32(buf + 4);
+ bit_depth = buf[8];
+ color_type = buf[9];
+ compression_type = buf[10];
+ filter_type = buf[11];
+ interlace_type = buf[12];
+
+
+ /* set internal variables */
+ png_ptr->width = width;
+ png_ptr->height = height;
+ png_ptr->bit_depth = (png_byte)bit_depth;
+ png_ptr->interlaced = (png_byte)interlace_type;
+ png_ptr->color_type = (png_byte)color_type;
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ png_ptr->filter_type = (png_byte)filter_type;
+#endif
+
+ /* find number of channels */
+ switch (png_ptr->color_type)
+ {
+ case PNG_COLOR_TYPE_GRAY:
+ case PNG_COLOR_TYPE_PALETTE:
+ png_ptr->channels = 1;
+ break;
+ case PNG_COLOR_TYPE_RGB:
+ png_ptr->channels = 3;
+ break;
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ png_ptr->channels = 2;
+ break;
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ png_ptr->channels = 4;
+ break;
+ }
+
+ /* set up other useful info */
+ png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth *
+ png_ptr->channels);
+ png_ptr->rowbytes = ((png_ptr->width *
+ (png_uint_32)png_ptr->pixel_depth + 7) >> 3);
+ png_debug1(3,"bit_depth = %d\n", png_ptr->bit_depth);
+ png_debug1(3,"channels = %d\n", png_ptr->channels);
+ png_debug1(3,"rowbytes = %lu\n", png_ptr->rowbytes);
+ png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
+ color_type, interlace_type, compression_type, filter_type);
+}
+
+/* read and check the palette */
+void /* PRIVATE */
+png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_color palette[PNG_MAX_PALETTE_LENGTH];
+ int num, i;
+#ifndef PNG_NO_POINTER_INDEXING
+ png_colorp pal_ptr;
+#endif
+
+ png_debug(1, "in png_handle_PLTE\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before PLTE");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid PLTE after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ png_error(png_ptr, "Duplicate PLTE chunk");
+
+ png_ptr->mode |= PNG_HAVE_PLTE;
+
+ if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
+ {
+ png_warning(png_ptr,
+ "Ignoring PLTE chunk in grayscale PNG");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
+ if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
+ {
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+#endif
+
+ if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3)
+ {
+ if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
+ {
+ png_warning(png_ptr, "Invalid palette chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else
+ {
+ png_error(png_ptr, "Invalid palette chunk");
+ }
+ }
+
+ num = (int)length / 3;
+
+#ifndef PNG_NO_POINTER_INDEXING
+ for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)
+ {
+ png_byte buf[3];
+
+ png_crc_read(png_ptr, buf, 3);
+ pal_ptr->red = buf[0];
+ pal_ptr->green = buf[1];
+ pal_ptr->blue = buf[2];
+ }
+#else
+ for (i = 0; i < num; i++)
+ {
+ png_byte buf[3];
+
+ png_crc_read(png_ptr, buf, 3);
+ /* don't depend upon png_color being any order */
+ palette[i].red = buf[0];
+ palette[i].green = buf[1];
+ palette[i].blue = buf[2];
+ }
+#endif
+
+ /* If we actually NEED the PLTE chunk (ie for a paletted image), we do
+ whatever the normal CRC configuration tells us. However, if we
+ have an RGB image, the PLTE can be considered ancillary, so
+ we will act as though it is. */
+#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+#endif
+ {
+ png_crc_finish(png_ptr, 0);
+ }
+#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
+ else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
+ {
+ /* If we don't want to use the data from an ancillary chunk,
+ we have two options: an error abort, or a warning and we
+ ignore the data in this chunk (which should be OK, since
+ it's considered ancillary for a RGB or RGBA image). */
+ if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE))
+ {
+ if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)
+ {
+ png_chunk_error(png_ptr, "CRC error");
+ }
+ else
+ {
+ png_chunk_warning(png_ptr, "CRC error");
+ return;
+ }
+ }
+ /* Otherwise, we (optionally) emit a warning and use the chunk. */
+ else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))
+ {
+ png_chunk_warning(png_ptr, "CRC error");
+ }
+ }
+#endif
+
+ png_set_PLTE(png_ptr, info_ptr, palette, num);
+
+#if defined(PNG_READ_tRNS_SUPPORTED)
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
+ {
+ if (png_ptr->num_trans > (png_uint_16)num)
+ {
+ png_warning(png_ptr, "Truncating incorrect tRNS chunk length");
+ png_ptr->num_trans = (png_uint_16)num;
+ }
+ if (info_ptr->num_trans > (png_uint_16)num)
+ {
+ png_warning(png_ptr, "Truncating incorrect info tRNS chunk length");
+ info_ptr->num_trans = (png_uint_16)num;
+ }
+ }
+ }
+#endif
+
+}
+
+void /* PRIVATE */
+png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_debug(1, "in png_handle_IEND\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))
+ {
+ png_error(png_ptr, "No image in file");
+
+ info_ptr = info_ptr; /* quiet compiler warnings about unused info_ptr */
+ }
+
+ png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND);
+
+ if (length != 0)
+ {
+ png_warning(png_ptr, "Incorrect IEND chunk length");
+ }
+ png_crc_finish(png_ptr, length);
+}
+
+#if defined(PNG_READ_gAMA_SUPPORTED)
+void /* PRIVATE */
+png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_fixed_point igamma;
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ float file_gamma;
+#endif
+ png_byte buf[4];
+
+ png_debug(1, "in png_handle_gAMA\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before gAMA");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid gAMA after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ /* Should be an error, but we can cope with it */
+ png_warning(png_ptr, "Out of place gAMA chunk");
+
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ && !(info_ptr->valid & PNG_INFO_sRGB)
+#endif
+ )
+ {
+ png_warning(png_ptr, "Duplicate gAMA chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (length != 4)
+ {
+ png_warning(png_ptr, "Incorrect gAMA chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 4);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ igamma = (png_fixed_point)png_get_uint_32(buf);
+ /* check for zero gamma */
+ if (igamma == 0)
+ {
+ png_warning(png_ptr,
+ "Ignoring gAMA chunk with gamma=0");
+ return;
+ }
+
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_sRGB)
+ if(igamma < 45000L || igamma > 46000L)
+ {
+ png_warning(png_ptr,
+ "Ignoring incorrect gAMA value when sRGB is also present");
+#ifndef PNG_NO_CONSOLE_IO
+ fprintf(stderr, "gamma = (%d/100000)\n", (int)igamma);
+#endif
+ return;
+ }
+#endif /* PNG_READ_sRGB_SUPPORTED */
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ file_gamma = (float)igamma / (float)100000.0;
+# ifdef PNG_READ_GAMMA_SUPPORTED
+ png_ptr->gamma = file_gamma;
+# endif
+ png_set_gAMA(png_ptr, info_ptr, file_gamma);
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ png_set_gAMA_fixed(png_ptr, info_ptr, igamma);
+#endif
+}
+#endif
+
+#if defined(PNG_READ_sBIT_SUPPORTED)
+void /* PRIVATE */
+png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_size_t truelen;
+ png_byte buf[4];
+
+ png_debug(1, "in png_handle_sBIT\n");
+
+ buf[0] = buf[1] = buf[2] = buf[3] = 0;
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before sBIT");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid sBIT after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ {
+ /* Should be an error, but we can cope with it */
+ png_warning(png_ptr, "Out of place sBIT chunk");
+ }
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT))
+ {
+ png_warning(png_ptr, "Duplicate sBIT chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ truelen = 3;
+ else
+ truelen = (png_size_t)png_ptr->channels;
+
+ if (length != truelen)
+ {
+ png_warning(png_ptr, "Incorrect sBIT chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, truelen);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ {
+ png_ptr->sig_bit.red = buf[0];
+ png_ptr->sig_bit.green = buf[1];
+ png_ptr->sig_bit.blue = buf[2];
+ png_ptr->sig_bit.alpha = buf[3];
+ }
+ else
+ {
+ png_ptr->sig_bit.gray = buf[0];
+ png_ptr->sig_bit.red = buf[0];
+ png_ptr->sig_bit.green = buf[0];
+ png_ptr->sig_bit.blue = buf[0];
+ png_ptr->sig_bit.alpha = buf[1];
+ }
+ png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
+}
+#endif
+
+#if defined(PNG_READ_cHRM_SUPPORTED)
+void /* PRIVATE */
+png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte buf[4];
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
+#endif
+ png_fixed_point int_x_white, int_y_white, int_x_red, int_y_red, int_x_green,
+ int_y_green, int_x_blue, int_y_blue;
+
+ png_debug(1, "in png_handle_cHRM\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before cHRM");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid cHRM after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ /* Should be an error, but we can cope with it */
+ png_warning(png_ptr, "Missing PLTE before cHRM");
+
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ && !(info_ptr->valid & PNG_INFO_sRGB)
+#endif
+ )
+ {
+ png_warning(png_ptr, "Duplicate cHRM chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (length != 32)
+ {
+ png_warning(png_ptr, "Incorrect cHRM chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 4);
+ int_x_white = (png_fixed_point)png_get_uint_32(buf);
+
+ png_crc_read(png_ptr, buf, 4);
+ int_y_white = (png_fixed_point)png_get_uint_32(buf);
+
+ if (int_x_white > 80000L || int_y_white > 80000L ||
+ int_x_white + int_y_white > 100000L)
+ {
+ png_warning(png_ptr, "Invalid cHRM white point");
+ png_crc_finish(png_ptr, 24);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 4);
+ int_x_red = (png_fixed_point)png_get_uint_32(buf);
+
+ png_crc_read(png_ptr, buf, 4);
+ int_y_red = (png_fixed_point)png_get_uint_32(buf);
+
+ if (int_x_red > 80000L || int_y_red > 80000L ||
+ int_x_red + int_y_red > 100000L)
+ {
+ png_warning(png_ptr, "Invalid cHRM red point");
+ png_crc_finish(png_ptr, 16);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 4);
+ int_x_green = (png_fixed_point)png_get_uint_32(buf);
+
+ png_crc_read(png_ptr, buf, 4);
+ int_y_green = (png_fixed_point)png_get_uint_32(buf);
+
+ if (int_x_green > 80000L || int_y_green > 80000L ||
+ int_x_green + int_y_green > 100000L)
+ {
+ png_warning(png_ptr, "Invalid cHRM green point");
+ png_crc_finish(png_ptr, 8);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 4);
+ int_x_blue = (png_fixed_point)png_get_uint_32(buf);
+
+ png_crc_read(png_ptr, buf, 4);
+ int_y_blue = (png_fixed_point)png_get_uint_32(buf);
+
+ if (int_x_blue > 80000L || int_y_blue > 80000L ||
+ int_x_blue + int_y_blue > 100000L)
+ {
+ png_warning(png_ptr, "Invalid cHRM blue point");
+ png_crc_finish(png_ptr, 0);
+ return;
+ }
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ white_x = (float)int_x_white / (float)100000.0;
+ white_y = (float)int_y_white / (float)100000.0;
+ red_x = (float)int_x_red / (float)100000.0;
+ red_y = (float)int_y_red / (float)100000.0;
+ green_x = (float)int_x_green / (float)100000.0;
+ green_y = (float)int_y_green / (float)100000.0;
+ blue_x = (float)int_x_blue / (float)100000.0;
+ blue_y = (float)int_y_blue / (float)100000.0;
+#endif
+
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_sRGB)
+ {
+ if (abs(int_x_white - 31270L) > 1000 ||
+ abs(int_y_white - 32900L) > 1000 ||
+ abs(int_x_red - 64000L) > 1000 ||
+ abs(int_y_red - 33000L) > 1000 ||
+ abs(int_x_green - 30000L) > 1000 ||
+ abs(int_y_green - 60000L) > 1000 ||
+ abs(int_x_blue - 15000L) > 1000 ||
+ abs(int_y_blue - 6000L) > 1000)
+ {
+
+ png_warning(png_ptr,
+ "Ignoring incorrect cHRM value when sRGB is also present");
+#ifndef PNG_NO_CONSOLE_IO
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ fprintf(stderr,"wx=%f, wy=%f, rx=%f, ry=%f\n",
+ white_x, white_y, red_x, red_y);
+ fprintf(stderr,"gx=%f, gy=%f, bx=%f, by=%f\n",
+ green_x, green_y, blue_x, blue_y);
+#else
+ fprintf(stderr,"wx=%ld, wy=%ld, rx=%ld, ry=%ld\n",
+ int_x_white, int_y_white, int_x_red, int_y_red);
+ fprintf(stderr,"gx=%ld, gy=%ld, bx=%ld, by=%ld\n",
+ int_x_green, int_y_green, int_x_blue, int_y_blue);
+#endif
+#endif /* PNG_NO_CONSOLE_IO */
+ }
+ png_crc_finish(png_ptr, 0);
+ return;
+ }
+#endif /* PNG_READ_sRGB_SUPPORTED */
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ png_set_cHRM(png_ptr, info_ptr,
+ white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ png_set_cHRM_fixed(png_ptr, info_ptr,
+ int_x_white, int_y_white, int_x_red, int_y_red, int_x_green,
+ int_y_green, int_x_blue, int_y_blue);
+#endif
+ if (png_crc_finish(png_ptr, 0))
+ return;
+}
+#endif
+
+#if defined(PNG_READ_sRGB_SUPPORTED)
+void /* PRIVATE */
+png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ int intent;
+ png_byte buf[1];
+
+ png_debug(1, "in png_handle_sRGB\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before sRGB");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid sRGB after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ /* Should be an error, but we can cope with it */
+ png_warning(png_ptr, "Out of place sRGB chunk");
+
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
+ {
+ png_warning(png_ptr, "Duplicate sRGB chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (length != 1)
+ {
+ png_warning(png_ptr, "Incorrect sRGB chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 1);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ intent = buf[0];
+ /* check for bad intent */
+ if (intent >= PNG_sRGB_INTENT_LAST)
+ {
+ png_warning(png_ptr, "Unknown sRGB intent");
+ return;
+ }
+
+#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
+ if ((info_ptr->valid & PNG_INFO_gAMA))
+ {
+ int igamma;
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ igamma=(int)info_ptr->int_gamma;
+#else
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+ igamma=(int)(info_ptr->gamma * 100000.);
+# endif
+#endif
+#if 0 && defined(PNG_cHRM_SUPPORTED) && !defined(PNG_FIXED_POINT_SUPPORTED)
+/* We need to define these here because they aren't in png.h */
+ png_fixed_point int_x_white;
+ png_fixed_point int_y_white;
+ png_fixed_point int_x_red;
+ png_fixed_point int_y_red;
+ png_fixed_point int_x_green;
+ png_fixed_point int_y_green;
+ png_fixed_point int_x_blue;
+ png_fixed_point int_y_blue;
+#endif
+ if(igamma < 45000L || igamma > 46000L)
+ {
+ png_warning(png_ptr,
+ "Ignoring incorrect gAMA value when sRGB is also present");
+#ifndef PNG_NO_CONSOLE_IO
+# ifdef PNG_FIXED_POINT_SUPPORTED
+ fprintf(stderr,"incorrect gamma=(%d/100000)\n",(int)png_ptr->int_gamma);
+# else
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+ fprintf(stderr,"incorrect gamma=%f\n",png_ptr->gamma);
+# endif
+# endif
+#endif
+ }
+ }
+#endif /* PNG_READ_gAMA_SUPPORTED */
+
+#ifdef PNG_READ_cHRM_SUPPORTED
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ if (info_ptr->valid & PNG_INFO_cHRM)
+ if (abs(info_ptr->int_x_white - 31270L) > 1000 ||
+ abs(info_ptr->int_y_white - 32900L) > 1000 ||
+ abs(info_ptr->int_x_red - 64000L) > 1000 ||
+ abs(info_ptr->int_y_red - 33000L) > 1000 ||
+ abs(info_ptr->int_x_green - 30000L) > 1000 ||
+ abs(info_ptr->int_y_green - 60000L) > 1000 ||
+ abs(info_ptr->int_x_blue - 15000L) > 1000 ||
+ abs(info_ptr->int_y_blue - 6000L) > 1000)
+ {
+ png_warning(png_ptr,
+ "Ignoring incorrect cHRM value when sRGB is also present");
+ }
+#endif /* PNG_FIXED_POINT_SUPPORTED */
+#endif /* PNG_READ_cHRM_SUPPORTED */
+
+ png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent);
+}
+#endif /* PNG_READ_sRGB_SUPPORTED */
+
+#if defined(PNG_READ_iCCP_SUPPORTED)
+void /* PRIVATE */
+png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+/* Note: this does not properly handle chunks that are > 64K under DOS */
+{
+ png_charp chunkdata;
+ png_byte compression_type;
+ png_charp profile;
+ png_uint_32 skip = 0;
+ png_uint_32 profile_size = 0;
+ png_uint_32 profile_length = 0;
+ png_size_t slength, prefix_length, data_length;
+
+ png_debug(1, "in png_handle_iCCP\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before iCCP");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid iCCP after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ /* Should be an error, but we can cope with it */
+ png_warning(png_ptr, "Out of place iCCP chunk");
+
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP))
+ {
+ png_warning(png_ptr, "Duplicate iCCP chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (length > (png_uint_32)65535L)
+ {
+ png_warning(png_ptr, "iCCP chunk too large to fit in memory");
+ skip = length - (png_uint_32)65535L;
+ length = (png_uint_32)65535L;
+ }
+#endif
+
+ chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
+ slength = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
+
+ if (png_crc_finish(png_ptr, skip))
+ {
+ png_free(png_ptr, chunkdata);
+ return;
+ }
+
+ chunkdata[slength] = 0x00;
+
+ for (profile = chunkdata; *profile; profile++)
+ /* empty loop to find end of name */ ;
+
+ ++profile;
+
+ /* there should be at least one zero (the compression type byte)
+ following the separator, and we should be on it */
+ if ( profile >= chunkdata + slength)
+ {
+ png_free(png_ptr, chunkdata);
+ png_warning(png_ptr, "Malformed iCCP chunk");
+ return;
+ }
+
+ /* compression_type should always be zero */
+ compression_type = *profile++;
+ if (compression_type)
+ {
+ png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk");
+ compression_type=0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8
+ wrote nonzero) */
+ }
+
+ prefix_length = profile - chunkdata;
+ chunkdata = png_decompress_chunk(png_ptr, compression_type, chunkdata,
+ slength, prefix_length, &data_length);
+
+ profile_length = data_length - prefix_length;
+
+ if ( profile_length < 4)
+ {
+ png_free(png_ptr, chunkdata);
+ png_warning(png_ptr, "Profile size field missing from iCCP chunk");
+ return;
+ }
+
+ /* Check the profile_size recorded in the first 32 bits of the ICC profile */
+ profile_size = ((*(chunkdata+prefix_length))<<24) |
+ ((*(chunkdata+prefix_length+1))<<16) |
+ ((*(chunkdata+prefix_length+2))<< 8) |
+ ((*(chunkdata+prefix_length+3)) );
+
+ if(profile_size < profile_length)
+ profile_length = profile_size;
+
+ if(profile_size > profile_length)
+ {
+ png_free(png_ptr, chunkdata);
+ png_warning(png_ptr, "Ignoring truncated iCCP profile.\n");
+ return;
+ }
+
+ png_set_iCCP(png_ptr, info_ptr, chunkdata, compression_type,
+ chunkdata + prefix_length, profile_length);
+ png_free(png_ptr, chunkdata);
+}
+#endif /* PNG_READ_iCCP_SUPPORTED */
+
+#if defined(PNG_READ_sPLT_SUPPORTED)
+void /* PRIVATE */
+png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+/* Note: this does not properly handle chunks that are > 64K under DOS */
+{
+ png_bytep chunkdata;
+ png_bytep entry_start;
+ png_sPLT_t new_palette;
+#ifdef PNG_NO_POINTER_INDEXING
+ png_sPLT_entryp pp;
+#endif
+ int data_length, entry_size, i;
+ png_uint_32 skip = 0;
+ png_size_t slength;
+
+ png_debug(1, "in png_handle_sPLT\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before sPLT");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid sPLT after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (length > (png_uint_32)65535L)
+ {
+ png_warning(png_ptr, "sPLT chunk too large to fit in memory");
+ skip = length - (png_uint_32)65535L;
+ length = (png_uint_32)65535L;
+ }
+#endif
+
+ chunkdata = (png_bytep)png_malloc(png_ptr, length + 1);
+ slength = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
+
+ if (png_crc_finish(png_ptr, skip))
+ {
+ png_free(png_ptr, chunkdata);
+ return;
+ }
+
+ chunkdata[slength] = 0x00;
+
+ for (entry_start = chunkdata; *entry_start; entry_start++)
+ /* empty loop to find end of name */ ;
+ ++entry_start;
+
+ /* a sample depth should follow the separator, and we should be on it */
+ if (entry_start > chunkdata + slength)
+ {
+ png_free(png_ptr, chunkdata);
+ png_warning(png_ptr, "malformed sPLT chunk");
+ return;
+ }
+
+ new_palette.depth = *entry_start++;
+ entry_size = (new_palette.depth == 8 ? 6 : 10);
+ data_length = (slength - (entry_start - chunkdata));
+
+ /* integrity-check the data length */
+ if (data_length % entry_size)
+ {
+ png_free(png_ptr, chunkdata);
+ png_warning(png_ptr, "sPLT chunk has bad length");
+ return;
+ }
+
+ new_palette.nentries = data_length / entry_size;
+ new_palette.entries = (png_sPLT_entryp)png_malloc(
+ png_ptr, new_palette.nentries * sizeof(png_sPLT_entry));
+
+#ifndef PNG_NO_POINTER_INDEXING
+ for (i = 0; i < new_palette.nentries; i++)
+ {
+ png_sPLT_entryp pp = new_palette.entries + i;
+
+ if (new_palette.depth == 8)
+ {
+ pp->red = *entry_start++;
+ pp->green = *entry_start++;
+ pp->blue = *entry_start++;
+ pp->alpha = *entry_start++;
+ }
+ else
+ {
+ pp->red = png_get_uint_16(entry_start); entry_start += 2;
+ pp->green = png_get_uint_16(entry_start); entry_start += 2;
+ pp->blue = png_get_uint_16(entry_start); entry_start += 2;
+ pp->alpha = png_get_uint_16(entry_start); entry_start += 2;
+ }
+ pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
+ }
+#else
+ pp = new_palette.entries;
+ for (i = 0; i < new_palette.nentries; i++)
+ {
+
+ if (new_palette.depth == 8)
+ {
+ pp[i].red = *entry_start++;
+ pp[i].green = *entry_start++;
+ pp[i].blue = *entry_start++;
+ pp[i].alpha = *entry_start++;
+ }
+ else
+ {
+ pp[i].red = png_get_uint_16(entry_start); entry_start += 2;
+ pp[i].green = png_get_uint_16(entry_start); entry_start += 2;
+ pp[i].blue = png_get_uint_16(entry_start); entry_start += 2;
+ pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2;
+ }
+ pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
+ }
+#endif
+
+ /* discard all chunk data except the name and stash that */
+ new_palette.name = (png_charp)chunkdata;
+
+ png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
+
+ png_free(png_ptr, chunkdata);
+ png_free(png_ptr, new_palette.entries);
+}
+#endif /* PNG_READ_sPLT_SUPPORTED */
+
+#if defined(PNG_READ_tRNS_SUPPORTED)
+void /* PRIVATE */
+png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte readbuf[PNG_MAX_PALETTE_LENGTH];
+
+ png_debug(1, "in png_handle_tRNS\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before tRNS");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid tRNS after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
+ {
+ png_warning(png_ptr, "Duplicate tRNS chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (!(png_ptr->mode & PNG_HAVE_PLTE))
+ {
+ /* Should be an error, but we can cope with it */
+ png_warning(png_ptr, "Missing PLTE before tRNS");
+ }
+ else if (length > (png_uint_32)png_ptr->num_palette)
+ {
+ png_warning(png_ptr, "Incorrect tRNS chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ if (length == 0)
+ {
+ png_warning(png_ptr, "Zero length tRNS chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, readbuf, (png_size_t)length);
+ png_ptr->num_trans = (png_uint_16)length;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ png_byte buf[6];
+
+ if (length != 6)
+ {
+ png_warning(png_ptr, "Incorrect tRNS chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, (png_size_t)length);
+ png_ptr->num_trans = 1;
+ png_ptr->trans_values.red = png_get_uint_16(buf);
+ png_ptr->trans_values.green = png_get_uint_16(buf + 2);
+ png_ptr->trans_values.blue = png_get_uint_16(buf + 4);
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ png_byte buf[6];
+
+ if (length != 2)
+ {
+ png_warning(png_ptr, "Incorrect tRNS chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 2);
+ png_ptr->num_trans = 1;
+ png_ptr->trans_values.gray = png_get_uint_16(buf);
+ }
+ else
+ {
+ png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
+ &(png_ptr->trans_values));
+}
+#endif
+
+#if defined(PNG_READ_bKGD_SUPPORTED)
+void /* PRIVATE */
+png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_size_t truelen;
+ png_byte buf[6];
+
+ png_debug(1, "in png_handle_bKGD\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before bKGD");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid bKGD after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+ !(png_ptr->mode & PNG_HAVE_PLTE))
+ {
+ png_warning(png_ptr, "Missing PLTE before bKGD");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD))
+ {
+ png_warning(png_ptr, "Duplicate bKGD chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ truelen = 1;
+ else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ truelen = 6;
+ else
+ truelen = 2;
+
+ if (length != truelen)
+ {
+ png_warning(png_ptr, "Incorrect bKGD chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, truelen);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ /* We convert the index value into RGB components so that we can allow
+ * arbitrary RGB values for background when we have transparency, and
+ * so it is easy to determine the RGB values of the background color
+ * from the info_ptr struct. */
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_ptr->background.index = buf[0];
+ if(info_ptr->num_palette)
+ {
+ if(buf[0] > info_ptr->num_palette)
+ {
+ png_warning(png_ptr, "Incorrect bKGD chunk index value");
+ return;
+ }
+ png_ptr->background.red =
+ (png_uint_16)png_ptr->palette[buf[0]].red;
+ png_ptr->background.green =
+ (png_uint_16)png_ptr->palette[buf[0]].green;
+ png_ptr->background.blue =
+ (png_uint_16)png_ptr->palette[buf[0]].blue;
+ }
+ }
+ else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
+ {
+ png_ptr->background.red =
+ png_ptr->background.green =
+ png_ptr->background.blue =
+ png_ptr->background.gray = png_get_uint_16(buf);
+ }
+ else
+ {
+ png_ptr->background.red = png_get_uint_16(buf);
+ png_ptr->background.green = png_get_uint_16(buf + 2);
+ png_ptr->background.blue = png_get_uint_16(buf + 4);
+ }
+
+ png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
+}
+#endif
+
+#if defined(PNG_READ_hIST_SUPPORTED)
+void /* PRIVATE */
+png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ int num, i;
+ png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH];
+
+ png_debug(1, "in png_handle_hIST\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before hIST");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid hIST after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (!(png_ptr->mode & PNG_HAVE_PLTE))
+ {
+ png_warning(png_ptr, "Missing PLTE before hIST");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST))
+ {
+ png_warning(png_ptr, "Duplicate hIST chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ num = (int)length / 2 ;
+ if (num != png_ptr->num_palette)
+ {
+ png_warning(png_ptr, "Incorrect hIST chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ for (i = 0; i < num; i++)
+ {
+ png_byte buf[2];
+
+ png_crc_read(png_ptr, buf, 2);
+ readbuf[i] = png_get_uint_16(buf);
+ }
+
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ png_set_hIST(png_ptr, info_ptr, readbuf);
+}
+#endif
+
+#if defined(PNG_READ_pHYs_SUPPORTED)
+void /* PRIVATE */
+png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte buf[9];
+ png_uint_32 res_x, res_y;
+ int unit_type;
+
+ png_debug(1, "in png_handle_pHYs\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before pHYs");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid pHYs after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
+ {
+ png_warning(png_ptr, "Duplicate pHYs chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (length != 9)
+ {
+ png_warning(png_ptr, "Incorrect pHYs chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 9);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ res_x = png_get_uint_32(buf);
+ res_y = png_get_uint_32(buf + 4);
+ unit_type = buf[8];
+ png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
+}
+#endif
+
+#if defined(PNG_READ_oFFs_SUPPORTED)
+void /* PRIVATE */
+png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte buf[9];
+ png_int_32 offset_x, offset_y;
+ int unit_type;
+
+ png_debug(1, "in png_handle_oFFs\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before oFFs");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid oFFs after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))
+ {
+ png_warning(png_ptr, "Duplicate oFFs chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (length != 9)
+ {
+ png_warning(png_ptr, "Incorrect oFFs chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 9);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ offset_x = png_get_int_32(buf);
+ offset_y = png_get_int_32(buf + 4);
+ unit_type = buf[8];
+ png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
+}
+#endif
+
+#if defined(PNG_READ_pCAL_SUPPORTED)
+/* read the pCAL chunk (described in the PNG Extensions document) */
+void /* PRIVATE */
+png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_charp purpose;
+ png_int_32 X0, X1;
+ png_byte type, nparams;
+ png_charp buf, units, endptr;
+ png_charpp params;
+ png_size_t slength;
+ int i;
+
+ png_debug(1, "in png_handle_pCAL\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before pCAL");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid pCAL after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL))
+ {
+ png_warning(png_ptr, "Duplicate pCAL chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_debug1(2, "Allocating and reading pCAL chunk data (%lu bytes)\n",
+ length + 1);
+ purpose = (png_charp)png_malloc(png_ptr, length + 1);
+ slength = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)purpose, slength);
+
+ if (png_crc_finish(png_ptr, 0))
+ {
+ png_free(png_ptr, purpose);
+ return;
+ }
+
+ purpose[slength] = 0x00; /* null terminate the last string */
+
+ png_debug(3, "Finding end of pCAL purpose string\n");
+ for (buf = purpose; *buf; buf++)
+ /* empty loop */ ;
+
+ endptr = purpose + slength;
+
+ /* We need to have at least 12 bytes after the purpose string
+ in order to get the parameter information. */
+ if (endptr <= buf + 12)
+ {
+ png_warning(png_ptr, "Invalid pCAL data");
+ png_free(png_ptr, purpose);
+ return;
+ }
+
+ png_debug(3, "Reading pCAL X0, X1, type, nparams, and units\n");
+ X0 = png_get_int_32((png_bytep)buf+1);
+ X1 = png_get_int_32((png_bytep)buf+5);
+ type = buf[9];
+ nparams = buf[10];
+ units = buf + 11;
+
+ png_debug(3, "Checking pCAL equation type and number of parameters\n");
+ /* Check that we have the right number of parameters for known
+ equation types. */
+ if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
+ (type == PNG_EQUATION_BASE_E && nparams != 3) ||
+ (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
+ (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
+ {
+ png_warning(png_ptr, "Invalid pCAL parameters for equation type");
+ png_free(png_ptr, purpose);
+ return;
+ }
+ else if (type >= PNG_EQUATION_LAST)
+ {
+ png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
+ }
+
+ for (buf = units; *buf; buf++)
+ /* Empty loop to move past the units string. */ ;
+
+ png_debug(3, "Allocating pCAL parameters array\n");
+ params = (png_charpp)png_malloc(png_ptr, (png_uint_32)(nparams
+ *sizeof(png_charp))) ;
+
+ /* Get pointers to the start of each parameter string. */
+ for (i = 0; i < (int)nparams; i++)
+ {
+ buf++; /* Skip the null string terminator from previous parameter. */
+
+ png_debug1(3, "Reading pCAL parameter %d\n", i);
+ for (params[i] = buf; *buf != 0x00 && buf <= endptr; buf++)
+ /* Empty loop to move past each parameter string */ ;
+
+ /* Make sure we haven't run out of data yet */
+ if (buf > endptr)
+ {
+ png_warning(png_ptr, "Invalid pCAL data");
+ png_free(png_ptr, purpose);
+ png_free(png_ptr, params);
+ return;
+ }
+ }
+
+ png_set_pCAL(png_ptr, info_ptr, purpose, X0, X1, type, nparams,
+ units, params);
+
+ png_free(png_ptr, purpose);
+ png_free(png_ptr, params);
+}
+#endif
+
+#if defined(PNG_READ_sCAL_SUPPORTED)
+/* read the sCAL chunk */
+void /* PRIVATE */
+png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_charp buffer, ep;
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ double width, height;
+ png_charp vp;
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ png_charp swidth, sheight;
+#endif
+#endif
+ png_size_t slength;
+
+ png_debug(1, "in png_handle_sCAL\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before sCAL");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid sCAL after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL))
+ {
+ png_warning(png_ptr, "Duplicate sCAL chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_debug1(2, "Allocating and reading sCAL chunk data (%lu bytes)\n",
+ length + 1);
+ buffer = (png_charp)png_malloc(png_ptr, length + 1);
+ slength = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)buffer, slength);
+
+ if (png_crc_finish(png_ptr, 0))
+ {
+ png_free(png_ptr, buffer);
+ return;
+ }
+
+ buffer[slength] = 0x00; /* null terminate the last string */
+
+ ep = buffer + 1; /* skip unit byte */
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ width = strtod(ep, &vp);
+ if (*vp)
+ {
+ png_warning(png_ptr, "malformed width string in sCAL chunk");
+ return;
+ }
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ swidth = (png_charp)png_malloc(png_ptr, png_strlen(ep) + 1);
+ png_memcpy(swidth, ep, (png_size_t)png_strlen(ep));
+#endif
+#endif
+
+ for (ep = buffer; *ep; ep++)
+ /* empty loop */ ;
+ ep++;
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ height = strtod(ep, &vp);
+ if (*vp)
+ {
+ png_warning(png_ptr, "malformed height string in sCAL chunk");
+ return;
+ }
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ sheight = (png_charp)png_malloc(png_ptr, png_strlen(ep) + 1);
+ png_memcpy(sheight, ep, (png_size_t)png_strlen(ep));
+#endif
+#endif
+
+ if (buffer + slength < ep
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ || width <= 0. || height <= 0.
+#endif
+ )
+ {
+ png_warning(png_ptr, "Invalid sCAL data");
+ png_free(png_ptr, buffer);
+#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
+ png_free(png_ptr, swidth);
+ png_free(png_ptr, sheight);
+#endif
+ return;
+ }
+
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ png_set_sCAL(png_ptr, info_ptr, buffer[0], width, height);
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ png_set_sCAL_s(png_ptr, info_ptr, buffer[0], swidth, sheight);
+#endif
+#endif
+
+ png_free(png_ptr, buffer);
+#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
+ png_free(png_ptr, swidth);
+ png_free(png_ptr, sheight);
+#endif
+}
+#endif
+
+#if defined(PNG_READ_tIME_SUPPORTED)
+void /* PRIVATE */
+png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte buf[7];
+ png_time mod_time;
+
+ png_debug(1, "in png_handle_tIME\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Out of place tIME chunk");
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME))
+ {
+ png_warning(png_ptr, "Duplicate tIME chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ png_ptr->mode |= PNG_AFTER_IDAT;
+
+ if (length != 7)
+ {
+ png_warning(png_ptr, "Incorrect tIME chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 7);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ mod_time.second = buf[6];
+ mod_time.minute = buf[5];
+ mod_time.hour = buf[4];
+ mod_time.day = buf[3];
+ mod_time.month = buf[2];
+ mod_time.year = png_get_uint_16(buf);
+
+ png_set_tIME(png_ptr, info_ptr, &mod_time);
+}
+#endif
+
+#if defined(PNG_READ_tEXt_SUPPORTED)
+/* Note: this does not properly handle chunks that are > 64K under DOS */
+void /* PRIVATE */
+png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_textp text_ptr;
+ png_charp key;
+ png_charp text;
+ png_uint_32 skip = 0;
+ png_size_t slength;
+
+ png_debug(1, "in png_handle_tEXt\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before tEXt");
+
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ png_ptr->mode |= PNG_AFTER_IDAT;
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (length > (png_uint_32)65535L)
+ {
+ png_warning(png_ptr, "tEXt chunk too large to fit in memory");
+ skip = length - (png_uint_32)65535L;
+ length = (png_uint_32)65535L;
+ }
+#endif
+
+ key = (png_charp)png_malloc(png_ptr, length + 1);
+ slength = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)key, slength);
+
+ if (png_crc_finish(png_ptr, skip))
+ {
+ png_free(png_ptr, key);
+ return;
+ }
+
+ key[slength] = 0x00;
+
+ for (text = key; *text; text++)
+ /* empty loop to find end of key */ ;
+
+ if (text != key + slength)
+ text++;
+
+ text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text));
+ text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
+ text_ptr->key = key;
+#ifdef PNG_iTXt_SUPPORTED
+ text_ptr->lang = NULL;
+ text_ptr->lang_key = NULL;
+ text_ptr->itxt_length = 0;
+#endif
+ text_ptr->text = text;
+ text_ptr->text_length = png_strlen(text);
+
+ png_set_text(png_ptr, info_ptr, text_ptr, 1);
+
+ png_free(png_ptr, key);
+ png_free(png_ptr, text_ptr);
+}
+#endif
+
+#if defined(PNG_READ_zTXt_SUPPORTED)
+/* note: this does not correctly handle chunks that are > 64K under DOS */
+void /* PRIVATE */
+png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_textp text_ptr;
+ png_charp chunkdata;
+ png_charp text;
+ int comp_type;
+ png_size_t slength, prefix_len, data_len;
+
+ png_debug(1, "in png_handle_zTXt\n");
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before zTXt");
+
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ png_ptr->mode |= PNG_AFTER_IDAT;
+
+#ifdef PNG_MAX_MALLOC_64K
+ /* We will no doubt have problems with chunks even half this size, but
+ there is no hard and fast rule to tell us where to stop. */
+ if (length > (png_uint_32)65535L)
+ {
+ png_warning(png_ptr,"zTXt chunk too large to fit in memory");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+#endif
+
+ chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
+ slength = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
+ if (png_crc_finish(png_ptr, 0))
+ {
+ png_free(png_ptr, chunkdata);
+ return;
+ }
+
+ chunkdata[slength] = 0x00;
+
+ for (text = chunkdata; *text; text++)
+ /* empty loop */ ;
+
+ /* zTXt must have some text after the chunkdataword */
+ if (text == chunkdata + slength)
+ {
+ comp_type = PNG_TEXT_COMPRESSION_NONE;
+ png_warning(png_ptr, "Zero length zTXt chunk");
+ }
+ else
+ {
+ comp_type = *(++text);
+ if (comp_type != PNG_TEXT_COMPRESSION_zTXt)
+ {
+ png_warning(png_ptr, "Unknown compression type in zTXt chunk");
+ comp_type = PNG_TEXT_COMPRESSION_zTXt;
+ }
+ text++; /* skip the compression_method byte */
+ }
+ prefix_len = text - chunkdata;
+
+ chunkdata = (png_charp)png_decompress_chunk(png_ptr, comp_type, chunkdata,
+ (png_size_t)length, prefix_len, &data_len);
+
+ text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text));
+ text_ptr->compression = comp_type;
+ text_ptr->key = chunkdata;
+#ifdef PNG_iTXt_SUPPORTED
+ text_ptr->lang = NULL;
+ text_ptr->lang_key = NULL;
+ text_ptr->itxt_length = 0;
+#endif
+ text_ptr->text = chunkdata + prefix_len;
+ text_ptr->text_length = data_len;
+
+ png_set_text(png_ptr, info_ptr, text_ptr, 1);
+
+ png_free(png_ptr, text_ptr);
+ png_free(png_ptr, chunkdata);
+}
+#endif
+
+#if defined(PNG_READ_iTXt_SUPPORTED)
+/* note: this does not correctly handle chunks that are > 64K under DOS */
+void /* PRIVATE */
+png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_textp text_ptr;
+ png_charp chunkdata;
+ png_charp key, lang, text, lang_key;
+ int comp_flag;
+ int comp_type = 0;
+ png_size_t slength, prefix_len, data_len;
+
+ png_debug(1, "in png_handle_iTXt\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before iTXt");
+
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ png_ptr->mode |= PNG_AFTER_IDAT;
+
+#ifdef PNG_MAX_MALLOC_64K
+ /* We will no doubt have problems with chunks even half this size, but
+ there is no hard and fast rule to tell us where to stop. */
+ if (length > (png_uint_32)65535L)
+ {
+ png_warning(png_ptr,"iTXt chunk too large to fit in memory");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+#endif
+
+ chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
+ slength = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
+ if (png_crc_finish(png_ptr, 0))
+ {
+ png_free(png_ptr, chunkdata);
+ return;
+ }
+
+ chunkdata[slength] = 0x00;
+
+ for (lang = chunkdata; *lang; lang++)
+ /* empty loop */ ;
+ lang++; /* skip NUL separator */
+
+ /* iTXt must have a language tag (possibly empty), two compression bytes,
+ translated keyword (possibly empty), and possibly some text after the
+ keyword */
+
+ if (lang >= chunkdata + slength)
+ {
+ comp_flag = PNG_TEXT_COMPRESSION_NONE;
+ png_warning(png_ptr, "Zero length iTXt chunk");
+ }
+ else
+ {
+ comp_flag = *lang++;
+ comp_type = *lang++;
+ }
+
+ for (lang_key = lang; *lang_key; lang_key++)
+ /* empty loop */ ;
+ lang_key++; /* skip NUL separator */
+
+ for (text = lang_key; *text; text++)
+ /* empty loop */ ;
+ text++; /* skip NUL separator */
+
+ prefix_len = text - chunkdata;
+
+ key=chunkdata;
+ if (comp_flag)
+ chunkdata = png_decompress_chunk(png_ptr, comp_type, chunkdata,
+ (size_t)length, prefix_len, &data_len);
+ else
+ data_len=png_strlen(chunkdata + prefix_len);
+ text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text));
+ text_ptr->compression = (int)comp_flag + 1;
+ text_ptr->lang_key = chunkdata+(lang_key-key);
+ text_ptr->lang = chunkdata+(lang-key);
+ text_ptr->itxt_length = data_len;
+ text_ptr->text_length = 0;
+ text_ptr->key = chunkdata;
+ text_ptr->text = chunkdata + prefix_len;
+
+ png_set_text(png_ptr, info_ptr, text_ptr, 1);
+
+ png_free(png_ptr, text_ptr);
+ png_free(png_ptr, chunkdata);
+}
+#endif
+
+/* This function is called when we haven't found a handler for a
+ chunk. If there isn't a problem with the chunk itself (ie bad
+ chunk name, CRC, or a critical chunk), the chunk is silently ignored
+ -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which
+ case it will be saved away to be written out later. */
+void /* PRIVATE */
+png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_uint_32 skip = 0;
+
+ png_debug(1, "in png_handle_unknown\n");
+
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_IDAT;
+#endif
+ if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* not an IDAT */
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ }
+
+ png_check_chunk_name(png_ptr, png_ptr->chunk_name);
+
+ if (!(png_ptr->chunk_name[0] & 0x20))
+ {
+#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
+ if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
+ HANDLE_CHUNK_ALWAYS
+#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
+ && png_ptr->read_user_chunk_fn == NULL
+#endif
+ )
+#endif
+ png_chunk_error(png_ptr, "unknown critical chunk");
+ }
+
+#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
+ if (png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS)
+ {
+ png_unknown_chunk chunk;
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (length > (png_uint_32)65535L)
+ {
+ png_warning(png_ptr, "unknown chunk too large to fit in memory");
+ skip = length - (png_uint_32)65535L;
+ length = (png_uint_32)65535L;
+ }
+#endif
+ png_strcpy((png_charp)chunk.name, (png_charp)png_ptr->chunk_name);
+ chunk.data = (png_bytep)png_malloc(png_ptr, length);
+ chunk.size = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)chunk.data, length);
+#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
+ if(png_ptr->read_user_chunk_fn != NULL)
+ {
+ /* callback to user unknown chunk handler */
+ if ((*(png_ptr->read_user_chunk_fn)) (png_ptr, &chunk) <= 0)
+ {
+ if (!(png_ptr->chunk_name[0] & 0x20))
+ if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
+ HANDLE_CHUNK_ALWAYS)
+ png_chunk_error(png_ptr, "unknown critical chunk");
+ png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1);
+ }
+ }
+ else
+#endif
+ png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1);
+ png_free(png_ptr, chunk.data);
+ }
+ else
+#endif
+ skip = length;
+
+ png_crc_finish(png_ptr, skip);
+
+#if !defined(PNG_READ_USER_CHUNKS_SUPPORTED)
+ info_ptr = info_ptr; /* quiet compiler warnings about unused info_ptr */
+#endif
+}
+
+/* This function is called to verify that a chunk name is valid.
+ This function can't have the "critical chunk check" incorporated
+ into it, since in the future we will need to be able to call user
+ functions to handle unknown critical chunks after we check that
+ the chunk name itself is valid. */
+
+#define isnonalpha(c) ((c) < 41 || (c) > 122 || ((c) > 90 && (c) < 97))
+
+void /* PRIVATE */
+png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name)
+{
+ png_debug(1, "in png_check_chunk_name\n");
+ if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
+ isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
+ {
+ png_chunk_error(png_ptr, "invalid chunk type");
+ }
+}
+
+/* Combines the row recently read in with the existing pixels in the
+ row. This routine takes care of alpha and transparency if requested.
+ This routine also handles the two methods of progressive display
+ of interlaced images, depending on the mask value.
+ The mask value describes which pixels are to be combined with
+ the row. The pattern always repeats every 8 pixels, so just 8
+ bits are needed. A one indicates the pixel is to be combined,
+ a zero indicates the pixel is to be skipped. This is in addition
+ to any alpha or transparency value associated with the pixel. If
+ you want all pixels to be combined, pass 0xff (255) in mask. */
+#ifndef PNG_HAVE_ASSEMBLER_COMBINE_ROW
+void /* PRIVATE */
+png_combine_row(png_structp png_ptr, png_bytep row, int mask)
+{
+ png_debug(1,"in png_combine_row\n");
+ if (mask == 0xff)
+ {
+ png_memcpy(row, png_ptr->row_buf + 1,
+ (png_size_t)((png_ptr->width *
+ png_ptr->row_info.pixel_depth + 7) >> 3));
+ }
+ else
+ {
+ switch (png_ptr->row_info.pixel_depth)
+ {
+ case 1:
+ {
+ png_bytep sp = png_ptr->row_buf + 1;
+ png_bytep dp = row;
+ int s_inc, s_start, s_end;
+ int m = 0x80;
+ int shift;
+ png_uint_32 i;
+ png_uint_32 row_width = png_ptr->width;
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 7;
+ s_inc = 1;
+ }
+ else
+#endif
+ {
+ s_start = 7;
+ s_end = 0;
+ s_inc = -1;
+ }
+
+ shift = s_start;
+
+ for (i = 0; i < row_width; i++)
+ {
+ if (m & mask)
+ {
+ int value;
+
+ value = (*sp >> shift) & 0x01;
+ *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+ case 2:
+ {
+ png_bytep sp = png_ptr->row_buf + 1;
+ png_bytep dp = row;
+ int s_start, s_end, s_inc;
+ int m = 0x80;
+ int shift;
+ png_uint_32 i;
+ png_uint_32 row_width = png_ptr->width;
+ int value;
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 6;
+ s_inc = 2;
+ }
+ else
+#endif
+ {
+ s_start = 6;
+ s_end = 0;
+ s_inc = -2;
+ }
+
+ shift = s_start;
+
+ for (i = 0; i < row_width; i++)
+ {
+ if (m & mask)
+ {
+ value = (*sp >> shift) & 0x03;
+ *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_bytep sp = png_ptr->row_buf + 1;
+ png_bytep dp = row;
+ int s_start, s_end, s_inc;
+ int m = 0x80;
+ int shift;
+ png_uint_32 i;
+ png_uint_32 row_width = png_ptr->width;
+ int value;
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 4;
+ s_inc = 4;
+ }
+ else
+#endif
+ {
+ s_start = 4;
+ s_end = 0;
+ s_inc = -4;
+ }
+ shift = s_start;
+
+ for (i = 0; i < row_width; i++)
+ {
+ if (m & mask)
+ {
+ value = (*sp >> shift) & 0xf;
+ *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+ default:
+ {
+ png_bytep sp = png_ptr->row_buf + 1;
+ png_bytep dp = row;
+ png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
+ png_uint_32 i;
+ png_uint_32 row_width = png_ptr->width;
+ png_byte m = 0x80;
+
+
+ for (i = 0; i < row_width; i++)
+ {
+ if (m & mask)
+ {
+ png_memcpy(dp, sp, pixel_bytes);
+ }
+
+ sp += pixel_bytes;
+ dp += pixel_bytes;
+
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+ }
+ }
+}
+#endif /* !PNG_HAVE_ASSEMBLER_COMBINE_ROW */
+
+#ifdef PNG_READ_INTERLACING_SUPPORTED
+#ifndef PNG_HAVE_ASSEMBLER_READ_INTERLACE /* else in pngvcrd.c, pnggccrd.c */
+/* OLD pre-1.0.9 interface:
+void png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
+ png_uint_32 transformations)
+ */
+void /* PRIVATE */
+png_do_read_interlace(png_structp png_ptr)
+{
+ png_row_infop row_info = &(png_ptr->row_info);
+ png_bytep row = png_ptr->row_buf + 1;
+ int pass = png_ptr->pass;
+ png_uint_32 transformations = png_ptr->transformations;
+#ifdef PNG_USE_LOCAL_ARRAYS
+ /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+ /* offset to next interlace block */
+ const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+#endif
+
+ png_debug(1,"in png_do_read_interlace (stock C version)\n");
+ if (row != NULL && row_info != NULL)
+ {
+ png_uint_32 final_width;
+
+ final_width = row_info->width * png_pass_inc[pass];
+
+ switch (row_info->pixel_depth)
+ {
+ case 1:
+ {
+ png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3);
+ png_bytep dp = row + (png_size_t)((final_width - 1) >> 3);
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ int jstop = png_pass_inc[pass];
+ png_byte v;
+ png_uint_32 i;
+ int j;
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (int)((row_info->width + 7) & 0x07);
+ dshift = (int)((final_width + 7) & 0x07);
+ s_start = 7;
+ s_end = 0;
+ s_inc = -1;
+ }
+ else
+#endif
+ {
+ sshift = 7 - (int)((row_info->width + 7) & 0x07);
+ dshift = 7 - (int)((final_width + 7) & 0x07);
+ s_start = 0;
+ s_end = 7;
+ s_inc = 1;
+ }
+
+ for (i = 0; i < row_info->width; i++)
+ {
+ v = (png_byte)((*sp >> sshift) & 0x01);
+ for (j = 0; j < jstop; j++)
+ {
+ *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+ case 2:
+ {
+ png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);
+ png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ int jstop = png_pass_inc[pass];
+ png_uint_32 i;
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (int)(((row_info->width + 3) & 0x03) << 1);
+ dshift = (int)(((final_width + 3) & 0x03) << 1);
+ s_start = 6;
+ s_end = 0;
+ s_inc = -2;
+ }
+ else
+#endif
+ {
+ sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1);
+ dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1);
+ s_start = 0;
+ s_end = 6;
+ s_inc = 2;
+ }
+
+ for (i = 0; i < row_info->width; i++)
+ {
+ png_byte v;
+ int j;
+
+ v = (png_byte)((*sp >> sshift) & 0x03);
+ for (j = 0; j < jstop; j++)
+ {
+ *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1);
+ png_bytep dp = row + (png_size_t)((final_width - 1) >> 1);
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ png_uint_32 i;
+ int jstop = png_pass_inc[pass];
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (int)(((row_info->width + 1) & 0x01) << 2);
+ dshift = (int)(((final_width + 1) & 0x01) << 2);
+ s_start = 4;
+ s_end = 0;
+ s_inc = -4;
+ }
+ else
+#endif
+ {
+ sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2);
+ dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2);
+ s_start = 0;
+ s_end = 4;
+ s_inc = 4;
+ }
+
+ for (i = 0; i < row_info->width; i++)
+ {
+ png_byte v = (png_byte)((*sp >> sshift) & 0xf);
+ int j;
+
+ for (j = 0; j < jstop; j++)
+ {
+ *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+ default:
+ {
+ png_size_t pixel_bytes = (row_info->pixel_depth >> 3);
+ png_bytep sp = row + (png_size_t)(row_info->width - 1) * pixel_bytes;
+ png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes;
+
+ int jstop = png_pass_inc[pass];
+ png_uint_32 i;
+
+ for (i = 0; i < row_info->width; i++)
+ {
+ png_byte v[8];
+ int j;
+
+ png_memcpy(v, sp, pixel_bytes);
+ for (j = 0; j < jstop; j++)
+ {
+ png_memcpy(dp, v, pixel_bytes);
+ dp -= pixel_bytes;
+ }
+ sp -= pixel_bytes;
+ }
+ break;
+ }
+ }
+ row_info->width = final_width;
+ row_info->rowbytes = ((final_width *
+ (png_uint_32)row_info->pixel_depth + 7) >> 3);
+ }
+#if !defined(PNG_READ_PACKSWAP_SUPPORTED)
+ transformations = transformations; /* silence compiler warning */
+#endif
+}
+#endif /* !PNG_HAVE_ASSEMBLER_READ_INTERLACE */
+#endif /* PNG_READ_INTERLACING_SUPPORTED */
+
+#ifndef PNG_HAVE_ASSEMBLER_READ_FILTER_ROW
+void /* PRIVATE */
+png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
+ png_bytep prev_row, int filter)
+{
+ png_debug(1, "in png_read_filter_row\n");
+ png_debug2(2,"row = %lu, filter = %d\n", png_ptr->row_number, filter);
+ switch (filter)
+ {
+ case PNG_FILTER_VALUE_NONE:
+ break;
+ case PNG_FILTER_VALUE_SUB:
+ {
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
+ png_bytep rp = row + bpp;
+ png_bytep lp = row;
+
+ for (i = bpp; i < istop; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
+ rp++;
+ }
+ break;
+ }
+ case PNG_FILTER_VALUE_UP:
+ {
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+
+ for (i = 0; i < istop; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
+ rp++;
+ }
+ break;
+ }
+ case PNG_FILTER_VALUE_AVG:
+ {
+ png_uint_32 i;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+ png_bytep lp = row;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
+ png_uint_32 istop = row_info->rowbytes - bpp;
+
+ for (i = 0; i < bpp; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ ((int)(*pp++) / 2 )) & 0xff);
+ rp++;
+ }
+
+ for (i = 0; i < istop; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ (int)(*pp++ + *lp++) / 2 ) & 0xff);
+ rp++;
+ }
+ break;
+ }
+ case PNG_FILTER_VALUE_PAETH:
+ {
+ png_uint_32 i;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+ png_bytep lp = row;
+ png_bytep cp = prev_row;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
+ png_uint_32 istop=row_info->rowbytes - bpp;
+
+ for (i = 0; i < bpp; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
+ rp++;
+ }
+
+ for (i = 0; i < istop; i++) /* use leftover rp,pp */
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ a = *lp++;
+ b = *pp++;
+ c = *cp++;
+
+ p = b - c;
+ pc = a - c;
+
+#ifdef PNG_USE_ABS
+ pa = abs(p);
+ pb = abs(pc);
+ pc = abs(p + pc);
+#else
+ pa = p < 0 ? -p : p;
+ pb = pc < 0 ? -pc : pc;
+ pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+#endif
+
+ /*
+ if (pa <= pb && pa <= pc)
+ p = a;
+ else if (pb <= pc)
+ p = b;
+ else
+ p = c;
+ */
+
+ p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
+
+ *rp = (png_byte)(((int)(*rp) + p) & 0xff);
+ rp++;
+ }
+ break;
+ }
+ default:
+ png_warning(png_ptr, "Ignoring bad adaptive filter type");
+ *row=0;
+ break;
+ }
+}
+#endif /* !PNG_HAVE_ASSEMBLER_READ_FILTER_ROW */
+
+void /* PRIVATE */
+png_read_finish_row(png_structp png_ptr)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+
+ /* start of interlace block */
+ const int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+
+ /* offset to next interlace block */
+ const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+
+ /* start of interlace block in the y direction */
+ const int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
+
+ /* offset to next interlace block in the y direction */
+ const int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
+#endif
+
+ png_debug(1, "in png_read_finish_row\n");
+ png_ptr->row_number++;
+ if (png_ptr->row_number < png_ptr->num_rows)
+ return;
+
+ if (png_ptr->interlaced)
+ {
+ png_ptr->row_number = 0;
+ png_memset_check(png_ptr, png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
+ do
+ {
+ png_ptr->pass++;
+ if (png_ptr->pass >= 7)
+ break;
+ png_ptr->iwidth = (png_ptr->width +
+ png_pass_inc[png_ptr->pass] - 1 -
+ png_pass_start[png_ptr->pass]) /
+ png_pass_inc[png_ptr->pass];
+ png_ptr->irowbytes = ((png_ptr->iwidth *
+ (png_uint_32)png_ptr->pixel_depth + 7) >> 3) +1;
+
+ if (!(png_ptr->transformations & PNG_INTERLACE))
+ {
+ png_ptr->num_rows = (png_ptr->height +
+ png_pass_yinc[png_ptr->pass] - 1 -
+ png_pass_ystart[png_ptr->pass]) /
+ png_pass_yinc[png_ptr->pass];
+ if (!(png_ptr->num_rows))
+ continue;
+ }
+ else /* if (png_ptr->transformations & PNG_INTERLACE) */
+ break;
+ } while (png_ptr->iwidth == 0);
+
+ if (png_ptr->pass < 7)
+ return;
+ }
+
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
+ {
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_IDAT;
+#endif
+ char extra;
+ int ret;
+
+ png_ptr->zstream.next_out = (Byte *)&extra;
+ png_ptr->zstream.avail_out = (uInt)1;
+ for(;;)
+ {
+ if (!(png_ptr->zstream.avail_in))
+ {
+ while (!png_ptr->idat_size)
+ {
+ png_byte chunk_length[4];
+
+ png_crc_finish(png_ptr, 0);
+
+ png_read_data(png_ptr, chunk_length, 4);
+ png_ptr->idat_size = png_get_uint_32(chunk_length);
+
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+ if (png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4))
+ png_error(png_ptr, "Not enough image data");
+
+ }
+ png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_in = png_ptr->zbuf;
+ if (png_ptr->zbuf_size > png_ptr->idat_size)
+ png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
+ png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
+ png_ptr->idat_size -= png_ptr->zstream.avail_in;
+ }
+ ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
+ if (ret == Z_STREAM_END)
+ {
+ if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
+ png_ptr->idat_size)
+ png_error(png_ptr, "Extra compressed data");
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
+ break;
+ }
+ if (ret != Z_OK)
+ png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
+ "Decompression Error");
+
+ if (!(png_ptr->zstream.avail_out))
+ png_error(png_ptr, "Extra compressed data");
+
+ }
+ png_ptr->zstream.avail_out = 0;
+ }
+
+ if (png_ptr->idat_size || png_ptr->zstream.avail_in)
+ png_error(png_ptr, "Extra compression data");
+
+ inflateReset(&png_ptr->zstream);
+
+ png_ptr->mode |= PNG_AFTER_IDAT;
+}
+
+void /* PRIVATE */
+png_read_start_row(png_structp png_ptr)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+
+ /* start of interlace block */
+ const int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+
+ /* offset to next interlace block */
+ const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+
+ /* start of interlace block in the y direction */
+ const int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
+
+ /* offset to next interlace block in the y direction */
+ const int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
+#endif
+
+ int max_pixel_depth;
+ png_uint_32 row_bytes;
+
+ png_debug(1, "in png_read_start_row\n");
+ png_ptr->zstream.avail_in = 0;
+ png_init_read_transformations(png_ptr);
+ if (png_ptr->interlaced)
+ {
+ if (!(png_ptr->transformations & PNG_INTERLACE))
+ png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
+ png_pass_ystart[0]) / png_pass_yinc[0];
+ else
+ png_ptr->num_rows = png_ptr->height;
+
+ png_ptr->iwidth = (png_ptr->width +
+ png_pass_inc[png_ptr->pass] - 1 -
+ png_pass_start[png_ptr->pass]) /
+ png_pass_inc[png_ptr->pass];
+
+ row_bytes = ((png_ptr->iwidth *
+ (png_uint_32)png_ptr->pixel_depth + 7) >> 3) +1;
+ png_ptr->irowbytes = (png_size_t)row_bytes;
+ if((png_uint_32)png_ptr->irowbytes != row_bytes)
+ png_error(png_ptr, "Rowbytes overflow in png_read_start_row");
+ }
+ else
+ {
+ png_ptr->num_rows = png_ptr->height;
+ png_ptr->iwidth = png_ptr->width;
+ png_ptr->irowbytes = png_ptr->rowbytes + 1;
+ }
+ max_pixel_depth = png_ptr->pixel_depth;
+
+#if defined(PNG_READ_PACK_SUPPORTED)
+ if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
+ max_pixel_depth = 8;
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ if (png_ptr->transformations & PNG_EXPAND)
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (png_ptr->num_trans)
+ max_pixel_depth = 32;
+ else
+ max_pixel_depth = 24;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ if (max_pixel_depth < 8)
+ max_pixel_depth = 8;
+ if (png_ptr->num_trans)
+ max_pixel_depth *= 2;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ if (png_ptr->num_trans)
+ {
+ max_pixel_depth *= 4;
+ max_pixel_depth /= 3;
+ }
+ }
+ }
+#endif
+
+#if defined(PNG_READ_FILLER_SUPPORTED)
+ if (png_ptr->transformations & (PNG_FILLER))
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ max_pixel_depth = 32;
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ if (max_pixel_depth <= 8)
+ max_pixel_depth = 16;
+ else
+ max_pixel_depth = 32;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ if (max_pixel_depth <= 32)
+ max_pixel_depth = 32;
+ else
+ max_pixel_depth = 64;
+ }
+ }
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+ if (png_ptr->transformations & PNG_GRAY_TO_RGB)
+ {
+ if (
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
+#endif
+#if defined(PNG_READ_FILLER_SUPPORTED)
+ (png_ptr->transformations & (PNG_FILLER)) ||
+#endif
+ png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ if (max_pixel_depth <= 16)
+ max_pixel_depth = 32;
+ else
+ max_pixel_depth = 64;
+ }
+ else
+ {
+ if (max_pixel_depth <= 8)
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ max_pixel_depth = 32;
+ else
+ max_pixel_depth = 24;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ max_pixel_depth = 64;
+ else
+ max_pixel_depth = 48;
+ }
+ }
+#endif
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \
+defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
+ if(png_ptr->transformations & PNG_USER_TRANSFORM)
+ {
+ int user_pixel_depth=png_ptr->user_transform_depth*
+ png_ptr->user_transform_channels;
+ if(user_pixel_depth > max_pixel_depth)
+ max_pixel_depth=user_pixel_depth;
+ }
+#endif
+
+ /* align the width on the next larger 8 pixels. Mainly used
+ for interlacing */
+ row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
+ /* calculate the maximum bytes needed, adding a byte and a pixel
+ for safety's sake */
+ row_bytes = ((row_bytes * (png_uint_32)max_pixel_depth + 7) >> 3) +
+ 1 + ((max_pixel_depth + 7) >> 3);
+#ifdef PNG_MAX_MALLOC_64K
+ if (row_bytes > (png_uint_32)65536L)
+ png_error(png_ptr, "This image requires a row greater than 64KB");
+#endif
+ png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes+64);
+ png_ptr->row_buf = png_ptr->big_row_buf+32;
+#if defined(PNG_DEBUG) && defined(PNG_USE_PNGGCCRD)
+ png_ptr->row_buf_size = row_bytes;
+#endif
+
+#ifdef PNG_MAX_MALLOC_64K
+ if ((png_uint_32)png_ptr->rowbytes + 1 > (png_uint_32)65536L)
+ png_error(png_ptr, "This image requires a row greater than 64KB");
+#endif
+ png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)(
+ png_ptr->rowbytes + 1));
+
+ png_memset_check(png_ptr, png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
+
+ png_debug1(3, "width = %lu,\n", png_ptr->width);
+ png_debug1(3, "height = %lu,\n", png_ptr->height);
+ png_debug1(3, "iwidth = %lu,\n", png_ptr->iwidth);
+ png_debug1(3, "num_rows = %lu\n", png_ptr->num_rows);
+ png_debug1(3, "rowbytes = %lu,\n", png_ptr->rowbytes);
+ png_debug1(3, "irowbytes = %lu,\n", png_ptr->irowbytes);
+
+ png_ptr->flags |= PNG_FLAG_ROW_INIT;
+}
--- /dev/null
+
+/* pngset.c - storage of image information into info struct
+ *
+ * libpng 1.2.0 - September 1, 2001
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ *
+ * The functions here are used during reads to store data from the file
+ * into the info struct, and during writes to store application data
+ * into the info struct for writing into the file. This abstracts the
+ * info struct and allows us to change the structure in the future.
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#if defined(PNG_bKGD_SUPPORTED)
+void PNGAPI
+png_set_bKGD(png_structp png_ptr, png_infop info_ptr, png_color_16p background)
+{
+ png_debug1(1, "in %s storage function\n", "bKGD");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ png_memcpy(&(info_ptr->background), background, sizeof(png_color_16));
+ info_ptr->valid |= PNG_INFO_bKGD;
+}
+#endif
+
+#if defined(PNG_cHRM_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+void PNGAPI
+png_set_cHRM(png_structp png_ptr, png_infop info_ptr,
+ double white_x, double white_y, double red_x, double red_y,
+ double green_x, double green_y, double blue_x, double blue_y)
+{
+ png_debug1(1, "in %s storage function\n", "cHRM");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->x_white = (float)white_x;
+ info_ptr->y_white = (float)white_y;
+ info_ptr->x_red = (float)red_x;
+ info_ptr->y_red = (float)red_y;
+ info_ptr->x_green = (float)green_x;
+ info_ptr->y_green = (float)green_y;
+ info_ptr->x_blue = (float)blue_x;
+ info_ptr->y_blue = (float)blue_y;
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ info_ptr->int_x_white = (png_fixed_point)(white_x*100000.+0.5);
+ info_ptr->int_y_white = (png_fixed_point)(white_y*100000.+0.5);
+ info_ptr->int_x_red = (png_fixed_point)(red_x*100000.+0.5);
+ info_ptr->int_y_red = (png_fixed_point)(red_y*100000.+0.5);
+ info_ptr->int_x_green = (png_fixed_point)(green_x*100000.+0.5);
+ info_ptr->int_y_green = (png_fixed_point)(green_y*100000.+0.5);
+ info_ptr->int_x_blue = (png_fixed_point)(blue_x*100000.+0.5);
+ info_ptr->int_y_blue = (png_fixed_point)(blue_y*100000.+0.5);
+#endif
+ info_ptr->valid |= PNG_INFO_cHRM;
+}
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+void PNGAPI
+png_set_cHRM_fixed(png_structp png_ptr, png_infop info_ptr,
+ png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x,
+ png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y,
+ png_fixed_point blue_x, png_fixed_point blue_y)
+{
+ png_debug1(1, "in %s storage function\n", "cHRM");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->int_x_white = white_x;
+ info_ptr->int_y_white = white_y;
+ info_ptr->int_x_red = red_x;
+ info_ptr->int_y_red = red_y;
+ info_ptr->int_x_green = green_x;
+ info_ptr->int_y_green = green_y;
+ info_ptr->int_x_blue = blue_x;
+ info_ptr->int_y_blue = blue_y;
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ info_ptr->x_white = (float)(white_x/100000.);
+ info_ptr->y_white = (float)(white_y/100000.);
+ info_ptr->x_red = (float)(red_x/100000.);
+ info_ptr->y_red = (float)(red_y/100000.);
+ info_ptr->x_green = (float)(green_x/100000.);
+ info_ptr->y_green = (float)(green_y/100000.);
+ info_ptr->x_blue = (float)(blue_x/100000.);
+ info_ptr->y_blue = (float)(blue_y/100000.);
+#endif
+ info_ptr->valid |= PNG_INFO_cHRM;
+}
+#endif
+#endif
+
+#if defined(PNG_gAMA_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+void PNGAPI
+png_set_gAMA(png_structp png_ptr, png_infop info_ptr, double file_gamma)
+{
+ png_debug1(1, "in %s storage function\n", "gAMA");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->gamma = (float)file_gamma;
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ info_ptr->int_gamma = (int)(file_gamma*100000.+.5);
+#endif
+ info_ptr->valid |= PNG_INFO_gAMA;
+ if(file_gamma == 0.0)
+ png_warning(png_ptr, "Setting gamma=0");
+}
+#endif
+void PNGAPI
+png_set_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, png_fixed_point
+ int_gamma)
+{
+ png_debug1(1, "in %s storage function\n", "gAMA");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ info_ptr->gamma = (float)(int_gamma/100000.);
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ info_ptr->int_gamma = int_gamma;
+#endif
+ info_ptr->valid |= PNG_INFO_gAMA;
+ if(int_gamma == 0)
+ png_warning(png_ptr, "Setting gamma=0");
+}
+#endif
+
+#if defined(PNG_hIST_SUPPORTED)
+void PNGAPI
+png_set_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p hist)
+{
+ int i;
+
+ png_debug1(1, "in %s storage function\n", "hIST");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+ if (info_ptr->num_palette == 0)
+ {
+ png_warning(png_ptr,
+ "Palette size 0, hIST allocation skipped.");
+ return;
+ }
+
+#ifdef PNG_FREE_ME_SUPPORTED
+ png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0);
+#endif
+ png_ptr->hist = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(info_ptr->num_palette * sizeof (png_uint_16)));
+
+ for (i = 0; i < info_ptr->num_palette; i++)
+ png_ptr->hist[i] = hist[i];
+ info_ptr->hist = png_ptr->hist;
+ info_ptr->valid |= PNG_INFO_hIST;
+
+#ifdef PNG_FREE_ME_SUPPORTED
+ info_ptr->free_me |= PNG_FREE_HIST;
+#else
+ png_ptr->flags |= PNG_FLAG_FREE_HIST;
+#endif
+}
+#endif
+
+void PNGAPI
+png_set_IHDR(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 width, png_uint_32 height, int bit_depth,
+ int color_type, int interlace_type, int compression_type,
+ int filter_type)
+{
+ int rowbytes_per_pixel;
+ png_debug1(1, "in %s storage function\n", "IHDR");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ /* check for width and height valid values */
+ if (width == 0 || height == 0)
+ png_error(png_ptr, "Image width or height is zero in IHDR");
+ if (width > PNG_MAX_UINT || height > PNG_MAX_UINT)
+ png_error(png_ptr, "Invalid image size in IHDR");
+
+ /* check other values */
+ if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 &&
+ bit_depth != 8 && bit_depth != 16)
+ png_error(png_ptr, "Invalid bit depth in IHDR");
+
+ if (color_type < 0 || color_type == 1 ||
+ color_type == 5 || color_type > 6)
+ png_error(png_ptr, "Invalid color type in IHDR");
+
+ if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) ||
+ ((color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8))
+ png_error(png_ptr, "Invalid color type/bit depth combination in IHDR");
+
+ if (interlace_type >= PNG_INTERLACE_LAST)
+ png_error(png_ptr, "Unknown interlace method in IHDR");
+
+ if (compression_type != PNG_COMPRESSION_TYPE_BASE)
+ png_error(png_ptr, "Unknown compression method in IHDR");
+
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ /* Accept filter_method 64 (intrapixel differencing) only if
+ * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
+ * 2. Libpng did not read a PNG signature (this filter_method is only
+ * used in PNG datastreams that are embedded in MNG datastreams) and
+ * 3. The application called png_permit_mng_features with a mask that
+ * included PNG_FLAG_MNG_FILTER_64 and
+ * 4. The filter_method is 64 and
+ * 5. The color_type is RGB or RGBA
+ */
+ if((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)&&png_ptr->mng_features_permitted)
+ png_warning(png_ptr,"MNG features are not allowed in a PNG datastream\n");
+ if(filter_type != PNG_FILTER_TYPE_BASE)
+ {
+ if(!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
+ (filter_type == PNG_INTRAPIXEL_DIFFERENCING) &&
+ ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) &&
+ (color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA)))
+ png_error(png_ptr, "Unknown filter method in IHDR");
+ if(png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)
+ png_warning(png_ptr, "Invalid filter method in IHDR");
+ }
+#else
+ if(filter_type != PNG_FILTER_TYPE_BASE)
+ png_error(png_ptr, "Unknown filter method in IHDR");
+#endif
+
+ info_ptr->width = width;
+ info_ptr->height = height;
+ info_ptr->bit_depth = (png_byte)bit_depth;
+ info_ptr->color_type =(png_byte) color_type;
+ info_ptr->compression_type = (png_byte)compression_type;
+ info_ptr->filter_type = (png_byte)filter_type;
+ info_ptr->interlace_type = (png_byte)interlace_type;
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ info_ptr->channels = 1;
+ else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ info_ptr->channels = 3;
+ else
+ info_ptr->channels = 1;
+ if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
+ info_ptr->channels++;
+ info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
+
+ /* check for overflow */
+ rowbytes_per_pixel = (info_ptr->pixel_depth + 7) >> 3;
+ if (( width > PNG_MAX_UINT/rowbytes_per_pixel))
+ {
+ png_warning(png_ptr,
+ "Width too large to process image data; rowbytes will overflow.");
+ info_ptr->rowbytes = (png_size_t)0;
+ }
+ else
+ info_ptr->rowbytes = (info_ptr->width * info_ptr->pixel_depth + 7) >> 3;
+}
+
+#if defined(PNG_oFFs_SUPPORTED)
+void PNGAPI
+png_set_oFFs(png_structp png_ptr, png_infop info_ptr,
+ png_int_32 offset_x, png_int_32 offset_y, int unit_type)
+{
+ png_debug1(1, "in %s storage function\n", "oFFs");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->x_offset = offset_x;
+ info_ptr->y_offset = offset_y;
+ info_ptr->offset_unit_type = (png_byte)unit_type;
+ info_ptr->valid |= PNG_INFO_oFFs;
+}
+#endif
+
+#if defined(PNG_pCAL_SUPPORTED)
+void PNGAPI
+png_set_pCAL(png_structp png_ptr, png_infop info_ptr,
+ png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams,
+ png_charp units, png_charpp params)
+{
+ png_uint_32 length;
+ int i;
+
+ png_debug1(1, "in %s storage function\n", "pCAL");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ length = png_strlen(purpose) + 1;
+ png_debug1(3, "allocating purpose for info (%lu bytes)\n", length);
+ info_ptr->pcal_purpose = (png_charp)png_malloc(png_ptr, length);
+ png_memcpy(info_ptr->pcal_purpose, purpose, (png_size_t)length);
+
+ png_debug(3, "storing X0, X1, type, and nparams in info\n");
+ info_ptr->pcal_X0 = X0;
+ info_ptr->pcal_X1 = X1;
+ info_ptr->pcal_type = (png_byte)type;
+ info_ptr->pcal_nparams = (png_byte)nparams;
+
+ length = png_strlen(units) + 1;
+ png_debug1(3, "allocating units for info (%lu bytes)\n", length);
+ info_ptr->pcal_units = (png_charp)png_malloc(png_ptr, length);
+ png_memcpy(info_ptr->pcal_units, units, (png_size_t)length);
+
+ info_ptr->pcal_params = (png_charpp)png_malloc(png_ptr,
+ (png_uint_32)((nparams + 1) * sizeof(png_charp)));
+
+ info_ptr->pcal_params[nparams] = NULL;
+
+ for (i = 0; i < nparams; i++)
+ {
+ length = png_strlen(params[i]) + 1;
+ png_debug2(3, "allocating parameter %d for info (%lu bytes)\n", i, length);
+ info_ptr->pcal_params[i] = (png_charp)png_malloc(png_ptr, length);
+ png_memcpy(info_ptr->pcal_params[i], params[i], (png_size_t)length);
+ }
+
+ info_ptr->valid |= PNG_INFO_pCAL;
+#ifdef PNG_FREE_ME_SUPPORTED
+ info_ptr->free_me |= PNG_FREE_PCAL;
+#endif
+}
+#endif
+
+#if defined(PNG_READ_sCAL_SUPPORTED) || defined(PNG_WRITE_sCAL_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+void PNGAPI
+png_set_sCAL(png_structp png_ptr, png_infop info_ptr,
+ int unit, double width, double height)
+{
+ png_debug1(1, "in %s storage function\n", "sCAL");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->scal_unit = (png_byte)unit;
+ info_ptr->scal_pixel_width = width;
+ info_ptr->scal_pixel_height = height;
+
+ info_ptr->valid |= PNG_INFO_sCAL;
+}
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+void PNGAPI
+png_set_sCAL_s(png_structp png_ptr, png_infop info_ptr,
+ int unit, png_charp swidth, png_charp sheight)
+{
+ png_uint_32 length;
+
+ png_debug1(1, "in %s storage function\n", "sCAL");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->scal_unit = (png_byte)unit;
+
+ length = png_strlen(swidth) + 1;
+ png_debug1(3, "allocating unit for info (%d bytes)\n", length);
+ info_ptr->scal_s_width = (png_charp)png_malloc(png_ptr, length);
+ png_memcpy(info_ptr->scal_s_width, swidth, (png_size_t)length);
+
+ length = png_strlen(sheight) + 1;
+ png_debug1(3, "allocating unit for info (%d bytes)\n", length);
+ info_ptr->scal_s_height = (png_charp)png_malloc(png_ptr, length);
+ png_memcpy(info_ptr->scal_s_height, sheight, (png_size_t)length);
+
+ info_ptr->valid |= PNG_INFO_sCAL;
+#ifdef PNG_FREE_ME_SUPPORTED
+ info_ptr->free_me |= PNG_FREE_SCAL;
+#endif
+}
+#endif
+#endif
+#endif
+
+#if defined(PNG_pHYs_SUPPORTED)
+void PNGAPI
+png_set_pHYs(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 res_x, png_uint_32 res_y, int unit_type)
+{
+ png_debug1(1, "in %s storage function\n", "pHYs");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->x_pixels_per_unit = res_x;
+ info_ptr->y_pixels_per_unit = res_y;
+ info_ptr->phys_unit_type = (png_byte)unit_type;
+ info_ptr->valid |= PNG_INFO_pHYs;
+}
+#endif
+
+void PNGAPI
+png_set_PLTE(png_structp png_ptr, png_infop info_ptr,
+ png_colorp palette, int num_palette)
+{
+
+ png_debug1(1, "in %s storage function\n", "PLTE");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ /*
+ * It may not actually be necessary to set png_ptr->palette here;
+ * we do it for backward compatibility with the way the png_handle_tRNS
+ * function used to do the allocation.
+ */
+#ifdef PNG_FREE_ME_SUPPORTED
+ png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
+#endif
+ png_ptr->palette = (png_colorp)png_zalloc(png_ptr, (uInt)num_palette,
+ sizeof (png_color));
+ png_memcpy(png_ptr->palette, palette, num_palette * sizeof (png_color));
+ info_ptr->palette = png_ptr->palette;
+ info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette;
+
+#ifdef PNG_FREE_ME_SUPPORTED
+ info_ptr->free_me |= PNG_FREE_PLTE;
+#else
+ png_ptr->flags |= PNG_FLAG_FREE_PLTE;
+#endif
+
+ info_ptr->valid |= PNG_INFO_PLTE;
+}
+
+#if defined(PNG_sBIT_SUPPORTED)
+void PNGAPI
+png_set_sBIT(png_structp png_ptr, png_infop info_ptr,
+ png_color_8p sig_bit)
+{
+ png_debug1(1, "in %s storage function\n", "sBIT");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ png_memcpy(&(info_ptr->sig_bit), sig_bit, sizeof (png_color_8));
+ info_ptr->valid |= PNG_INFO_sBIT;
+}
+#endif
+
+#if defined(PNG_sRGB_SUPPORTED)
+void PNGAPI
+png_set_sRGB(png_structp png_ptr, png_infop info_ptr, int intent)
+{
+ png_debug1(1, "in %s storage function\n", "sRGB");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->srgb_intent = (png_byte)intent;
+ info_ptr->valid |= PNG_INFO_sRGB;
+}
+
+void PNGAPI
+png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr,
+ int intent)
+{
+#if defined(PNG_gAMA_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ float file_gamma;
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ png_fixed_point int_file_gamma;
+#endif
+#endif
+#if defined(PNG_cHRM_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ png_fixed_point int_white_x, int_white_y, int_red_x, int_red_y, int_green_x,
+ int_green_y, int_blue_x, int_blue_y;
+#endif
+#endif
+ png_debug1(1, "in %s storage function\n", "sRGB_gAMA_and_cHRM");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ png_set_sRGB(png_ptr, info_ptr, intent);
+
+#if defined(PNG_gAMA_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ file_gamma = (float).45455;
+ png_set_gAMA(png_ptr, info_ptr, file_gamma);
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ int_file_gamma = 45455L;
+ png_set_gAMA_fixed(png_ptr, info_ptr, int_file_gamma);
+#endif
+#endif
+
+#if defined(PNG_cHRM_SUPPORTED)
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ int_white_x = 31270L;
+ int_white_y = 32900L;
+ int_red_x = 64000L;
+ int_red_y = 33000L;
+ int_green_x = 30000L;
+ int_green_y = 60000L;
+ int_blue_x = 15000L;
+ int_blue_y = 6000L;
+
+ png_set_cHRM_fixed(png_ptr, info_ptr,
+ int_white_x, int_white_y, int_red_x, int_red_y, int_green_x, int_green_y,
+ int_blue_x, int_blue_y);
+#endif
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ white_x = (float).3127;
+ white_y = (float).3290;
+ red_x = (float).64;
+ red_y = (float).33;
+ green_x = (float).30;
+ green_y = (float).60;
+ blue_x = (float).15;
+ blue_y = (float).06;
+
+ png_set_cHRM(png_ptr, info_ptr,
+ white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
+#endif
+#endif
+}
+#endif
+
+
+#if defined(PNG_iCCP_SUPPORTED)
+void PNGAPI
+png_set_iCCP(png_structp png_ptr, png_infop info_ptr,
+ png_charp name, int compression_type,
+ png_charp profile, png_uint_32 proflen)
+{
+ png_charp new_iccp_name;
+ png_charp new_iccp_profile;
+
+ png_debug1(1, "in %s storage function\n", "iCCP");
+ if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL)
+ return;
+
+ new_iccp_name = (png_charp)png_malloc(png_ptr, png_strlen(name)+1);
+ png_strcpy(new_iccp_name, name);
+ new_iccp_profile = (png_charp)png_malloc(png_ptr, proflen);
+ png_memcpy(new_iccp_profile, profile, (png_size_t)proflen);
+
+ png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0);
+
+ info_ptr->iccp_proflen = proflen;
+ info_ptr->iccp_name = new_iccp_name;
+ info_ptr->iccp_profile = new_iccp_profile;
+ /* Compression is always zero but is here so the API and info structure
+ * does not have to change if we introduce multiple compression types */
+ info_ptr->iccp_compression = (png_byte)compression_type;
+#ifdef PNG_FREE_ME_SUPPORTED
+ info_ptr->free_me |= PNG_FREE_ICCP;
+#endif
+ info_ptr->valid |= PNG_INFO_iCCP;
+}
+#endif
+
+#if defined(PNG_TEXT_SUPPORTED)
+void PNGAPI
+png_set_text(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr,
+ int num_text)
+{
+ int i;
+
+ png_debug1(1, "in %s storage function\n", (png_ptr->chunk_name[0] == '\0' ?
+ "text" : (png_const_charp)png_ptr->chunk_name));
+
+ if (png_ptr == NULL || info_ptr == NULL || num_text == 0)
+ return;
+
+ /* Make sure we have enough space in the "text" array in info_struct
+ * to hold all of the incoming text_ptr objects.
+ */
+ if (info_ptr->num_text + num_text > info_ptr->max_text)
+ {
+ if (info_ptr->text != NULL)
+ {
+ png_textp old_text;
+ int old_max;
+
+ old_max = info_ptr->max_text;
+ info_ptr->max_text = info_ptr->num_text + num_text + 8;
+ old_text = info_ptr->text;
+ info_ptr->text = (png_textp)png_malloc(png_ptr,
+ (png_uint_32)(info_ptr->max_text * sizeof (png_text)));
+ png_memcpy(info_ptr->text, old_text, (png_size_t)(old_max *
+ sizeof(png_text)));
+ png_free(png_ptr, old_text);
+ }
+ else
+ {
+ info_ptr->max_text = num_text + 8;
+ info_ptr->num_text = 0;
+ info_ptr->text = (png_textp)png_malloc(png_ptr,
+ (png_uint_32)(info_ptr->max_text * sizeof (png_text)));
+#ifdef PNG_FREE_ME_SUPPORTED
+ info_ptr->free_me |= PNG_FREE_TEXT;
+#endif
+ }
+ png_debug1(3, "allocated %d entries for info_ptr->text\n",
+ info_ptr->max_text);
+ }
+ for (i = 0; i < num_text; i++)
+ {
+ png_size_t text_length,key_len;
+ png_size_t lang_len,lang_key_len;
+ png_textp textp = &(info_ptr->text[info_ptr->num_text]);
+
+ if (text_ptr[i].key == NULL)
+ continue;
+
+ key_len = png_strlen(text_ptr[i].key);
+
+ if(text_ptr[i].compression <= 0)
+ {
+ lang_len = 0;
+ lang_key_len = 0;
+ }
+ else
+#ifdef PNG_iTXt_SUPPORTED
+ {
+ /* set iTXt data */
+ if (text_ptr[i].key != NULL)
+ lang_len = png_strlen(text_ptr[i].lang);
+ else
+ lang_len = 0;
+ if (text_ptr[i].lang_key != NULL)
+ lang_key_len = png_strlen(text_ptr[i].lang_key);
+ else
+ lang_key_len = 0;
+ }
+#else
+ {
+ png_warning(png_ptr, "iTXt chunk not supported.");
+ continue;
+ }
+#endif
+
+ if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0')
+ {
+ text_length = 0;
+#ifdef PNG_iTXt_SUPPORTED
+ if(text_ptr[i].compression > 0)
+ textp->compression = PNG_ITXT_COMPRESSION_NONE;
+ else
+#endif
+ textp->compression = PNG_TEXT_COMPRESSION_NONE;
+ }
+ else
+ {
+ text_length = png_strlen(text_ptr[i].text);
+ textp->compression = text_ptr[i].compression;
+ }
+
+ textp->key = (png_charp)png_malloc(png_ptr,
+ (png_uint_32)(key_len + text_length + lang_len + lang_key_len + 4));
+ png_debug2(2, "Allocated %lu bytes at %x in png_set_text\n",
+ (png_uint_32)(key_len + lang_len + lang_key_len + text_length + 4),
+ (int)textp->key);
+
+ png_memcpy(textp->key, text_ptr[i].key,
+ (png_size_t)(key_len));
+ *(textp->key+key_len) = '\0';
+#ifdef PNG_iTXt_SUPPORTED
+ if (text_ptr[i].compression > 0)
+ {
+ textp->lang=textp->key + key_len + 1;
+ png_memcpy(textp->lang, text_ptr[i].lang, lang_len);
+ *(textp->lang+lang_len) = '\0';
+ textp->lang_key=textp->lang + lang_len + 1;
+ png_memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len);
+ *(textp->lang_key+lang_key_len) = '\0';
+ textp->text=textp->lang_key + lang_key_len + 1;
+ }
+ else
+#endif
+ {
+#ifdef PNG_iTXt_SUPPORTED
+ textp->lang=(png_charp)NULL;
+ textp->lang_key=(png_charp)NULL;
+#endif
+ textp->text=textp->key + key_len + 1;
+ }
+ if(text_length)
+ png_memcpy(textp->text, text_ptr[i].text,
+ (png_size_t)(text_length));
+ *(textp->text+text_length) = '\0';
+
+#ifdef PNG_iTXt_SUPPORTED
+ if(textp->compression > 0)
+ {
+ textp->text_length = 0;
+ textp->itxt_length = text_length;
+ }
+ else
+#endif
+ {
+ textp->text_length = text_length;
+#ifdef PNG_iTXt_SUPPORTED
+ textp->itxt_length = 0;
+#endif
+ }
+ info_ptr->text[info_ptr->num_text]= *textp;
+ info_ptr->num_text++;
+ png_debug1(3, "transferred text chunk %d\n", info_ptr->num_text);
+ }
+}
+#endif
+
+#if defined(PNG_tIME_SUPPORTED)
+void PNGAPI
+png_set_tIME(png_structp png_ptr, png_infop info_ptr, png_timep mod_time)
+{
+ png_debug1(1, "in %s storage function\n", "tIME");
+ if (png_ptr == NULL || info_ptr == NULL ||
+ (png_ptr->mode & PNG_WROTE_tIME))
+ return;
+
+ png_memcpy(&(info_ptr->mod_time), mod_time, sizeof (png_time));
+ info_ptr->valid |= PNG_INFO_tIME;
+}
+#endif
+
+#if defined(PNG_tRNS_SUPPORTED)
+void PNGAPI
+png_set_tRNS(png_structp png_ptr, png_infop info_ptr,
+ png_bytep trans, int num_trans, png_color_16p trans_values)
+{
+ png_debug1(1, "in %s storage function\n", "tRNS");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ if (trans != NULL)
+ {
+ /*
+ * It may not actually be necessary to set png_ptr->trans here;
+ * we do it for backward compatibility with the way the png_handle_tRNS
+ * function used to do the allocation.
+ */
+#ifdef PNG_FREE_ME_SUPPORTED
+ png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
+#endif
+ png_ptr->trans = info_ptr->trans = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)num_trans);
+ png_memcpy(info_ptr->trans, trans, (png_size_t)num_trans);
+#ifdef PNG_FREE_ME_SUPPORTED
+ info_ptr->free_me |= PNG_FREE_TRNS;
+#else
+ png_ptr->flags |= PNG_FLAG_FREE_TRNS;
+#endif
+ }
+
+ if (trans_values != NULL)
+ {
+ png_memcpy(&(info_ptr->trans_values), trans_values,
+ sizeof(png_color_16));
+ if (num_trans == 0)
+ num_trans = 1;
+ }
+ info_ptr->num_trans = (png_uint_16)num_trans;
+ info_ptr->valid |= PNG_INFO_tRNS;
+}
+#endif
+
+#if defined(PNG_sPLT_SUPPORTED)
+void PNGAPI
+png_set_sPLT(png_structp png_ptr,
+ png_infop info_ptr, png_sPLT_tp entries, int nentries)
+{
+ png_sPLT_tp np;
+ int i;
+
+ np = (png_sPLT_tp)png_malloc(png_ptr,
+ (info_ptr->splt_palettes_num + nentries) * sizeof(png_sPLT_t));
+
+ png_memcpy(np, info_ptr->splt_palettes,
+ info_ptr->splt_palettes_num * sizeof(png_sPLT_t));
+ png_free(png_ptr, info_ptr->splt_palettes);
+ info_ptr->splt_palettes=NULL;
+
+ for (i = 0; i < nentries; i++)
+ {
+ png_sPLT_tp to = np + info_ptr->splt_palettes_num + i;
+ png_sPLT_tp from = entries + i;
+
+ to->name = (png_charp)png_malloc(png_ptr,
+ png_strlen(from->name) + 1);
+ png_strcpy(to->name, from->name);
+ to->entries = (png_sPLT_entryp)png_malloc(png_ptr,
+ from->nentries * sizeof(png_sPLT_t));
+ png_memcpy(to->entries, from->entries,
+ from->nentries * sizeof(png_sPLT_t));
+ to->nentries = from->nentries;
+ to->depth = from->depth;
+ }
+
+ info_ptr->splt_palettes = np;
+ info_ptr->splt_palettes_num += nentries;
+ info_ptr->valid |= PNG_INFO_sPLT;
+#ifdef PNG_FREE_ME_SUPPORTED
+ info_ptr->free_me |= PNG_FREE_SPLT;
+#endif
+}
+#endif /* PNG_sPLT_SUPPORTED */
+
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+void PNGAPI
+png_set_unknown_chunks(png_structp png_ptr,
+ png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns)
+{
+ png_unknown_chunkp np;
+ int i;
+
+ if (png_ptr == NULL || info_ptr == NULL || num_unknowns == 0)
+ return;
+
+ np = (png_unknown_chunkp)png_malloc(png_ptr,
+ (info_ptr->unknown_chunks_num + num_unknowns) *
+ sizeof(png_unknown_chunk));
+
+ png_memcpy(np, info_ptr->unknown_chunks,
+ info_ptr->unknown_chunks_num * sizeof(png_unknown_chunk));
+ png_free(png_ptr, info_ptr->unknown_chunks);
+ info_ptr->unknown_chunks=NULL;
+
+ for (i = 0; i < num_unknowns; i++)
+ {
+ png_unknown_chunkp to = np + info_ptr->unknown_chunks_num + i;
+ png_unknown_chunkp from = unknowns + i;
+
+ png_strcpy((png_charp)to->name, (png_charp)from->name);
+ to->data = (png_bytep)png_malloc(png_ptr, from->size);
+ png_memcpy(to->data, from->data, from->size);
+ to->size = from->size;
+
+ /* note our location in the read or write sequence */
+ to->location = (png_byte)(png_ptr->mode & 0xff);
+ }
+
+ info_ptr->unknown_chunks = np;
+ info_ptr->unknown_chunks_num += num_unknowns;
+#ifdef PNG_FREE_ME_SUPPORTED
+ info_ptr->free_me |= PNG_FREE_UNKN;
+#endif
+}
+void PNGAPI
+png_set_unknown_chunk_location(png_structp png_ptr, png_infop info_ptr,
+ int chunk, int location)
+{
+ if(png_ptr != NULL && info_ptr != NULL && chunk >= 0 && chunk <
+ (int)info_ptr->unknown_chunks_num)
+ info_ptr->unknown_chunks[chunk].location = (png_byte)location;
+}
+#endif
+
+#if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \
+ defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED)
+void PNGAPI
+png_permit_empty_plte (png_structp png_ptr, int empty_plte_permitted)
+{
+ /* This function is deprecated in favor of png_permit_mng_features()
+ and will be removed from libpng-2.0.0 */
+ png_debug(1, "in png_permit_empty_plte, DEPRECATED.\n");
+ if (png_ptr == NULL)
+ return;
+ png_ptr->mng_features_permitted = (png_byte)
+ ((png_ptr->mng_features_permitted & (~(PNG_FLAG_MNG_EMPTY_PLTE))) |
+ ((empty_plte_permitted & PNG_FLAG_MNG_EMPTY_PLTE)));
+}
+#endif
+
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+png_uint_32 PNGAPI
+png_permit_mng_features (png_structp png_ptr, png_uint_32 mng_features)
+{
+ png_debug(1, "in png_permit_mng_features\n");
+ if (png_ptr == NULL)
+ return (png_uint_32)0;
+ png_ptr->mng_features_permitted =
+ (png_byte)(mng_features & PNG_ALL_MNG_FEATURES);
+ return (png_uint_32)png_ptr->mng_features_permitted;
+}
+#endif
+
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+void PNGAPI
+png_set_keep_unknown_chunks(png_structp png_ptr, int keep, png_bytep
+ chunk_list, int num_chunks)
+{
+ png_bytep new_list, p;
+ int i, old_num_chunks;
+ if (num_chunks == 0)
+ {
+ if(keep == HANDLE_CHUNK_ALWAYS || keep == HANDLE_CHUNK_IF_SAFE)
+ png_ptr->flags |= PNG_FLAG_KEEP_UNKNOWN_CHUNKS;
+ else
+ png_ptr->flags &= ~PNG_FLAG_KEEP_UNKNOWN_CHUNKS;
+
+ if(keep == HANDLE_CHUNK_ALWAYS)
+ png_ptr->flags |= PNG_FLAG_KEEP_UNSAFE_CHUNKS;
+ else
+ png_ptr->flags &= ~PNG_FLAG_KEEP_UNSAFE_CHUNKS;
+ return;
+ }
+ if (chunk_list == NULL)
+ return;
+ old_num_chunks=png_ptr->num_chunk_list;
+ new_list=(png_bytep)png_malloc(png_ptr,
+ (png_uint_32)(5*(num_chunks+old_num_chunks)));
+ if(png_ptr->chunk_list != NULL)
+ {
+ png_memcpy(new_list, png_ptr->chunk_list,
+ (png_size_t)(5*old_num_chunks));
+ png_free(png_ptr, png_ptr->chunk_list);
+ png_ptr->chunk_list=NULL;
+ }
+ png_memcpy(new_list+5*old_num_chunks, chunk_list,
+ (png_size_t)(5*num_chunks));
+ for (p=new_list+5*old_num_chunks+4, i=0; i<num_chunks; i++, p+=5)
+ *p=(png_byte)keep;
+ png_ptr->num_chunk_list=old_num_chunks+num_chunks;
+ png_ptr->chunk_list=new_list;
+#ifdef PNG_FREE_ME_SUPPORTED
+ png_ptr->free_me |= PNG_FREE_LIST;
+#endif
+}
+#endif
+
+#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
+void PNGAPI
+png_set_read_user_chunk_fn(png_structp png_ptr, png_voidp user_chunk_ptr,
+ png_user_chunk_ptr read_user_chunk_fn)
+{
+ png_debug(1, "in png_set_read_user_chunk_fn\n");
+ png_ptr->read_user_chunk_fn = read_user_chunk_fn;
+ png_ptr->user_chunk_ptr = user_chunk_ptr;
+}
+#endif
+
+#if defined(PNG_INFO_IMAGE_SUPPORTED)
+void PNGAPI
+png_set_rows(png_structp png_ptr, png_infop info_ptr, png_bytepp row_pointers)
+{
+ png_debug1(1, "in %s storage function\n", "rows");
+
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ if(info_ptr->row_pointers && (info_ptr->row_pointers != row_pointers))
+ png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
+ info_ptr->row_pointers = row_pointers;
+ if(row_pointers)
+ info_ptr->valid |= PNG_INFO_IDAT;
+}
+#endif
+
+void PNGAPI
+png_set_compression_buffer_size(png_structp png_ptr, png_uint_32 size)
+{
+ if(png_ptr->zbuf)
+ png_free(png_ptr, png_ptr->zbuf);
+ png_ptr->zbuf_size = (png_size_t)size;
+ png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, size);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+}
+
+void PNGAPI
+png_set_invalid(png_structp png_ptr, png_infop info_ptr, int mask)
+{
+ if (png_ptr && info_ptr)
+ info_ptr->valid &= ~(mask);
+}
+
+
+#ifdef PNG_ASSEMBLER_CODE_SUPPORTED
+/* this function was added to libpng 1.2.0 and should always exist by default */
+void PNGAPI
+png_set_asm_flags (png_structp png_ptr, png_uint_32 asm_flags)
+{
+ png_uint_32 settable_asm_flags;
+ png_uint_32 settable_mmx_flags;
+
+ settable_mmx_flags =
+#ifdef PNG_HAVE_ASSEMBLER_COMBINE_ROW
+ PNG_ASM_FLAG_MMX_READ_COMBINE_ROW |
+#endif
+#ifdef PNG_HAVE_ASSEMBLER_READ_INTERLACE
+ PNG_ASM_FLAG_MMX_READ_INTERLACE |
+#endif
+#ifdef PNG_HAVE_ASSEMBLER_READ_FILTER_ROW
+ PNG_ASM_FLAG_MMX_READ_FILTER_SUB |
+ PNG_ASM_FLAG_MMX_READ_FILTER_UP |
+ PNG_ASM_FLAG_MMX_READ_FILTER_AVG |
+ PNG_ASM_FLAG_MMX_READ_FILTER_PAETH |
+#endif
+ 0;
+
+ /* could be some non-MMX ones in the future, but not currently: */
+ settable_asm_flags = settable_mmx_flags;
+
+ if (!(png_ptr->asm_flags & PNG_ASM_FLAG_MMX_SUPPORT_COMPILED) ||
+ !(png_ptr->asm_flags & PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU))
+ {
+ /* clear all MMX flags if MMX isn't supported */
+ settable_asm_flags &= ~settable_mmx_flags;
+ png_ptr->asm_flags &= ~settable_mmx_flags;
+ }
+
+ /* we're replacing the settable bits with those passed in by the user,
+ * so first zero them out of the master copy, then logical-OR in the
+ * allowed subset that was requested */
+
+ png_ptr->asm_flags &= ~settable_asm_flags; /* zero them */
+ png_ptr->asm_flags |= (asm_flags & settable_asm_flags); /* set them */
+}
+#endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */
+
+#ifdef PNG_ASSEMBLER_CODE_SUPPORTED
+/* this function was added to libpng 1.2.0 */
+void PNGAPI
+png_set_mmx_thresholds (png_structp png_ptr,
+ png_byte mmx_bitdepth_threshold,
+ png_uint_32 mmx_rowbytes_threshold)
+{
+ png_ptr->mmx_bitdepth_threshold = mmx_bitdepth_threshold;
+ png_ptr->mmx_rowbytes_threshold = mmx_rowbytes_threshold;
+}
+#endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */
--- /dev/null
+
+/* pngtest.c - a simple test program to test libpng
+ *
+ * libpng 1.2.0 - September 1, 2001
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ *
+ * This program reads in a PNG image, writes it out again, and then
+ * compares the two files. If the files are identical, this shows that
+ * the basic chunk handling, filtering, and (de)compression code is working
+ * properly. It does not currently test all of the transforms, although
+ * it probably should.
+ *
+ * The program will report "FAIL" in certain legitimate cases:
+ * 1) when the compression level or filter selection method is changed.
+ * 2) when the maximum IDAT size (PNG_ZBUF_SIZE in pngconf.h) is not 8192.
+ * 3) unknown unsafe-to-copy ancillary chunks or unknown critical chunks
+ * exist in the input file.
+ * 4) others not listed here...
+ * In these cases, it is best to check with another tool such as "pngcheck"
+ * to see what the differences between the two files are.
+ *
+ * If a filename is given on the command-line, then this file is used
+ * for the input, rather than the default "pngtest.png". This allows
+ * testing a wide variety of files easily. You can also test a number
+ * of files at once by typing "pngtest -m file1.png file2.png ..."
+ */
+
+#if defined(_WIN32_WCE)
+# if _WIN32_WCE < 211
+ __error__ (f|w)printf functions are not supported on old WindowsCE.;
+# endif
+# include <windows.h>
+# include <stdlib.h>
+# define READFILE(file, data, length, check) \
+ if (ReadFile(file, data, length, &check,NULL)) check = 0
+# define WRITEFILE(file, data, length, check)) \
+ if (WriteFile(file, data, length, &check, NULL)) check = 0
+# define FCLOSE(file) CloseHandle(file)
+#else
+# include <stdio.h>
+# include <stdlib.h>
+# include <assert.h>
+# define READFILE(file, data, length, check) \
+ check=(png_size_t)fread(data,(png_size_t)1,length,file)
+# define WRITEFILE(file, data, length, check) \
+ check=(png_size_t)fwrite(data,(png_size_t)1, length, file)
+# define FCLOSE(file) fclose(file)
+#endif
+
+#if defined(PNG_NO_STDIO)
+# if defined(_WIN32_WCE)
+ typedef HANDLE png_FILE_p;
+# else
+ typedef FILE * png_FILE_p;
+# endif
+#endif
+
+/* Makes pngtest verbose so we can find problems (needs to be before png.h) */
+#ifndef PNG_DEBUG
+# define PNG_DEBUG 0
+#endif
+
+#if !PNG_DEBUG
+# define SINGLE_ROWBUF_ALLOC /* makes buffer overruns easier to nail */
+#endif
+
+/* Turn on CPU timing
+#define PNGTEST_TIMING
+*/
+
+#ifdef PNG_NO_FLOATING_POINT_SUPPORTED
+#undef PNGTEST_TIMING
+#endif
+
+#ifdef PNGTEST_TIMING
+static float t_start, t_stop, t_decode, t_encode, t_misc;
+#include <time.h>
+#endif
+
+#include "png.h"
+
+/* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */
+#ifndef png_jmpbuf
+# define png_jmpbuf(png_ptr) png_ptr->jmpbuf
+#endif
+
+#ifdef PNGTEST_TIMING
+static float t_start, t_stop, t_decode, t_encode, t_misc;
+#if !defined(PNG_tIME_SUPPORTED)
+#include <time.h>
+#endif
+#endif
+
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+static int tIME_chunk_present=0;
+static char tIME_string[30] = "no tIME chunk present in file";
+#endif
+
+static int verbose = 0;
+
+int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname));
+
+#ifdef __TURBOC__
+#include <mem.h>
+#endif
+
+/* defined so I can write to a file on gui/windowing platforms */
+/* #define STDERR stderr */
+#define STDERR stdout /* for DOS */
+
+/* example of using row callbacks to make a simple progress meter */
+static int status_pass=1;
+static int status_dots_requested=0;
+static int status_dots=1;
+
+void
+read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
+void
+read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
+{
+ if(png_ptr == NULL || row_number > PNG_MAX_UINT) return;
+ if(status_pass != pass)
+ {
+ fprintf(stdout,"\n Pass %d: ",pass);
+ status_pass = pass;
+ status_dots = 31;
+ }
+ status_dots--;
+ if(status_dots == 0)
+ {
+ fprintf(stdout, "\n ");
+ status_dots=30;
+ }
+ fprintf(stdout, "r");
+}
+
+void
+write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
+void
+write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
+{
+ if(png_ptr == NULL || row_number > PNG_MAX_UINT || pass > 7) return;
+ fprintf(stdout, "w");
+}
+
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
+/* Example of using user transform callback (we don't transform anything,
+ but merely examine the row filters. We set this to 256 rather than
+ 5 in case illegal filter values are present.) */
+static png_uint_32 filters_used[256];
+void
+count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data);
+void
+count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data)
+{
+ if(png_ptr != NULL && row_info != NULL)
+ ++filters_used[*(data-1)];
+}
+#endif
+
+#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+/* example of using user transform callback (we don't transform anything,
+ but merely count the zero samples) */
+
+static png_uint_32 zero_samples;
+
+void
+count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data);
+void
+count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
+{
+ png_bytep dp = data;
+ if(png_ptr == NULL)return;
+
+ /* contents of row_info:
+ * png_uint_32 width width of row
+ * png_uint_32 rowbytes number of bytes in row
+ * png_byte color_type color type of pixels
+ * png_byte bit_depth bit depth of samples
+ * png_byte channels number of channels (1-4)
+ * png_byte pixel_depth bits per pixel (depth*channels)
+ */
+
+
+ /* counts the number of zero samples (or zero pixels if color_type is 3 */
+
+ if(row_info->color_type == 0 || row_info->color_type == 3)
+ {
+ int pos=0;
+ png_uint_32 n, nstop;
+ for (n=0, nstop=row_info->width; n<nstop; n++)
+ {
+ if(row_info->bit_depth == 1)
+ {
+ if(((*dp << pos++ ) & 0x80) == 0) zero_samples++;
+ if(pos == 8)
+ {
+ pos = 0;
+ dp++;
+ }
+ }
+ if(row_info->bit_depth == 2)
+ {
+ if(((*dp << (pos+=2)) & 0xc0) == 0) zero_samples++;
+ if(pos == 8)
+ {
+ pos = 0;
+ dp++;
+ }
+ }
+ if(row_info->bit_depth == 4)
+ {
+ if(((*dp << (pos+=4)) & 0xf0) == 0) zero_samples++;
+ if(pos == 8)
+ {
+ pos = 0;
+ dp++;
+ }
+ }
+ if(row_info->bit_depth == 8)
+ if(*dp++ == 0) zero_samples++;
+ if(row_info->bit_depth == 16)
+ {
+ if((*dp | *(dp+1)) == 0) zero_samples++;
+ dp+=2;
+ }
+ }
+ }
+ else /* other color types */
+ {
+ png_uint_32 n, nstop;
+ int channel;
+ int color_channels = row_info->channels;
+ if(row_info->color_type > 3)color_channels--;
+
+ for (n=0, nstop=row_info->width; n<nstop; n++)
+ {
+ for (channel = 0; channel < color_channels; channel++)
+ {
+ if(row_info->bit_depth == 8)
+ if(*dp++ == 0) zero_samples++;
+ if(row_info->bit_depth == 16)
+ {
+ if((*dp | *(dp+1)) == 0) zero_samples++;
+ dp+=2;
+ }
+ }
+ if(row_info->color_type > 3)
+ {
+ dp++;
+ if(row_info->bit_depth == 16)dp++;
+ }
+ }
+ }
+}
+#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */
+
+static int wrote_question = 0;
+
+#if defined(PNG_NO_STDIO)
+/* START of code to validate stdio-free compilation */
+/* These copies of the default read/write functions come from pngrio.c and */
+/* pngwio.c. They allow "don't include stdio" testing of the library. */
+/* This is the function that does the actual reading of data. If you are
+ not reading from a standard C stream, you should create a replacement
+ read_data function and use it at run time with png_set_read_fn(), rather
+ than changing the library. */
+
+#ifndef USE_FAR_KEYWORD
+static void
+pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_size_t check;
+
+ /* fread() returns 0 on error, so it is OK to store this in a png_size_t
+ * instead of an int, which is what fread() actually returns.
+ */
+ READFILE((png_FILE_p)png_ptr->io_ptr, data, length, check);
+
+ if (check != length)
+ {
+ png_error(png_ptr, "Read Error!");
+ }
+}
+#else
+/* this is the model-independent version. Since the standard I/O library
+ can't handle far buffers in the medium and small models, we have to copy
+ the data.
+*/
+
+#define NEAR_BUF_SIZE 1024
+#define MIN(a,b) (a <= b ? a : b)
+
+static void
+pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ int check;
+ png_byte *n_data;
+ png_FILE_p io_ptr;
+
+ /* Check if data really is near. If so, use usual code. */
+ n_data = (png_byte *)CVT_PTR_NOCHECK(data);
+ io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
+ if ((png_bytep)n_data == data)
+ {
+ READFILE(io_ptr, n_data, length, check);
+ }
+ else
+ {
+ png_byte buf[NEAR_BUF_SIZE];
+ png_size_t read, remaining, err;
+ check = 0;
+ remaining = length;
+ do
+ {
+ read = MIN(NEAR_BUF_SIZE, remaining);
+ READFILE(io_ptr, buf, 1, err);
+ png_memcpy(data, buf, read); /* copy far buffer to near buffer */
+ if(err != read)
+ break;
+ else
+ check += err;
+ data += read;
+ remaining -= read;
+ }
+ while (remaining != 0);
+ }
+ if (check != length)
+ {
+ png_error(png_ptr, "read Error");
+ }
+}
+#endif /* USE_FAR_KEYWORD */
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+static void
+pngtest_flush(png_structp png_ptr)
+{
+#if !defined(_WIN32_WCE)
+ png_FILE_p io_ptr;
+ io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr));
+ if (io_ptr != NULL)
+ fflush(io_ptr);
+#endif
+}
+#endif
+
+/* This is the function that does the actual writing of data. If you are
+ not writing to a standard C stream, you should create a replacement
+ write_data function and use it at run time with png_set_write_fn(), rather
+ than changing the library. */
+#ifndef USE_FAR_KEYWORD
+static void
+pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_uint_32 check;
+
+ WRITEFILE((png_FILE_p)png_ptr->io_ptr, data, length, check);
+ if (check != length)
+ {
+ png_error(png_ptr, "Write Error");
+ }
+}
+#else
+/* this is the model-independent version. Since the standard I/O library
+ can't handle far buffers in the medium and small models, we have to copy
+ the data.
+*/
+
+#define NEAR_BUF_SIZE 1024
+#define MIN(a,b) (a <= b ? a : b)
+
+static void
+pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_uint_32 check;
+ png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */
+ png_FILE_p io_ptr;
+
+ /* Check if data really is near. If so, use usual code. */
+ near_data = (png_byte *)CVT_PTR_NOCHECK(data);
+ io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
+ if ((png_bytep)near_data == data)
+ {
+ WRITEFILE(io_ptr, near_data, length, check);
+ }
+ else
+ {
+ png_byte buf[NEAR_BUF_SIZE];
+ png_size_t written, remaining, err;
+ check = 0;
+ remaining = length;
+ do
+ {
+ written = MIN(NEAR_BUF_SIZE, remaining);
+ png_memcpy(buf, data, written); /* copy far buffer to near buffer */
+ WRITEFILE(io_ptr, buf, written, err);
+ if (err != written)
+ break;
+ else
+ check += err;
+ data += written;
+ remaining -= written;
+ }
+ while (remaining != 0);
+ }
+ if (check != length)
+ {
+ png_error(png_ptr, "Write Error");
+ }
+}
+
+#endif /* USE_FAR_KEYWORD */
+
+/* This function is called when there is a warning, but the library thinks
+ * it can continue anyway. Replacement functions don't have to do anything
+ * here if you don't want to. In the default configuration, png_ptr is
+ * not used, but it is passed in case it may be useful.
+ */
+static void
+pngtest_warning(png_structp png_ptr, png_const_charp message)
+{
+ PNG_CONST char *name = "UNKNOWN (ERROR!)";
+ if (png_ptr != NULL && png_ptr->error_ptr != NULL)
+ name = png_ptr->error_ptr;
+ fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
+}
+
+/* This is the default error handling function. Note that replacements for
+ * this function MUST NOT RETURN, or the program will likely crash. This
+ * function is used by default, or if the program supplies NULL for the
+ * error function pointer in png_set_error_fn().
+ */
+static void
+pngtest_error(png_structp png_ptr, png_const_charp message)
+{
+ pngtest_warning(png_ptr, message);
+ /* We can return because png_error calls the default handler, which is
+ * actually OK in this case. */
+}
+#endif /* PNG_NO_STDIO */
+/* END of code to validate stdio-free compilation */
+
+/* START of code to validate memory allocation and deallocation */
+#ifdef PNG_USER_MEM_SUPPORTED
+
+/* Allocate memory. For reasonable files, size should never exceed
+ 64K. However, zlib may allocate more then 64K if you don't tell
+ it not to. See zconf.h and png.h for more information. zlib does
+ need to allocate exactly 64K, so whatever you call here must
+ have the ability to do that.
+
+ This piece of code can be compiled to validate max 64K allocations
+ by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K. */
+typedef struct memory_information
+{
+ png_uint_32 size;
+ png_voidp pointer;
+ struct memory_information FAR *next;
+} memory_information;
+typedef memory_information FAR *memory_infop;
+
+static memory_infop pinformation = NULL;
+static int current_allocation = 0;
+static int maximum_allocation = 0;
+static int total_allocation = 0;
+static int num_allocations = 0;
+
+png_voidp png_debug_malloc PNGARG((png_structp png_ptr, png_uint_32 size));
+void png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr));
+
+png_voidp
+png_debug_malloc(png_structp png_ptr, png_uint_32 size)
+{
+
+ /* png_malloc has already tested for NULL; png_create_struct calls
+ png_debug_malloc directly, with png_ptr == NULL which is OK */
+
+ if (size == 0)
+ return (png_voidp)(NULL);
+
+ /* This calls the library allocator twice, once to get the requested
+ buffer and once to get a new free list entry. */
+ {
+ memory_infop pinfo = (memory_infop)png_malloc_default(png_ptr,
+ (png_uint_32)sizeof *pinfo);
+ pinfo->size = size;
+ current_allocation += size;
+ total_allocation += size;
+ num_allocations ++;
+ if (current_allocation > maximum_allocation)
+ maximum_allocation = current_allocation;
+ pinfo->pointer = (png_voidp)png_malloc_default(png_ptr, size);
+ pinfo->next = pinformation;
+ pinformation = pinfo;
+ /* Make sure the caller isn't assuming zeroed memory. */
+ png_memset(pinfo->pointer, 0xdd, pinfo->size);
+#if PNG_DEBUG
+ if(verbose)
+ printf("png_malloc %lu bytes at %x\n",size,pinfo->pointer);
+#endif
+ assert(pinfo->size != 12345678);
+ return (png_voidp)(pinfo->pointer);
+ }
+}
+
+/* Free a pointer. It is removed from the list at the same time. */
+void
+png_debug_free(png_structp png_ptr, png_voidp ptr)
+{
+ if (png_ptr == NULL)
+ fprintf(STDERR, "NULL pointer to png_debug_free.\n");
+ if (ptr == 0)
+ {
+#if 0 /* This happens all the time. */
+ fprintf(STDERR, "WARNING: freeing NULL pointer\n");
+#endif
+ return;
+ }
+
+ /* Unlink the element from the list. */
+ {
+ memory_infop FAR *ppinfo = &pinformation;
+ for (;;)
+ {
+ memory_infop pinfo = *ppinfo;
+ if (pinfo->pointer == ptr)
+ {
+ *ppinfo = pinfo->next;
+ current_allocation -= pinfo->size;
+ if (current_allocation < 0)
+ fprintf(STDERR, "Duplicate free of memory\n");
+ /* We must free the list element too, but first kill
+ the memory that is to be freed. */
+ png_memset(ptr, 0x55, pinfo->size);
+ png_free_default(png_ptr, pinfo);
+ pinfo=NULL;
+ break;
+ }
+ if (pinfo->next == NULL)
+ {
+ fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr);
+ break;
+ }
+ ppinfo = &pinfo->next;
+ }
+ }
+
+ /* Finally free the data. */
+#if PNG_DEBUG
+ if(verbose)
+ printf("Freeing %x\n",ptr);
+#endif
+ png_free_default(png_ptr, ptr);
+ ptr=NULL;
+}
+#endif /* PNG_USER_MEM_SUPPORTED */
+/* END of code to test memory allocation/deallocation */
+
+/* Test one file */
+int
+test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
+{
+ static png_FILE_p fpin;
+ static png_FILE_p fpout; /* "static" prevents setjmp corruption */
+ png_structp read_ptr;
+ png_infop read_info_ptr, end_info_ptr;
+#ifdef PNG_WRITE_SUPPORTED
+ png_structp write_ptr;
+ png_infop write_info_ptr;
+ png_infop write_end_info_ptr;
+#else
+ png_structp write_ptr = NULL;
+ png_infop write_info_ptr = NULL;
+ png_infop write_end_info_ptr = NULL;
+#endif
+ png_bytep row_buf;
+ png_uint_32 y;
+ png_uint_32 width, height;
+ int num_pass, pass;
+ int bit_depth, color_type;
+#ifdef PNG_SETJMP_SUPPORTED
+#ifdef USE_FAR_KEYWORD
+ jmp_buf jmpbuf;
+#endif
+#endif
+
+#if defined(_WIN32_WCE)
+ TCHAR path[MAX_PATH];
+#endif
+ char inbuf[256], outbuf[256];
+
+ row_buf = (png_bytep)NULL;
+
+#if defined(_WIN32_WCE)
+ MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH);
+ if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
+#else
+ if ((fpin = fopen(inname, "rb")) == NULL)
+#endif
+ {
+ fprintf(STDERR, "Could not find input file %s\n", inname);
+ return (1);
+ }
+
+#if defined(_WIN32_WCE)
+ MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH);
+ if ((fpout = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL)) == INVALID_HANDLE_VALUE)
+#else
+ if ((fpout = fopen(outname, "wb")) == NULL)
+#endif
+ {
+ fprintf(STDERR, "Could not open output file %s\n", outname);
+ FCLOSE(fpin);
+ return (1);
+ }
+
+ png_debug(0, "Allocating read and write structures\n");
+#ifdef PNG_USER_MEM_SUPPORTED
+ read_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
+ (png_error_ptr)NULL, (png_error_ptr)NULL, (png_voidp)NULL,
+ (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
+#else
+ read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
+ (png_error_ptr)NULL, (png_error_ptr)NULL);
+#endif
+#if defined(PNG_NO_STDIO)
+ png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error,
+ pngtest_warning);
+#endif
+#ifdef PNG_WRITE_SUPPORTED
+#ifdef PNG_USER_MEM_SUPPORTED
+ write_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
+ (png_error_ptr)NULL, (png_error_ptr)NULL, (png_voidp)NULL,
+ (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
+#else
+ write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
+ (png_error_ptr)NULL, (png_error_ptr)NULL);
+#endif
+#if defined(PNG_NO_STDIO)
+ png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error,
+ pngtest_warning);
+#endif
+#endif
+ png_debug(0, "Allocating read_info, write_info and end_info structures\n");
+ read_info_ptr = png_create_info_struct(read_ptr);
+ end_info_ptr = png_create_info_struct(read_ptr);
+#ifdef PNG_WRITE_SUPPORTED
+ write_info_ptr = png_create_info_struct(write_ptr);
+ write_end_info_ptr = png_create_info_struct(write_ptr);
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+ png_debug(0, "Setting jmpbuf for read struct\n");
+#ifdef USE_FAR_KEYWORD
+ if (setjmp(jmpbuf))
+#else
+ if (setjmp(png_jmpbuf(read_ptr)))
+#endif
+ {
+ fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
+ png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
+#ifdef PNG_WRITE_SUPPORTED
+ png_destroy_info_struct(write_ptr, &write_end_info_ptr);
+ png_destroy_write_struct(&write_ptr, &write_info_ptr);
+#endif
+ FCLOSE(fpin);
+ FCLOSE(fpout);
+ return (1);
+ }
+#ifdef USE_FAR_KEYWORD
+ png_memcpy(png_jmpbuf(read_ptr),jmpbuf,sizeof(jmp_buf));
+#endif
+
+#ifdef PNG_WRITE_SUPPORTED
+ png_debug(0, "Setting jmpbuf for write struct\n");
+#ifdef USE_FAR_KEYWORD
+ if (setjmp(jmpbuf))
+#else
+ if (setjmp(png_jmpbuf(write_ptr)))
+#endif
+ {
+ fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
+ png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
+ png_destroy_info_struct(write_ptr, &write_end_info_ptr);
+#ifdef PNG_WRITE_SUPPORTED
+ png_destroy_write_struct(&write_ptr, &write_info_ptr);
+#endif
+ FCLOSE(fpin);
+ FCLOSE(fpout);
+ return (1);
+ }
+#ifdef USE_FAR_KEYWORD
+ png_memcpy(png_jmpbuf(write_ptr),jmpbuf,sizeof(jmp_buf));
+#endif
+#endif
+#endif
+
+ png_debug(0, "Initializing input and output streams\n");
+#if !defined(PNG_NO_STDIO)
+ png_init_io(read_ptr, fpin);
+# ifdef PNG_WRITE_SUPPORTED
+ png_init_io(write_ptr, fpout);
+# endif
+#else
+ png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
+# ifdef PNG_WRITE_SUPPORTED
+ png_set_write_fn(write_ptr, (png_voidp)fpout, pngtest_write_data,
+# if defined(PNG_WRITE_FLUSH_SUPPORTED)
+ pngtest_flush);
+# else
+ NULL);
+# endif
+# endif
+#endif
+ if(status_dots_requested == 1)
+ {
+#ifdef PNG_WRITE_SUPPORTED
+ png_set_write_status_fn(write_ptr, write_row_callback);
+#endif
+ png_set_read_status_fn(read_ptr, read_row_callback);
+ }
+ else
+ {
+#ifdef PNG_WRITE_SUPPORTED
+ png_set_write_status_fn(write_ptr, NULL);
+#endif
+ png_set_read_status_fn(read_ptr, NULL);
+ }
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
+ {
+ int i;
+ for(i=0; i<256; i++)
+ filters_used[i]=0;
+ png_set_read_user_transform_fn(read_ptr, count_filters);
+ }
+#endif
+#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+ zero_samples=0;
+ png_set_write_user_transform_fn(write_ptr, count_zero_samples);
+#endif
+
+#define HANDLE_CHUNK_IF_SAFE 2
+#define HANDLE_CHUNK_ALWAYS 3
+#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
+ png_set_keep_unknown_chunks(read_ptr, HANDLE_CHUNK_ALWAYS, NULL, 0);
+#endif
+#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
+ png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_IF_SAFE, NULL, 0);
+#endif
+
+ png_debug(0, "Reading info struct\n");
+ png_read_info(read_ptr, read_info_ptr);
+
+ png_debug(0, "Transferring info struct\n");
+ {
+ int interlace_type, compression_type, filter_type;
+
+ if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
+ &color_type, &interlace_type, &compression_type, &filter_type))
+ {
+ png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+ color_type, interlace_type, compression_type, filter_type);
+#else
+ color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
+#endif
+ }
+ }
+#if defined(PNG_FIXED_POINT_SUPPORTED)
+#if defined(PNG_cHRM_SUPPORTED)
+ {
+ png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
+ blue_y;
+ if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
+ &red_y, &green_x, &green_y, &blue_x, &blue_y))
+ {
+ png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x,
+ red_y, green_x, green_y, blue_x, blue_y);
+ }
+ }
+#endif
+#if defined(PNG_gAMA_SUPPORTED)
+ {
+ png_fixed_point gamma;
+
+ if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma))
+ {
+ png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
+ }
+ }
+#endif
+#else /* Use floating point versions */
+#if defined(PNG_FLOATING_POINT_SUPPORTED)
+#if defined(PNG_cHRM_SUPPORTED)
+ {
+ double white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
+ blue_y;
+ if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
+ &red_y, &green_x, &green_y, &blue_x, &blue_y))
+ {
+ png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x,
+ red_y, green_x, green_y, blue_x, blue_y);
+ }
+ }
+#endif
+#if defined(PNG_gAMA_SUPPORTED)
+ {
+ double gamma;
+
+ if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
+ {
+ png_set_gAMA(write_ptr, write_info_ptr, gamma);
+ }
+ }
+#endif
+#endif /* floating point */
+#endif /* fixed point */
+#if defined(PNG_iCCP_SUPPORTED)
+ {
+ png_charp name;
+ png_charp profile;
+ png_uint_32 proflen;
+ int compression_type;
+
+ if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type,
+ &profile, &proflen))
+ {
+ png_set_iCCP(write_ptr, write_info_ptr, name, compression_type,
+ profile, proflen);
+ }
+ }
+#endif
+#if defined(PNG_sRGB_SUPPORTED)
+ {
+ int intent;
+
+ if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
+ {
+ png_set_sRGB(write_ptr, write_info_ptr, intent);
+ }
+ }
+#endif
+ {
+ png_colorp palette;
+ int num_palette;
+
+ if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette))
+ {
+ png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
+ }
+ }
+#if defined(PNG_bKGD_SUPPORTED)
+ {
+ png_color_16p background;
+
+ if (png_get_bKGD(read_ptr, read_info_ptr, &background))
+ {
+ png_set_bKGD(write_ptr, write_info_ptr, background);
+ }
+ }
+#endif
+#if defined(PNG_hIST_SUPPORTED)
+ {
+ png_uint_16p hist;
+
+ if (png_get_hIST(read_ptr, read_info_ptr, &hist))
+ {
+ png_set_hIST(write_ptr, write_info_ptr, hist);
+ }
+ }
+#endif
+#if defined(PNG_oFFs_SUPPORTED)
+ {
+ png_int_32 offset_x, offset_y;
+ int unit_type;
+
+ if (png_get_oFFs(read_ptr, read_info_ptr,&offset_x,&offset_y,&unit_type))
+ {
+ png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
+ }
+ }
+#endif
+#if defined(PNG_pCAL_SUPPORTED)
+ {
+ png_charp purpose, units;
+ png_charpp params;
+ png_int_32 X0, X1;
+ int type, nparams;
+
+ if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type,
+ &nparams, &units, ¶ms))
+ {
+ png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
+ nparams, units, params);
+ }
+ }
+#endif
+#if defined(PNG_pHYs_SUPPORTED)
+ {
+ png_uint_32 res_x, res_y;
+ int unit_type;
+
+ if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type))
+ {
+ png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
+ }
+ }
+#endif
+#if defined(PNG_sBIT_SUPPORTED)
+ {
+ png_color_8p sig_bit;
+
+ if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit))
+ {
+ png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
+ }
+ }
+#endif
+#if defined(PNG_sCAL_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ {
+ int unit;
+ double scal_width, scal_height;
+
+ if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
+ &scal_height))
+ {
+ png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
+ }
+ }
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ {
+ int unit;
+ png_charp scal_width, scal_height;
+
+ if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
+ &scal_height))
+ {
+ png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width, scal_height);
+ }
+ }
+#endif
+#endif
+#endif
+#if defined(PNG_TEXT_SUPPORTED)
+ {
+ png_textp text_ptr;
+ int num_text;
+
+ if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0)
+ {
+ png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text);
+ png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
+ }
+ }
+#endif
+#if defined(PNG_tIME_SUPPORTED)
+ {
+ png_timep mod_time;
+
+ if (png_get_tIME(read_ptr, read_info_ptr, &mod_time))
+ {
+ png_set_tIME(write_ptr, write_info_ptr, mod_time);
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+ /* we have to use png_strcpy instead of "=" because the string
+ pointed to by png_convert_to_rfc1123() gets free'ed before
+ we use it */
+ png_strcpy(tIME_string,png_convert_to_rfc1123(read_ptr, mod_time));
+ tIME_chunk_present++;
+#endif /* PNG_TIME_RFC1123_SUPPORTED */
+ }
+ }
+#endif
+#if defined(PNG_tRNS_SUPPORTED)
+ {
+ png_bytep trans;
+ int num_trans;
+ png_color_16p trans_values;
+
+ if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans,
+ &trans_values))
+ {
+ png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans,
+ trans_values);
+ }
+ }
+#endif
+#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
+ {
+ png_unknown_chunkp unknowns;
+ int num_unknowns = (int)png_get_unknown_chunks(read_ptr, read_info_ptr,
+ &unknowns);
+ if (num_unknowns)
+ {
+ png_size_t i;
+ png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
+ num_unknowns);
+ /* copy the locations from the read_info_ptr. The automatically
+ generated locations in write_info_ptr are wrong because we
+ haven't written anything yet */
+ for (i = 0; i < (png_size_t)num_unknowns; i++)
+ png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
+ unknowns[i].location);
+ }
+ }
+#endif
+
+#ifdef PNG_WRITE_SUPPORTED
+ png_debug(0, "\nWriting info struct\n");
+
+/* If we wanted, we could write info in two steps:
+ png_write_info_before_PLTE(write_ptr, write_info_ptr);
+ */
+ png_write_info(write_ptr, write_info_ptr);
+#endif
+
+#ifdef SINGLE_ROWBUF_ALLOC
+ png_debug(0, "\nAllocating row buffer...");
+ row_buf = (png_bytep)png_malloc(read_ptr,
+ png_get_rowbytes(read_ptr, read_info_ptr));
+ png_debug1(0, "0x%08lx\n\n", (unsigned long)row_buf);
+#endif /* SINGLE_ROWBUF_ALLOC */
+ png_debug(0, "Writing row data\n");
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
+ defined(PNG_WRITE_INTERLACING_SUPPORTED)
+ num_pass = png_set_interlace_handling(read_ptr);
+# ifdef PNG_WRITE_SUPPORTED
+ png_set_interlace_handling(write_ptr);
+# endif
+#else
+ num_pass=1;
+#endif
+
+#ifdef PNGTEST_TIMING
+ t_stop = (float)clock();
+ t_misc += (t_stop - t_start);
+ t_start = t_stop;
+#endif
+ for (pass = 0; pass < num_pass; pass++)
+ {
+ png_debug1(0, "Writing row data for pass %d\n",pass);
+ for (y = 0; y < height; y++)
+ {
+#ifndef SINGLE_ROWBUF_ALLOC
+ png_debug2(0, "\nAllocating row buffer (pass %d, y = %ld)...", pass,y);
+ row_buf = (png_bytep)png_malloc(read_ptr,
+ png_get_rowbytes(read_ptr, read_info_ptr));
+ png_debug2(0, "0x%08lx (%ld bytes)\n", (unsigned long)row_buf,
+ png_get_rowbytes(read_ptr, read_info_ptr));
+#endif /* !SINGLE_ROWBUF_ALLOC */
+ png_read_rows(read_ptr, (png_bytepp)&row_buf, (png_bytepp)NULL, 1);
+
+#ifdef PNG_WRITE_SUPPORTED
+#ifdef PNGTEST_TIMING
+ t_stop = (float)clock();
+ t_decode += (t_stop - t_start);
+ t_start = t_stop;
+#endif
+ png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
+#ifdef PNGTEST_TIMING
+ t_stop = (float)clock();
+ t_encode += (t_stop - t_start);
+ t_start = t_stop;
+#endif
+#endif /* PNG_WRITE_SUPPORTED */
+
+#ifndef SINGLE_ROWBUF_ALLOC
+ png_debug2(0, "Freeing row buffer (pass %d, y = %ld)\n\n", pass, y);
+ png_free(read_ptr, row_buf);
+#endif /* !SINGLE_ROWBUF_ALLOC */
+ }
+ }
+
+#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
+ png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
+#endif
+#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
+ png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
+#endif
+
+ png_debug(0, "Reading and writing end_info data\n");
+
+ png_read_end(read_ptr, end_info_ptr);
+#if defined(PNG_TEXT_SUPPORTED)
+ {
+ png_textp text_ptr;
+ int num_text;
+
+ if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
+ {
+ png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text);
+ png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
+ }
+ }
+#endif
+#if defined(PNG_tIME_SUPPORTED)
+ {
+ png_timep mod_time;
+
+ if (png_get_tIME(read_ptr, end_info_ptr, &mod_time))
+ {
+ png_set_tIME(write_ptr, write_end_info_ptr, mod_time);
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+ /* we have to use png_strcpy instead of "=" because the string
+ pointed to by png_convert_to_rfc1123() gets free'ed before
+ we use it */
+ png_strcpy(tIME_string,png_convert_to_rfc1123(read_ptr, mod_time));
+ tIME_chunk_present++;
+#endif /* PNG_TIME_RFC1123_SUPPORTED */
+ }
+ }
+#endif
+#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
+ {
+ png_unknown_chunkp unknowns;
+ int num_unknowns;
+ num_unknowns = (int)png_get_unknown_chunks(read_ptr, end_info_ptr,
+ &unknowns);
+ if (num_unknowns)
+ {
+ png_size_t i;
+ png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
+ num_unknowns);
+ /* copy the locations from the read_info_ptr. The automatically
+ generated locations in write_end_info_ptr are wrong because we
+ haven't written the end_info yet */
+ for (i = 0; i < (png_size_t)num_unknowns; i++)
+ png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
+ unknowns[i].location);
+ }
+ }
+#endif
+#ifdef PNG_WRITE_SUPPORTED
+ png_write_end(write_ptr, write_end_info_ptr);
+#endif
+
+#ifdef PNG_EASY_ACCESS_SUPPORTED
+ if(verbose)
+ {
+ png_uint_32 iwidth, iheight;
+ iwidth = png_get_image_width(write_ptr, write_info_ptr);
+ iheight = png_get_image_height(write_ptr, write_info_ptr);
+ fprintf(STDERR, "Image width = %lu, height = %lu\n",
+ iwidth, iheight);
+ }
+#endif
+
+ png_debug(0, "Destroying data structs\n");
+#ifdef SINGLE_ROWBUF_ALLOC
+ png_debug(1, "destroying row_buf for read_ptr\n");
+ png_free(read_ptr, row_buf);
+ row_buf=NULL;
+#endif /* SINGLE_ROWBUF_ALLOC */
+ png_debug(1, "destroying read_ptr, read_info_ptr, end_info_ptr\n");
+ png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
+#ifdef PNG_WRITE_SUPPORTED
+ png_debug(1, "destroying write_end_info_ptr\n");
+ png_destroy_info_struct(write_ptr, &write_end_info_ptr);
+ png_debug(1, "destroying write_ptr, write_info_ptr\n");
+ png_destroy_write_struct(&write_ptr, &write_info_ptr);
+#endif
+ png_debug(0, "Destruction complete.\n");
+
+ FCLOSE(fpin);
+ FCLOSE(fpout);
+
+ png_debug(0, "Opening files for comparison\n");
+#if defined(_WIN32_WCE)
+ MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH);
+ if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
+#else
+ if ((fpin = fopen(inname, "rb")) == NULL)
+#endif
+ {
+ fprintf(STDERR, "Could not find file %s\n", inname);
+ return (1);
+ }
+
+#if defined(_WIN32_WCE)
+ MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH);
+ if ((fpout = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
+#else
+ if ((fpout = fopen(outname, "rb")) == NULL)
+#endif
+ {
+ fprintf(STDERR, "Could not find file %s\n", outname);
+ FCLOSE(fpin);
+ return (1);
+ }
+
+ for(;;)
+ {
+ png_size_t num_in, num_out;
+
+ READFILE(fpin, inbuf, 1, num_in);
+ READFILE(fpout, outbuf, 1, num_out);
+
+ if (num_in != num_out)
+ {
+ fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
+ inname, outname);
+ if(wrote_question == 0)
+ {
+ fprintf(STDERR,
+ " Was %s written with the same maximum IDAT chunk size (%d bytes),",
+ inname,PNG_ZBUF_SIZE);
+ fprintf(STDERR,
+ "\n filtering heuristic (libpng default), compression");
+ fprintf(STDERR,
+ " level (zlib default),\n and zlib version (%s)?\n\n",
+ ZLIB_VERSION);
+ wrote_question=1;
+ }
+ FCLOSE(fpin);
+ FCLOSE(fpout);
+ return (0);
+ }
+
+ if (!num_in)
+ break;
+
+ if (png_memcmp(inbuf, outbuf, num_in))
+ {
+ fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname);
+ if(wrote_question == 0)
+ {
+ fprintf(STDERR,
+ " Was %s written with the same maximum IDAT chunk size (%d bytes),",
+ inname,PNG_ZBUF_SIZE);
+ fprintf(STDERR,
+ "\n filtering heuristic (libpng default), compression");
+ fprintf(STDERR,
+ " level (zlib default),\n and zlib version (%s)?\n\n",
+ ZLIB_VERSION);
+ wrote_question=1;
+ }
+ FCLOSE(fpin);
+ FCLOSE(fpout);
+ return (0);
+ }
+ }
+
+ FCLOSE(fpin);
+ FCLOSE(fpout);
+
+ return (0);
+}
+
+/* input and output filenames */
+#ifdef RISCOS
+static PNG_CONST char *inname = "pngtest/png";
+static PNG_CONST char *outname = "pngout/png";
+#else
+static PNG_CONST char *inname = "pngtest.png";
+static PNG_CONST char *outname = "pngout.png";
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ int multiple = 0;
+ int ierror = 0;
+
+ fprintf(STDERR, "Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
+ fprintf(STDERR, " with zlib version %s\n", ZLIB_VERSION);
+ fprintf(STDERR,"%s",png_get_copyright(NULL));
+ /* Show the version of libpng used in building the library */
+ fprintf(STDERR," library (%lu):%s", png_access_version_number(),
+ png_get_header_version(NULL));
+ /* Show the version of libpng used in building the application */
+ fprintf(STDERR," pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
+ PNG_HEADER_VERSION_STRING);
+ fprintf(STDERR," sizeof(png_struct)=%ld, sizeof(png_info)=%ld\n",
+ (long)sizeof(png_struct), (long)sizeof(png_info));
+
+ /* Do some consistency checking on the memory allocation settings, I'm
+ not sure this matters, but it is nice to know, the first of these
+ tests should be impossible because of the way the macros are set
+ in pngconf.h */
+#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
+ fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
+#endif
+ /* I think the following can happen. */
+#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
+ fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
+#endif
+
+ if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING))
+ {
+ fprintf(STDERR,
+ "Warning: versions are different between png.h and png.c\n");
+ fprintf(STDERR, " png.h version: %s\n", PNG_LIBPNG_VER_STRING);
+ fprintf(STDERR, " png.c version: %s\n\n", png_libpng_ver);
+ ++ierror;
+ }
+
+ if (argc > 1)
+ {
+ if (strcmp(argv[1], "-m") == 0)
+ {
+ multiple = 1;
+ status_dots_requested = 0;
+ }
+ else if (strcmp(argv[1], "-mv") == 0 ||
+ strcmp(argv[1], "-vm") == 0 )
+ {
+ multiple = 1;
+ verbose = 1;
+ status_dots_requested = 1;
+ }
+ else if (strcmp(argv[1], "-v") == 0)
+ {
+ verbose = 1;
+ status_dots_requested = 1;
+ inname = argv[2];
+ }
+ else
+ {
+ inname = argv[1];
+ status_dots_requested = 0;
+ }
+ }
+
+ if (!multiple && argc == 3+verbose)
+ outname = argv[2+verbose];
+
+ if ((!multiple && argc > 3+verbose) || (multiple && argc < 2))
+ {
+ fprintf(STDERR,
+ "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
+ argv[0], argv[0]);
+ fprintf(STDERR,
+ " reads/writes one PNG file (without -m) or multiple files (-m)\n");
+ fprintf(STDERR,
+ " with -m %s is used as a temporary file\n", outname);
+ exit(1);
+ }
+
+ if (multiple)
+ {
+ int i;
+#ifdef PNG_USER_MEM_SUPPORTED
+ int allocation_now = current_allocation;
+#endif
+ for (i=2; i<argc; ++i)
+ {
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
+ int k;
+#endif
+ int kerror;
+ fprintf(STDERR, "Testing %s:",argv[i]);
+ kerror = test_one_file(argv[i], outname);
+ if (kerror == 0)
+ {
+#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+ fprintf(STDERR, "\n PASS (%lu zero samples)\n",zero_samples);
+#else
+ fprintf(STDERR, " PASS\n");
+#endif
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
+ for (k=0; k<256; k++)
+ if(filters_used[k])
+ fprintf(STDERR, " Filter %d was used %lu times\n",
+ k,filters_used[k]);
+#endif
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+ if(tIME_chunk_present != 0)
+ fprintf(STDERR, " tIME = %s\n",tIME_string);
+ tIME_chunk_present = 0;
+#endif /* PNG_TIME_RFC1123_SUPPORTED */
+ }
+ else
+ {
+ fprintf(STDERR, " FAIL\n");
+ ierror += kerror;
+ }
+#ifdef PNG_USER_MEM_SUPPORTED
+ if (allocation_now != current_allocation)
+ fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
+ current_allocation-allocation_now);
+ if (current_allocation != 0)
+ {
+ memory_infop pinfo = pinformation;
+
+ fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
+ current_allocation);
+ while (pinfo != NULL)
+ {
+ fprintf(STDERR, " %lu bytes at %x\n", pinfo->size,
+ (unsigned int) pinfo->pointer);
+ pinfo = pinfo->next;
+ }
+ }
+#endif
+ }
+#ifdef PNG_USER_MEM_SUPPORTED
+ fprintf(STDERR, " Current memory allocation: %10d bytes\n",
+ current_allocation);
+ fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
+ maximum_allocation);
+ fprintf(STDERR, " Total memory allocation: %10d bytes\n",
+ total_allocation);
+ fprintf(STDERR, " Number of allocations: %10d\n",
+ num_allocations);
+#endif
+ }
+ else
+ {
+ int i;
+ for (i=0; i<3; ++i)
+ {
+ int kerror;
+#ifdef PNG_USER_MEM_SUPPORTED
+ int allocation_now = current_allocation;
+#endif
+ if (i == 1) status_dots_requested = 1;
+ else if(verbose == 0)status_dots_requested = 0;
+ if (i == 0 || verbose == 1 || ierror != 0)
+ fprintf(STDERR, "Testing %s:",inname);
+ kerror = test_one_file(inname, outname);
+ if(kerror == 0)
+ {
+ if(verbose == 1 || i == 2)
+ {
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
+ int k;
+#endif
+#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+ fprintf(STDERR, "\n PASS (%lu zero samples)\n",zero_samples);
+#else
+ fprintf(STDERR, " PASS\n");
+#endif
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
+ for (k=0; k<256; k++)
+ if(filters_used[k])
+ fprintf(STDERR, " Filter %d was used %lu times\n",
+ k,filters_used[k]);
+#endif
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+ if(tIME_chunk_present != 0)
+ fprintf(STDERR, " tIME = %s\n",tIME_string);
+#endif /* PNG_TIME_RFC1123_SUPPORTED */
+ }
+ }
+ else
+ {
+ if(verbose == 0 && i != 2)
+ fprintf(STDERR, "Testing %s:",inname);
+ fprintf(STDERR, " FAIL\n");
+ ierror += kerror;
+ }
+#ifdef PNG_USER_MEM_SUPPORTED
+ if (allocation_now != current_allocation)
+ fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
+ current_allocation-allocation_now);
+ if (current_allocation != 0)
+ {
+ memory_infop pinfo = pinformation;
+
+ fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
+ current_allocation);
+ while (pinfo != NULL)
+ {
+ fprintf(STDERR," %lu bytes at %x\n",
+ pinfo->size, (unsigned int)pinfo->pointer);
+ pinfo = pinfo->next;
+ }
+ }
+#endif
+ }
+#ifdef PNG_USER_MEM_SUPPORTED
+ fprintf(STDERR, " Current memory allocation: %10d bytes\n",
+ current_allocation);
+ fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
+ maximum_allocation);
+ fprintf(STDERR, " Total memory allocation: %10d bytes\n",
+ total_allocation);
+ fprintf(STDERR, " Number of allocations: %10d\n",
+ num_allocations);
+#endif
+ }
+
+#ifdef PNGTEST_TIMING
+ t_stop = (float)clock();
+ t_misc += (t_stop - t_start);
+ t_start = t_stop;
+ fprintf(STDERR," CPU time used = %.3f seconds",
+ (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
+ fprintf(STDERR," (decoding %.3f,\n",
+ t_decode/(float)CLOCKS_PER_SEC);
+ fprintf(STDERR," encoding %.3f ,",
+ t_encode/(float)CLOCKS_PER_SEC);
+ fprintf(STDERR," other %.3f seconds)\n\n",
+ t_misc/(float)CLOCKS_PER_SEC);
+#endif
+
+ if (ierror == 0)
+ fprintf(STDERR, "libpng passes test\n");
+ else
+ fprintf(STDERR, "libpng FAILS test\n");
+ return (int)(ierror != 0);
+}
+
+/* Generate a compiler error if there is an old png.h in the search path. */
+typedef version_1_2_0 your_png_h_is_not_version_1_2_0;
--- /dev/null
+
+/* pngtrans.c - transforms the data in a row (used by both readers and writers)
+ *
+ * libpng 1.2.0 - September 1, 2001
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
+/* turn on BGR-to-RGB mapping */
+void PNGAPI
+png_set_bgr(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_bgr\n");
+ png_ptr->transformations |= PNG_BGR;
+}
+#endif
+
+#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
+/* turn on 16 bit byte swapping */
+void PNGAPI
+png_set_swap(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_swap\n");
+ if (png_ptr->bit_depth == 16)
+ png_ptr->transformations |= PNG_SWAP_BYTES;
+}
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
+/* turn on pixel packing */
+void PNGAPI
+png_set_packing(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_packing\n");
+ if (png_ptr->bit_depth < 8)
+ {
+ png_ptr->transformations |= PNG_PACK;
+ png_ptr->usr_bit_depth = 8;
+ }
+}
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+/* turn on packed pixel swapping */
+void PNGAPI
+png_set_packswap(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_packswap\n");
+ if (png_ptr->bit_depth < 8)
+ png_ptr->transformations |= PNG_PACKSWAP;
+}
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
+void PNGAPI
+png_set_shift(png_structp png_ptr, png_color_8p true_bits)
+{
+ png_debug(1, "in png_set_shift\n");
+ png_ptr->transformations |= PNG_SHIFT;
+ png_ptr->shift = *true_bits;
+}
+#endif
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
+ defined(PNG_WRITE_INTERLACING_SUPPORTED)
+int PNGAPI
+png_set_interlace_handling(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_interlace handling\n");
+ if (png_ptr->interlaced)
+ {
+ png_ptr->transformations |= PNG_INTERLACE;
+ return (7);
+ }
+
+ return (1);
+}
+#endif
+
+#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
+/* Add a filler byte on read, or remove a filler or alpha byte on write.
+ * The filler type has changed in v0.95 to allow future 2-byte fillers
+ * for 48-bit input data, as well as to avoid problems with some compilers
+ * that don't like bytes as parameters.
+ */
+void PNGAPI
+png_set_filler(png_structp png_ptr, png_uint_32 filler, int filler_loc)
+{
+ png_debug(1, "in png_set_filler\n");
+ png_ptr->transformations |= PNG_FILLER;
+ png_ptr->filler = (png_byte)filler;
+ if (filler_loc == PNG_FILLER_AFTER)
+ png_ptr->flags |= PNG_FLAG_FILLER_AFTER;
+ else
+ png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER;
+
+ /* This should probably go in the "do_filler" routine.
+ * I attempted to do that in libpng-1.0.1a but that caused problems
+ * so I restored it in libpng-1.0.2a
+ */
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ png_ptr->usr_channels = 4;
+ }
+
+ /* Also I added this in libpng-1.0.2a (what happens when we expand
+ * a less-than-8-bit grayscale to GA? */
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY && png_ptr->bit_depth >= 8)
+ {
+ png_ptr->usr_channels = 2;
+ }
+}
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \
+ defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+void PNGAPI
+png_set_swap_alpha(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_swap_alpha\n");
+ png_ptr->transformations |= PNG_SWAP_ALPHA;
+}
+#endif
+
+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \
+ defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
+void PNGAPI
+png_set_invert_alpha(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_invert_alpha\n");
+ png_ptr->transformations |= PNG_INVERT_ALPHA;
+}
+#endif
+
+#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
+void PNGAPI
+png_set_invert_mono(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_invert_mono\n");
+ png_ptr->transformations |= PNG_INVERT_MONO;
+}
+
+/* invert monochrome grayscale data */
+void /* PRIVATE */
+png_do_invert(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_invert\n");
+ /* This test removed from libpng version 1.0.13 and 1.2.0:
+ * if (row_info->bit_depth == 1 &&
+ */
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row == NULL || row_info == NULL)
+ return;
+#endif
+ if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ png_bytep rp = row;
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+
+ for (i = 0; i < istop; i++)
+ {
+ *rp = (png_byte)(~(*rp));
+ rp++;
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&
+ row_info->bit_depth == 8)
+ {
+ png_bytep rp = row;
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+
+ for (i = 0; i < istop; i+=2)
+ {
+ *rp = (png_byte)(~(*rp));
+ rp+=2;
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&
+ row_info->bit_depth == 16)
+ {
+ png_bytep rp = row;
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+
+ for (i = 0; i < istop; i+=4)
+ {
+ *rp = (png_byte)(~(*rp));
+ *(rp+1) = (png_byte)(~(*(rp+1)));
+ rp+=4;
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
+/* swaps byte order on 16 bit depth images */
+void /* PRIVATE */
+png_do_swap(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_swap\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ row_info->bit_depth == 16)
+ {
+ png_bytep rp = row;
+ png_uint_32 i;
+ png_uint_32 istop= row_info->width * row_info->channels;
+
+ for (i = 0; i < istop; i++, rp += 2)
+ {
+ png_byte t = *rp;
+ *rp = *(rp + 1);
+ *(rp + 1) = t;
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+static png_byte onebppswaptable[256] = {
+ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
+ 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
+ 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
+ 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
+ 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
+ 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
+ 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
+ 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
+ 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
+ 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
+ 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
+ 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
+ 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
+ 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
+ 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
+ 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
+ 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
+ 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
+ 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
+ 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
+ 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
+ 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
+ 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
+ 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
+ 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
+ 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+ 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
+ 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
+};
+
+static png_byte twobppswaptable[256] = {
+ 0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0,
+ 0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0,
+ 0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4,
+ 0x24, 0x64, 0xA4, 0xE4, 0x34, 0x74, 0xB4, 0xF4,
+ 0x08, 0x48, 0x88, 0xC8, 0x18, 0x58, 0x98, 0xD8,
+ 0x28, 0x68, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8,
+ 0x0C, 0x4C, 0x8C, 0xCC, 0x1C, 0x5C, 0x9C, 0xDC,
+ 0x2C, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC,
+ 0x01, 0x41, 0x81, 0xC1, 0x11, 0x51, 0x91, 0xD1,
+ 0x21, 0x61, 0xA1, 0xE1, 0x31, 0x71, 0xB1, 0xF1,
+ 0x05, 0x45, 0x85, 0xC5, 0x15, 0x55, 0x95, 0xD5,
+ 0x25, 0x65, 0xA5, 0xE5, 0x35, 0x75, 0xB5, 0xF5,
+ 0x09, 0x49, 0x89, 0xC9, 0x19, 0x59, 0x99, 0xD9,
+ 0x29, 0x69, 0xA9, 0xE9, 0x39, 0x79, 0xB9, 0xF9,
+ 0x0D, 0x4D, 0x8D, 0xCD, 0x1D, 0x5D, 0x9D, 0xDD,
+ 0x2D, 0x6D, 0xAD, 0xED, 0x3D, 0x7D, 0xBD, 0xFD,
+ 0x02, 0x42, 0x82, 0xC2, 0x12, 0x52, 0x92, 0xD2,
+ 0x22, 0x62, 0xA2, 0xE2, 0x32, 0x72, 0xB2, 0xF2,
+ 0x06, 0x46, 0x86, 0xC6, 0x16, 0x56, 0x96, 0xD6,
+ 0x26, 0x66, 0xA6, 0xE6, 0x36, 0x76, 0xB6, 0xF6,
+ 0x0A, 0x4A, 0x8A, 0xCA, 0x1A, 0x5A, 0x9A, 0xDA,
+ 0x2A, 0x6A, 0xAA, 0xEA, 0x3A, 0x7A, 0xBA, 0xFA,
+ 0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xDE,
+ 0x2E, 0x6E, 0xAE, 0xEE, 0x3E, 0x7E, 0xBE, 0xFE,
+ 0x03, 0x43, 0x83, 0xC3, 0x13, 0x53, 0x93, 0xD3,
+ 0x23, 0x63, 0xA3, 0xE3, 0x33, 0x73, 0xB3, 0xF3,
+ 0x07, 0x47, 0x87, 0xC7, 0x17, 0x57, 0x97, 0xD7,
+ 0x27, 0x67, 0xA7, 0xE7, 0x37, 0x77, 0xB7, 0xF7,
+ 0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x5B, 0x9B, 0xDB,
+ 0x2B, 0x6B, 0xAB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB,
+ 0x0F, 0x4F, 0x8F, 0xCF, 0x1F, 0x5F, 0x9F, 0xDF,
+ 0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF
+};
+
+static png_byte fourbppswaptable[256] = {
+ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+ 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0,
+ 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71,
+ 0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1,
+ 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72,
+ 0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2,
+ 0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73,
+ 0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3,
+ 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74,
+ 0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4,
+ 0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75,
+ 0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5,
+ 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76,
+ 0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6,
+ 0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77,
+ 0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7,
+ 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78,
+ 0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8,
+ 0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79,
+ 0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9,
+ 0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A,
+ 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA,
+ 0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B,
+ 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB,
+ 0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C,
+ 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC,
+ 0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D,
+ 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD,
+ 0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E,
+ 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE,
+ 0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F,
+ 0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF
+};
+
+/* swaps pixel packing order within bytes */
+void /* PRIVATE */
+png_do_packswap(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_packswap\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ row_info->bit_depth < 8)
+ {
+ png_bytep rp, end, table;
+
+ end = row + row_info->rowbytes;
+
+ if (row_info->bit_depth == 1)
+ table = onebppswaptable;
+ else if (row_info->bit_depth == 2)
+ table = twobppswaptable;
+ else if (row_info->bit_depth == 4)
+ table = fourbppswaptable;
+ else
+ return;
+
+ for (rp = row; rp < end; rp++)
+ *rp = table[*rp];
+ }
+}
+#endif /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */
+
+#if defined(PNG_WRITE_FILLER_SUPPORTED) || \
+ defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+/* remove filler or alpha byte(s) */
+void /* PRIVATE */
+png_do_strip_filler(png_row_infop row_info, png_bytep row, png_uint_32 flags)
+{
+ png_debug(1, "in png_do_strip_filler\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+/*
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB ||
+ row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+*/
+ png_bytep sp=row;
+ png_bytep dp=row;
+ png_uint_32 row_width=row_info->width;
+ png_uint_32 i;
+
+ if (row_info->channels == 4)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ /* This converts from RGBX or RGBA to RGB */
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ dp+=3; sp+=4;
+ for (i = 1; i < row_width; i++)
+ {
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ sp++;
+ }
+ }
+ /* This converts from XRGB or ARGB to RGB */
+ else
+ {
+ for (i = 0; i < row_width; i++)
+ {
+ sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ }
+ }
+ row_info->pixel_depth = 24;
+ row_info->rowbytes = row_width * 3;
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ /* This converts from RRGGBBXX or RRGGBBAA to RRGGBB */
+ sp += 8; dp += 6;
+ for (i = 1; i < row_width; i++)
+ {
+ /* This could be (although png_memcpy is probably slower):
+ png_memcpy(dp, sp, 6);
+ sp += 8;
+ dp += 6;
+ */
+
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ sp += 2;
+ }
+ }
+ else
+ {
+ /* This converts from XXRRGGBB or AARRGGBB to RRGGBB */
+ for (i = 0; i < row_width; i++)
+ {
+ /* This could be (although png_memcpy is probably slower):
+ png_memcpy(dp, sp, 6);
+ sp += 8;
+ dp += 6;
+ */
+
+ sp+=2;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ }
+ }
+ row_info->pixel_depth = 48;
+ row_info->rowbytes = row_width * 6;
+ }
+ row_info->channels = 3;
+ row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
+ }
+/*
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY ||
+ row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+*/
+ else if (row_info->channels == 2)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ /* This converts from GX or GA to G */
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ for (i = 0; i < row_width; i++)
+ {
+ *dp++ = *sp++;
+ sp++;
+ }
+ }
+ /* This converts from XG or AG to G */
+ else
+ {
+ for (i = 0; i < row_width; i++)
+ {
+ sp++;
+ *dp++ = *sp++;
+ }
+ }
+ row_info->pixel_depth = 8;
+ row_info->rowbytes = row_width;
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ /* This converts from GGXX or GGAA to GG */
+ sp += 4; dp += 2;
+ for (i = 1; i < row_width; i++)
+ {
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ sp += 2;
+ }
+ }
+ else
+ {
+ /* This converts from XXGG or AAGG to GG */
+ for (i = 0; i < row_width; i++)
+ {
+ sp += 2;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ }
+ }
+ row_info->pixel_depth = 16;
+ row_info->rowbytes = row_width * 2;
+ }
+ row_info->channels = 1;
+ row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
+/* swaps red and blue bytes within a pixel */
+void /* PRIVATE */
+png_do_bgr(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_bgr\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ (row_info->color_type & PNG_COLOR_MASK_COLOR))
+ {
+ png_uint_32 row_width = row_info->width;
+ if (row_info->bit_depth == 8)
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += 3)
+ {
+ png_byte save = *rp;
+ *rp = *(rp + 2);
+ *(rp + 2) = save;
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += 4)
+ {
+ png_byte save = *rp;
+ *rp = *(rp + 2);
+ *(rp + 2) = save;
+ }
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += 6)
+ {
+ png_byte save = *rp;
+ *rp = *(rp + 4);
+ *(rp + 4) = save;
+ save = *(rp + 1);
+ *(rp + 1) = *(rp + 5);
+ *(rp + 5) = save;
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += 8)
+ {
+ png_byte save = *rp;
+ *rp = *(rp + 4);
+ *(rp + 4) = save;
+ save = *(rp + 1);
+ *(rp + 1) = *(rp + 5);
+ *(rp + 5) = save;
+ }
+ }
+ }
+ }
+}
+#endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_LEGACY_SUPPORTED)
+void PNGAPI
+png_set_user_transform_info(png_structp png_ptr, png_voidp
+ user_transform_ptr, int user_transform_depth, int user_transform_channels)
+{
+ png_debug(1, "in png_set_user_transform_info\n");
+#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
+ png_ptr->user_transform_ptr = user_transform_ptr;
+ png_ptr->user_transform_depth = (png_byte)user_transform_depth;
+ png_ptr->user_transform_channels = (png_byte)user_transform_channels;
+#else
+ if(user_transform_ptr || user_transform_depth || user_transform_channels)
+ png_warning(png_ptr,
+ "This version of libpng does not support user transform info");
+#endif
+}
+#endif
+
+/* This function returns a pointer to the user_transform_ptr associated with
+ * the user transform functions. The application should free any memory
+ * associated with this pointer before png_write_destroy and png_read_destroy
+ * are called.
+ */
+png_voidp PNGAPI
+png_get_user_transform_ptr(png_structp png_ptr)
+{
+#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
+ return ((png_voidp)png_ptr->user_transform_ptr);
+#else
+ if(png_ptr)
+ return (NULL);
+ return (NULL);
+#endif
+}
--- /dev/null
+/* pngvcrd.c - mixed C/assembler version of utilities to read a PNG file
+ *
+ * For Intel x86 CPU and Microsoft Visual C++ compiler
+ *
+ * libpng 1.2.0 - September 1, 2001
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ * Copyright (c) 1998, Intel Corporation
+ *
+ * Contributed by Nirav Chhatrapati, Intel Corporation, 1998
+ * Interface to libpng contributed by Gilles Vollant, 1999
+ *
+ *
+ * In png_do_read_interlace() in libpng versions 1.0.3a through 1.0.4d,
+ * a sign error in the post-MMX cleanup code for each pixel_depth resulted
+ * in bad pixels at the beginning of some rows of some images, and also
+ * (due to out-of-range memory reads and writes) caused heap corruption
+ * when compiled with MSVC 6.0. The error was fixed in version 1.0.4e.
+ *
+ * [png_read_filter_row_mmx_avg() bpp == 2 bugfix, GRR 20000916]
+ *
+ * [runtime MMX configuration, GRR 20010102]
+ *
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_USE_PNGVCRD)
+
+static int mmx_supported=2;
+
+
+int PNGAPI
+png_mmx_support(void)
+{
+ int mmx_supported_local = 0;
+ _asm {
+ push ebx //CPUID will trash these
+ push ecx
+ push edx
+ pushfd //Save Eflag to stack
+ pop eax //Get Eflag from stack into eax
+ mov ecx, eax //Make another copy of Eflag in ecx
+ xor eax, 0x200000 //Toggle ID bit in Eflag [i.e. bit(21)]
+ push eax //Save modified Eflag back to stack
+
+ popfd //Restored modified value back to Eflag reg
+ pushfd //Save Eflag to stack
+ pop eax //Get Eflag from stack
+ xor eax, ecx //Compare the new Eflag with the original Eflag
+ jz NOT_SUPPORTED //If the same, CPUID instruction is not supported,
+ //skip following instructions and jump to
+ //NOT_SUPPORTED label
+
+ xor eax, eax //Set eax to zero
+
+ _asm _emit 0x0f //CPUID instruction (two bytes opcode)
+ _asm _emit 0xa2
+
+ cmp eax, 1 //make sure eax return non-zero value
+ jl NOT_SUPPORTED //If eax is zero, mmx not supported
+
+ xor eax, eax //set eax to zero
+ inc eax //Now increment eax to 1. This instruction is
+ //faster than the instruction "mov eax, 1"
+
+ _asm _emit 0x0f //CPUID instruction
+ _asm _emit 0xa2
+
+ and edx, 0x00800000 //mask out all bits but mmx bit(24)
+ cmp edx, 0 // 0 = mmx not supported
+ jz NOT_SUPPORTED // non-zero = Yes, mmx IS supported
+
+ mov mmx_supported_local, 1 //set return value to 1
+
+NOT_SUPPORTED:
+ mov eax, mmx_supported_local //move return value to eax
+ pop edx //CPUID trashed these
+ pop ecx
+ pop ebx
+ }
+
+ //mmx_supported_local=0; // test code for force don't support MMX
+ //printf("MMX : %u (1=MMX supported)\n",mmx_supported_local);
+
+ mmx_supported = mmx_supported_local;
+ return mmx_supported_local;
+}
+
+/* Combines the row recently read in with the previous row.
+ This routine takes care of alpha and transparency if requested.
+ This routine also handles the two methods of progressive display
+ of interlaced images, depending on the mask value.
+ The mask value describes which pixels are to be combined with
+ the row. The pattern always repeats every 8 pixels, so just 8
+ bits are needed. A one indicates the pixel is to be combined; a
+ zero indicates the pixel is to be skipped. This is in addition
+ to any alpha or transparency value associated with the pixel. If
+ you want all pixels to be combined, pass 0xff (255) in mask. */
+
+/* Use this routine for x86 platform - uses faster MMX routine if machine
+ supports MMX */
+
+void /* PRIVATE */
+png_combine_row(png_structp png_ptr, png_bytep row, int mask)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+#endif
+
+ png_debug(1,"in png_combine_row_asm\n");
+
+ if (mmx_supported == 2) {
+ /* this should have happened in png_init_mmx_flags() already */
+ png_warning(png_ptr, "asm_flags may not have been initialized");
+ png_mmx_support();
+ }
+
+ if (mask == 0xff)
+ {
+ png_memcpy(row, png_ptr->row_buf + 1,
+ (png_size_t)((png_ptr->width * png_ptr->row_info.pixel_depth + 7) >> 3));
+ }
+ /* GRR: add "else if (mask == 0)" case?
+ * or does png_combine_row() not even get called in that case? */
+ else
+ {
+ switch (png_ptr->row_info.pixel_depth)
+ {
+ case 1:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int s_inc, s_start, s_end;
+ int m;
+ int shift;
+ png_uint_32 i;
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ m = 0x80;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 7;
+ s_inc = 1;
+ }
+ else
+#endif
+ {
+ s_start = 7;
+ s_end = 0;
+ s_inc = -1;
+ }
+
+ shift = s_start;
+
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ int value;
+
+ value = (*sp >> shift) & 0x1;
+ *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+
+ case 2:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int s_start, s_end, s_inc;
+ int m;
+ int shift;
+ png_uint_32 i;
+ int value;
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ m = 0x80;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 6;
+ s_inc = 2;
+ }
+ else
+#endif
+ {
+ s_start = 6;
+ s_end = 0;
+ s_inc = -2;
+ }
+
+ shift = s_start;
+
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ value = (*sp >> shift) & 0x3;
+ *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+
+ case 4:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int s_start, s_end, s_inc;
+ int m;
+ int shift;
+ png_uint_32 i;
+ int value;
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ m = 0x80;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 4;
+ s_inc = 4;
+ }
+ else
+#endif
+ {
+ s_start = 4;
+ s_end = 0;
+ s_inc = -4;
+ }
+ shift = s_start;
+
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ value = (*sp >> shift) & 0xf;
+ *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+
+ case 8:
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+ png_uint_32 len;
+ int m;
+ int diff, unmask;
+
+ __int64 mask0=0x0102040810204080;
+
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
+ /* && mmx_supported */ )
+ {
+ srcptr = png_ptr->row_buf + 1;
+ dstptr = row;
+ m = 0x80;
+ unmask = ~mask;
+ len = png_ptr->width &~7; //reduce to multiple of 8
+ diff = png_ptr->width & 7; //amount lost
+
+ _asm
+ {
+ movd mm7, unmask //load bit pattern
+ psubb mm6,mm6 //zero mm6
+ punpcklbw mm7,mm7
+ punpcklwd mm7,mm7
+ punpckldq mm7,mm7 //fill register with 8 masks
+
+ movq mm0,mask0
+
+ pand mm0,mm7 //nonzero if keep byte
+ pcmpeqb mm0,mm6 //zeros->1s, v versa
+
+ mov ecx,len //load length of line (pixels)
+ mov esi,srcptr //load source
+ mov ebx,dstptr //load dest
+ cmp ecx,0 //lcr
+ je mainloop8end
+
+mainloop8:
+ movq mm4,[esi]
+ pand mm4,mm0
+ movq mm6,mm0
+ pandn mm6,[ebx]
+ por mm4,mm6
+ movq [ebx],mm4
+
+ add esi,8 //inc by 8 bytes processed
+ add ebx,8
+ sub ecx,8 //dec by 8 pixels processed
+
+ ja mainloop8
+mainloop8end:
+
+ mov ecx,diff
+ cmp ecx,0
+ jz end8
+
+ mov edx,mask
+ sal edx,24 //make low byte the high byte
+
+secondloop8:
+ sal edx,1 //move high bit to CF
+ jnc skip8 //if CF = 0
+ mov al,[esi]
+ mov [ebx],al
+skip8:
+ inc esi
+ inc ebx
+
+ dec ecx
+ jnz secondloop8
+end8:
+ emms
+ }
+ }
+ else /* mmx not supported - use modified C routine */
+ {
+ register unsigned int incr1, initial_val, final_val;
+ png_size_t pixel_bytes;
+ png_uint_32 i;
+ register int disp = png_pass_inc[png_ptr->pass];
+ int offset_table[7] = {0, 4, 0, 2, 0, 1, 0};
+
+ pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
+ srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]*
+ pixel_bytes;
+ dstptr = row + offset_table[png_ptr->pass]*pixel_bytes;
+ initial_val = offset_table[png_ptr->pass]*pixel_bytes;
+ final_val = png_ptr->width*pixel_bytes;
+ incr1 = (disp)*pixel_bytes;
+ for (i = initial_val; i < final_val; i += incr1)
+ {
+ png_memcpy(dstptr, srcptr, pixel_bytes);
+ srcptr += incr1;
+ dstptr += incr1;
+ }
+ } /* end of else */
+
+ break;
+ } // end 8 bpp
+
+ case 16:
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+ png_uint_32 len;
+ int unmask, diff;
+ __int64 mask1=0x0101020204040808,
+ mask0=0x1010202040408080;
+
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
+ /* && mmx_supported */ )
+ {
+ srcptr = png_ptr->row_buf + 1;
+ dstptr = row;
+
+ unmask = ~mask;
+ len = (png_ptr->width)&~7;
+ diff = (png_ptr->width)&7;
+ _asm
+ {
+ movd mm7, unmask //load bit pattern
+ psubb mm6,mm6 //zero mm6
+ punpcklbw mm7,mm7
+ punpcklwd mm7,mm7
+ punpckldq mm7,mm7 //fill register with 8 masks
+
+ movq mm0,mask0
+ movq mm1,mask1
+
+ pand mm0,mm7
+ pand mm1,mm7
+
+ pcmpeqb mm0,mm6
+ pcmpeqb mm1,mm6
+
+ mov ecx,len //load length of line
+ mov esi,srcptr //load source
+ mov ebx,dstptr //load dest
+ cmp ecx,0 //lcr
+ jz mainloop16end
+
+mainloop16:
+ movq mm4,[esi]
+ pand mm4,mm0
+ movq mm6,mm0
+ movq mm7,[ebx]
+ pandn mm6,mm7
+ por mm4,mm6
+ movq [ebx],mm4
+
+ movq mm5,[esi+8]
+ pand mm5,mm1
+ movq mm7,mm1
+ movq mm6,[ebx+8]
+ pandn mm7,mm6
+ por mm5,mm7
+ movq [ebx+8],mm5
+
+ add esi,16 //inc by 16 bytes processed
+ add ebx,16
+ sub ecx,8 //dec by 8 pixels processed
+
+ ja mainloop16
+
+mainloop16end:
+ mov ecx,diff
+ cmp ecx,0
+ jz end16
+
+ mov edx,mask
+ sal edx,24 //make low byte the high byte
+secondloop16:
+ sal edx,1 //move high bit to CF
+ jnc skip16 //if CF = 0
+ mov ax,[esi]
+ mov [ebx],ax
+skip16:
+ add esi,2
+ add ebx,2
+
+ dec ecx
+ jnz secondloop16
+end16:
+ emms
+ }
+ }
+ else /* mmx not supported - use modified C routine */
+ {
+ register unsigned int incr1, initial_val, final_val;
+ png_size_t pixel_bytes;
+ png_uint_32 i;
+ register int disp = png_pass_inc[png_ptr->pass];
+ int offset_table[7] = {0, 4, 0, 2, 0, 1, 0};
+
+ pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
+ srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]*
+ pixel_bytes;
+ dstptr = row + offset_table[png_ptr->pass]*pixel_bytes;
+ initial_val = offset_table[png_ptr->pass]*pixel_bytes;
+ final_val = png_ptr->width*pixel_bytes;
+ incr1 = (disp)*pixel_bytes;
+ for (i = initial_val; i < final_val; i += incr1)
+ {
+ png_memcpy(dstptr, srcptr, pixel_bytes);
+ srcptr += incr1;
+ dstptr += incr1;
+ }
+ } /* end of else */
+
+ break;
+ } // end 16 bpp
+
+ case 24:
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+ png_uint_32 len;
+ int unmask, diff;
+
+ __int64 mask2=0x0101010202020404, //24bpp
+ mask1=0x0408080810101020,
+ mask0=0x2020404040808080;
+
+ srcptr = png_ptr->row_buf + 1;
+ dstptr = row;
+
+ unmask = ~mask;
+ len = (png_ptr->width)&~7;
+ diff = (png_ptr->width)&7;
+
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
+ /* && mmx_supported */ )
+ {
+ _asm
+ {
+ movd mm7, unmask //load bit pattern
+ psubb mm6,mm6 //zero mm6
+ punpcklbw mm7,mm7
+ punpcklwd mm7,mm7
+ punpckldq mm7,mm7 //fill register with 8 masks
+
+ movq mm0,mask0
+ movq mm1,mask1
+ movq mm2,mask2
+
+ pand mm0,mm7
+ pand mm1,mm7
+ pand mm2,mm7
+
+ pcmpeqb mm0,mm6
+ pcmpeqb mm1,mm6
+ pcmpeqb mm2,mm6
+
+ mov ecx,len //load length of line
+ mov esi,srcptr //load source
+ mov ebx,dstptr //load dest
+ cmp ecx,0
+ jz mainloop24end
+
+mainloop24:
+ movq mm4,[esi]
+ pand mm4,mm0
+ movq mm6,mm0
+ movq mm7,[ebx]
+ pandn mm6,mm7
+ por mm4,mm6
+ movq [ebx],mm4
+
+
+ movq mm5,[esi+8]
+ pand mm5,mm1
+ movq mm7,mm1
+ movq mm6,[ebx+8]
+ pandn mm7,mm6
+ por mm5,mm7
+ movq [ebx+8],mm5
+
+ movq mm6,[esi+16]
+ pand mm6,mm2
+ movq mm4,mm2
+ movq mm7,[ebx+16]
+ pandn mm4,mm7
+ por mm6,mm4
+ movq [ebx+16],mm6
+
+ add esi,24 //inc by 24 bytes processed
+ add ebx,24
+ sub ecx,8 //dec by 8 pixels processed
+
+ ja mainloop24
+
+mainloop24end:
+ mov ecx,diff
+ cmp ecx,0
+ jz end24
+
+ mov edx,mask
+ sal edx,24 //make low byte the high byte
+secondloop24:
+ sal edx,1 //move high bit to CF
+ jnc skip24 //if CF = 0
+ mov ax,[esi]
+ mov [ebx],ax
+ xor eax,eax
+ mov al,[esi+2]
+ mov [ebx+2],al
+skip24:
+ add esi,3
+ add ebx,3
+
+ dec ecx
+ jnz secondloop24
+
+end24:
+ emms
+ }
+ }
+ else /* mmx not supported - use modified C routine */
+ {
+ register unsigned int incr1, initial_val, final_val;
+ png_size_t pixel_bytes;
+ png_uint_32 i;
+ register int disp = png_pass_inc[png_ptr->pass];
+ int offset_table[7] = {0, 4, 0, 2, 0, 1, 0};
+
+ pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
+ srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]*
+ pixel_bytes;
+ dstptr = row + offset_table[png_ptr->pass]*pixel_bytes;
+ initial_val = offset_table[png_ptr->pass]*pixel_bytes;
+ final_val = png_ptr->width*pixel_bytes;
+ incr1 = (disp)*pixel_bytes;
+ for (i = initial_val; i < final_val; i += incr1)
+ {
+ png_memcpy(dstptr, srcptr, pixel_bytes);
+ srcptr += incr1;
+ dstptr += incr1;
+ }
+ } /* end of else */
+
+ break;
+ } // end 24 bpp
+
+ case 32:
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+ png_uint_32 len;
+ int unmask, diff;
+
+ __int64 mask3=0x0101010102020202, //32bpp
+ mask2=0x0404040408080808,
+ mask1=0x1010101020202020,
+ mask0=0x4040404080808080;
+
+ srcptr = png_ptr->row_buf + 1;
+ dstptr = row;
+
+ unmask = ~mask;
+ len = (png_ptr->width)&~7;
+ diff = (png_ptr->width)&7;
+
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
+ /* && mmx_supported */ )
+ {
+ _asm
+ {
+ movd mm7, unmask //load bit pattern
+ psubb mm6,mm6 //zero mm6
+ punpcklbw mm7,mm7
+ punpcklwd mm7,mm7
+ punpckldq mm7,mm7 //fill register with 8 masks
+
+ movq mm0,mask0
+ movq mm1,mask1
+ movq mm2,mask2
+ movq mm3,mask3
+
+ pand mm0,mm7
+ pand mm1,mm7
+ pand mm2,mm7
+ pand mm3,mm7
+
+ pcmpeqb mm0,mm6
+ pcmpeqb mm1,mm6
+ pcmpeqb mm2,mm6
+ pcmpeqb mm3,mm6
+
+ mov ecx,len //load length of line
+ mov esi,srcptr //load source
+ mov ebx,dstptr //load dest
+
+ cmp ecx,0 //lcr
+ jz mainloop32end
+
+mainloop32:
+ movq mm4,[esi]
+ pand mm4,mm0
+ movq mm6,mm0
+ movq mm7,[ebx]
+ pandn mm6,mm7
+ por mm4,mm6
+ movq [ebx],mm4
+
+ movq mm5,[esi+8]
+ pand mm5,mm1
+ movq mm7,mm1
+ movq mm6,[ebx+8]
+ pandn mm7,mm6
+ por mm5,mm7
+ movq [ebx+8],mm5
+
+ movq mm6,[esi+16]
+ pand mm6,mm2
+ movq mm4,mm2
+ movq mm7,[ebx+16]
+ pandn mm4,mm7
+ por mm6,mm4
+ movq [ebx+16],mm6
+
+ movq mm7,[esi+24]
+ pand mm7,mm3
+ movq mm5,mm3
+ movq mm4,[ebx+24]
+ pandn mm5,mm4
+ por mm7,mm5
+ movq [ebx+24],mm7
+
+ add esi,32 //inc by 32 bytes processed
+ add ebx,32
+ sub ecx,8 //dec by 8 pixels processed
+
+ ja mainloop32
+
+mainloop32end:
+ mov ecx,diff
+ cmp ecx,0
+ jz end32
+
+ mov edx,mask
+ sal edx,24 //make low byte the high byte
+secondloop32:
+ sal edx,1 //move high bit to CF
+ jnc skip32 //if CF = 0
+ mov eax,[esi]
+ mov [ebx],eax
+skip32:
+ add esi,4
+ add ebx,4
+
+ dec ecx
+ jnz secondloop32
+
+end32:
+ emms
+ }
+ }
+ else /* mmx _not supported - Use modified C routine */
+ {
+ register unsigned int incr1, initial_val, final_val;
+ png_size_t pixel_bytes;
+ png_uint_32 i;
+ register int disp = png_pass_inc[png_ptr->pass];
+ int offset_table[7] = {0, 4, 0, 2, 0, 1, 0};
+
+ pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
+ srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]*
+ pixel_bytes;
+ dstptr = row + offset_table[png_ptr->pass]*pixel_bytes;
+ initial_val = offset_table[png_ptr->pass]*pixel_bytes;
+ final_val = png_ptr->width*pixel_bytes;
+ incr1 = (disp)*pixel_bytes;
+ for (i = initial_val; i < final_val; i += incr1)
+ {
+ png_memcpy(dstptr, srcptr, pixel_bytes);
+ srcptr += incr1;
+ dstptr += incr1;
+ }
+ } /* end of else */
+
+ break;
+ } // end 32 bpp
+
+ case 48:
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+ png_uint_32 len;
+ int unmask, diff;
+
+ __int64 mask5=0x0101010101010202,
+ mask4=0x0202020204040404,
+ mask3=0x0404080808080808,
+ mask2=0x1010101010102020,
+ mask1=0x2020202040404040,
+ mask0=0x4040808080808080;
+
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
+ /* && mmx_supported */ )
+ {
+ srcptr = png_ptr->row_buf + 1;
+ dstptr = row;
+
+ unmask = ~mask;
+ len = (png_ptr->width)&~7;
+ diff = (png_ptr->width)&7;
+ _asm
+ {
+ movd mm7, unmask //load bit pattern
+ psubb mm6,mm6 //zero mm6
+ punpcklbw mm7,mm7
+ punpcklwd mm7,mm7
+ punpckldq mm7,mm7 //fill register with 8 masks
+
+ movq mm0,mask0
+ movq mm1,mask1
+ movq mm2,mask2
+ movq mm3,mask3
+ movq mm4,mask4
+ movq mm5,mask5
+
+ pand mm0,mm7
+ pand mm1,mm7
+ pand mm2,mm7
+ pand mm3,mm7
+ pand mm4,mm7
+ pand mm5,mm7
+
+ pcmpeqb mm0,mm6
+ pcmpeqb mm1,mm6
+ pcmpeqb mm2,mm6
+ pcmpeqb mm3,mm6
+ pcmpeqb mm4,mm6
+ pcmpeqb mm5,mm6
+
+ mov ecx,len //load length of line
+ mov esi,srcptr //load source
+ mov ebx,dstptr //load dest
+
+ cmp ecx,0
+ jz mainloop48end
+
+mainloop48:
+ movq mm7,[esi]
+ pand mm7,mm0
+ movq mm6,mm0
+ pandn mm6,[ebx]
+ por mm7,mm6
+ movq [ebx],mm7
+
+ movq mm6,[esi+8]
+ pand mm6,mm1
+ movq mm7,mm1
+ pandn mm7,[ebx+8]
+ por mm6,mm7
+ movq [ebx+8],mm6
+
+ movq mm6,[esi+16]
+ pand mm6,mm2
+ movq mm7,mm2
+ pandn mm7,[ebx+16]
+ por mm6,mm7
+ movq [ebx+16],mm6
+
+ movq mm7,[esi+24]
+ pand mm7,mm3
+ movq mm6,mm3
+ pandn mm6,[ebx+24]
+ por mm7,mm6
+ movq [ebx+24],mm7
+
+ movq mm6,[esi+32]
+ pand mm6,mm4
+ movq mm7,mm4
+ pandn mm7,[ebx+32]
+ por mm6,mm7
+ movq [ebx+32],mm6
+
+ movq mm7,[esi+40]
+ pand mm7,mm5
+ movq mm6,mm5
+ pandn mm6,[ebx+40]
+ por mm7,mm6
+ movq [ebx+40],mm7
+
+ add esi,48 //inc by 32 bytes processed
+ add ebx,48
+ sub ecx,8 //dec by 8 pixels processed
+
+ ja mainloop48
+mainloop48end:
+
+ mov ecx,diff
+ cmp ecx,0
+ jz end48
+
+ mov edx,mask
+ sal edx,24 //make low byte the high byte
+
+secondloop48:
+ sal edx,1 //move high bit to CF
+ jnc skip48 //if CF = 0
+ mov eax,[esi]
+ mov [ebx],eax
+skip48:
+ add esi,4
+ add ebx,4
+
+ dec ecx
+ jnz secondloop48
+
+end48:
+ emms
+ }
+ }
+ else /* mmx _not supported - Use modified C routine */
+ {
+ register unsigned int incr1, initial_val, final_val;
+ png_size_t pixel_bytes;
+ png_uint_32 i;
+ register int disp = png_pass_inc[png_ptr->pass];
+ int offset_table[7] = {0, 4, 0, 2, 0, 1, 0};
+
+ pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
+ srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]*
+ pixel_bytes;
+ dstptr = row + offset_table[png_ptr->pass]*pixel_bytes;
+ initial_val = offset_table[png_ptr->pass]*pixel_bytes;
+ final_val = png_ptr->width*pixel_bytes;
+ incr1 = (disp)*pixel_bytes;
+ for (i = initial_val; i < final_val; i += incr1)
+ {
+ png_memcpy(dstptr, srcptr, pixel_bytes);
+ srcptr += incr1;
+ dstptr += incr1;
+ }
+ } /* end of else */
+
+ break;
+ } // end 48 bpp
+
+ default:
+ {
+ png_bytep sptr;
+ png_bytep dp;
+ png_size_t pixel_bytes;
+ int offset_table[7] = {0, 4, 0, 2, 0, 1, 0};
+ unsigned int i;
+ register int disp = png_pass_inc[png_ptr->pass]; // get the offset
+ register unsigned int incr1, initial_val, final_val;
+
+ pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
+ sptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]*
+ pixel_bytes;
+ dp = row + offset_table[png_ptr->pass]*pixel_bytes;
+ initial_val = offset_table[png_ptr->pass]*pixel_bytes;
+ final_val = png_ptr->width*pixel_bytes;
+ incr1 = (disp)*pixel_bytes;
+ for (i = initial_val; i < final_val; i += incr1)
+ {
+ png_memcpy(dp, sptr, pixel_bytes);
+ sptr += incr1;
+ dp += incr1;
+ }
+ break;
+ }
+ } /* end switch (png_ptr->row_info.pixel_depth) */
+ } /* end if (non-trivial mask) */
+
+} /* end png_combine_row() */
+
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+
+void /* PRIVATE */
+png_do_read_interlace(png_structp png_ptr)
+{
+ png_row_infop row_info = &(png_ptr->row_info);
+ png_bytep row = png_ptr->row_buf + 1;
+ int pass = png_ptr->pass;
+ png_uint_32 transformations = png_ptr->transformations;
+#ifdef PNG_USE_LOCAL_ARRAYS
+ const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+#endif
+
+ png_debug(1,"in png_do_read_interlace\n");
+
+ if (mmx_supported == 2) {
+ /* this should have happened in png_init_mmx_flags() already */
+ png_warning(png_ptr, "asm_flags may not have been initialized");
+ png_mmx_support();
+ }
+
+ if (row != NULL && row_info != NULL)
+ {
+ png_uint_32 final_width;
+
+ final_width = row_info->width * png_pass_inc[pass];
+
+ switch (row_info->pixel_depth)
+ {
+ case 1:
+ {
+ png_bytep sp, dp;
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ png_byte v;
+ png_uint_32 i;
+ int j;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 3);
+ dp = row + (png_size_t)((final_width - 1) >> 3);
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (int)((row_info->width + 7) & 7);
+ dshift = (int)((final_width + 7) & 7);
+ s_start = 7;
+ s_end = 0;
+ s_inc = -1;
+ }
+ else
+#endif
+ {
+ sshift = 7 - (int)((row_info->width + 7) & 7);
+ dshift = 7 - (int)((final_width + 7) & 7);
+ s_start = 0;
+ s_end = 7;
+ s_inc = 1;
+ }
+
+ for (i = row_info->width; i; i--)
+ {
+ v = (png_byte)((*sp >> sshift) & 0x1);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+
+ case 2:
+ {
+ png_bytep sp, dp;
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 2);
+ dp = row + (png_size_t)((final_width - 1) >> 2);
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (png_size_t)(((row_info->width + 3) & 3) << 1);
+ dshift = (png_size_t)(((final_width + 3) & 3) << 1);
+ s_start = 6;
+ s_end = 0;
+ s_inc = -2;
+ }
+ else
+#endif
+ {
+ sshift = (png_size_t)((3 - ((row_info->width + 3) & 3)) << 1);
+ dshift = (png_size_t)((3 - ((final_width + 3) & 3)) << 1);
+ s_start = 0;
+ s_end = 6;
+ s_inc = 2;
+ }
+
+ for (i = row_info->width; i; i--)
+ {
+ png_byte v;
+ int j;
+
+ v = (png_byte)((*sp >> sshift) & 0x3);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+
+ case 4:
+ {
+ png_bytep sp, dp;
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 1);
+ dp = row + (png_size_t)((final_width - 1) >> 1);
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (png_size_t)(((row_info->width + 1) & 1) << 2);
+ dshift = (png_size_t)(((final_width + 1) & 1) << 2);
+ s_start = 4;
+ s_end = 0;
+ s_inc = -4;
+ }
+ else
+#endif
+ {
+ sshift = (png_size_t)((1 - ((row_info->width + 1) & 1)) << 2);
+ dshift = (png_size_t)((1 - ((final_width + 1) & 1)) << 2);
+ s_start = 0;
+ s_end = 4;
+ s_inc = 4;
+ }
+
+ for (i = row_info->width; i; i--)
+ {
+ png_byte v;
+ int j;
+
+ v = (png_byte)((*sp >> sshift) & 0xf);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+
+ default: // This is the place where the routine is modified
+ {
+ __int64 const4 = 0x0000000000FFFFFF;
+ // __int64 const5 = 0x000000FFFFFF0000; // unused...
+ __int64 const6 = 0x00000000000000FF;
+ png_bytep sptr, dp;
+ png_uint_32 i;
+ png_size_t pixel_bytes;
+ int width = row_info->width;
+
+ pixel_bytes = (row_info->pixel_depth >> 3);
+
+ sptr = row + (width - 1) * pixel_bytes;
+ dp = row + (final_width - 1) * pixel_bytes;
+ // New code by Nirav Chhatrapati - Intel Corporation
+ // sign fix by GRR
+ // NOTE: there is NO MMX code for 48-bit and 64-bit images
+
+ // use MMX routine if machine supports it
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_INTERLACE)
+ /* && mmx_supported */ )
+ {
+ if (pixel_bytes == 3)
+ {
+ if (((pass == 0) || (pass == 1)) && width)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width
+ sub edi, 21 // (png_pass_inc[pass] - 1)*pixel_bytes
+loop_pass0:
+ movd mm0, [esi] ; X X X X X v2 v1 v0
+ pand mm0, const4 ; 0 0 0 0 0 v2 v1 v0
+ movq mm1, mm0 ; 0 0 0 0 0 v2 v1 v0
+ psllq mm0, 16 ; 0 0 0 v2 v1 v0 0 0
+ movq mm2, mm0 ; 0 0 0 v2 v1 v0 0 0
+ psllq mm0, 24 ; v2 v1 v0 0 0 0 0 0
+ psrlq mm1, 8 ; 0 0 0 0 0 0 v2 v1
+ por mm0, mm2 ; v2 v1 v0 v2 v1 v0 0 0
+ por mm0, mm1 ; v2 v1 v0 v2 v1 v0 v2 v1
+ movq mm3, mm0 ; v2 v1 v0 v2 v1 v0 v2 v1
+ psllq mm0, 16 ; v0 v2 v1 v0 v2 v1 0 0
+ movq mm4, mm3 ; v2 v1 v0 v2 v1 v0 v2 v1
+ punpckhdq mm3, mm0 ; v0 v2 v1 v0 v2 v1 v0 v2
+ movq [edi+16] , mm4
+ psrlq mm0, 32 ; 0 0 0 0 v0 v2 v1 v0
+ movq [edi+8] , mm3
+ punpckldq mm0, mm4 ; v1 v0 v2 v1 v0 v2 v1 v0
+ sub esi, 3
+ movq [edi], mm0
+ sub edi, 24
+ //sub esi, 3
+ dec ecx
+ jnz loop_pass0
+ EMMS
+ }
+ }
+ else if (((pass == 2) || (pass == 3)) && width)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width
+ sub edi, 9 // (png_pass_inc[pass] - 1)*pixel_bytes
+loop_pass2:
+ movd mm0, [esi] ; X X X X X v2 v1 v0
+ pand mm0, const4 ; 0 0 0 0 0 v2 v1 v0
+ movq mm1, mm0 ; 0 0 0 0 0 v2 v1 v0
+ psllq mm0, 16 ; 0 0 0 v2 v1 v0 0 0
+ movq mm2, mm0 ; 0 0 0 v2 v1 v0 0 0
+ psllq mm0, 24 ; v2 v1 v0 0 0 0 0 0
+ psrlq mm1, 8 ; 0 0 0 0 0 0 v2 v1
+ por mm0, mm2 ; v2 v1 v0 v2 v1 v0 0 0
+ por mm0, mm1 ; v2 v1 v0 v2 v1 v0 v2 v1
+ movq [edi+4], mm0 ; move to memory
+ psrlq mm0, 16 ; 0 0 v2 v1 v0 v2 v1 v0
+ movd [edi], mm0 ; move to memory
+ sub esi, 3
+ sub edi, 12
+ dec ecx
+ jnz loop_pass2
+ EMMS
+ }
+ }
+ else if (width) /* && ((pass == 4) || (pass == 5)) */
+ {
+ int width_mmx = ((width >> 1) << 1) - 8;
+ if (width_mmx < 0)
+ width_mmx = 0;
+ width -= width_mmx; // 8 or 9 pix, 24 or 27 bytes
+ if (width_mmx)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width_mmx
+ sub esi, 3
+ sub edi, 9
+loop_pass4:
+ movq mm0, [esi] ; X X v2 v1 v0 v5 v4 v3
+ movq mm7, mm0 ; X X v2 v1 v0 v5 v4 v3
+ movq mm6, mm0 ; X X v2 v1 v0 v5 v4 v3
+ psllq mm0, 24 ; v1 v0 v5 v4 v3 0 0 0
+ pand mm7, const4 ; 0 0 0 0 0 v5 v4 v3
+ psrlq mm6, 24 ; 0 0 0 X X v2 v1 v0
+ por mm0, mm7 ; v1 v0 v5 v4 v3 v5 v4 v3
+ movq mm5, mm6 ; 0 0 0 X X v2 v1 v0
+ psllq mm6, 8 ; 0 0 X X v2 v1 v0 0
+ movq [edi], mm0 ; move quad to memory
+ psrlq mm5, 16 ; 0 0 0 0 0 X X v2
+ pand mm5, const6 ; 0 0 0 0 0 0 0 v2
+ por mm6, mm5 ; 0 0 X X v2 v1 v0 v2
+ movd [edi+8], mm6 ; move double to memory
+ sub esi, 6
+ sub edi, 12
+ sub ecx, 2
+ jnz loop_pass4
+ EMMS
+ }
+ }
+
+ sptr -= width_mmx*3;
+ dp -= width_mmx*6;
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+
+ png_memcpy(v, sptr, 3);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, 3);
+ dp -= 3;
+ }
+ sptr -= 3;
+ }
+ }
+ } /* end of pixel_bytes == 3 */
+
+ else if (pixel_bytes == 1)
+ {
+ if (((pass == 0) || (pass == 1)) && width)
+ {
+ int width_mmx = ((width >> 2) << 2);
+ width -= width_mmx;
+ if (width_mmx)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width_mmx
+ sub edi, 31
+ sub esi, 3
+loop1_pass0:
+ movd mm0, [esi] ; X X X X v0 v1 v2 v3
+ movq mm1, mm0 ; X X X X v0 v1 v2 v3
+ punpcklbw mm0, mm0 ; v0 v0 v1 v1 v2 v2 v3 v3
+ movq mm2, mm0 ; v0 v0 v1 v1 v2 v2 v3 v3
+ punpcklwd mm0, mm0 ; v2 v2 v2 v2 v3 v3 v3 v3
+ movq mm3, mm0 ; v2 v2 v2 v2 v3 v3 v3 v3
+ punpckldq mm0, mm0 ; v3 v3 v3 v3 v3 v3 v3 v3
+ punpckhdq mm3, mm3 ; v2 v2 v2 v2 v2 v2 v2 v2
+ movq [edi], mm0 ; move to memory v3
+ punpckhwd mm2, mm2 ; v0 v0 v0 v0 v1 v1 v1 v1
+ movq [edi+8], mm3 ; move to memory v2
+ movq mm4, mm2 ; v0 v0 v0 v0 v1 v1 v1 v1
+ punpckldq mm2, mm2 ; v1 v1 v1 v1 v1 v1 v1 v1
+ punpckhdq mm4, mm4 ; v0 v0 v0 v0 v0 v0 v0 v0
+ movq [edi+16], mm2 ; move to memory v1
+ movq [edi+24], mm4 ; move to memory v0
+ sub esi, 4
+ sub edi, 32
+ sub ecx, 4
+ jnz loop1_pass0
+ EMMS
+ }
+ }
+
+ sptr -= width_mmx;
+ dp -= width_mmx*8;
+ for (i = width; i; i--)
+ {
+ int j;
+
+ /* I simplified this part in version 1.0.4e
+ * here and in several other instances where
+ * pixel_bytes == 1 -- GR-P
+ *
+ * Original code:
+ *
+ * png_byte v[8];
+ * png_memcpy(v, sptr, pixel_bytes);
+ * for (j = 0; j < png_pass_inc[pass]; j++)
+ * {
+ * png_memcpy(dp, v, pixel_bytes);
+ * dp -= pixel_bytes;
+ * }
+ * sptr -= pixel_bytes;
+ *
+ * Replacement code is in the next three lines:
+ */
+
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ *dp-- = *sptr;
+ sptr--;
+ }
+ }
+ else if (((pass == 2) || (pass == 3)) && width)
+ {
+ int width_mmx = ((width >> 2) << 2);
+ width -= width_mmx;
+ if (width_mmx)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width_mmx
+ sub edi, 15
+ sub esi, 3
+loop1_pass2:
+ movd mm0, [esi] ; X X X X v0 v1 v2 v3
+ punpcklbw mm0, mm0 ; v0 v0 v1 v1 v2 v2 v3 v3
+ movq mm1, mm0 ; v0 v0 v1 v1 v2 v2 v3 v3
+ punpcklwd mm0, mm0 ; v2 v2 v2 v2 v3 v3 v3 v3
+ punpckhwd mm1, mm1 ; v0 v0 v0 v0 v1 v1 v1 v1
+ movq [edi], mm0 ; move to memory v2 and v3
+ sub esi, 4
+ movq [edi+8], mm1 ; move to memory v1 and v0
+ sub edi, 16
+ sub ecx, 4
+ jnz loop1_pass2
+ EMMS
+ }
+ }
+
+ sptr -= width_mmx;
+ dp -= width_mmx*4;
+ for (i = width; i; i--)
+ {
+ int j;
+
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp-- = *sptr;
+ }
+ sptr --;
+ }
+ }
+ else if (width) /* && ((pass == 4) || (pass == 5))) */
+ {
+ int width_mmx = ((width >> 3) << 3);
+ width -= width_mmx;
+ if (width_mmx)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width_mmx
+ sub edi, 15
+ sub esi, 7
+loop1_pass4:
+ movq mm0, [esi] ; v0 v1 v2 v3 v4 v5 v6 v7
+ movq mm1, mm0 ; v0 v1 v2 v3 v4 v5 v6 v7
+ punpcklbw mm0, mm0 ; v4 v4 v5 v5 v6 v6 v7 v7
+ //movq mm1, mm0 ; v0 v0 v1 v1 v2 v2 v3 v3
+ punpckhbw mm1, mm1 ;v0 v0 v1 v1 v2 v2 v3 v3
+ movq [edi+8], mm1 ; move to memory v0 v1 v2 and v3
+ sub esi, 8
+ movq [edi], mm0 ; move to memory v4 v5 v6 and v7
+ //sub esi, 4
+ sub edi, 16
+ sub ecx, 8
+ jnz loop1_pass4
+ EMMS
+ }
+ }
+
+ sptr -= width_mmx;
+ dp -= width_mmx*2;
+ for (i = width; i; i--)
+ {
+ int j;
+
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp-- = *sptr;
+ }
+ sptr --;
+ }
+ }
+ } /* end of pixel_bytes == 1 */
+
+ else if (pixel_bytes == 2)
+ {
+ if (((pass == 0) || (pass == 1)) && width)
+ {
+ int width_mmx = ((width >> 1) << 1);
+ width -= width_mmx;
+ if (width_mmx)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width_mmx
+ sub esi, 2
+ sub edi, 30
+loop2_pass0:
+ movd mm0, [esi] ; X X X X v1 v0 v3 v2
+ punpcklwd mm0, mm0 ; v1 v0 v1 v0 v3 v2 v3 v2
+ movq mm1, mm0 ; v1 v0 v1 v0 v3 v2 v3 v2
+ punpckldq mm0, mm0 ; v3 v2 v3 v2 v3 v2 v3 v2
+ punpckhdq mm1, mm1 ; v1 v0 v1 v0 v1 v0 v1 v0
+ movq [edi], mm0
+ movq [edi + 8], mm0
+ movq [edi + 16], mm1
+ movq [edi + 24], mm1
+ sub esi, 4
+ sub edi, 32
+ sub ecx, 2
+ jnz loop2_pass0
+ EMMS
+ }
+ }
+
+ sptr -= (width_mmx*2 - 2); // sign fixed
+ dp -= (width_mmx*16 - 2); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 2;
+ png_memcpy(v, sptr, 2);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 2;
+ png_memcpy(dp, v, 2);
+ }
+ }
+ }
+ else if (((pass == 2) || (pass == 3)) && width)
+ {
+ int width_mmx = ((width >> 1) << 1) ;
+ width -= width_mmx;
+ if (width_mmx)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width_mmx
+ sub esi, 2
+ sub edi, 14
+loop2_pass2:
+ movd mm0, [esi] ; X X X X v1 v0 v3 v2
+ punpcklwd mm0, mm0 ; v1 v0 v1 v0 v3 v2 v3 v2
+ movq mm1, mm0 ; v1 v0 v1 v0 v3 v2 v3 v2
+ punpckldq mm0, mm0 ; v3 v2 v3 v2 v3 v2 v3 v2
+ punpckhdq mm1, mm1 ; v1 v0 v1 v0 v1 v0 v1 v0
+ movq [edi], mm0
+ sub esi, 4
+ movq [edi + 8], mm1
+ //sub esi, 4
+ sub edi, 16
+ sub ecx, 2
+ jnz loop2_pass2
+ EMMS
+ }
+ }
+
+ sptr -= (width_mmx*2 - 2); // sign fixed
+ dp -= (width_mmx*8 - 2); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 2;
+ png_memcpy(v, sptr, 2);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 2;
+ png_memcpy(dp, v, 2);
+ }
+ }
+ }
+ else if (width) // pass == 4 or 5
+ {
+ int width_mmx = ((width >> 1) << 1) ;
+ width -= width_mmx;
+ if (width_mmx)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width_mmx
+ sub esi, 2
+ sub edi, 6
+loop2_pass4:
+ movd mm0, [esi] ; X X X X v1 v0 v3 v2
+ punpcklwd mm0, mm0 ; v1 v0 v1 v0 v3 v2 v3 v2
+ sub esi, 4
+ movq [edi], mm0
+ sub edi, 8
+ sub ecx, 2
+ jnz loop2_pass4
+ EMMS
+ }
+ }
+
+ sptr -= (width_mmx*2 - 2); // sign fixed
+ dp -= (width_mmx*4 - 2); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 2;
+ png_memcpy(v, sptr, 2);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 2;
+ png_memcpy(dp, v, 2);
+ }
+ }
+ }
+ } /* end of pixel_bytes == 2 */
+
+ else if (pixel_bytes == 4)
+ {
+ if (((pass == 0) || (pass == 1)) && width)
+ {
+ int width_mmx = ((width >> 1) << 1) ;
+ width -= width_mmx;
+ if (width_mmx)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width_mmx
+ sub esi, 4
+ sub edi, 60
+loop4_pass0:
+ movq mm0, [esi] ; v3 v2 v1 v0 v7 v6 v5 v4
+ movq mm1, mm0 ; v3 v2 v1 v0 v7 v6 v5 v4
+ punpckldq mm0, mm0 ; v7 v6 v5 v4 v7 v6 v5 v4
+ punpckhdq mm1, mm1 ; v3 v2 v1 v0 v3 v2 v1 v0
+ movq [edi], mm0
+ movq [edi + 8], mm0
+ movq [edi + 16], mm0
+ movq [edi + 24], mm0
+ movq [edi+32], mm1
+ movq [edi + 40], mm1
+ movq [edi+ 48], mm1
+ sub esi, 8
+ movq [edi + 56], mm1
+ sub edi, 64
+ sub ecx, 2
+ jnz loop4_pass0
+ EMMS
+ }
+ }
+
+ sptr -= (width_mmx*4 - 4); // sign fixed
+ dp -= (width_mmx*32 - 4); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 4;
+ png_memcpy(v, sptr, 4);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 4;
+ png_memcpy(dp, v, 4);
+ }
+ }
+ }
+ else if (((pass == 2) || (pass == 3)) && width)
+ {
+ int width_mmx = ((width >> 1) << 1) ;
+ width -= width_mmx;
+ if (width_mmx)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width_mmx
+ sub esi, 4
+ sub edi, 28
+loop4_pass2:
+ movq mm0, [esi] ; v3 v2 v1 v0 v7 v6 v5 v4
+ movq mm1, mm0 ; v3 v2 v1 v0 v7 v6 v5 v4
+ punpckldq mm0, mm0 ; v7 v6 v5 v4 v7 v6 v5 v4
+ punpckhdq mm1, mm1 ; v3 v2 v1 v0 v3 v2 v1 v0
+ movq [edi], mm0
+ movq [edi + 8], mm0
+ movq [edi+16], mm1
+ movq [edi + 24], mm1
+ sub esi, 8
+ sub edi, 32
+ sub ecx, 2
+ jnz loop4_pass2
+ EMMS
+ }
+ }
+
+ sptr -= (width_mmx*4 - 4); // sign fixed
+ dp -= (width_mmx*16 - 4); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 4;
+ png_memcpy(v, sptr, 4);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 4;
+ png_memcpy(dp, v, 4);
+ }
+ }
+ }
+ else if (width) // pass == 4 or 5
+ {
+ int width_mmx = ((width >> 1) << 1) ;
+ width -= width_mmx;
+ if (width_mmx)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width_mmx
+ sub esi, 4
+ sub edi, 12
+loop4_pass4:
+ movq mm0, [esi] ; v3 v2 v1 v0 v7 v6 v5 v4
+ movq mm1, mm0 ; v3 v2 v1 v0 v7 v6 v5 v4
+ punpckldq mm0, mm0 ; v7 v6 v5 v4 v7 v6 v5 v4
+ punpckhdq mm1, mm1 ; v3 v2 v1 v0 v3 v2 v1 v0
+ movq [edi], mm0
+ sub esi, 8
+ movq [edi + 8], mm1
+ sub edi, 16
+ sub ecx, 2
+ jnz loop4_pass4
+ EMMS
+ }
+ }
+
+ sptr -= (width_mmx*4 - 4); // sign fixed
+ dp -= (width_mmx*8 - 4); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 4;
+ png_memcpy(v, sptr, 4);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 4;
+ png_memcpy(dp, v, 4);
+ }
+ }
+ }
+
+ } /* end of pixel_bytes == 4 */
+
+ else if (pixel_bytes == 6)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, 6);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, 6);
+ dp -= 6;
+ }
+ sptr -= 6;
+ }
+ } /* end of pixel_bytes == 6 */
+
+ else
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, pixel_bytes);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, pixel_bytes);
+ dp -= pixel_bytes;
+ }
+ sptr-= pixel_bytes;
+ }
+ }
+ } /* end of mmx_supported */
+
+ else /* MMX not supported: use modified C code - takes advantage
+ * of inlining of memcpy for a constant */
+ {
+ if (pixel_bytes == 1)
+ {
+ for (i = width; i; i--)
+ {
+ int j;
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ *dp-- = *sptr;
+ sptr--;
+ }
+ }
+ else if (pixel_bytes == 3)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, pixel_bytes);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, pixel_bytes);
+ dp -= pixel_bytes;
+ }
+ sptr -= pixel_bytes;
+ }
+ }
+ else if (pixel_bytes == 2)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, pixel_bytes);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, pixel_bytes);
+ dp -= pixel_bytes;
+ }
+ sptr -= pixel_bytes;
+ }
+ }
+ else if (pixel_bytes == 4)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, pixel_bytes);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, pixel_bytes);
+ dp -= pixel_bytes;
+ }
+ sptr -= pixel_bytes;
+ }
+ }
+ else if (pixel_bytes == 6)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, pixel_bytes);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, pixel_bytes);
+ dp -= pixel_bytes;
+ }
+ sptr -= pixel_bytes;
+ }
+ }
+ else
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, pixel_bytes);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, pixel_bytes);
+ dp -= pixel_bytes;
+ }
+ sptr -= pixel_bytes;
+ }
+ }
+
+ } /* end of MMX not supported */
+ break;
+ }
+ } /* end switch (row_info->pixel_depth) */
+
+ row_info->width = final_width;
+ row_info->rowbytes = ((final_width *
+ (png_uint_32)row_info->pixel_depth + 7) >> 3);
+ }
+
+}
+
+#endif /* PNG_READ_INTERLACING_SUPPORTED */
+
+
+// These variables are utilized in the functions below. They are declared
+// globally here to ensure alignment on 8-byte boundaries.
+
+union uAll {
+ __int64 use;
+ double align;
+} LBCarryMask = {0x0101010101010101},
+ HBClearMask = {0x7f7f7f7f7f7f7f7f},
+ ActiveMask, ActiveMask2, ActiveMaskEnd, ShiftBpp, ShiftRem;
+
+
+// Optimized code for PNG Average filter decoder
+void /* PRIVATE */
+png_read_filter_row_mmx_avg(png_row_infop row_info, png_bytep row
+ , png_bytep prev_row)
+{
+ int bpp;
+ png_uint_32 FullLength;
+ png_uint_32 MMXLength;
+ //png_uint_32 len;
+ int diff;
+
+ bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel
+ FullLength = row_info->rowbytes; // # of bytes to filter
+ _asm {
+ // Init address pointers and offset
+ mov edi, row // edi ==> Avg(x)
+ xor ebx, ebx // ebx ==> x
+ mov edx, edi
+ mov esi, prev_row // esi ==> Prior(x)
+ sub edx, bpp // edx ==> Raw(x-bpp)
+
+ xor eax, eax
+ // Compute the Raw value for the first bpp bytes
+ // Raw(x) = Avg(x) + (Prior(x)/2)
+davgrlp:
+ mov al, [esi + ebx] // Load al with Prior(x)
+ inc ebx
+ shr al, 1 // divide by 2
+ add al, [edi+ebx-1] // Add Avg(x); -1 to offset inc ebx
+ cmp ebx, bpp
+ mov [edi+ebx-1], al // Write back Raw(x);
+ // mov does not affect flags; -1 to offset inc ebx
+ jb davgrlp
+ // get # of bytes to alignment
+ mov diff, edi // take start of row
+ add diff, ebx // add bpp
+ add diff, 0xf // add 7 + 8 to incr past alignment boundary
+ and diff, 0xfffffff8 // mask to alignment boundary
+ sub diff, edi // subtract from start ==> value ebx at alignment
+ jz davggo
+ // fix alignment
+ // Compute the Raw value for the bytes upto the alignment boundary
+ // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
+ xor ecx, ecx
+davglp1:
+ xor eax, eax
+ mov cl, [esi + ebx] // load cl with Prior(x)
+ mov al, [edx + ebx] // load al with Raw(x-bpp)
+ add ax, cx
+ inc ebx
+ shr ax, 1 // divide by 2
+ add al, [edi+ebx-1] // Add Avg(x); -1 to offset inc ebx
+ cmp ebx, diff // Check if at alignment boundary
+ mov [edi+ebx-1], al // Write back Raw(x);
+ // mov does not affect flags; -1 to offset inc ebx
+ jb davglp1 // Repeat until at alignment boundary
+davggo:
+ mov eax, FullLength
+ mov ecx, eax
+ sub eax, ebx // subtract alignment fix
+ and eax, 0x00000007 // calc bytes over mult of 8
+ sub ecx, eax // drop over bytes from original length
+ mov MMXLength, ecx
+ } // end _asm block
+ // Now do the math for the rest of the row
+ switch ( bpp )
+ {
+ case 3:
+ {
+ ActiveMask.use = 0x0000000000ffffff;
+ ShiftBpp.use = 24; // == 3 * 8
+ ShiftRem.use = 40; // == 64 - 24
+ _asm {
+ // Re-init address pointers and offset
+ movq mm7, ActiveMask
+ mov ebx, diff // ebx ==> x = offset to alignment boundary
+ movq mm5, LBCarryMask
+ mov edi, row // edi ==> Avg(x)
+ movq mm4, HBClearMask
+ mov esi, prev_row // esi ==> Prior(x)
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm2, [edi + ebx - 8] // Load previous aligned 8 bytes
+ // (we correct position in loop below)
+davg3lp:
+ movq mm0, [edi + ebx] // Load mm0 with Avg(x)
+ // Add (Prev_row/2) to Average
+ movq mm3, mm5
+ psrlq mm2, ShiftRem // Correct position Raw(x-bpp) data
+ movq mm1, [esi + ebx] // Load mm1 with Prior(x)
+ movq mm6, mm7
+ pand mm3, mm1 // get lsb for each prev_row byte
+ psrlq mm1, 1 // divide prev_row bytes by 2
+ pand mm1, mm4 // clear invalid bit 7 of each byte
+ paddb mm0, mm1 // add (Prev_row/2) to Avg for each byte
+ // Add 1st active group (Raw(x-bpp)/2) to Average with LBCarry
+ movq mm1, mm3 // now use mm1 for getting LBCarrys
+ pand mm1, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1 (Only valid for active group)
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte
+ pand mm2, mm6 // Leave only Active Group 1 bytes to add to Avg
+ paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active
+ // byte
+ // Add 2nd active group (Raw(x-bpp)/2) to Average with LBCarry
+ psllq mm6, ShiftBpp // shift the mm6 mask to cover bytes 3-5
+ movq mm2, mm0 // mov updated Raws to mm2
+ psllq mm2, ShiftBpp // shift data to position correctly
+ movq mm1, mm3 // now use mm1 for getting LBCarrys
+ pand mm1, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1 (Only valid for active group)
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte
+ pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg
+ paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active
+ // byte
+
+ // Add 3rd active group (Raw(x-bpp)/2) to Average with LBCarry
+ psllq mm6, ShiftBpp // shift the mm6 mask to cover the last two
+ // bytes
+ movq mm2, mm0 // mov updated Raws to mm2
+ psllq mm2, ShiftBpp // shift data to position correctly
+ // Data only needs to be shifted once here to
+ // get the correct x-bpp offset.
+ movq mm1, mm3 // now use mm1 for getting LBCarrys
+ pand mm1, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1 (Only valid for active group)
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte
+ pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg
+ add ebx, 8
+ paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active
+ // byte
+
+ // Now ready to write back to memory
+ movq [edi + ebx - 8], mm0
+ // Move updated Raw(x) to use as Raw(x-bpp) for next loop
+ cmp ebx, MMXLength
+ movq mm2, mm0 // mov updated Raw(x) to mm2
+ jb davg3lp
+ } // end _asm block
+ }
+ break;
+
+ case 6:
+ case 4:
+ case 7:
+ case 5:
+ {
+ ActiveMask.use = 0xffffffffffffffff; // use shift below to clear
+ // appropriate inactive bytes
+ ShiftBpp.use = bpp << 3;
+ ShiftRem.use = 64 - ShiftBpp.use;
+ _asm {
+ movq mm4, HBClearMask
+ // Re-init address pointers and offset
+ mov ebx, diff // ebx ==> x = offset to alignment boundary
+ // Load ActiveMask and clear all bytes except for 1st active group
+ movq mm7, ActiveMask
+ mov edi, row // edi ==> Avg(x)
+ psrlq mm7, ShiftRem
+ mov esi, prev_row // esi ==> Prior(x)
+ movq mm6, mm7
+ movq mm5, LBCarryMask
+ psllq mm6, ShiftBpp // Create mask for 2nd active group
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm2, [edi + ebx - 8] // Load previous aligned 8 bytes
+ // (we correct position in loop below)
+davg4lp:
+ movq mm0, [edi + ebx]
+ psrlq mm2, ShiftRem // shift data to position correctly
+ movq mm1, [esi + ebx]
+ // Add (Prev_row/2) to Average
+ movq mm3, mm5
+ pand mm3, mm1 // get lsb for each prev_row byte
+ psrlq mm1, 1 // divide prev_row bytes by 2
+ pand mm1, mm4 // clear invalid bit 7 of each byte
+ paddb mm0, mm1 // add (Prev_row/2) to Avg for each byte
+ // Add 1st active group (Raw(x-bpp)/2) to Average with LBCarry
+ movq mm1, mm3 // now use mm1 for getting LBCarrys
+ pand mm1, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1 (Only valid for active group)
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte
+ pand mm2, mm7 // Leave only Active Group 1 bytes to add to Avg
+ paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active
+ // byte
+ // Add 2nd active group (Raw(x-bpp)/2) to Average with LBCarry
+ movq mm2, mm0 // mov updated Raws to mm2
+ psllq mm2, ShiftBpp // shift data to position correctly
+ add ebx, 8
+ movq mm1, mm3 // now use mm1 for getting LBCarrys
+ pand mm1, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1 (Only valid for active group)
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte
+ pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg
+ paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active
+ // byte
+ cmp ebx, MMXLength
+ // Now ready to write back to memory
+ movq [edi + ebx - 8], mm0
+ // Prep Raw(x-bpp) for next loop
+ movq mm2, mm0 // mov updated Raws to mm2
+ jb davg4lp
+ } // end _asm block
+ }
+ break;
+ case 2:
+ {
+ ActiveMask.use = 0x000000000000ffff;
+ ShiftBpp.use = 16; // == 2 * 8 [BUGFIX]
+ ShiftRem.use = 48; // == 64 - 16 [BUGFIX]
+ _asm {
+ // Load ActiveMask
+ movq mm7, ActiveMask
+ // Re-init address pointers and offset
+ mov ebx, diff // ebx ==> x = offset to alignment boundary
+ movq mm5, LBCarryMask
+ mov edi, row // edi ==> Avg(x)
+ movq mm4, HBClearMask
+ mov esi, prev_row // esi ==> Prior(x)
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm2, [edi + ebx - 8] // Load previous aligned 8 bytes
+ // (we correct position in loop below)
+davg2lp:
+ movq mm0, [edi + ebx]
+ psrlq mm2, ShiftRem // shift data to position correctly [BUGFIX]
+ movq mm1, [esi + ebx]
+ // Add (Prev_row/2) to Average
+ movq mm3, mm5
+ pand mm3, mm1 // get lsb for each prev_row byte
+ psrlq mm1, 1 // divide prev_row bytes by 2
+ pand mm1, mm4 // clear invalid bit 7 of each byte
+ movq mm6, mm7
+ paddb mm0, mm1 // add (Prev_row/2) to Avg for each byte
+ // Add 1st active group (Raw(x-bpp)/2) to Average with LBCarry
+ movq mm1, mm3 // now use mm1 for getting LBCarrys
+ pand mm1, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1 (Only valid for active group)
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte
+ pand mm2, mm6 // Leave only Active Group 1 bytes to add to Avg
+ paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active byte
+ // Add 2nd active group (Raw(x-bpp)/2) to Average with LBCarry
+ psllq mm6, ShiftBpp // shift the mm6 mask to cover bytes 2 & 3
+ movq mm2, mm0 // mov updated Raws to mm2
+ psllq mm2, ShiftBpp // shift data to position correctly
+ movq mm1, mm3 // now use mm1 for getting LBCarrys
+ pand mm1, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1 (Only valid for active group)
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte
+ pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg
+ paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active byte
+
+ // Add rdd active group (Raw(x-bpp)/2) to Average with LBCarry
+ psllq mm6, ShiftBpp // shift the mm6 mask to cover bytes 4 & 5
+ movq mm2, mm0 // mov updated Raws to mm2
+ psllq mm2, ShiftBpp // shift data to position correctly
+ // Data only needs to be shifted once here to
+ // get the correct x-bpp offset.
+ movq mm1, mm3 // now use mm1 for getting LBCarrys
+ pand mm1, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1 (Only valid for active group)
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte
+ pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg
+ paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active byte
+
+ // Add 4th active group (Raw(x-bpp)/2) to Average with LBCarry
+ psllq mm6, ShiftBpp // shift the mm6 mask to cover bytes 6 & 7
+ movq mm2, mm0 // mov updated Raws to mm2
+ psllq mm2, ShiftBpp // shift data to position correctly
+ // Data only needs to be shifted once here to
+ // get the correct x-bpp offset.
+ add ebx, 8
+ movq mm1, mm3 // now use mm1 for getting LBCarrys
+ pand mm1, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1 (Only valid for active group)
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte
+ pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg
+ paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active byte
+
+ cmp ebx, MMXLength
+ // Now ready to write back to memory
+ movq [edi + ebx - 8], mm0
+ // Prep Raw(x-bpp) for next loop
+ movq mm2, mm0 // mov updated Raws to mm2
+ jb davg2lp
+ } // end _asm block
+ }
+ break;
+
+ case 1: // bpp == 1
+ {
+ _asm {
+ // Re-init address pointers and offset
+ mov ebx, diff // ebx ==> x = offset to alignment boundary
+ mov edi, row // edi ==> Avg(x)
+ cmp ebx, FullLength // Test if offset at end of array
+ jnb davg1end
+ // Do Paeth decode for remaining bytes
+ mov esi, prev_row // esi ==> Prior(x)
+ mov edx, edi
+ xor ecx, ecx // zero ecx before using cl & cx in loop below
+ sub edx, bpp // edx ==> Raw(x-bpp)
+davg1lp:
+ // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
+ xor eax, eax
+ mov cl, [esi + ebx] // load cl with Prior(x)
+ mov al, [edx + ebx] // load al with Raw(x-bpp)
+ add ax, cx
+ inc ebx
+ shr ax, 1 // divide by 2
+ add al, [edi+ebx-1] // Add Avg(x); -1 to offset inc ebx
+ cmp ebx, FullLength // Check if at end of array
+ mov [edi+ebx-1], al // Write back Raw(x);
+ // mov does not affect flags; -1 to offset inc ebx
+ jb davg1lp
+davg1end:
+ } // end _asm block
+ }
+ return;
+
+ case 8: // bpp == 8
+ {
+ _asm {
+ // Re-init address pointers and offset
+ mov ebx, diff // ebx ==> x = offset to alignment boundary
+ movq mm5, LBCarryMask
+ mov edi, row // edi ==> Avg(x)
+ movq mm4, HBClearMask
+ mov esi, prev_row // esi ==> Prior(x)
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm2, [edi + ebx - 8] // Load previous aligned 8 bytes
+ // (NO NEED to correct position in loop below)
+davg8lp:
+ movq mm0, [edi + ebx]
+ movq mm3, mm5
+ movq mm1, [esi + ebx]
+ add ebx, 8
+ pand mm3, mm1 // get lsb for each prev_row byte
+ psrlq mm1, 1 // divide prev_row bytes by 2
+ pand mm3, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm1, mm4 // clear invalid bit 7 of each byte
+ paddb mm0, mm3 // add LBCarrys to Avg for each byte
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm0, mm1 // add (Prev_row/2) to Avg for each byte
+ paddb mm0, mm2 // add (Raw/2) to Avg for each byte
+ cmp ebx, MMXLength
+ movq [edi + ebx - 8], mm0
+ movq mm2, mm0 // reuse as Raw(x-bpp)
+ jb davg8lp
+ } // end _asm block
+ }
+ break;
+ default: // bpp greater than 8
+ {
+ _asm {
+ movq mm5, LBCarryMask
+ // Re-init address pointers and offset
+ mov ebx, diff // ebx ==> x = offset to alignment boundary
+ mov edi, row // edi ==> Avg(x)
+ movq mm4, HBClearMask
+ mov edx, edi
+ mov esi, prev_row // esi ==> Prior(x)
+ sub edx, bpp // edx ==> Raw(x-bpp)
+davgAlp:
+ movq mm0, [edi + ebx]
+ movq mm3, mm5
+ movq mm1, [esi + ebx]
+ pand mm3, mm1 // get lsb for each prev_row byte
+ movq mm2, [edx + ebx]
+ psrlq mm1, 1 // divide prev_row bytes by 2
+ pand mm3, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm1, mm4 // clear invalid bit 7 of each byte
+ paddb mm0, mm3 // add LBCarrys to Avg for each byte
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm0, mm1 // add (Prev_row/2) to Avg for each byte
+ add ebx, 8
+ paddb mm0, mm2 // add (Raw/2) to Avg for each byte
+ cmp ebx, MMXLength
+ movq [edi + ebx - 8], mm0
+ jb davgAlp
+ } // end _asm block
+ }
+ break;
+ } // end switch ( bpp )
+
+ _asm {
+ // MMX acceleration complete now do clean-up
+ // Check if any remaining bytes left to decode
+ mov ebx, MMXLength // ebx ==> x = offset bytes remaining after MMX
+ mov edi, row // edi ==> Avg(x)
+ cmp ebx, FullLength // Test if offset at end of array
+ jnb davgend
+ // Do Paeth decode for remaining bytes
+ mov esi, prev_row // esi ==> Prior(x)
+ mov edx, edi
+ xor ecx, ecx // zero ecx before using cl & cx in loop below
+ sub edx, bpp // edx ==> Raw(x-bpp)
+davglp2:
+ // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
+ xor eax, eax
+ mov cl, [esi + ebx] // load cl with Prior(x)
+ mov al, [edx + ebx] // load al with Raw(x-bpp)
+ add ax, cx
+ inc ebx
+ shr ax, 1 // divide by 2
+ add al, [edi+ebx-1] // Add Avg(x); -1 to offset inc ebx
+ cmp ebx, FullLength // Check if at end of array
+ mov [edi+ebx-1], al // Write back Raw(x);
+ // mov does not affect flags; -1 to offset inc ebx
+ jb davglp2
+davgend:
+ emms // End MMX instructions; prep for possible FP instrs.
+ } // end _asm block
+}
+
+// Optimized code for PNG Paeth filter decoder
+void /* PRIVATE */
+png_read_filter_row_mmx_paeth(png_row_infop row_info, png_bytep row,
+ png_bytep prev_row)
+{
+ png_uint_32 FullLength;
+ png_uint_32 MMXLength;
+ //png_uint_32 len;
+ int bpp;
+ int diff;
+ //int ptemp;
+ int patemp, pbtemp, pctemp;
+
+ bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel
+ FullLength = row_info->rowbytes; // # of bytes to filter
+ _asm
+ {
+ xor ebx, ebx // ebx ==> x offset
+ mov edi, row
+ xor edx, edx // edx ==> x-bpp offset
+ mov esi, prev_row
+ xor eax, eax
+
+ // Compute the Raw value for the first bpp bytes
+ // Note: the formula works out to be always
+ // Paeth(x) = Raw(x) + Prior(x) where x < bpp
+dpthrlp:
+ mov al, [edi + ebx]
+ add al, [esi + ebx]
+ inc ebx
+ cmp ebx, bpp
+ mov [edi + ebx - 1], al
+ jb dpthrlp
+ // get # of bytes to alignment
+ mov diff, edi // take start of row
+ add diff, ebx // add bpp
+ xor ecx, ecx
+ add diff, 0xf // add 7 + 8 to incr past alignment boundary
+ and diff, 0xfffffff8 // mask to alignment boundary
+ sub diff, edi // subtract from start ==> value ebx at alignment
+ jz dpthgo
+ // fix alignment
+dpthlp1:
+ xor eax, eax
+ // pav = p - a = (a + b - c) - a = b - c
+ mov al, [esi + ebx] // load Prior(x) into al
+ mov cl, [esi + edx] // load Prior(x-bpp) into cl
+ sub eax, ecx // subtract Prior(x-bpp)
+ mov patemp, eax // Save pav for later use
+ xor eax, eax
+ // pbv = p - b = (a + b - c) - b = a - c
+ mov al, [edi + edx] // load Raw(x-bpp) into al
+ sub eax, ecx // subtract Prior(x-bpp)
+ mov ecx, eax
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ add eax, patemp // pcv = pav + pbv
+ // pc = abs(pcv)
+ test eax, 0x80000000
+ jz dpthpca
+ neg eax // reverse sign of neg values
+dpthpca:
+ mov pctemp, eax // save pc for later use
+ // pb = abs(pbv)
+ test ecx, 0x80000000
+ jz dpthpba
+ neg ecx // reverse sign of neg values
+dpthpba:
+ mov pbtemp, ecx // save pb for later use
+ // pa = abs(pav)
+ mov eax, patemp
+ test eax, 0x80000000
+ jz dpthpaa
+ neg eax // reverse sign of neg values
+dpthpaa:
+ mov patemp, eax // save pa for later use
+ // test if pa <= pb
+ cmp eax, ecx
+ jna dpthabb
+ // pa > pb; now test if pb <= pc
+ cmp ecx, pctemp
+ jna dpthbbc
+ // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ mov cl, [esi + edx] // load Prior(x-bpp) into cl
+ jmp dpthpaeth
+dpthbbc:
+ // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
+ mov cl, [esi + ebx] // load Prior(x) into cl
+ jmp dpthpaeth
+dpthabb:
+ // pa <= pb; now test if pa <= pc
+ cmp eax, pctemp
+ jna dpthabc
+ // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ mov cl, [esi + edx] // load Prior(x-bpp) into cl
+ jmp dpthpaeth
+dpthabc:
+ // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
+ mov cl, [edi + edx] // load Raw(x-bpp) into cl
+dpthpaeth:
+ inc ebx
+ inc edx
+ // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
+ add [edi + ebx - 1], cl
+ cmp ebx, diff
+ jb dpthlp1
+dpthgo:
+ mov ecx, FullLength
+ mov eax, ecx
+ sub eax, ebx // subtract alignment fix
+ and eax, 0x00000007 // calc bytes over mult of 8
+ sub ecx, eax // drop over bytes from original length
+ mov MMXLength, ecx
+ } // end _asm block
+ // Now do the math for the rest of the row
+ switch ( bpp )
+ {
+ case 3:
+ {
+ ActiveMask.use = 0x0000000000ffffff;
+ ActiveMaskEnd.use = 0xffff000000000000;
+ ShiftBpp.use = 24; // == bpp(3) * 8
+ ShiftRem.use = 40; // == 64 - 24
+ _asm
+ {
+ mov ebx, diff
+ mov edi, row
+ mov esi, prev_row
+ pxor mm0, mm0
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm1, [edi+ebx-8]
+dpth3lp:
+ psrlq mm1, ShiftRem // shift last 3 bytes to 1st 3 bytes
+ movq mm2, [esi + ebx] // load b=Prior(x)
+ punpcklbw mm1, mm0 // Unpack High bytes of a
+ movq mm3, [esi+ebx-8] // Prep c=Prior(x-bpp) bytes
+ punpcklbw mm2, mm0 // Unpack High bytes of b
+ psrlq mm3, ShiftRem // shift last 3 bytes to 1st 3 bytes
+ // pav = p - a = (a + b - c) - a = b - c
+ movq mm4, mm2
+ punpcklbw mm3, mm0 // Unpack High bytes of c
+ // pbv = p - b = (a + b - c) - b = a - c
+ movq mm5, mm1
+ psubw mm4, mm3
+ pxor mm7, mm7
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ movq mm6, mm4
+ psubw mm5, mm3
+
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ pcmpgtw mm0, mm4 // Create mask pav bytes < 0
+ paddw mm6, mm5
+ pand mm0, mm4 // Only pav bytes < 0 in mm7
+ pcmpgtw mm7, mm5 // Create mask pbv bytes < 0
+ psubw mm4, mm0
+ pand mm7, mm5 // Only pbv bytes < 0 in mm0
+ psubw mm4, mm0
+ psubw mm5, mm7
+ pxor mm0, mm0
+ pcmpgtw mm0, mm6 // Create mask pcv bytes < 0
+ pand mm0, mm6 // Only pav bytes < 0 in mm7
+ psubw mm5, mm7
+ psubw mm6, mm0
+ // test pa <= pb
+ movq mm7, mm4
+ psubw mm6, mm0
+ pcmpgtw mm7, mm5 // pa > pb?
+ movq mm0, mm7
+ // use mm7 mask to merge pa & pb
+ pand mm5, mm7
+ // use mm0 mask copy to merge a & b
+ pand mm2, mm0
+ pandn mm7, mm4
+ pandn mm0, mm1
+ paddw mm7, mm5
+ paddw mm0, mm2
+ // test ((pa <= pb)? pa:pb) <= pc
+ pcmpgtw mm7, mm6 // pab > pc?
+ pxor mm1, mm1
+ pand mm3, mm7
+ pandn mm7, mm0
+ paddw mm7, mm3
+ pxor mm0, mm0
+ packuswb mm7, mm1
+ movq mm3, [esi + ebx] // load c=Prior(x-bpp)
+ pand mm7, ActiveMask
+ movq mm2, mm3 // load b=Prior(x) step 1
+ paddb mm7, [edi + ebx] // add Paeth predictor with Raw(x)
+ punpcklbw mm3, mm0 // Unpack High bytes of c
+ movq [edi + ebx], mm7 // write back updated value
+ movq mm1, mm7 // Now mm1 will be used as Raw(x-bpp)
+ // Now do Paeth for 2nd set of bytes (3-5)
+ psrlq mm2, ShiftBpp // load b=Prior(x) step 2
+ punpcklbw mm1, mm0 // Unpack High bytes of a
+ pxor mm7, mm7
+ punpcklbw mm2, mm0 // Unpack High bytes of b
+ // pbv = p - b = (a + b - c) - b = a - c
+ movq mm5, mm1
+ // pav = p - a = (a + b - c) - a = b - c
+ movq mm4, mm2
+ psubw mm5, mm3
+ psubw mm4, mm3
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) =
+ // pav + pbv = pbv + pav
+ movq mm6, mm5
+ paddw mm6, mm4
+
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ pcmpgtw mm0, mm5 // Create mask pbv bytes < 0
+ pcmpgtw mm7, mm4 // Create mask pav bytes < 0
+ pand mm0, mm5 // Only pbv bytes < 0 in mm0
+ pand mm7, mm4 // Only pav bytes < 0 in mm7
+ psubw mm5, mm0
+ psubw mm4, mm7
+ psubw mm5, mm0
+ psubw mm4, mm7
+ pxor mm0, mm0
+ pcmpgtw mm0, mm6 // Create mask pcv bytes < 0
+ pand mm0, mm6 // Only pav bytes < 0 in mm7
+ psubw mm6, mm0
+ // test pa <= pb
+ movq mm7, mm4
+ psubw mm6, mm0
+ pcmpgtw mm7, mm5 // pa > pb?
+ movq mm0, mm7
+ // use mm7 mask to merge pa & pb
+ pand mm5, mm7
+ // use mm0 mask copy to merge a & b
+ pand mm2, mm0
+ pandn mm7, mm4
+ pandn mm0, mm1
+ paddw mm7, mm5
+ paddw mm0, mm2
+ // test ((pa <= pb)? pa:pb) <= pc
+ pcmpgtw mm7, mm6 // pab > pc?
+ movq mm2, [esi + ebx] // load b=Prior(x)
+ pand mm3, mm7
+ pandn mm7, mm0
+ pxor mm1, mm1
+ paddw mm7, mm3
+ pxor mm0, mm0
+ packuswb mm7, mm1
+ movq mm3, mm2 // load c=Prior(x-bpp) step 1
+ pand mm7, ActiveMask
+ punpckhbw mm2, mm0 // Unpack High bytes of b
+ psllq mm7, ShiftBpp // Shift bytes to 2nd group of 3 bytes
+ // pav = p - a = (a + b - c) - a = b - c
+ movq mm4, mm2
+ paddb mm7, [edi + ebx] // add Paeth predictor with Raw(x)
+ psllq mm3, ShiftBpp // load c=Prior(x-bpp) step 2
+ movq [edi + ebx], mm7 // write back updated value
+ movq mm1, mm7
+ punpckhbw mm3, mm0 // Unpack High bytes of c
+ psllq mm1, ShiftBpp // Shift bytes
+ // Now mm1 will be used as Raw(x-bpp)
+ // Now do Paeth for 3rd, and final, set of bytes (6-7)
+ pxor mm7, mm7
+ punpckhbw mm1, mm0 // Unpack High bytes of a
+ psubw mm4, mm3
+ // pbv = p - b = (a + b - c) - b = a - c
+ movq mm5, mm1
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ movq mm6, mm4
+ psubw mm5, mm3
+ pxor mm0, mm0
+ paddw mm6, mm5
+
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ pcmpgtw mm0, mm4 // Create mask pav bytes < 0
+ pcmpgtw mm7, mm5 // Create mask pbv bytes < 0
+ pand mm0, mm4 // Only pav bytes < 0 in mm7
+ pand mm7, mm5 // Only pbv bytes < 0 in mm0
+ psubw mm4, mm0
+ psubw mm5, mm7
+ psubw mm4, mm0
+ psubw mm5, mm7
+ pxor mm0, mm0
+ pcmpgtw mm0, mm6 // Create mask pcv bytes < 0
+ pand mm0, mm6 // Only pav bytes < 0 in mm7
+ psubw mm6, mm0
+ // test pa <= pb
+ movq mm7, mm4
+ psubw mm6, mm0
+ pcmpgtw mm7, mm5 // pa > pb?
+ movq mm0, mm7
+ // use mm0 mask copy to merge a & b
+ pand mm2, mm0
+ // use mm7 mask to merge pa & pb
+ pand mm5, mm7
+ pandn mm0, mm1
+ pandn mm7, mm4
+ paddw mm0, mm2
+ paddw mm7, mm5
+ // test ((pa <= pb)? pa:pb) <= pc
+ pcmpgtw mm7, mm6 // pab > pc?
+ pand mm3, mm7
+ pandn mm7, mm0
+ paddw mm7, mm3
+ pxor mm1, mm1
+ packuswb mm1, mm7
+ // Step ebx to next set of 8 bytes and repeat loop til done
+ add ebx, 8
+ pand mm1, ActiveMaskEnd
+ paddb mm1, [edi + ebx - 8] // add Paeth predictor with Raw(x)
+
+ cmp ebx, MMXLength
+ pxor mm0, mm0 // pxor does not affect flags
+ movq [edi + ebx - 8], mm1 // write back updated value
+ // mm1 will be used as Raw(x-bpp) next loop
+ // mm3 ready to be used as Prior(x-bpp) next loop
+ jb dpth3lp
+ } // end _asm block
+ }
+ break;
+
+ case 6:
+ case 7:
+ case 5:
+ {
+ ActiveMask.use = 0x00000000ffffffff;
+ ActiveMask2.use = 0xffffffff00000000;
+ ShiftBpp.use = bpp << 3; // == bpp * 8
+ ShiftRem.use = 64 - ShiftBpp.use;
+ _asm
+ {
+ mov ebx, diff
+ mov edi, row
+ mov esi, prev_row
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm1, [edi+ebx-8]
+ pxor mm0, mm0
+dpth6lp:
+ // Must shift to position Raw(x-bpp) data
+ psrlq mm1, ShiftRem
+ // Do first set of 4 bytes
+ movq mm3, [esi+ebx-8] // read c=Prior(x-bpp) bytes
+ punpcklbw mm1, mm0 // Unpack Low bytes of a
+ movq mm2, [esi + ebx] // load b=Prior(x)
+ punpcklbw mm2, mm0 // Unpack Low bytes of b
+ // Must shift to position Prior(x-bpp) data
+ psrlq mm3, ShiftRem
+ // pav = p - a = (a + b - c) - a = b - c
+ movq mm4, mm2
+ punpcklbw mm3, mm0 // Unpack Low bytes of c
+ // pbv = p - b = (a + b - c) - b = a - c
+ movq mm5, mm1
+ psubw mm4, mm3
+ pxor mm7, mm7
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ movq mm6, mm4
+ psubw mm5, mm3
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ pcmpgtw mm0, mm4 // Create mask pav bytes < 0
+ paddw mm6, mm5
+ pand mm0, mm4 // Only pav bytes < 0 in mm7
+ pcmpgtw mm7, mm5 // Create mask pbv bytes < 0
+ psubw mm4, mm0
+ pand mm7, mm5 // Only pbv bytes < 0 in mm0
+ psubw mm4, mm0
+ psubw mm5, mm7
+ pxor mm0, mm0
+ pcmpgtw mm0, mm6 // Create mask pcv bytes < 0
+ pand mm0, mm6 // Only pav bytes < 0 in mm7
+ psubw mm5, mm7
+ psubw mm6, mm0
+ // test pa <= pb
+ movq mm7, mm4
+ psubw mm6, mm0
+ pcmpgtw mm7, mm5 // pa > pb?
+ movq mm0, mm7
+ // use mm7 mask to merge pa & pb
+ pand mm5, mm7
+ // use mm0 mask copy to merge a & b
+ pand mm2, mm0
+ pandn mm7, mm4
+ pandn mm0, mm1
+ paddw mm7, mm5
+ paddw mm0, mm2
+ // test ((pa <= pb)? pa:pb) <= pc
+ pcmpgtw mm7, mm6 // pab > pc?
+ pxor mm1, mm1
+ pand mm3, mm7
+ pandn mm7, mm0
+ paddw mm7, mm3
+ pxor mm0, mm0
+ packuswb mm7, mm1
+ movq mm3, [esi + ebx - 8] // load c=Prior(x-bpp)
+ pand mm7, ActiveMask
+ psrlq mm3, ShiftRem
+ movq mm2, [esi + ebx] // load b=Prior(x) step 1
+ paddb mm7, [edi + ebx] // add Paeth predictor with Raw(x)
+ movq mm6, mm2
+ movq [edi + ebx], mm7 // write back updated value
+ movq mm1, [edi+ebx-8]
+ psllq mm6, ShiftBpp
+ movq mm5, mm7
+ psrlq mm1, ShiftRem
+ por mm3, mm6
+ psllq mm5, ShiftBpp
+ punpckhbw mm3, mm0 // Unpack High bytes of c
+ por mm1, mm5
+ // Do second set of 4 bytes
+ punpckhbw mm2, mm0 // Unpack High bytes of b
+ punpckhbw mm1, mm0 // Unpack High bytes of a
+ // pav = p - a = (a + b - c) - a = b - c
+ movq mm4, mm2
+ // pbv = p - b = (a + b - c) - b = a - c
+ movq mm5, mm1
+ psubw mm4, mm3
+ pxor mm7, mm7
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ movq mm6, mm4
+ psubw mm5, mm3
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ pcmpgtw mm0, mm4 // Create mask pav bytes < 0
+ paddw mm6, mm5
+ pand mm0, mm4 // Only pav bytes < 0 in mm7
+ pcmpgtw mm7, mm5 // Create mask pbv bytes < 0
+ psubw mm4, mm0
+ pand mm7, mm5 // Only pbv bytes < 0 in mm0
+ psubw mm4, mm0
+ psubw mm5, mm7
+ pxor mm0, mm0
+ pcmpgtw mm0, mm6 // Create mask pcv bytes < 0
+ pand mm0, mm6 // Only pav bytes < 0 in mm7
+ psubw mm5, mm7
+ psubw mm6, mm0
+ // test pa <= pb
+ movq mm7, mm4
+ psubw mm6, mm0
+ pcmpgtw mm7, mm5 // pa > pb?
+ movq mm0, mm7
+ // use mm7 mask to merge pa & pb
+ pand mm5, mm7
+ // use mm0 mask copy to merge a & b
+ pand mm2, mm0
+ pandn mm7, mm4
+ pandn mm0, mm1
+ paddw mm7, mm5
+ paddw mm0, mm2
+ // test ((pa <= pb)? pa:pb) <= pc
+ pcmpgtw mm7, mm6 // pab > pc?
+ pxor mm1, mm1
+ pand mm3, mm7
+ pandn mm7, mm0
+ pxor mm1, mm1
+ paddw mm7, mm3
+ pxor mm0, mm0
+ // Step ex to next set of 8 bytes and repeat loop til done
+ add ebx, 8
+ packuswb mm1, mm7
+ paddb mm1, [edi + ebx - 8] // add Paeth predictor with Raw(x)
+ cmp ebx, MMXLength
+ movq [edi + ebx - 8], mm1 // write back updated value
+ // mm1 will be used as Raw(x-bpp) next loop
+ jb dpth6lp
+ } // end _asm block
+ }
+ break;
+
+ case 4:
+ {
+ ActiveMask.use = 0x00000000ffffffff;
+ _asm {
+ mov ebx, diff
+ mov edi, row
+ mov esi, prev_row
+ pxor mm0, mm0
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm1, [edi+ebx-8] // Only time should need to read
+ // a=Raw(x-bpp) bytes
+dpth4lp:
+ // Do first set of 4 bytes
+ movq mm3, [esi+ebx-8] // read c=Prior(x-bpp) bytes
+ punpckhbw mm1, mm0 // Unpack Low bytes of a
+ movq mm2, [esi + ebx] // load b=Prior(x)
+ punpcklbw mm2, mm0 // Unpack High bytes of b
+ // pav = p - a = (a + b - c) - a = b - c
+ movq mm4, mm2
+ punpckhbw mm3, mm0 // Unpack High bytes of c
+ // pbv = p - b = (a + b - c) - b = a - c
+ movq mm5, mm1
+ psubw mm4, mm3
+ pxor mm7, mm7
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ movq mm6, mm4
+ psubw mm5, mm3
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ pcmpgtw mm0, mm4 // Create mask pav bytes < 0
+ paddw mm6, mm5
+ pand mm0, mm4 // Only pav bytes < 0 in mm7
+ pcmpgtw mm7, mm5 // Create mask pbv bytes < 0
+ psubw mm4, mm0
+ pand mm7, mm5 // Only pbv bytes < 0 in mm0
+ psubw mm4, mm0
+ psubw mm5, mm7
+ pxor mm0, mm0
+ pcmpgtw mm0, mm6 // Create mask pcv bytes < 0
+ pand mm0, mm6 // Only pav bytes < 0 in mm7
+ psubw mm5, mm7
+ psubw mm6, mm0
+ // test pa <= pb
+ movq mm7, mm4
+ psubw mm6, mm0
+ pcmpgtw mm7, mm5 // pa > pb?
+ movq mm0, mm7
+ // use mm7 mask to merge pa & pb
+ pand mm5, mm7
+ // use mm0 mask copy to merge a & b
+ pand mm2, mm0
+ pandn mm7, mm4
+ pandn mm0, mm1
+ paddw mm7, mm5
+ paddw mm0, mm2
+ // test ((pa <= pb)? pa:pb) <= pc
+ pcmpgtw mm7, mm6 // pab > pc?
+ pxor mm1, mm1
+ pand mm3, mm7
+ pandn mm7, mm0
+ paddw mm7, mm3
+ pxor mm0, mm0
+ packuswb mm7, mm1
+ movq mm3, [esi + ebx] // load c=Prior(x-bpp)
+ pand mm7, ActiveMask
+ movq mm2, mm3 // load b=Prior(x) step 1
+ paddb mm7, [edi + ebx] // add Paeth predictor with Raw(x)
+ punpcklbw mm3, mm0 // Unpack High bytes of c
+ movq [edi + ebx], mm7 // write back updated value
+ movq mm1, mm7 // Now mm1 will be used as Raw(x-bpp)
+ // Do second set of 4 bytes
+ punpckhbw mm2, mm0 // Unpack Low bytes of b
+ punpcklbw mm1, mm0 // Unpack Low bytes of a
+ // pav = p - a = (a + b - c) - a = b - c
+ movq mm4, mm2
+ // pbv = p - b = (a + b - c) - b = a - c
+ movq mm5, mm1
+ psubw mm4, mm3
+ pxor mm7, mm7
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ movq mm6, mm4
+ psubw mm5, mm3
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ pcmpgtw mm0, mm4 // Create mask pav bytes < 0
+ paddw mm6, mm5
+ pand mm0, mm4 // Only pav bytes < 0 in mm7
+ pcmpgtw mm7, mm5 // Create mask pbv bytes < 0
+ psubw mm4, mm0
+ pand mm7, mm5 // Only pbv bytes < 0 in mm0
+ psubw mm4, mm0
+ psubw mm5, mm7
+ pxor mm0, mm0
+ pcmpgtw mm0, mm6 // Create mask pcv bytes < 0
+ pand mm0, mm6 // Only pav bytes < 0 in mm7
+ psubw mm5, mm7
+ psubw mm6, mm0
+ // test pa <= pb
+ movq mm7, mm4
+ psubw mm6, mm0
+ pcmpgtw mm7, mm5 // pa > pb?
+ movq mm0, mm7
+ // use mm7 mask to merge pa & pb
+ pand mm5, mm7
+ // use mm0 mask copy to merge a & b
+ pand mm2, mm0
+ pandn mm7, mm4
+ pandn mm0, mm1
+ paddw mm7, mm5
+ paddw mm0, mm2
+ // test ((pa <= pb)? pa:pb) <= pc
+ pcmpgtw mm7, mm6 // pab > pc?
+ pxor mm1, mm1
+ pand mm3, mm7
+ pandn mm7, mm0
+ pxor mm1, mm1
+ paddw mm7, mm3
+ pxor mm0, mm0
+ // Step ex to next set of 8 bytes and repeat loop til done
+ add ebx, 8
+ packuswb mm1, mm7
+ paddb mm1, [edi + ebx - 8] // add Paeth predictor with Raw(x)
+ cmp ebx, MMXLength
+ movq [edi + ebx - 8], mm1 // write back updated value
+ // mm1 will be used as Raw(x-bpp) next loop
+ jb dpth4lp
+ } // end _asm block
+ }
+ break;
+ case 8: // bpp == 8
+ {
+ ActiveMask.use = 0x00000000ffffffff;
+ _asm {
+ mov ebx, diff
+ mov edi, row
+ mov esi, prev_row
+ pxor mm0, mm0
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm1, [edi+ebx-8] // Only time should need to read
+ // a=Raw(x-bpp) bytes
+dpth8lp:
+ // Do first set of 4 bytes
+ movq mm3, [esi+ebx-8] // read c=Prior(x-bpp) bytes
+ punpcklbw mm1, mm0 // Unpack Low bytes of a
+ movq mm2, [esi + ebx] // load b=Prior(x)
+ punpcklbw mm2, mm0 // Unpack Low bytes of b
+ // pav = p - a = (a + b - c) - a = b - c
+ movq mm4, mm2
+ punpcklbw mm3, mm0 // Unpack Low bytes of c
+ // pbv = p - b = (a + b - c) - b = a - c
+ movq mm5, mm1
+ psubw mm4, mm3
+ pxor mm7, mm7
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ movq mm6, mm4
+ psubw mm5, mm3
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ pcmpgtw mm0, mm4 // Create mask pav bytes < 0
+ paddw mm6, mm5
+ pand mm0, mm4 // Only pav bytes < 0 in mm7
+ pcmpgtw mm7, mm5 // Create mask pbv bytes < 0
+ psubw mm4, mm0
+ pand mm7, mm5 // Only pbv bytes < 0 in mm0
+ psubw mm4, mm0
+ psubw mm5, mm7
+ pxor mm0, mm0
+ pcmpgtw mm0, mm6 // Create mask pcv bytes < 0
+ pand mm0, mm6 // Only pav bytes < 0 in mm7
+ psubw mm5, mm7
+ psubw mm6, mm0
+ // test pa <= pb
+ movq mm7, mm4
+ psubw mm6, mm0
+ pcmpgtw mm7, mm5 // pa > pb?
+ movq mm0, mm7
+ // use mm7 mask to merge pa & pb
+ pand mm5, mm7
+ // use mm0 mask copy to merge a & b
+ pand mm2, mm0
+ pandn mm7, mm4
+ pandn mm0, mm1
+ paddw mm7, mm5
+ paddw mm0, mm2
+ // test ((pa <= pb)? pa:pb) <= pc
+ pcmpgtw mm7, mm6 // pab > pc?
+ pxor mm1, mm1
+ pand mm3, mm7
+ pandn mm7, mm0
+ paddw mm7, mm3
+ pxor mm0, mm0
+ packuswb mm7, mm1
+ movq mm3, [esi+ebx-8] // read c=Prior(x-bpp) bytes
+ pand mm7, ActiveMask
+ movq mm2, [esi + ebx] // load b=Prior(x)
+ paddb mm7, [edi + ebx] // add Paeth predictor with Raw(x)
+ punpckhbw mm3, mm0 // Unpack High bytes of c
+ movq [edi + ebx], mm7 // write back updated value
+ movq mm1, [edi+ebx-8] // read a=Raw(x-bpp) bytes
+
+ // Do second set of 4 bytes
+ punpckhbw mm2, mm0 // Unpack High bytes of b
+ punpckhbw mm1, mm0 // Unpack High bytes of a
+ // pav = p - a = (a + b - c) - a = b - c
+ movq mm4, mm2
+ // pbv = p - b = (a + b - c) - b = a - c
+ movq mm5, mm1
+ psubw mm4, mm3
+ pxor mm7, mm7
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ movq mm6, mm4
+ psubw mm5, mm3
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ pcmpgtw mm0, mm4 // Create mask pav bytes < 0
+ paddw mm6, mm5
+ pand mm0, mm4 // Only pav bytes < 0 in mm7
+ pcmpgtw mm7, mm5 // Create mask pbv bytes < 0
+ psubw mm4, mm0
+ pand mm7, mm5 // Only pbv bytes < 0 in mm0
+ psubw mm4, mm0
+ psubw mm5, mm7
+ pxor mm0, mm0
+ pcmpgtw mm0, mm6 // Create mask pcv bytes < 0
+ pand mm0, mm6 // Only pav bytes < 0 in mm7
+ psubw mm5, mm7
+ psubw mm6, mm0
+ // test pa <= pb
+ movq mm7, mm4
+ psubw mm6, mm0
+ pcmpgtw mm7, mm5 // pa > pb?
+ movq mm0, mm7
+ // use mm7 mask to merge pa & pb
+ pand mm5, mm7
+ // use mm0 mask copy to merge a & b
+ pand mm2, mm0
+ pandn mm7, mm4
+ pandn mm0, mm1
+ paddw mm7, mm5
+ paddw mm0, mm2
+ // test ((pa <= pb)? pa:pb) <= pc
+ pcmpgtw mm7, mm6 // pab > pc?
+ pxor mm1, mm1
+ pand mm3, mm7
+ pandn mm7, mm0
+ pxor mm1, mm1
+ paddw mm7, mm3
+ pxor mm0, mm0
+ // Step ex to next set of 8 bytes and repeat loop til done
+ add ebx, 8
+ packuswb mm1, mm7
+ paddb mm1, [edi + ebx - 8] // add Paeth predictor with Raw(x)
+ cmp ebx, MMXLength
+ movq [edi + ebx - 8], mm1 // write back updated value
+ // mm1 will be used as Raw(x-bpp) next loop
+ jb dpth8lp
+ } // end _asm block
+ }
+ break;
+
+ case 1: // bpp = 1
+ case 2: // bpp = 2
+ default: // bpp > 8
+ {
+ _asm {
+ mov ebx, diff
+ cmp ebx, FullLength
+ jnb dpthdend
+ mov edi, row
+ mov esi, prev_row
+ // Do Paeth decode for remaining bytes
+ mov edx, ebx
+ xor ecx, ecx // zero ecx before using cl & cx in loop below
+ sub edx, bpp // Set edx = ebx - bpp
+dpthdlp:
+ xor eax, eax
+ // pav = p - a = (a + b - c) - a = b - c
+ mov al, [esi + ebx] // load Prior(x) into al
+ mov cl, [esi + edx] // load Prior(x-bpp) into cl
+ sub eax, ecx // subtract Prior(x-bpp)
+ mov patemp, eax // Save pav for later use
+ xor eax, eax
+ // pbv = p - b = (a + b - c) - b = a - c
+ mov al, [edi + edx] // load Raw(x-bpp) into al
+ sub eax, ecx // subtract Prior(x-bpp)
+ mov ecx, eax
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ add eax, patemp // pcv = pav + pbv
+ // pc = abs(pcv)
+ test eax, 0x80000000
+ jz dpthdpca
+ neg eax // reverse sign of neg values
+dpthdpca:
+ mov pctemp, eax // save pc for later use
+ // pb = abs(pbv)
+ test ecx, 0x80000000
+ jz dpthdpba
+ neg ecx // reverse sign of neg values
+dpthdpba:
+ mov pbtemp, ecx // save pb for later use
+ // pa = abs(pav)
+ mov eax, patemp
+ test eax, 0x80000000
+ jz dpthdpaa
+ neg eax // reverse sign of neg values
+dpthdpaa:
+ mov patemp, eax // save pa for later use
+ // test if pa <= pb
+ cmp eax, ecx
+ jna dpthdabb
+ // pa > pb; now test if pb <= pc
+ cmp ecx, pctemp
+ jna dpthdbbc
+ // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ mov cl, [esi + edx] // load Prior(x-bpp) into cl
+ jmp dpthdpaeth
+dpthdbbc:
+ // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
+ mov cl, [esi + ebx] // load Prior(x) into cl
+ jmp dpthdpaeth
+dpthdabb:
+ // pa <= pb; now test if pa <= pc
+ cmp eax, pctemp
+ jna dpthdabc
+ // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ mov cl, [esi + edx] // load Prior(x-bpp) into cl
+ jmp dpthdpaeth
+dpthdabc:
+ // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
+ mov cl, [edi + edx] // load Raw(x-bpp) into cl
+dpthdpaeth:
+ inc ebx
+ inc edx
+ // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
+ add [edi + ebx - 1], cl
+ cmp ebx, FullLength
+ jb dpthdlp
+dpthdend:
+ } // end _asm block
+ }
+ return; // No need to go further with this one
+ } // end switch ( bpp )
+ _asm
+ {
+ // MMX acceleration complete now do clean-up
+ // Check if any remaining bytes left to decode
+ mov ebx, MMXLength
+ cmp ebx, FullLength
+ jnb dpthend
+ mov edi, row
+ mov esi, prev_row
+ // Do Paeth decode for remaining bytes
+ mov edx, ebx
+ xor ecx, ecx // zero ecx before using cl & cx in loop below
+ sub edx, bpp // Set edx = ebx - bpp
+dpthlp2:
+ xor eax, eax
+ // pav = p - a = (a + b - c) - a = b - c
+ mov al, [esi + ebx] // load Prior(x) into al
+ mov cl, [esi + edx] // load Prior(x-bpp) into cl
+ sub eax, ecx // subtract Prior(x-bpp)
+ mov patemp, eax // Save pav for later use
+ xor eax, eax
+ // pbv = p - b = (a + b - c) - b = a - c
+ mov al, [edi + edx] // load Raw(x-bpp) into al
+ sub eax, ecx // subtract Prior(x-bpp)
+ mov ecx, eax
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ add eax, patemp // pcv = pav + pbv
+ // pc = abs(pcv)
+ test eax, 0x80000000
+ jz dpthpca2
+ neg eax // reverse sign of neg values
+dpthpca2:
+ mov pctemp, eax // save pc for later use
+ // pb = abs(pbv)
+ test ecx, 0x80000000
+ jz dpthpba2
+ neg ecx // reverse sign of neg values
+dpthpba2:
+ mov pbtemp, ecx // save pb for later use
+ // pa = abs(pav)
+ mov eax, patemp
+ test eax, 0x80000000
+ jz dpthpaa2
+ neg eax // reverse sign of neg values
+dpthpaa2:
+ mov patemp, eax // save pa for later use
+ // test if pa <= pb
+ cmp eax, ecx
+ jna dpthabb2
+ // pa > pb; now test if pb <= pc
+ cmp ecx, pctemp
+ jna dpthbbc2
+ // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ mov cl, [esi + edx] // load Prior(x-bpp) into cl
+ jmp dpthpaeth2
+dpthbbc2:
+ // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
+ mov cl, [esi + ebx] // load Prior(x) into cl
+ jmp dpthpaeth2
+dpthabb2:
+ // pa <= pb; now test if pa <= pc
+ cmp eax, pctemp
+ jna dpthabc2
+ // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ mov cl, [esi + edx] // load Prior(x-bpp) into cl
+ jmp dpthpaeth2
+dpthabc2:
+ // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
+ mov cl, [edi + edx] // load Raw(x-bpp) into cl
+dpthpaeth2:
+ inc ebx
+ inc edx
+ // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
+ add [edi + ebx - 1], cl
+ cmp ebx, FullLength
+ jb dpthlp2
+dpthend:
+ emms // End MMX instructions; prep for possible FP instrs.
+ } // end _asm block
+}
+
+// Optimized code for PNG Sub filter decoder
+void /* PRIVATE */
+png_read_filter_row_mmx_sub(png_row_infop row_info, png_bytep row)
+{
+ //int test;
+ int bpp;
+ png_uint_32 FullLength;
+ png_uint_32 MMXLength;
+ int diff;
+
+ bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel
+ FullLength = row_info->rowbytes - bpp; // # of bytes to filter
+ _asm {
+ mov edi, row
+ mov esi, edi // lp = row
+ add edi, bpp // rp = row + bpp
+ xor eax, eax
+ // get # of bytes to alignment
+ mov diff, edi // take start of row
+ add diff, 0xf // add 7 + 8 to incr past
+ // alignment boundary
+ xor ebx, ebx
+ and diff, 0xfffffff8 // mask to alignment boundary
+ sub diff, edi // subtract from start ==> value
+ // ebx at alignment
+ jz dsubgo
+ // fix alignment
+dsublp1:
+ mov al, [esi+ebx]
+ add [edi+ebx], al
+ inc ebx
+ cmp ebx, diff
+ jb dsublp1
+dsubgo:
+ mov ecx, FullLength
+ mov edx, ecx
+ sub edx, ebx // subtract alignment fix
+ and edx, 0x00000007 // calc bytes over mult of 8
+ sub ecx, edx // drop over bytes from length
+ mov MMXLength, ecx
+ } // end _asm block
+
+ // Now do the math for the rest of the row
+ switch ( bpp )
+ {
+ case 3:
+ {
+ ActiveMask.use = 0x0000ffffff000000;
+ ShiftBpp.use = 24; // == 3 * 8
+ ShiftRem.use = 40; // == 64 - 24
+ _asm {
+ mov edi, row
+ movq mm7, ActiveMask // Load ActiveMask for 2nd active byte group
+ mov esi, edi // lp = row
+ add edi, bpp // rp = row + bpp
+ movq mm6, mm7
+ mov ebx, diff
+ psllq mm6, ShiftBpp // Move mask in mm6 to cover 3rd active
+ // byte group
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm1, [edi+ebx-8]
+dsub3lp:
+ psrlq mm1, ShiftRem // Shift data for adding 1st bpp bytes
+ // no need for mask; shift clears inactive bytes
+ // Add 1st active group
+ movq mm0, [edi+ebx]
+ paddb mm0, mm1
+ // Add 2nd active group
+ movq mm1, mm0 // mov updated Raws to mm1
+ psllq mm1, ShiftBpp // shift data to position correctly
+ pand mm1, mm7 // mask to use only 2nd active group
+ paddb mm0, mm1
+ // Add 3rd active group
+ movq mm1, mm0 // mov updated Raws to mm1
+ psllq mm1, ShiftBpp // shift data to position correctly
+ pand mm1, mm6 // mask to use only 3rd active group
+ add ebx, 8
+ paddb mm0, mm1
+ cmp ebx, MMXLength
+ movq [edi+ebx-8], mm0 // Write updated Raws back to array
+ // Prep for doing 1st add at top of loop
+ movq mm1, mm0
+ jb dsub3lp
+ } // end _asm block
+ }
+ break;
+
+ case 1:
+ {
+ // Placed here just in case this is a duplicate of the
+ // non-MMX code for the SUB filter in png_read_filter_row below
+ //
+ // png_bytep rp;
+ // png_bytep lp;
+ // png_uint_32 i;
+ // bpp = (row_info->pixel_depth + 7) >> 3;
+ // for (i = (png_uint_32)bpp, rp = row + bpp, lp = row;
+ // i < row_info->rowbytes; i++, rp++, lp++)
+ // {
+ // *rp = (png_byte)(((int)(*rp) + (int)(*lp)) & 0xff);
+ // }
+ _asm {
+ mov ebx, diff
+ mov edi, row
+ cmp ebx, FullLength
+ jnb dsub1end
+ mov esi, edi // lp = row
+ xor eax, eax
+ add edi, bpp // rp = row + bpp
+dsub1lp:
+ mov al, [esi+ebx]
+ add [edi+ebx], al
+ inc ebx
+ cmp ebx, FullLength
+ jb dsub1lp
+dsub1end:
+ } // end _asm block
+ }
+ return;
+
+ case 6:
+ case 7:
+ case 4:
+ case 5:
+ {
+ ShiftBpp.use = bpp << 3;
+ ShiftRem.use = 64 - ShiftBpp.use;
+ _asm {
+ mov edi, row
+ mov ebx, diff
+ mov esi, edi // lp = row
+ add edi, bpp // rp = row + bpp
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm1, [edi+ebx-8]
+dsub4lp:
+ psrlq mm1, ShiftRem // Shift data for adding 1st bpp bytes
+ // no need for mask; shift clears inactive bytes
+ movq mm0, [edi+ebx]
+ paddb mm0, mm1
+ // Add 2nd active group
+ movq mm1, mm0 // mov updated Raws to mm1
+ psllq mm1, ShiftBpp // shift data to position correctly
+ // there is no need for any mask
+ // since shift clears inactive bits/bytes
+ add ebx, 8
+ paddb mm0, mm1
+ cmp ebx, MMXLength
+ movq [edi+ebx-8], mm0
+ movq mm1, mm0 // Prep for doing 1st add at top of loop
+ jb dsub4lp
+ } // end _asm block
+ }
+ break;
+
+ case 2:
+ {
+ ActiveMask.use = 0x00000000ffff0000;
+ ShiftBpp.use = 16; // == 2 * 8
+ ShiftRem.use = 48; // == 64 - 16
+ _asm {
+ movq mm7, ActiveMask // Load ActiveMask for 2nd active byte group
+ mov ebx, diff
+ movq mm6, mm7
+ mov edi, row
+ psllq mm6, ShiftBpp // Move mask in mm6 to cover 3rd active
+ // byte group
+ mov esi, edi // lp = row
+ movq mm5, mm6
+ add edi, bpp // rp = row + bpp
+ psllq mm5, ShiftBpp // Move mask in mm5 to cover 4th active
+ // byte group
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm1, [edi+ebx-8]
+dsub2lp:
+ // Add 1st active group
+ psrlq mm1, ShiftRem // Shift data for adding 1st bpp bytes
+ // no need for mask; shift clears inactive
+ // bytes
+ movq mm0, [edi+ebx]
+ paddb mm0, mm1
+ // Add 2nd active group
+ movq mm1, mm0 // mov updated Raws to mm1
+ psllq mm1, ShiftBpp // shift data to position correctly
+ pand mm1, mm7 // mask to use only 2nd active group
+ paddb mm0, mm1
+ // Add 3rd active group
+ movq mm1, mm0 // mov updated Raws to mm1
+ psllq mm1, ShiftBpp // shift data to position correctly
+ pand mm1, mm6 // mask to use only 3rd active group
+ paddb mm0, mm1
+ // Add 4th active group
+ movq mm1, mm0 // mov updated Raws to mm1
+ psllq mm1, ShiftBpp // shift data to position correctly
+ pand mm1, mm5 // mask to use only 4th active group
+ add ebx, 8
+ paddb mm0, mm1
+ cmp ebx, MMXLength
+ movq [edi+ebx-8], mm0 // Write updated Raws back to array
+ movq mm1, mm0 // Prep for doing 1st add at top of loop
+ jb dsub2lp
+ } // end _asm block
+ }
+ break;
+ case 8:
+ {
+ _asm {
+ mov edi, row
+ mov ebx, diff
+ mov esi, edi // lp = row
+ add edi, bpp // rp = row + bpp
+ mov ecx, MMXLength
+ movq mm7, [edi+ebx-8] // PRIME the pump (load the first
+ // Raw(x-bpp) data set
+ and ecx, 0x0000003f // calc bytes over mult of 64
+dsub8lp:
+ movq mm0, [edi+ebx] // Load Sub(x) for 1st 8 bytes
+ paddb mm0, mm7
+ movq mm1, [edi+ebx+8] // Load Sub(x) for 2nd 8 bytes
+ movq [edi+ebx], mm0 // Write Raw(x) for 1st 8 bytes
+ // Now mm0 will be used as Raw(x-bpp) for
+ // the 2nd group of 8 bytes. This will be
+ // repeated for each group of 8 bytes with
+ // the 8th group being used as the Raw(x-bpp)
+ // for the 1st group of the next loop.
+ paddb mm1, mm0
+ movq mm2, [edi+ebx+16] // Load Sub(x) for 3rd 8 bytes
+ movq [edi+ebx+8], mm1 // Write Raw(x) for 2nd 8 bytes
+ paddb mm2, mm1
+ movq mm3, [edi+ebx+24] // Load Sub(x) for 4th 8 bytes
+ movq [edi+ebx+16], mm2 // Write Raw(x) for 3rd 8 bytes
+ paddb mm3, mm2
+ movq mm4, [edi+ebx+32] // Load Sub(x) for 5th 8 bytes
+ movq [edi+ebx+24], mm3 // Write Raw(x) for 4th 8 bytes
+ paddb mm4, mm3
+ movq mm5, [edi+ebx+40] // Load Sub(x) for 6th 8 bytes
+ movq [edi+ebx+32], mm4 // Write Raw(x) for 5th 8 bytes
+ paddb mm5, mm4
+ movq mm6, [edi+ebx+48] // Load Sub(x) for 7th 8 bytes
+ movq [edi+ebx+40], mm5 // Write Raw(x) for 6th 8 bytes
+ paddb mm6, mm5
+ movq mm7, [edi+ebx+56] // Load Sub(x) for 8th 8 bytes
+ movq [edi+ebx+48], mm6 // Write Raw(x) for 7th 8 bytes
+ add ebx, 64
+ paddb mm7, mm6
+ cmp ebx, ecx
+ movq [edi+ebx-8], mm7 // Write Raw(x) for 8th 8 bytes
+ jb dsub8lp
+ cmp ebx, MMXLength
+ jnb dsub8lt8
+dsub8lpA:
+ movq mm0, [edi+ebx]
+ add ebx, 8
+ paddb mm0, mm7
+ cmp ebx, MMXLength
+ movq [edi+ebx-8], mm0 // use -8 to offset early add to ebx
+ movq mm7, mm0 // Move calculated Raw(x) data to mm1 to
+ // be the new Raw(x-bpp) for the next loop
+ jb dsub8lpA
+dsub8lt8:
+ } // end _asm block
+ }
+ break;
+
+ default: // bpp greater than 8 bytes
+ {
+ _asm {
+ mov ebx, diff
+ mov edi, row
+ mov esi, edi // lp = row
+ add edi, bpp // rp = row + bpp
+dsubAlp:
+ movq mm0, [edi+ebx]
+ movq mm1, [esi+ebx]
+ add ebx, 8
+ paddb mm0, mm1
+ cmp ebx, MMXLength
+ movq [edi+ebx-8], mm0 // mov does not affect flags; -8 to offset
+ // add ebx
+ jb dsubAlp
+ } // end _asm block
+ }
+ break;
+
+ } // end switch ( bpp )
+
+ _asm {
+ mov ebx, MMXLength
+ mov edi, row
+ cmp ebx, FullLength
+ jnb dsubend
+ mov esi, edi // lp = row
+ xor eax, eax
+ add edi, bpp // rp = row + bpp
+dsublp2:
+ mov al, [esi+ebx]
+ add [edi+ebx], al
+ inc ebx
+ cmp ebx, FullLength
+ jb dsublp2
+dsubend:
+ emms // End MMX instructions; prep for possible FP instrs.
+ } // end _asm block
+}
+
+// Optimized code for PNG Up filter decoder
+void /* PRIVATE */
+png_read_filter_row_mmx_up(png_row_infop row_info, png_bytep row,
+ png_bytep prev_row)
+{
+ png_uint_32 len;
+ len = row_info->rowbytes; // # of bytes to filter
+ _asm {
+ mov edi, row
+ // get # of bytes to alignment
+ mov ecx, edi
+ xor ebx, ebx
+ add ecx, 0x7
+ xor eax, eax
+ and ecx, 0xfffffff8
+ mov esi, prev_row
+ sub ecx, edi
+ jz dupgo
+ // fix alignment
+duplp1:
+ mov al, [edi+ebx]
+ add al, [esi+ebx]
+ inc ebx
+ cmp ebx, ecx
+ mov [edi + ebx-1], al // mov does not affect flags; -1 to offset inc ebx
+ jb duplp1
+dupgo:
+ mov ecx, len
+ mov edx, ecx
+ sub edx, ebx // subtract alignment fix
+ and edx, 0x0000003f // calc bytes over mult of 64
+ sub ecx, edx // drop over bytes from length
+ // Unrolled loop - use all MMX registers and interleave to reduce
+ // number of branch instructions (loops) and reduce partial stalls
+duploop:
+ movq mm1, [esi+ebx]
+ movq mm0, [edi+ebx]
+ movq mm3, [esi+ebx+8]
+ paddb mm0, mm1
+ movq mm2, [edi+ebx+8]
+ movq [edi+ebx], mm0
+ paddb mm2, mm3
+ movq mm5, [esi+ebx+16]
+ movq [edi+ebx+8], mm2
+ movq mm4, [edi+ebx+16]
+ movq mm7, [esi+ebx+24]
+ paddb mm4, mm5
+ movq mm6, [edi+ebx+24]
+ movq [edi+ebx+16], mm4
+ paddb mm6, mm7
+ movq mm1, [esi+ebx+32]
+ movq [edi+ebx+24], mm6
+ movq mm0, [edi+ebx+32]
+ movq mm3, [esi+ebx+40]
+ paddb mm0, mm1
+ movq mm2, [edi+ebx+40]
+ movq [edi+ebx+32], mm0
+ paddb mm2, mm3
+ movq mm5, [esi+ebx+48]
+ movq [edi+ebx+40], mm2
+ movq mm4, [edi+ebx+48]
+ movq mm7, [esi+ebx+56]
+ paddb mm4, mm5
+ movq mm6, [edi+ebx+56]
+ movq [edi+ebx+48], mm4
+ add ebx, 64
+ paddb mm6, mm7
+ cmp ebx, ecx
+ movq [edi+ebx-8], mm6 // (+56)movq does not affect flags;
+ // -8 to offset add ebx
+ jb duploop
+
+ cmp edx, 0 // Test for bytes over mult of 64
+ jz dupend
+
+
+ // 2 lines added by lcreeve@netins.net
+ // (mail 11 Jul 98 in png-implement list)
+ cmp edx, 8 //test for less than 8 bytes
+ jb duplt8
+
+
+ add ecx, edx
+ and edx, 0x00000007 // calc bytes over mult of 8
+ sub ecx, edx // drop over bytes from length
+ jz duplt8
+ // Loop using MMX registers mm0 & mm1 to update 8 bytes simultaneously
+duplpA:
+ movq mm1, [esi+ebx]
+ movq mm0, [edi+ebx]
+ add ebx, 8
+ paddb mm0, mm1
+ cmp ebx, ecx
+ movq [edi+ebx-8], mm0 // movq does not affect flags; -8 to offset add ebx
+ jb duplpA
+ cmp edx, 0 // Test for bytes over mult of 8
+ jz dupend
+duplt8:
+ xor eax, eax
+ add ecx, edx // move over byte count into counter
+ // Loop using x86 registers to update remaining bytes
+duplp2:
+ mov al, [edi + ebx]
+ add al, [esi + ebx]
+ inc ebx
+ cmp ebx, ecx
+ mov [edi + ebx-1], al // mov does not affect flags; -1 to offset inc ebx
+ jb duplp2
+dupend:
+ // Conversion of filtered row completed
+ emms // End MMX instructions; prep for possible FP instrs.
+ } // end _asm block
+}
+
+
+// Optimized png_read_filter_row routines
+void /* PRIVATE */
+png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep
+ row, png_bytep prev_row, int filter)
+{
+#ifdef PNG_DEBUG
+ char filnm[10];
+#endif
+
+ if (mmx_supported == 2) {
+ /* this should have happened in png_init_mmx_flags() already */
+ png_warning(png_ptr, "asm_flags may not have been initialized");
+ png_mmx_support();
+ }
+
+#ifdef PNG_DEBUG
+ png_debug(1, "in png_read_filter_row\n");
+ switch (filter)
+ {
+ case 0: sprintf(filnm, "none");
+ break;
+ case 1: sprintf(filnm, "sub-%s",
+ (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB)? "MMX" : "x86");
+ break;
+ case 2: sprintf(filnm, "up-%s",
+ (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP)? "MMX" : "x86");
+ break;
+ case 3: sprintf(filnm, "avg-%s",
+ (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG)? "MMX" : "x86");
+ break;
+ case 4: sprintf(filnm, "Paeth-%s",
+ (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH)? "MMX":"x86");
+ break;
+ default: sprintf(filnm, "unknw");
+ break;
+ }
+ png_debug2(0,"row=%5d, %s, ", png_ptr->row_number, filnm);
+ png_debug2(0, "pd=%2d, b=%d, ", (int)row_info->pixel_depth,
+ (int)((row_info->pixel_depth + 7) >> 3));
+ png_debug1(0,"len=%8d, ", row_info->rowbytes);
+#endif /* PNG_DEBUG */
+
+ switch (filter)
+ {
+ case PNG_FILTER_VALUE_NONE:
+ break;
+
+ case PNG_FILTER_VALUE_SUB:
+ {
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB) &&
+ (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
+ (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
+ {
+ png_read_filter_row_mmx_sub(row_info, row);
+ }
+ else
+ {
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
+ png_bytep rp = row + bpp;
+ png_bytep lp = row;
+
+ for (i = bpp; i < istop; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
+ rp++;
+ }
+ }
+ break;
+ }
+
+ case PNG_FILTER_VALUE_UP:
+ {
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP) &&
+ (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
+ (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
+ {
+ png_read_filter_row_mmx_up(row_info, row, prev_row);
+ }
+ else
+ {
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+
+ for (i = 0; i < istop; ++i)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
+ rp++;
+ }
+ }
+ break;
+ }
+
+ case PNG_FILTER_VALUE_AVG:
+ {
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG) &&
+ (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
+ (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
+ {
+ png_read_filter_row_mmx_avg(row_info, row, prev_row);
+ }
+ else
+ {
+ png_uint_32 i;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+ png_bytep lp = row;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
+ png_uint_32 istop = row_info->rowbytes - bpp;
+
+ for (i = 0; i < bpp; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ ((int)(*pp++) >> 1)) & 0xff);
+ rp++;
+ }
+
+ for (i = 0; i < istop; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ ((int)(*pp++ + *lp++) >> 1)) & 0xff);
+ rp++;
+ }
+ }
+ break;
+ }
+
+ case PNG_FILTER_VALUE_PAETH:
+ {
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH) &&
+ (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
+ (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
+ {
+ png_read_filter_row_mmx_paeth(row_info, row, prev_row);
+ }
+ else
+ {
+ png_uint_32 i;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+ png_bytep lp = row;
+ png_bytep cp = prev_row;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
+ png_uint_32 istop=row_info->rowbytes - bpp;
+
+ for (i = 0; i < bpp; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
+ rp++;
+ }
+
+ for (i = 0; i < istop; i++) // use leftover rp,pp
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ a = *lp++;
+ b = *pp++;
+ c = *cp++;
+
+ p = b - c;
+ pc = a - c;
+
+#ifdef PNG_USE_ABS
+ pa = abs(p);
+ pb = abs(pc);
+ pc = abs(p + pc);
+#else
+ pa = p < 0 ? -p : p;
+ pb = pc < 0 ? -pc : pc;
+ pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+#endif
+
+ /*
+ if (pa <= pb && pa <= pc)
+ p = a;
+ else if (pb <= pc)
+ p = b;
+ else
+ p = c;
+ */
+
+ p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
+
+ *rp = (png_byte)(((int)(*rp) + p) & 0xff);
+ rp++;
+ }
+ }
+ break;
+ }
+
+ default:
+ png_warning(png_ptr, "Ignoring bad row filter type");
+ *row=0;
+ break;
+ }
+}
+
+#endif /* PNG_ASSEMBLER_CODE_SUPPORTED && PNG_USE_PNGVCRD */
--- /dev/null
+
+/* pngwio.c - functions for data output
+ *
+ * libpng 1.2.0 - September 1, 2001
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ *
+ * This file provides a location for all output. Users who need
+ * special handling are expected to write functions that have the same
+ * arguments as these and perform similar functions, but that possibly
+ * use different output methods. Note that you shouldn't change these
+ * functions, but rather write replacement functions and then change
+ * them at run time with png_set_write_fn(...).
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+#ifdef PNG_WRITE_SUPPORTED
+
+/* Write the data to whatever output you are using. The default routine
+ writes to a file pointer. Note that this routine sometimes gets called
+ with very small lengths, so you should implement some kind of simple
+ buffering if you are using unbuffered writes. This should never be asked
+ to write more than 64K on a 16 bit machine. */
+
+void /* PRIVATE */
+png_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ if (png_ptr->write_data_fn != NULL )
+ (*(png_ptr->write_data_fn))(png_ptr, data, length);
+ else
+ png_error(png_ptr, "Call to NULL write function");
+}
+
+#if !defined(PNG_NO_STDIO)
+/* This is the function that does the actual writing of data. If you are
+ not writing to a standard C stream, you should create a replacement
+ write_data function and use it at run time with png_set_write_fn(), rather
+ than changing the library. */
+#ifndef USE_FAR_KEYWORD
+static void /* PRIVATE */
+png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_uint_32 check;
+
+#if defined(_WIN32_WCE)
+ if ( !WriteFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) )
+ check = 0;
+#else
+ check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr));
+#endif
+ if (check != length)
+ png_error(png_ptr, "Write Error");
+}
+#else
+/* this is the model-independent version. Since the standard I/O library
+ can't handle far buffers in the medium and small models, we have to copy
+ the data.
+*/
+
+#define NEAR_BUF_SIZE 1024
+#define MIN(a,b) (a <= b ? a : b)
+
+static void /* PRIVATE */
+png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_uint_32 check;
+ png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */
+ png_FILE_p io_ptr;
+
+ /* Check if data really is near. If so, use usual code. */
+ near_data = (png_byte *)CVT_PTR_NOCHECK(data);
+ io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
+ if ((png_bytep)near_data == data)
+ {
+#if defined(_WIN32_WCE)
+ if ( !WriteFile(io_ptr, near_data, length, &check, NULL) )
+ check = 0;
+#else
+ check = fwrite(near_data, 1, length, io_ptr);
+#endif
+ }
+ else
+ {
+ png_byte buf[NEAR_BUF_SIZE];
+ png_size_t written, remaining, err;
+ check = 0;
+ remaining = length;
+ do
+ {
+ written = MIN(NEAR_BUF_SIZE, remaining);
+ png_memcpy(buf, data, written); /* copy far buffer to near buffer */
+#if defined(_WIN32_WCE)
+ if ( !WriteFile(io_ptr, buf, written, &err, NULL) )
+ err = 0;
+#else
+ err = fwrite(buf, 1, written, io_ptr);
+#endif
+ if (err != written)
+ break;
+ else
+ check += err;
+ data += written;
+ remaining -= written;
+ }
+ while (remaining != 0);
+ }
+ if (check != length)
+ png_error(png_ptr, "Write Error");
+}
+
+#endif
+#endif
+
+/* This function is called to output any data pending writing (normally
+ to disk). After png_flush is called, there should be no data pending
+ writing in any buffers. */
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+void /* PRIVATE */
+png_flush(png_structp png_ptr)
+{
+ if (png_ptr->output_flush_fn != NULL)
+ (*(png_ptr->output_flush_fn))(png_ptr);
+}
+
+#if !defined(PNG_NO_STDIO)
+static void /* PRIVATE */
+png_default_flush(png_structp png_ptr)
+{
+#if !defined(_WIN32_WCE)
+ png_FILE_p io_ptr;
+ io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr));
+ if (io_ptr != NULL)
+ fflush(io_ptr);
+#endif
+}
+#endif
+#endif
+
+/* This function allows the application to supply new output functions for
+ libpng if standard C streams aren't being used.
+
+ This function takes as its arguments:
+ png_ptr - pointer to a png output data structure
+ io_ptr - pointer to user supplied structure containing info about
+ the output functions. May be NULL.
+ write_data_fn - pointer to a new output function that takes as its
+ arguments a pointer to a png_struct, a pointer to
+ data to be written, and a 32-bit unsigned int that is
+ the number of bytes to be written. The new write
+ function should call png_error(png_ptr, "Error msg")
+ to exit and output any fatal error messages.
+ flush_data_fn - pointer to a new flush function that takes as its
+ arguments a pointer to a png_struct. After a call to
+ the flush function, there should be no data in any buffers
+ or pending transmission. If the output method doesn't do
+ any buffering of ouput, a function prototype must still be
+ supplied although it doesn't have to do anything. If
+ PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile
+ time, output_flush_fn will be ignored, although it must be
+ supplied for compatibility. */
+void PNGAPI
+png_set_write_fn(png_structp png_ptr, png_voidp io_ptr,
+ png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)
+{
+ png_ptr->io_ptr = io_ptr;
+
+#if !defined(PNG_NO_STDIO)
+ if (write_data_fn != NULL)
+ png_ptr->write_data_fn = write_data_fn;
+ else
+ png_ptr->write_data_fn = png_default_write_data;
+#else
+ png_ptr->write_data_fn = write_data_fn;
+#endif
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+#if !defined(PNG_NO_STDIO)
+ if (output_flush_fn != NULL)
+ png_ptr->output_flush_fn = output_flush_fn;
+ else
+ png_ptr->output_flush_fn = png_default_flush;
+#else
+ png_ptr->output_flush_fn = output_flush_fn;
+#endif
+#endif /* PNG_WRITE_FLUSH_SUPPORTED */
+
+ /* It is an error to read while writing a png file */
+ if (png_ptr->read_data_fn != NULL)
+ {
+ png_ptr->read_data_fn = NULL;
+ png_warning(png_ptr,
+ "Attempted to set both read_data_fn and write_data_fn in");
+ png_warning(png_ptr,
+ "the same structure. Resetting read_data_fn to NULL.");
+ }
+}
+
+#if defined(USE_FAR_KEYWORD)
+#if defined(_MSC_VER)
+void *png_far_to_near(png_structp png_ptr,png_voidp ptr, int check)
+{
+ void *near_ptr;
+ void FAR *far_ptr;
+ FP_OFF(near_ptr) = FP_OFF(ptr);
+ far_ptr = (void FAR *)near_ptr;
+ if(check != 0)
+ if(FP_SEG(ptr) != FP_SEG(far_ptr))
+ png_error(png_ptr,"segment lost in conversion");
+ return(near_ptr);
+}
+# else
+void *png_far_to_near(png_structp png_ptr,png_voidp ptr, int check)
+{
+ void *near_ptr;
+ void FAR *far_ptr;
+ near_ptr = (void FAR *)ptr;
+ far_ptr = (void FAR *)near_ptr;
+ if(check != 0)
+ if(far_ptr != ptr)
+ png_error(png_ptr,"segment lost in conversion");
+ return(near_ptr);
+}
+# endif
+# endif
+#endif /* PNG_WRITE_SUPPORTED */
--- /dev/null
+
+/* pngwrite.c - general routines to write a PNG file
+ *
+ * libpng 1.2.0 - September 1, 2001
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ */
+
+/* get internal access to png.h */
+#define PNG_INTERNAL
+#include "png.h"
+#ifdef PNG_WRITE_SUPPORTED
+
+/* Writes all the PNG information. This is the suggested way to use the
+ * library. If you have a new chunk to add, make a function to write it,
+ * and put it in the correct location here. If you want the chunk written
+ * after the image data, put it in png_write_end(). I strongly encourage
+ * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing
+ * the chunk, as that will keep the code from breaking if you want to just
+ * write a plain PNG file. If you have long comments, I suggest writing
+ * them in png_write_end(), and compressing them.
+ */
+void PNGAPI
+png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_write_info_before_PLTE\n");
+ if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
+ {
+ png_write_sig(png_ptr); /* write PNG signature */
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ if((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)&&(png_ptr->mng_features_permitted))
+ {
+ png_warning(png_ptr,"MNG features are not allowed in a PNG datastream\n");
+ png_ptr->mng_features_permitted=0;
+ }
+#endif
+ /* write IHDR information. */
+ png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
+ info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
+ info_ptr->filter_type,
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+ info_ptr->interlace_type);
+#else
+ 0);
+#endif
+ /* the rest of these check to see if the valid field has the appropriate
+ flag set, and if it does, writes the chunk. */
+#if defined(PNG_WRITE_gAMA_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_gAMA)
+ {
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+ png_write_gAMA(png_ptr, info_ptr->gamma);
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ png_write_gAMA_fixed(png_ptr, info_ptr->int_gamma);
+# endif
+#endif
+ }
+#endif
+#if defined(PNG_WRITE_sRGB_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_sRGB)
+ png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent);
+#endif
+#if defined(PNG_WRITE_iCCP_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_iCCP)
+ png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE,
+ info_ptr->iccp_profile, (int)info_ptr->iccp_proflen);
+#endif
+#if defined(PNG_WRITE_sBIT_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_sBIT)
+ png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
+#endif
+#if defined(PNG_WRITE_cHRM_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_cHRM)
+ {
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ png_write_cHRM(png_ptr,
+ info_ptr->x_white, info_ptr->y_white,
+ info_ptr->x_red, info_ptr->y_red,
+ info_ptr->x_green, info_ptr->y_green,
+ info_ptr->x_blue, info_ptr->y_blue);
+#else
+# ifdef PNG_FIXED_POINT_SUPPORTED
+ png_write_cHRM_fixed(png_ptr,
+ info_ptr->int_x_white, info_ptr->int_y_white,
+ info_ptr->int_x_red, info_ptr->int_y_red,
+ info_ptr->int_x_green, info_ptr->int_y_green,
+ info_ptr->int_x_blue, info_ptr->int_y_blue);
+# endif
+#endif
+ }
+#endif
+#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
+ if (info_ptr->unknown_chunks_num)
+ {
+ png_unknown_chunk *up;
+
+ png_debug(5, "writing extra chunks\n");
+
+ for (up = info_ptr->unknown_chunks;
+ up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
+ up++)
+ {
+ int keep=png_handle_as_unknown(png_ptr, up->name);
+ if (keep != HANDLE_CHUNK_NEVER &&
+ up->location && (!(up->location & PNG_HAVE_PLTE)) &&
+ ((up->name[3] & 0x20) || keep == HANDLE_CHUNK_ALWAYS ||
+ (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
+ {
+ png_write_chunk(png_ptr, up->name, up->data, up->size);
+ }
+ }
+ }
+#endif
+ png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
+ }
+}
+
+void PNGAPI
+png_write_info(png_structp png_ptr, png_infop info_ptr)
+{
+#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
+ int i;
+#endif
+
+ png_debug(1, "in png_write_info\n");
+
+ png_write_info_before_PLTE(png_ptr, info_ptr);
+
+ if (info_ptr->valid & PNG_INFO_PLTE)
+ png_write_PLTE(png_ptr, info_ptr->palette,
+ (png_uint_32)info_ptr->num_palette);
+ else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ png_error(png_ptr, "Valid palette required for paletted images\n");
+
+#if defined(PNG_WRITE_tRNS_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_tRNS)
+ {
+#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
+ /* invert the alpha channel (in tRNS) */
+ if ((png_ptr->transformations & PNG_INVERT_ALPHA) &&
+ info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ int j;
+ for (j=0; j<(int)info_ptr->num_trans; j++)
+ info_ptr->trans[j] = (png_byte)(255 - info_ptr->trans[j]);
+ }
+#endif
+ png_write_tRNS(png_ptr, info_ptr->trans, &(info_ptr->trans_values),
+ info_ptr->num_trans, info_ptr->color_type);
+ }
+#endif
+#if defined(PNG_WRITE_bKGD_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_bKGD)
+ png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);
+#endif
+#if defined(PNG_WRITE_hIST_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_hIST)
+ png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
+#endif
+#if defined(PNG_WRITE_oFFs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_oFFs)
+ png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,
+ info_ptr->offset_unit_type);
+#endif
+#if defined(PNG_WRITE_pCAL_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_pCAL)
+ png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,
+ info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,
+ info_ptr->pcal_units, info_ptr->pcal_params);
+#endif
+#if defined(PNG_WRITE_sCAL_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_sCAL)
+#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
+ png_write_sCAL(png_ptr, (int)info_ptr->scal_unit,
+ info_ptr->scal_pixel_width, info_ptr->scal_pixel_height);
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit,
+ info_ptr->scal_s_width, info_ptr->scal_s_height);
+#else
+ png_warning(png_ptr,
+ "png_write_sCAL not supported; sCAL chunk not written.\n");
+#endif
+#endif
+#endif
+#if defined(PNG_WRITE_pHYs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_pHYs)
+ png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
+ info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
+#endif
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_tIME)
+ {
+ png_write_tIME(png_ptr, &(info_ptr->mod_time));
+ png_ptr->mode |= PNG_WROTE_tIME;
+ }
+#endif
+#if defined(PNG_WRITE_sPLT_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_sPLT)
+ for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
+ png_write_sPLT(png_ptr, info_ptr->splt_palettes + i);
+#endif
+#if defined(PNG_WRITE_TEXT_SUPPORTED)
+ /* Check to see if we need to write text chunks */
+ for (i = 0; i < info_ptr->num_text; i++)
+ {
+ png_debug2(2, "Writing header text chunk %d, type %d\n", i,
+ info_ptr->text[i].compression);
+ /* an internationalized chunk? */
+ if (info_ptr->text[i].compression > 0)
+ {
+#if defined(PNG_WRITE_iTXt_SUPPORTED)
+ /* write international chunk */
+ png_write_iTXt(png_ptr,
+ info_ptr->text[i].compression,
+ info_ptr->text[i].key,
+ info_ptr->text[i].lang,
+ info_ptr->text[i].lang_key,
+ info_ptr->text[i].text);
+#else
+ png_warning(png_ptr, "Unable to write international text\n");
+#endif
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
+ }
+ /* If we want a compressed text chunk */
+ else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt)
+ {
+#if defined(PNG_WRITE_zTXt_SUPPORTED)
+ /* write compressed chunk */
+ png_write_zTXt(png_ptr, info_ptr->text[i].key,
+ info_ptr->text[i].text, 0,
+ info_ptr->text[i].compression);
+#else
+ png_warning(png_ptr, "Unable to write compressed text\n");
+#endif
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
+ }
+ else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
+ {
+#if defined(PNG_WRITE_tEXt_SUPPORTED)
+ /* write uncompressed chunk */
+ png_write_tEXt(png_ptr, info_ptr->text[i].key,
+ info_ptr->text[i].text,
+ 0);
+#else
+ png_warning(png_ptr, "Unable to write uncompressed text\n");
+#endif
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
+ }
+ }
+#endif
+#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
+ if (info_ptr->unknown_chunks_num)
+ {
+ png_unknown_chunk *up;
+
+ png_debug(5, "writing extra chunks\n");
+
+ for (up = info_ptr->unknown_chunks;
+ up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
+ up++)
+ {
+ int keep=png_handle_as_unknown(png_ptr, up->name);
+ if (keep != HANDLE_CHUNK_NEVER &&
+ up->location && (up->location & PNG_HAVE_PLTE) &&
+ !(up->location & PNG_HAVE_IDAT) &&
+ ((up->name[3] & 0x20) || keep == HANDLE_CHUNK_ALWAYS ||
+ (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
+ {
+ png_write_chunk(png_ptr, up->name, up->data, up->size);
+ }
+ }
+ }
+#endif
+}
+
+/* Writes the end of the PNG file. If you don't want to write comments or
+ * time information, you can pass NULL for info. If you already wrote these
+ * in png_write_info(), do not write them again here. If you have long
+ * comments, I suggest writing them here, and compressing them.
+ */
+void PNGAPI
+png_write_end(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_write_end\n");
+ if (!(png_ptr->mode & PNG_HAVE_IDAT))
+ png_error(png_ptr, "No IDATs written into file");
+
+ /* see if user wants us to write information chunks */
+ if (info_ptr != NULL)
+ {
+#if defined(PNG_WRITE_TEXT_SUPPORTED)
+ int i; /* local index variable */
+#endif
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+ /* check to see if user has supplied a time chunk */
+ if ((info_ptr->valid & PNG_INFO_tIME) &&
+ !(png_ptr->mode & PNG_WROTE_tIME))
+ png_write_tIME(png_ptr, &(info_ptr->mod_time));
+#endif
+#if defined(PNG_WRITE_TEXT_SUPPORTED)
+ /* loop through comment chunks */
+ for (i = 0; i < info_ptr->num_text; i++)
+ {
+ png_debug2(2, "Writing trailer text chunk %d, type %d\n", i,
+ info_ptr->text[i].compression);
+ /* an internationalized chunk? */
+ if (info_ptr->text[i].compression > 0)
+ {
+#if defined(PNG_WRITE_iTXt_SUPPORTED)
+ /* write international chunk */
+ png_write_iTXt(png_ptr,
+ info_ptr->text[i].compression,
+ info_ptr->text[i].key,
+ info_ptr->text[i].lang,
+ info_ptr->text[i].lang_key,
+ info_ptr->text[i].text);
+#else
+ png_warning(png_ptr, "Unable to write international text\n");
+#endif
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
+ }
+ else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
+ {
+#if defined(PNG_WRITE_zTXt_SUPPORTED)
+ /* write compressed chunk */
+ png_write_zTXt(png_ptr, info_ptr->text[i].key,
+ info_ptr->text[i].text, 0,
+ info_ptr->text[i].compression);
+#else
+ png_warning(png_ptr, "Unable to write compressed text\n");
+#endif
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
+ }
+ else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
+ {
+#if defined(PNG_WRITE_tEXt_SUPPORTED)
+ /* write uncompressed chunk */
+ png_write_tEXt(png_ptr, info_ptr->text[i].key,
+ info_ptr->text[i].text, 0);
+#else
+ png_warning(png_ptr, "Unable to write uncompressed text\n");
+#endif
+
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
+ }
+ }
+#endif
+#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
+ if (info_ptr->unknown_chunks_num)
+ {
+ png_unknown_chunk *up;
+
+ png_debug(5, "writing extra chunks\n");
+
+ for (up = info_ptr->unknown_chunks;
+ up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
+ up++)
+ {
+ int keep=png_handle_as_unknown(png_ptr, up->name);
+ if (keep != HANDLE_CHUNK_NEVER &&
+ up->location && (up->location & PNG_AFTER_IDAT) &&
+ ((up->name[3] & 0x20) || keep == HANDLE_CHUNK_ALWAYS ||
+ (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
+ {
+ png_write_chunk(png_ptr, up->name, up->data, up->size);
+ }
+ }
+ }
+#endif
+ }
+
+ png_ptr->mode |= PNG_AFTER_IDAT;
+
+ /* write end of PNG file */
+ png_write_IEND(png_ptr);
+#if 0
+/* This flush, added in libpng-1.0.8, causes some applications to crash
+ because they do not set png_ptr->output_flush_fn */
+ png_flush(png_ptr);
+#endif
+}
+
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+#if !defined(_WIN32_WCE)
+/* "time.h" functions are not supported on WindowsCE */
+void PNGAPI
+png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime)
+{
+ png_debug(1, "in png_convert_from_struct_tm\n");
+ ptime->year = (png_uint_16)(1900 + ttime->tm_year);
+ ptime->month = (png_byte)(ttime->tm_mon + 1);
+ ptime->day = (png_byte)ttime->tm_mday;
+ ptime->hour = (png_byte)ttime->tm_hour;
+ ptime->minute = (png_byte)ttime->tm_min;
+ ptime->second = (png_byte)ttime->tm_sec;
+}
+
+void PNGAPI
+png_convert_from_time_t(png_timep ptime, time_t ttime)
+{
+ struct tm *tbuf;
+
+ png_debug(1, "in png_convert_from_time_t\n");
+ tbuf = gmtime(&ttime);
+ png_convert_from_struct_tm(ptime, tbuf);
+}
+#endif
+#endif
+
+/* Initialize png_ptr structure, and allocate any memory needed */
+png_structp PNGAPI
+png_create_write_struct(png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn)
+{
+#ifdef PNG_USER_MEM_SUPPORTED
+ return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn,
+ warn_fn, NULL, NULL, NULL));
+}
+
+/* Alternate initialize png_ptr structure, and allocate any memory needed */
+png_structp PNGAPI
+png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
+ png_malloc_ptr malloc_fn, png_free_ptr free_fn)
+{
+#endif /* PNG_USER_MEM_SUPPORTED */
+ png_structp png_ptr;
+#ifdef PNG_SETJMP_SUPPORTED
+#ifdef USE_FAR_KEYWORD
+ jmp_buf jmpbuf;
+#endif
+#endif
+ int i;
+ png_debug(1, "in png_create_write_struct\n");
+#ifdef PNG_USER_MEM_SUPPORTED
+ if ((png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG,
+ (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr)) == NULL)
+#else
+ if ((png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG)) == NULL)
+#endif /* PNG_USER_MEM_SUPPORTED */
+ {
+ return ((png_structp)NULL);
+ }
+
+#ifdef PNG_ASSEMBLER_CODE_SUPPORTED
+ png_init_mmx_flags(png_ptr); /* 1.2.0 addition */
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+#ifdef USE_FAR_KEYWORD
+ if (setjmp(jmpbuf))
+#else
+ if (setjmp(png_ptr->jmpbuf))
+#endif
+ {
+ png_free(png_ptr, png_ptr->zbuf);
+ png_ptr->zbuf=NULL;
+ png_destroy_struct(png_ptr);
+ return ((png_structp)NULL);
+ }
+#ifdef USE_FAR_KEYWORD
+ png_memcpy(png_ptr->jmpbuf,jmpbuf,sizeof(jmp_buf));
+#endif
+#endif
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn);
+#endif /* PNG_USER_MEM_SUPPORTED */
+ png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
+
+ i=0;
+ do
+ {
+ if(user_png_ver[i] != png_libpng_ver[i])
+ png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
+ } while (png_libpng_ver[i++]);
+
+ if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)
+ {
+ /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
+ * we must recompile any applications that use any older library version.
+ * For versions after libpng 1.0, we will be compatible, so we need
+ * only check the first digit.
+ */
+ if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
+ (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) ||
+ (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
+ {
+#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
+ char msg[80];
+ if (user_png_ver)
+ {
+ sprintf(msg, "Application was compiled with png.h from libpng-%.20s",
+ user_png_ver);
+ png_warning(png_ptr, msg);
+ }
+ sprintf(msg, "Application is running with png.c from libpng-%.20s",
+ png_libpng_ver);
+ png_warning(png_ptr, msg);
+#endif
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+ png_ptr->flags=0;
+#endif
+ png_error(png_ptr,
+ "Incompatible libpng version in application and library");
+ }
+ }
+
+ /* initialize zbuf - compression buffer */
+ png_ptr->zbuf_size = PNG_ZBUF_SIZE;
+ png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)png_ptr->zbuf_size);
+
+ png_set_write_fn(png_ptr, NULL, NULL, NULL);
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
+ 1, NULL, NULL);
+#endif
+
+ return ((png_structp)png_ptr);
+}
+
+/* Initialize png_ptr structure, and allocate any memory needed */
+#undef png_write_init
+void PNGAPI
+png_write_init(png_structp png_ptr)
+{
+ /* We only come here via pre-1.0.7-compiled applications */
+ png_write_init_2(png_ptr, "1.0.6 or earlier", 0, 0);
+}
+
+#undef png_write_init_2
+void PNGAPI
+png_write_init_2(png_structp png_ptr, png_const_charp user_png_ver,
+ png_size_t png_struct_size, png_size_t png_info_size)
+{
+ /* We only come here via pre-1.0.12-compiled applications */
+#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
+ if(sizeof(png_struct) > png_struct_size || sizeof(png_info) > png_info_size)
+ {
+ char msg[80];
+ png_ptr->warning_fn=(png_error_ptr)NULL;
+ if (user_png_ver)
+ {
+ sprintf(msg, "Application was compiled with png.h from libpng-%.20s",
+ user_png_ver);
+ png_warning(png_ptr, msg);
+ }
+ sprintf(msg, "Application is running with png.c from libpng-%.20s",
+ png_libpng_ver);
+ png_warning(png_ptr, msg);
+ }
+#endif
+ if(sizeof(png_struct) > png_struct_size)
+ {
+ png_ptr->error_fn=(png_error_ptr)NULL;
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+ png_ptr->flags=0;
+#endif
+ png_error(png_ptr,
+ "The png struct allocated by the application for writing is too small.");
+ }
+ if(sizeof(png_info) > png_info_size)
+ {
+ png_ptr->error_fn=(png_error_ptr)NULL;
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+ png_ptr->flags=0;
+#endif
+ png_error(png_ptr,
+ "The info struct allocated by the application for writing is too small.");
+ }
+ png_write_init_3(&png_ptr, user_png_ver, png_struct_size);
+}
+
+
+void PNGAPI
+png_write_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver,
+ png_size_t png_struct_size)
+{
+ png_structp png_ptr=*ptr_ptr;
+#ifdef PNG_SETJMP_SUPPORTED
+ jmp_buf tmp_jmp; /* to save current jump buffer */
+#endif
+ int i = 0;
+ do
+ {
+ if (user_png_ver[i] != png_libpng_ver[i])
+ {
+#ifdef PNG_LEGACY_SUPPORTED
+ png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
+#else
+ png_ptr->warning_fn=(png_error_ptr)NULL;
+ png_warning(png_ptr,
+ "Application uses deprecated png_write_init() and should be recompiled.");
+ break;
+#endif
+ }
+ } while (png_libpng_ver[i++]);
+
+ png_debug(1, "in png_write_init_3\n");
+
+#ifdef PNG_SETJMP_SUPPORTED
+ /* save jump buffer and error functions */
+ png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
+#endif
+
+ if (sizeof(png_struct) > png_struct_size)
+ {
+ png_destroy_struct(png_ptr);
+ png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
+ *ptr_ptr = png_ptr;
+ }
+
+ /* reset all variables to 0 */
+ png_memset(png_ptr, 0, sizeof (png_struct));
+
+#ifdef PNG_ASSEMBLER_CODE_SUPPORTED
+ png_init_mmx_flags(png_ptr); /* 1.2.0 addition */
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+ /* restore jump buffer */
+ png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
+#endif
+
+ png_set_write_fn(png_ptr, NULL, NULL, NULL);
+
+ /* initialize zbuf - compression buffer */
+ png_ptr->zbuf_size = PNG_ZBUF_SIZE;
+ png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)png_ptr->zbuf_size);
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
+ 1, NULL, NULL);
+#endif
+}
+
+/* Write a few rows of image data. If the image is interlaced,
+ * either you will have to write the 7 sub images, or, if you
+ * have called png_set_interlace_handling(), you will have to
+ * "write" the image seven times.
+ */
+void PNGAPI
+png_write_rows(png_structp png_ptr, png_bytepp row,
+ png_uint_32 num_rows)
+{
+ png_uint_32 i; /* row counter */
+ png_bytepp rp; /* row pointer */
+
+ png_debug(1, "in png_write_rows\n");
+ /* loop through the rows */
+ for (i = 0, rp = row; i < num_rows; i++, rp++)
+ {
+ png_write_row(png_ptr, *rp);
+ }
+}
+
+/* Write the image. You only need to call this function once, even
+ * if you are writing an interlaced image.
+ */
+void PNGAPI
+png_write_image(png_structp png_ptr, png_bytepp image)
+{
+ png_uint_32 i; /* row index */
+ int pass, num_pass; /* pass variables */
+ png_bytepp rp; /* points to current row */
+
+ png_debug(1, "in png_write_image\n");
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+ /* intialize interlace handling. If image is not interlaced,
+ this will set pass to 1 */
+ num_pass = png_set_interlace_handling(png_ptr);
+#else
+ num_pass = 1;
+#endif
+ /* loop through passes */
+ for (pass = 0; pass < num_pass; pass++)
+ {
+ /* loop through image */
+ for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
+ {
+ png_write_row(png_ptr, *rp);
+ }
+ }
+}
+
+/* called by user to write a row of image data */
+void PNGAPI
+png_write_row(png_structp png_ptr, png_bytep row)
+{
+ png_debug2(1, "in png_write_row (row %ld, pass %d)\n",
+ png_ptr->row_number, png_ptr->pass);
+ /* initialize transformations and other stuff if first time */
+ if (png_ptr->row_number == 0 && png_ptr->pass == 0)
+ {
+ /* check for transforms that have been set but were defined out */
+#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_MONO)
+ png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined.");
+#endif
+#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED)
+ if (png_ptr->transformations & PNG_FILLER)
+ png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined.");
+#endif
+#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ png_warning(png_ptr, "PNG_WRITE_PACKSWAP_SUPPORTED is not defined.");
+#endif
+#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACK)
+ png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined.");
+#endif
+#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED)
+ if (png_ptr->transformations & PNG_SHIFT)
+ png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined.");
+#endif
+#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED)
+ if (png_ptr->transformations & PNG_BGR)
+ png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined.");
+#endif
+#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_BYTES)
+ png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined.");
+#endif
+
+ png_write_start_row(png_ptr);
+ }
+
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+ /* if interlaced and not interested in row, return */
+ if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
+ {
+ switch (png_ptr->pass)
+ {
+ case 0:
+ if (png_ptr->row_number & 0x07)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 1:
+ if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 2:
+ if ((png_ptr->row_number & 0x07) != 4)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 3:
+ if ((png_ptr->row_number & 0x03) || png_ptr->width < 3)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 4:
+ if ((png_ptr->row_number & 0x03) != 2)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 5:
+ if ((png_ptr->row_number & 0x01) || png_ptr->width < 2)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 6:
+ if (!(png_ptr->row_number & 0x01))
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ }
+ }
+#endif
+
+ /* set up row info for transformations */
+ png_ptr->row_info.color_type = png_ptr->color_type;
+ png_ptr->row_info.width = png_ptr->usr_width;
+ png_ptr->row_info.channels = png_ptr->usr_channels;
+ png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth;
+ png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
+ png_ptr->row_info.channels);
+
+ png_ptr->row_info.rowbytes = ((png_ptr->row_info.width *
+ (png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3);
+
+ png_debug1(3, "row_info->color_type = %d\n", png_ptr->row_info.color_type);
+ png_debug1(3, "row_info->width = %lu\n", png_ptr->row_info.width);
+ png_debug1(3, "row_info->channels = %d\n", png_ptr->row_info.channels);
+ png_debug1(3, "row_info->bit_depth = %d\n", png_ptr->row_info.bit_depth);
+ png_debug1(3, "row_info->pixel_depth = %d\n", png_ptr->row_info.pixel_depth);
+ png_debug1(3, "row_info->rowbytes = %lu\n", png_ptr->row_info.rowbytes);
+
+ /* Copy user's row into buffer, leaving room for filter byte. */
+ png_memcpy_check(png_ptr, png_ptr->row_buf + 1, row,
+ png_ptr->row_info.rowbytes);
+
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+ /* handle interlacing */
+ if (png_ptr->interlaced && png_ptr->pass < 6 &&
+ (png_ptr->transformations & PNG_INTERLACE))
+ {
+ png_do_write_interlace(&(png_ptr->row_info),
+ png_ptr->row_buf + 1, png_ptr->pass);
+ /* this should always get caught above, but still ... */
+ if (!(png_ptr->row_info.width))
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ }
+#endif
+
+ /* handle other transformations */
+ if (png_ptr->transformations)
+ png_do_write_transformations(png_ptr);
+
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ /* Write filter_method 64 (intrapixel differencing) only if
+ * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
+ * 2. Libpng did not write a PNG signature (this filter_method is only
+ * used in PNG datastreams that are embedded in MNG datastreams) and
+ * 3. The application called png_permit_mng_features with a mask that
+ * included PNG_FLAG_MNG_FILTER_64 and
+ * 4. The filter_method is 64 and
+ * 5. The color_type is RGB or RGBA
+ */
+ if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
+ (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))
+ {
+ /* Intrapixel differencing */
+ png_do_write_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1);
+ }
+#endif
+
+ /* Find a filter if necessary, filter the row and write it out. */
+ png_write_find_filter(png_ptr, &(png_ptr->row_info));
+
+ if (png_ptr->write_row_fn != NULL)
+ (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
+}
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+/* Set the automatic flush interval or 0 to turn flushing off */
+void PNGAPI
+png_set_flush(png_structp png_ptr, int nrows)
+{
+ png_debug(1, "in png_set_flush\n");
+ png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
+}
+
+/* flush the current output buffers now */
+void PNGAPI
+png_write_flush(png_structp png_ptr)
+{
+ int wrote_IDAT;
+
+ png_debug(1, "in png_write_flush\n");
+ /* We have already written out all of the data */
+ if (png_ptr->row_number >= png_ptr->num_rows)
+ return;
+
+ do
+ {
+ int ret;
+
+ /* compress the data */
+ ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH);
+ wrote_IDAT = 0;
+
+ /* check for compression errors */
+ if (ret != Z_OK)
+ {
+ if (png_ptr->zstream.msg != NULL)
+ png_error(png_ptr, png_ptr->zstream.msg);
+ else
+ png_error(png_ptr, "zlib error");
+ }
+
+ if (!(png_ptr->zstream.avail_out))
+ {
+ /* write the IDAT and reset the zlib output buffer */
+ png_write_IDAT(png_ptr, png_ptr->zbuf,
+ png_ptr->zbuf_size);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ wrote_IDAT = 1;
+ }
+ } while(wrote_IDAT == 1);
+
+ /* If there is any data left to be output, write it into a new IDAT */
+ if (png_ptr->zbuf_size != png_ptr->zstream.avail_out)
+ {
+ /* write the IDAT and reset the zlib output buffer */
+ png_write_IDAT(png_ptr, png_ptr->zbuf,
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ }
+ png_ptr->flush_rows = 0;
+ png_flush(png_ptr);
+}
+#endif /* PNG_WRITE_FLUSH_SUPPORTED */
+
+/* free all memory used by the write */
+void PNGAPI
+png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
+{
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_free_ptr free_fn = NULL;
+ png_voidp mem_ptr = NULL;
+#endif
+
+ png_debug(1, "in png_destroy_write_struct\n");
+ if (png_ptr_ptr != NULL)
+ {
+ png_ptr = *png_ptr_ptr;
+#ifdef PNG_USER_MEM_SUPPORTED
+ free_fn = png_ptr->free_fn;
+#endif
+ }
+
+ if (info_ptr_ptr != NULL)
+ info_ptr = *info_ptr_ptr;
+
+ if (info_ptr != NULL)
+ {
+ png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
+
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+ if (png_ptr->num_chunk_list)
+ {
+ png_free(png_ptr, png_ptr->chunk_list);
+ png_ptr->chunk_list=NULL;
+ png_ptr->num_chunk_list=0;
+ }
+#endif
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn,
+ (png_voidp)mem_ptr);
+#else
+ png_destroy_struct((png_voidp)info_ptr);
+#endif
+ *info_ptr_ptr = (png_infop)NULL;
+ }
+
+ if (png_ptr != NULL)
+ {
+ png_write_destroy(png_ptr);
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn,
+ (png_voidp)mem_ptr);
+#else
+ png_destroy_struct((png_voidp)png_ptr);
+#endif
+ *png_ptr_ptr = (png_structp)NULL;
+ }
+}
+
+
+/* Free any memory used in png_ptr struct (old method) */
+void /* PRIVATE */
+png_write_destroy(png_structp png_ptr)
+{
+#ifdef PNG_SETJMP_SUPPORTED
+ jmp_buf tmp_jmp; /* save jump buffer */
+#endif
+ png_error_ptr error_fn;
+ png_error_ptr warning_fn;
+ png_voidp error_ptr;
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_free_ptr free_fn;
+#endif
+
+ png_debug(1, "in png_write_destroy\n");
+ /* free any memory zlib uses */
+ deflateEnd(&png_ptr->zstream);
+
+ /* free our memory. png_free checks NULL for us. */
+ png_free(png_ptr, png_ptr->zbuf);
+ png_free(png_ptr, png_ptr->row_buf);
+ png_free(png_ptr, png_ptr->prev_row);
+ png_free(png_ptr, png_ptr->sub_row);
+ png_free(png_ptr, png_ptr->up_row);
+ png_free(png_ptr, png_ptr->avg_row);
+ png_free(png_ptr, png_ptr->paeth_row);
+
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+ png_free(png_ptr, png_ptr->time_buffer);
+#endif
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ png_free(png_ptr, png_ptr->prev_filters);
+ png_free(png_ptr, png_ptr->filter_weights);
+ png_free(png_ptr, png_ptr->inv_filter_weights);
+ png_free(png_ptr, png_ptr->filter_costs);
+ png_free(png_ptr, png_ptr->inv_filter_costs);
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+ /* reset structure */
+ png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
+#endif
+
+ error_fn = png_ptr->error_fn;
+ warning_fn = png_ptr->warning_fn;
+ error_ptr = png_ptr->error_ptr;
+#ifdef PNG_USER_MEM_SUPPORTED
+ free_fn = png_ptr->free_fn;
+#endif
+
+ png_memset(png_ptr, 0, sizeof (png_struct));
+
+ png_ptr->error_fn = error_fn;
+ png_ptr->warning_fn = warning_fn;
+ png_ptr->error_ptr = error_ptr;
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_ptr->free_fn = free_fn;
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+ png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
+#endif
+}
+
+/* Allow the application to select one or more row filters to use. */
+void PNGAPI
+png_set_filter(png_structp png_ptr, int method, int filters)
+{
+ png_debug(1, "in png_set_filter\n");
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
+ (method == PNG_INTRAPIXEL_DIFFERENCING))
+ method = PNG_FILTER_TYPE_BASE;
+#endif
+ if (method == PNG_FILTER_TYPE_BASE)
+ {
+ switch (filters & (PNG_ALL_FILTERS | 0x07))
+ {
+ case 5:
+ case 6:
+ case 7: png_warning(png_ptr, "Unknown row filter for method 0");
+ case PNG_FILTER_VALUE_NONE: png_ptr->do_filter=PNG_FILTER_NONE; break;
+ case PNG_FILTER_VALUE_SUB: png_ptr->do_filter=PNG_FILTER_SUB; break;
+ case PNG_FILTER_VALUE_UP: png_ptr->do_filter=PNG_FILTER_UP; break;
+ case PNG_FILTER_VALUE_AVG: png_ptr->do_filter=PNG_FILTER_AVG; break;
+ case PNG_FILTER_VALUE_PAETH: png_ptr->do_filter=PNG_FILTER_PAETH;break;
+ default: png_ptr->do_filter = (png_byte)filters; break;
+ }
+
+ /* If we have allocated the row_buf, this means we have already started
+ * with the image and we should have allocated all of the filter buffers
+ * that have been selected. If prev_row isn't already allocated, then
+ * it is too late to start using the filters that need it, since we
+ * will be missing the data in the previous row. If an application
+ * wants to start and stop using particular filters during compression,
+ * it should start out with all of the filters, and then add and
+ * remove them after the start of compression.
+ */
+ if (png_ptr->row_buf != NULL)
+ {
+ if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL)
+ {
+ png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
+ }
+
+ if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL)
+ {
+ if (png_ptr->prev_row == NULL)
+ {
+ png_warning(png_ptr, "Can't add Up filter after starting");
+ png_ptr->do_filter &= ~PNG_FILTER_UP;
+ }
+ else
+ {
+ png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
+ }
+ }
+
+ if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL)
+ {
+ if (png_ptr->prev_row == NULL)
+ {
+ png_warning(png_ptr, "Can't add Average filter after starting");
+ png_ptr->do_filter &= ~PNG_FILTER_AVG;
+ }
+ else
+ {
+ png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
+ }
+ }
+
+ if ((png_ptr->do_filter & PNG_FILTER_PAETH) &&
+ png_ptr->paeth_row == NULL)
+ {
+ if (png_ptr->prev_row == NULL)
+ {
+ png_warning(png_ptr, "Can't add Paeth filter after starting");
+ png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH);
+ }
+ else
+ {
+ png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
+ }
+ }
+
+ if (png_ptr->do_filter == PNG_NO_FILTERS)
+ png_ptr->do_filter = PNG_FILTER_NONE;
+ }
+ }
+ else
+ png_error(png_ptr, "Unknown custom filter method");
+}
+
+/* This allows us to influence the way in which libpng chooses the "best"
+ * filter for the current scanline. While the "minimum-sum-of-absolute-
+ * differences metric is relatively fast and effective, there is some
+ * question as to whether it can be improved upon by trying to keep the
+ * filtered data going to zlib more consistent, hopefully resulting in
+ * better compression.
+ */
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* GRR 970116 */
+void PNGAPI
+png_set_filter_heuristics(png_structp png_ptr, int heuristic_method,
+ int num_weights, png_doublep filter_weights,
+ png_doublep filter_costs)
+{
+ int i;
+
+ png_debug(1, "in png_set_filter_heuristics\n");
+ if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST)
+ {
+ png_warning(png_ptr, "Unknown filter heuristic method");
+ return;
+ }
+
+ if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT)
+ {
+ heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED;
+ }
+
+ if (num_weights < 0 || filter_weights == NULL ||
+ heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED)
+ {
+ num_weights = 0;
+ }
+
+ png_ptr->num_prev_filters = (png_byte)num_weights;
+ png_ptr->heuristic_method = (png_byte)heuristic_method;
+
+ if (num_weights > 0)
+ {
+ if (png_ptr->prev_filters == NULL)
+ {
+ png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)(sizeof(png_byte) * num_weights));
+
+ /* To make sure that the weighting starts out fairly */
+ for (i = 0; i < num_weights; i++)
+ {
+ png_ptr->prev_filters[i] = 255;
+ }
+ }
+
+ if (png_ptr->filter_weights == NULL)
+ {
+ png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(sizeof(png_uint_16) * num_weights));
+
+ png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(sizeof(png_uint_16) * num_weights));
+ for (i = 0; i < num_weights; i++)
+ {
+ png_ptr->inv_filter_weights[i] =
+ png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
+ }
+ }
+
+ for (i = 0; i < num_weights; i++)
+ {
+ if (filter_weights[i] < 0.0)
+ {
+ png_ptr->inv_filter_weights[i] =
+ png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
+ }
+ else
+ {
+ png_ptr->inv_filter_weights[i] =
+ (png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5);
+ png_ptr->filter_weights[i] =
+ (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5);
+ }
+ }
+ }
+
+ /* If, in the future, there are other filter methods, this would
+ * need to be based on png_ptr->filter.
+ */
+ if (png_ptr->filter_costs == NULL)
+ {
+ png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
+
+ png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
+
+ for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
+ {
+ png_ptr->inv_filter_costs[i] =
+ png_ptr->filter_costs[i] = PNG_COST_FACTOR;
+ }
+ }
+
+ /* Here is where we set the relative costs of the different filters. We
+ * should take the desired compression level into account when setting
+ * the costs, so that Paeth, for instance, has a high relative cost at low
+ * compression levels, while it has a lower relative cost at higher
+ * compression settings. The filter types are in order of increasing
+ * relative cost, so it would be possible to do this with an algorithm.
+ */
+ for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
+ {
+ if (filter_costs == NULL || filter_costs[i] < 0.0)
+ {
+ png_ptr->inv_filter_costs[i] =
+ png_ptr->filter_costs[i] = PNG_COST_FACTOR;
+ }
+ else if (filter_costs[i] >= 1.0)
+ {
+ png_ptr->inv_filter_costs[i] =
+ (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5);
+ png_ptr->filter_costs[i] =
+ (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5);
+ }
+ }
+}
+#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
+
+void PNGAPI
+png_set_compression_level(png_structp png_ptr, int level)
+{
+ png_debug(1, "in png_set_compression_level\n");
+ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
+ png_ptr->zlib_level = level;
+}
+
+void PNGAPI
+png_set_compression_mem_level(png_structp png_ptr, int mem_level)
+{
+ png_debug(1, "in png_set_compression_mem_level\n");
+ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
+ png_ptr->zlib_mem_level = mem_level;
+}
+
+void PNGAPI
+png_set_compression_strategy(png_structp png_ptr, int strategy)
+{
+ png_debug(1, "in png_set_compression_strategy\n");
+ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
+ png_ptr->zlib_strategy = strategy;
+}
+
+void PNGAPI
+png_set_compression_window_bits(png_structp png_ptr, int window_bits)
+{
+ if (window_bits > 15)
+ png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
+ else if (window_bits < 8)
+ png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
+#ifndef WBITS_8_OK
+ /* avoid libpng bug with 256-byte windows */
+ if (window_bits == 8)
+ {
+ png_warning(png_ptr, "Compression window is being reset to 512");
+ window_bits=9;
+ }
+#endif
+ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS;
+ png_ptr->zlib_window_bits = window_bits;
+}
+
+void PNGAPI
+png_set_compression_method(png_structp png_ptr, int method)
+{
+ png_debug(1, "in png_set_compression_method\n");
+ if (method != 8)
+ png_warning(png_ptr, "Only compression method 8 is supported by PNG");
+ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD;
+ png_ptr->zlib_method = method;
+}
+
+void PNGAPI
+png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn)
+{
+ png_ptr->write_row_fn = write_row_fn;
+}
+
+#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+void PNGAPI
+png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
+ write_user_transform_fn)
+{
+ png_debug(1, "in png_set_write_user_transform_fn\n");
+ png_ptr->transformations |= PNG_USER_TRANSFORM;
+ png_ptr->write_user_transform_fn = write_user_transform_fn;
+}
+#endif
+
+
+#if defined(PNG_INFO_IMAGE_SUPPORTED)
+void PNGAPI
+png_write_png(png_structp png_ptr, png_infop info_ptr,
+ int transforms, voidp params)
+{
+#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
+ /* invert the alpha channel from opacity to transparency */
+ if (transforms & PNG_TRANSFORM_INVERT_ALPHA)
+ png_set_invert_alpha(png_ptr);
+#endif
+
+ /* Write the file header information. */
+ png_write_info(png_ptr, info_ptr);
+
+ /* ------ these transformations don't touch the info structure ------- */
+
+#if defined(PNG_WRITE_INVERT_SUPPORTED)
+ /* invert monochrome pixels */
+ if (transforms & PNG_TRANSFORM_INVERT_MONO)
+ png_set_invert_mono(png_ptr);
+#endif
+
+#if defined(PNG_WRITE_SHIFT_SUPPORTED)
+ /* Shift the pixels up to a legal bit depth and fill in
+ * as appropriate to correctly scale the image.
+ */
+ if ((transforms & PNG_TRANSFORM_SHIFT)
+ && (info_ptr->valid & PNG_INFO_sBIT))
+ png_set_shift(png_ptr, &info_ptr->sig_bit);
+#endif
+
+#if defined(PNG_WRITE_PACK_SUPPORTED)
+ /* pack pixels into bytes */
+ if (transforms & PNG_TRANSFORM_PACKING)
+ png_set_packing(png_ptr);
+#endif
+
+#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+ /* swap location of alpha bytes from ARGB to RGBA */
+ if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
+ png_set_swap_alpha(png_ptr);
+#endif
+
+#if defined(PNG_WRITE_FILLER_SUPPORTED)
+ /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
+ * RGB (4 channels -> 3 channels). The second parameter is not used.
+ */
+ if (transforms & PNG_TRANSFORM_STRIP_FILLER)
+ png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
+#endif
+
+#if defined(PNG_WRITE_BGR_SUPPORTED)
+ /* flip BGR pixels to RGB */
+ if (transforms & PNG_TRANSFORM_BGR)
+ png_set_bgr(png_ptr);
+#endif
+
+#if defined(PNG_WRITE_SWAP_SUPPORTED)
+ /* swap bytes of 16-bit files to most significant byte first */
+ if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
+ png_set_swap(png_ptr);
+#endif
+
+#if defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+ /* swap bits of 1, 2, 4 bit packed pixel formats */
+ if (transforms & PNG_TRANSFORM_PACKSWAP)
+ png_set_packswap(png_ptr);
+#endif
+
+ /* ----------------------- end of transformations ------------------- */
+
+ /* write the bits */
+ if (info_ptr->valid & PNG_INFO_IDAT)
+ png_write_image(png_ptr, info_ptr->row_pointers);
+
+ /* It is REQUIRED to call this to finish writing the rest of the file */
+ png_write_end(png_ptr, info_ptr);
+
+ if(transforms == 0 || params == NULL)
+ /* quiet compiler warnings */ return;
+}
+#endif
+#endif /* PNG_WRITE_SUPPORTED */
--- /dev/null
+
+/* pngwtran.c - transforms the data in a row for PNG writers
+ *
+ * libpng 1.2.0 - September 1, 2001
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+#ifdef PNG_WRITE_SUPPORTED
+
+/* Transform the data according to the user's wishes. The order of
+ * transformations is significant.
+ */
+void /* PRIVATE */
+png_do_write_transformations(png_structp png_ptr)
+{
+ png_debug(1, "in png_do_write_transformations\n");
+
+ if (png_ptr == NULL)
+ return;
+
+#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+ if (png_ptr->transformations & PNG_USER_TRANSFORM)
+ if(png_ptr->write_user_transform_fn != NULL)
+ (*(png_ptr->write_user_transform_fn)) /* user write transform function */
+ (png_ptr, /* png_ptr */
+ &(png_ptr->row_info), /* row_info: */
+ /* png_uint_32 width; width of row */
+ /* png_uint_32 rowbytes; number of bytes in row */
+ /* png_byte color_type; color type of pixels */
+ /* png_byte bit_depth; bit depth of samples */
+ /* png_byte channels; number of channels (1-4) */
+ /* png_byte pixel_depth; bits per pixel (depth*channels) */
+ png_ptr->row_buf + 1); /* start of pixel data for row */
+#endif
+#if defined(PNG_WRITE_FILLER_SUPPORTED)
+ if (png_ptr->transformations & PNG_FILLER)
+ png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ png_ptr->flags);
+#endif
+#if defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+#if defined(PNG_WRITE_PACK_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACK)
+ png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ (png_uint_32)png_ptr->bit_depth);
+#endif
+#if defined(PNG_WRITE_SWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_BYTES)
+ png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+#if defined(PNG_WRITE_SHIFT_SUPPORTED)
+ if (png_ptr->transformations & PNG_SHIFT)
+ png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ &(png_ptr->shift));
+#endif
+#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_ALPHA)
+ png_do_write_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_ALPHA)
+ png_do_write_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+#if defined(PNG_WRITE_BGR_SUPPORTED)
+ if (png_ptr->transformations & PNG_BGR)
+ png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+#if defined(PNG_WRITE_INVERT_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_MONO)
+ png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+}
+
+#if defined(PNG_WRITE_PACK_SUPPORTED)
+/* Pack pixels into bytes. Pass the true bit depth in bit_depth. The
+ * row_info bit depth should be 8 (one pixel per byte). The channels
+ * should be 1 (this only happens on grayscale and paletted images).
+ */
+void /* PRIVATE */
+png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
+{
+ png_debug(1, "in png_do_pack\n");
+ if (row_info->bit_depth == 8 &&
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ row_info->channels == 1)
+ {
+ switch ((int)bit_depth)
+ {
+ case 1:
+ {
+ png_bytep sp, dp;
+ int mask, v;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ sp = row;
+ dp = row;
+ mask = 0x80;
+ v = 0;
+
+ for (i = 0; i < row_width; i++)
+ {
+ if (*sp != 0)
+ v |= mask;
+ sp++;
+ if (mask > 1)
+ mask >>= 1;
+ else
+ {
+ mask = 0x80;
+ *dp = (png_byte)v;
+ dp++;
+ v = 0;
+ }
+ }
+ if (mask != 0x80)
+ *dp = (png_byte)v;
+ break;
+ }
+ case 2:
+ {
+ png_bytep sp, dp;
+ int shift, v;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ sp = row;
+ dp = row;
+ shift = 6;
+ v = 0;
+ for (i = 0; i < row_width; i++)
+ {
+ png_byte value;
+
+ value = (png_byte)(*sp & 0x03);
+ v |= (value << shift);
+ if (shift == 0)
+ {
+ shift = 6;
+ *dp = (png_byte)v;
+ dp++;
+ v = 0;
+ }
+ else
+ shift -= 2;
+ sp++;
+ }
+ if (shift != 6)
+ *dp = (png_byte)v;
+ break;
+ }
+ case 4:
+ {
+ png_bytep sp, dp;
+ int shift, v;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ sp = row;
+ dp = row;
+ shift = 4;
+ v = 0;
+ for (i = 0; i < row_width; i++)
+ {
+ png_byte value;
+
+ value = (png_byte)(*sp & 0x0f);
+ v |= (value << shift);
+
+ if (shift == 0)
+ {
+ shift = 4;
+ *dp = (png_byte)v;
+ dp++;
+ v = 0;
+ }
+ else
+ shift -= 4;
+
+ sp++;
+ }
+ if (shift != 4)
+ *dp = (png_byte)v;
+ break;
+ }
+ }
+ row_info->bit_depth = (png_byte)bit_depth;
+ row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels);
+ row_info->rowbytes =
+ ((row_info->width * row_info->pixel_depth + 7) >> 3);
+ }
+}
+#endif
+
+#if defined(PNG_WRITE_SHIFT_SUPPORTED)
+/* Shift pixel values to take advantage of whole range. Pass the
+ * true number of bits in bit_depth. The row should be packed
+ * according to row_info->bit_depth. Thus, if you had a row of
+ * bit depth 4, but the pixels only had values from 0 to 7, you
+ * would pass 3 as bit_depth, and this routine would translate the
+ * data to 0 to 15.
+ */
+void /* PRIVATE */
+png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth)
+{
+ png_debug(1, "in png_do_shift\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL &&
+#else
+ if (
+#endif
+ row_info->color_type != PNG_COLOR_TYPE_PALETTE)
+ {
+ int shift_start[4], shift_dec[4];
+ int channels = 0;
+
+ if (row_info->color_type & PNG_COLOR_MASK_COLOR)
+ {
+ shift_start[channels] = row_info->bit_depth - bit_depth->red;
+ shift_dec[channels] = bit_depth->red;
+ channels++;
+ shift_start[channels] = row_info->bit_depth - bit_depth->green;
+ shift_dec[channels] = bit_depth->green;
+ channels++;
+ shift_start[channels] = row_info->bit_depth - bit_depth->blue;
+ shift_dec[channels] = bit_depth->blue;
+ channels++;
+ }
+ else
+ {
+ shift_start[channels] = row_info->bit_depth - bit_depth->gray;
+ shift_dec[channels] = bit_depth->gray;
+ channels++;
+ }
+ if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ shift_start[channels] = row_info->bit_depth - bit_depth->alpha;
+ shift_dec[channels] = bit_depth->alpha;
+ channels++;
+ }
+
+ /* with low row depths, could only be grayscale, so one channel */
+ if (row_info->bit_depth < 8)
+ {
+ png_bytep bp = row;
+ png_uint_32 i;
+ png_byte mask;
+ png_uint_32 row_bytes = row_info->rowbytes;
+
+ if (bit_depth->gray == 1 && row_info->bit_depth == 2)
+ mask = 0x55;
+ else if (row_info->bit_depth == 4 && bit_depth->gray == 3)
+ mask = 0x11;
+ else
+ mask = 0xff;
+
+ for (i = 0; i < row_bytes; i++, bp++)
+ {
+ png_uint_16 v;
+ int j;
+
+ v = *bp;
+ *bp = 0;
+ for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])
+ {
+ if (j > 0)
+ *bp |= (png_byte)((v << j) & 0xff);
+ else
+ *bp |= (png_byte)((v >> (-j)) & mask);
+ }
+ }
+ }
+ else if (row_info->bit_depth == 8)
+ {
+ png_bytep bp = row;
+ png_uint_32 i;
+ png_uint_32 istop = channels * row_info->width;
+
+ for (i = 0; i < istop; i++, bp++)
+ {
+
+ png_uint_16 v;
+ int j;
+ int c = (int)(i%channels);
+
+ v = *bp;
+ *bp = 0;
+ for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
+ {
+ if (j > 0)
+ *bp |= (png_byte)((v << j) & 0xff);
+ else
+ *bp |= (png_byte)((v >> (-j)) & 0xff);
+ }
+ }
+ }
+ else
+ {
+ png_bytep bp;
+ png_uint_32 i;
+ png_uint_32 istop = channels * row_info->width;
+
+ for (bp = row, i = 0; i < istop; i++)
+ {
+ int c = (int)(i%channels);
+ png_uint_16 value, v;
+ int j;
+
+ v = (png_uint_16)(((png_uint_16)(*bp) << 8) + *(bp + 1));
+ value = 0;
+ for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
+ {
+ if (j > 0)
+ value |= (png_uint_16)((v << j) & (png_uint_16)0xffff);
+ else
+ value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff);
+ }
+ *bp++ = (png_byte)(value >> 8);
+ *bp++ = (png_byte)(value & 0xff);
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+void /* PRIVATE */
+png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_write_swap_alpha\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ /* This converts from ARGB to RGBA */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ png_byte save = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = save;
+ }
+ }
+ /* This converts from AARRGGBB to RRGGBBAA */
+ else
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ png_byte save[2];
+ save[0] = *(sp++);
+ save[1] = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = save[0];
+ *(dp++) = save[1];
+ }
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ /* This converts from AG to GA */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ png_byte save = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = save;
+ }
+ }
+ /* This converts from AAGG to GGAA */
+ else
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ png_byte save[2];
+ save[0] = *(sp++);
+ save[1] = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = save[0];
+ *(dp++) = save[1];
+ }
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
+void /* PRIVATE */
+png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_write_invert_alpha\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ /* This inverts the alpha channel in RGBA */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = (png_byte)(255 - *(sp++));
+ }
+ }
+ /* This inverts the alpha channel in RRGGBBAA */
+ else
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = (png_byte)(255 - *(sp++));
+ *(dp++) = (png_byte)(255 - *(sp++));
+ }
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ /* This inverts the alpha channel in GA */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ *(dp++) = *(sp++);
+ *(dp++) = (png_byte)(255 - *(sp++));
+ }
+ }
+ /* This inverts the alpha channel in GGAA */
+ else
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = (png_byte)(255 - *(sp++));
+ *(dp++) = (png_byte)(255 - *(sp++));
+ }
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+/* undoes intrapixel differencing */
+void /* PRIVATE */
+png_do_write_intrapixel(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_write_intrapixel\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ (row_info->color_type & PNG_COLOR_MASK_COLOR))
+ {
+ int bytes_per_pixel;
+ png_uint_32 row_width = row_info->width;
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ bytes_per_pixel = 3;
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ bytes_per_pixel = 4;
+ else
+ return;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
+ {
+ *(rp) = (png_byte)((*rp - *(rp+1))&0xff);
+ *(rp+2) = (png_byte)((*(rp+2) - *(rp+1))&0xff);
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ bytes_per_pixel = 6;
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ bytes_per_pixel = 8;
+ else
+ return;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
+ {
+ png_uint_32 s0=*(rp )<<8 | *(rp+1);
+ png_uint_32 s1=*(rp+2)<<8 | *(rp+3);
+ png_uint_32 s2=*(rp+4)<<8 | *(rp+5);
+ png_uint_32 red=(s0-s1)&0xffff;
+ png_uint_32 blue=(s2-s1)&0xffff;
+ *(rp ) = (png_byte)((red>>8)&0xff);
+ *(rp+1) = (png_byte)(red&0xff);
+ *(rp+4) = (png_byte)((blue>>8)&0xff);
+ *(rp+5) = (png_byte)(blue&0xff);
+ }
+ }
+ }
+}
+#endif /* PNG_MNG_FEATURES_SUPPORTED */
+#endif /* PNG_WRITE_SUPPORTED */
--- /dev/null
+
+/* pngwutil.c - utilities to write a PNG file
+ *
+ * libpng 1.2.0 - September 1, 2001
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2001 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+#ifdef PNG_WRITE_SUPPORTED
+
+/* Place a 32-bit number into a buffer in PNG byte order. We work
+ * with unsigned numbers for convenience, although one supported
+ * ancillary chunk uses signed (two's complement) numbers.
+ */
+void /* PRIVATE */
+png_save_uint_32(png_bytep buf, png_uint_32 i)
+{
+ buf[0] = (png_byte)((i >> 24) & 0xff);
+ buf[1] = (png_byte)((i >> 16) & 0xff);
+ buf[2] = (png_byte)((i >> 8) & 0xff);
+ buf[3] = (png_byte)(i & 0xff);
+}
+
+#if defined(PNG_WRITE_pCAL_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED)
+/* The png_save_int_32 function assumes integers are stored in two's
+ * complement format. If this isn't the case, then this routine needs to
+ * be modified to write data in two's complement format.
+ */
+void /* PRIVATE */
+png_save_int_32(png_bytep buf, png_int_32 i)
+{
+ buf[0] = (png_byte)((i >> 24) & 0xff);
+ buf[1] = (png_byte)((i >> 16) & 0xff);
+ buf[2] = (png_byte)((i >> 8) & 0xff);
+ buf[3] = (png_byte)(i & 0xff);
+}
+#endif
+
+/* Place a 16-bit number into a buffer in PNG byte order.
+ * The parameter is declared unsigned int, not png_uint_16,
+ * just to avoid potential problems on pre-ANSI C compilers.
+ */
+void /* PRIVATE */
+png_save_uint_16(png_bytep buf, unsigned int i)
+{
+ buf[0] = (png_byte)((i >> 8) & 0xff);
+ buf[1] = (png_byte)(i & 0xff);
+}
+
+/* Write a PNG chunk all at once. The type is an array of ASCII characters
+ * representing the chunk name. The array must be at least 4 bytes in
+ * length, and does not need to be null terminated. To be safe, pass the
+ * pre-defined chunk names here, and if you need a new one, define it
+ * where the others are defined. The length is the length of the data.
+ * All the data must be present. If that is not possible, use the
+ * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()
+ * functions instead.
+ */
+void PNGAPI
+png_write_chunk(png_structp png_ptr, png_bytep chunk_name,
+ png_bytep data, png_size_t length)
+{
+ png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length);
+ png_write_chunk_data(png_ptr, data, length);
+ png_write_chunk_end(png_ptr);
+}
+
+/* Write the start of a PNG chunk. The type is the chunk type.
+ * The total_length is the sum of the lengths of all the data you will be
+ * passing in png_write_chunk_data().
+ */
+void PNGAPI
+png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name,
+ png_uint_32 length)
+{
+ png_byte buf[4];
+ png_debug2(0, "Writing %s chunk (%lu bytes)\n", chunk_name, length);
+
+ /* write the length */
+ png_save_uint_32(buf, length);
+ png_write_data(png_ptr, buf, (png_size_t)4);
+
+ /* write the chunk name */
+ png_write_data(png_ptr, chunk_name, (png_size_t)4);
+ /* reset the crc and run it over the chunk name */
+ png_reset_crc(png_ptr);
+ png_calculate_crc(png_ptr, chunk_name, (png_size_t)4);
+}
+
+/* Write the data of a PNG chunk started with png_write_chunk_start().
+ * Note that multiple calls to this function are allowed, and that the
+ * sum of the lengths from these calls *must* add up to the total_length
+ * given to png_write_chunk_start().
+ */
+void PNGAPI
+png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ /* write the data, and run the CRC over it */
+ if (data != NULL && length > 0)
+ {
+ png_calculate_crc(png_ptr, data, length);
+ png_write_data(png_ptr, data, length);
+ }
+}
+
+/* Finish a chunk started with png_write_chunk_start(). */
+void PNGAPI
+png_write_chunk_end(png_structp png_ptr)
+{
+ png_byte buf[4];
+
+ /* write the crc */
+ png_save_uint_32(buf, png_ptr->crc);
+
+ png_write_data(png_ptr, buf, (png_size_t)4);
+}
+
+/* Simple function to write the signature. If we have already written
+ * the magic bytes of the signature, or more likely, the PNG stream is
+ * being embedded into another stream and doesn't need its own signature,
+ * we should call png_set_sig_bytes() to tell libpng how many of the
+ * bytes have already been written.
+ */
+void /* PRIVATE */
+png_write_sig(png_structp png_ptr)
+{
+ png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
+ /* write the rest of the 8 byte signature */
+ png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes],
+ (png_size_t)8 - png_ptr->sig_bytes);
+ if(png_ptr->sig_bytes < 3)
+ png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
+}
+
+#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED)
+/*
+ * This pair of functions encapsulates the operation of (a) compressing a
+ * text string, and (b) issuing it later as a series of chunk data writes.
+ * The compression_state structure is shared context for these functions
+ * set up by the caller in order to make the whole mess thread-safe.
+ */
+
+typedef struct
+{
+ char *input; /* the uncompressed input data */
+ int input_len; /* its length */
+ int num_output_ptr; /* number of output pointers used */
+ int max_output_ptr; /* size of output_ptr */
+ png_charpp output_ptr; /* array of pointers to output */
+} compression_state;
+
+/* compress given text into storage in the png_ptr structure */
+static int /* PRIVATE */
+png_text_compress(png_structp png_ptr,
+ png_charp text, png_size_t text_len, int compression,
+ compression_state *comp)
+{
+ int ret;
+
+ comp->num_output_ptr = comp->max_output_ptr = 0;
+ comp->output_ptr = NULL;
+ comp->input = NULL;
+
+ /* we may just want to pass the text right through */
+ if (compression == PNG_TEXT_COMPRESSION_NONE)
+ {
+ comp->input = text;
+ comp->input_len = text_len;
+ return((int)text_len);
+ }
+
+ if (compression >= PNG_TEXT_COMPRESSION_LAST)
+ {
+#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
+ char msg[50];
+ sprintf(msg, "Unknown compression type %d", compression);
+ png_warning(png_ptr, msg);
+#else
+ png_warning(png_ptr, "Unknown compression type");
+#endif
+ }
+
+ /* We can't write the chunk until we find out how much data we have,
+ * which means we need to run the compressor first and save the
+ * output. This shouldn't be a problem, as the vast majority of
+ * comments should be reasonable, but we will set up an array of
+ * malloc'd pointers to be sure.
+ *
+ * If we knew the application was well behaved, we could simplify this
+ * greatly by assuming we can always malloc an output buffer large
+ * enough to hold the compressed text ((1001 * text_len / 1000) + 12)
+ * and malloc this directly. The only time this would be a bad idea is
+ * if we can't malloc more than 64K and we have 64K of random input
+ * data, or if the input string is incredibly large (although this
+ * wouldn't cause a failure, just a slowdown due to swapping).
+ */
+
+ /* set up the compression buffers */
+ png_ptr->zstream.avail_in = (uInt)text_len;
+ png_ptr->zstream.next_in = (Bytef *)text;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf;
+
+ /* this is the same compression loop as in png_write_row() */
+ do
+ {
+ /* compress the data */
+ ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
+ if (ret != Z_OK)
+ {
+ /* error */
+ if (png_ptr->zstream.msg != NULL)
+ png_error(png_ptr, png_ptr->zstream.msg);
+ else
+ png_error(png_ptr, "zlib error");
+ }
+ /* check to see if we need more room */
+ if (!png_ptr->zstream.avail_out && png_ptr->zstream.avail_in)
+ {
+ /* make sure the output array has room */
+ if (comp->num_output_ptr >= comp->max_output_ptr)
+ {
+ int old_max;
+
+ old_max = comp->max_output_ptr;
+ comp->max_output_ptr = comp->num_output_ptr + 4;
+ if (comp->output_ptr != NULL)
+ {
+ png_charpp old_ptr;
+
+ old_ptr = comp->output_ptr;
+ comp->output_ptr = (png_charpp)png_malloc(png_ptr,
+ (png_uint_32)(comp->max_output_ptr * sizeof (png_charpp)));
+ png_memcpy(comp->output_ptr, old_ptr, old_max
+ * sizeof (png_charp));
+ png_free(png_ptr, old_ptr);
+ }
+ else
+ comp->output_ptr = (png_charpp)png_malloc(png_ptr,
+ (png_uint_32)(comp->max_output_ptr * sizeof (png_charp)));
+ }
+
+ /* save the data */
+ comp->output_ptr[comp->num_output_ptr] = (png_charp)png_malloc(png_ptr,
+ (png_uint_32)png_ptr->zbuf_size);
+ png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
+ png_ptr->zbuf_size);
+ comp->num_output_ptr++;
+
+ /* and reset the buffer */
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ }
+ /* continue until we don't have any more to compress */
+ } while (png_ptr->zstream.avail_in);
+
+ /* finish the compression */
+ do
+ {
+ /* tell zlib we are finished */
+ ret = deflate(&png_ptr->zstream, Z_FINISH);
+
+ if (ret == Z_OK)
+ {
+ /* check to see if we need more room */
+ if (!(png_ptr->zstream.avail_out))
+ {
+ /* check to make sure our output array has room */
+ if (comp->num_output_ptr >= comp->max_output_ptr)
+ {
+ int old_max;
+
+ old_max = comp->max_output_ptr;
+ comp->max_output_ptr = comp->num_output_ptr + 4;
+ if (comp->output_ptr != NULL)
+ {
+ png_charpp old_ptr;
+
+ old_ptr = comp->output_ptr;
+ /* This could be optimized to realloc() */
+ comp->output_ptr = (png_charpp)png_malloc(png_ptr,
+ (png_uint_32)(comp->max_output_ptr * sizeof (png_charpp)));
+ png_memcpy(comp->output_ptr, old_ptr,
+ old_max * sizeof (png_charp));
+ png_free(png_ptr, old_ptr);
+ }
+ else
+ comp->output_ptr = (png_charpp)png_malloc(png_ptr,
+ (png_uint_32)(comp->max_output_ptr * sizeof (png_charp)));
+ }
+
+ /* save off the data */
+ comp->output_ptr[comp->num_output_ptr] =
+ (png_charp)png_malloc(png_ptr, (png_uint_32)png_ptr->zbuf_size);
+ png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
+ png_ptr->zbuf_size);
+ comp->num_output_ptr++;
+
+ /* and reset the buffer pointers */
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ }
+ }
+ else if (ret != Z_STREAM_END)
+ {
+ /* we got an error */
+ if (png_ptr->zstream.msg != NULL)
+ png_error(png_ptr, png_ptr->zstream.msg);
+ else
+ png_error(png_ptr, "zlib error");
+ }
+ } while (ret != Z_STREAM_END);
+
+ /* text length is number of buffers plus last buffer */
+ text_len = png_ptr->zbuf_size * comp->num_output_ptr;
+ if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
+ text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out;
+
+ return((int)text_len);
+}
+
+/* ship the compressed text out via chunk writes */
+static void /* PRIVATE */
+png_write_compressed_data_out(png_structp png_ptr, compression_state *comp)
+{
+ int i;
+
+ /* handle the no-compression case */
+ if (comp->input)
+ {
+ png_write_chunk_data(png_ptr, (png_bytep)comp->input,
+ (png_size_t)comp->input_len);
+ return;
+ }
+
+ /* write saved output buffers, if any */
+ for (i = 0; i < comp->num_output_ptr; i++)
+ {
+ png_write_chunk_data(png_ptr,(png_bytep)comp->output_ptr[i],
+ png_ptr->zbuf_size);
+ png_free(png_ptr, comp->output_ptr[i]);
+ comp->output_ptr[i]=NULL;
+ }
+ if (comp->max_output_ptr != 0)
+ png_free(png_ptr, comp->output_ptr);
+ comp->output_ptr=NULL;
+ /* write anything left in zbuf */
+ if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size)
+ png_write_chunk_data(png_ptr, png_ptr->zbuf,
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out);
+
+ /* reset zlib for another zTXt/iTXt or the image data */
+ deflateReset(&png_ptr->zstream);
+
+}
+#endif
+
+/* Write the IHDR chunk, and update the png_struct with the necessary
+ * information. Note that the rest of this code depends upon this
+ * information being correct.
+ */
+void /* PRIVATE */
+png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
+ int bit_depth, int color_type, int compression_type, int filter_type,
+ int interlace_type)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_IHDR;
+#endif
+ png_byte buf[13]; /* buffer to store the IHDR info */
+
+ png_debug(1, "in png_write_IHDR\n");
+ /* Check that we have valid input data from the application info */
+ switch (color_type)
+ {
+ case PNG_COLOR_TYPE_GRAY:
+ switch (bit_depth)
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16: png_ptr->channels = 1; break;
+ default: png_error(png_ptr,"Invalid bit depth for grayscale image");
+ }
+ break;
+ case PNG_COLOR_TYPE_RGB:
+ if (bit_depth != 8 && bit_depth != 16)
+ png_error(png_ptr, "Invalid bit depth for RGB image");
+ png_ptr->channels = 3;
+ break;
+ case PNG_COLOR_TYPE_PALETTE:
+ switch (bit_depth)
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8: png_ptr->channels = 1; break;
+ default: png_error(png_ptr, "Invalid bit depth for paletted image");
+ }
+ break;
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ if (bit_depth != 8 && bit_depth != 16)
+ png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
+ png_ptr->channels = 2;
+ break;
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ if (bit_depth != 8 && bit_depth != 16)
+ png_error(png_ptr, "Invalid bit depth for RGBA image");
+ png_ptr->channels = 4;
+ break;
+ default:
+ png_error(png_ptr, "Invalid image color type specified");
+ }
+
+ if (compression_type != PNG_COMPRESSION_TYPE_BASE)
+ {
+ png_warning(png_ptr, "Invalid compression type specified");
+ compression_type = PNG_COMPRESSION_TYPE_BASE;
+ }
+
+ /* Write filter_method 64 (intrapixel differencing) only if
+ * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
+ * 2. Libpng did not write a PNG signature (this filter_method is only
+ * used in PNG datastreams that are embedded in MNG datastreams) and
+ * 3. The application called png_permit_mng_features with a mask that
+ * included PNG_FLAG_MNG_FILTER_64 and
+ * 4. The filter_method is 64 and
+ * 5. The color_type is RGB or RGBA
+ */
+ if (
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
+ ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) &&
+ (color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
+ (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&
+#endif
+ filter_type != PNG_FILTER_TYPE_BASE)
+ {
+ png_warning(png_ptr, "Invalid filter type specified");
+ filter_type = PNG_FILTER_TYPE_BASE;
+ }
+
+#ifdef PNG_WRITE_INTERLACING_SUPPORTED
+ if (interlace_type != PNG_INTERLACE_NONE &&
+ interlace_type != PNG_INTERLACE_ADAM7)
+ {
+ png_warning(png_ptr, "Invalid interlace type specified");
+ interlace_type = PNG_INTERLACE_ADAM7;
+ }
+#else
+ interlace_type=PNG_INTERLACE_NONE;
+#endif
+
+ /* save off the relevent information */
+ png_ptr->bit_depth = (png_byte)bit_depth;
+ png_ptr->color_type = (png_byte)color_type;
+ png_ptr->interlaced = (png_byte)interlace_type;
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ png_ptr->filter_type = (png_byte)filter_type;
+#endif
+ png_ptr->width = width;
+ png_ptr->height = height;
+
+ png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
+ png_ptr->rowbytes = ((width * (png_size_t)png_ptr->pixel_depth + 7) >> 3);
+ /* set the usr info, so any transformations can modify it */
+ png_ptr->usr_width = png_ptr->width;
+ png_ptr->usr_bit_depth = png_ptr->bit_depth;
+ png_ptr->usr_channels = png_ptr->channels;
+
+ /* pack the header information into the buffer */
+ png_save_uint_32(buf, width);
+ png_save_uint_32(buf + 4, height);
+ buf[8] = (png_byte)bit_depth;
+ buf[9] = (png_byte)color_type;
+ buf[10] = (png_byte)compression_type;
+ buf[11] = (png_byte)filter_type;
+ buf[12] = (png_byte)interlace_type;
+
+ /* write the chunk */
+ png_write_chunk(png_ptr, (png_bytep)png_IHDR, buf, (png_size_t)13);
+
+ /* initialize zlib with PNG info */
+ png_ptr->zstream.zalloc = png_zalloc;
+ png_ptr->zstream.zfree = png_zfree;
+ png_ptr->zstream.opaque = (voidpf)png_ptr;
+ if (!(png_ptr->do_filter))
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
+ png_ptr->bit_depth < 8)
+ png_ptr->do_filter = PNG_FILTER_NONE;
+ else
+ png_ptr->do_filter = PNG_ALL_FILTERS;
+ }
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
+ {
+ if (png_ptr->do_filter != PNG_FILTER_NONE)
+ png_ptr->zlib_strategy = Z_FILTERED;
+ else
+ png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
+ }
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
+ png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
+ png_ptr->zlib_mem_level = 8;
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
+ png_ptr->zlib_window_bits = 15;
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
+ png_ptr->zlib_method = 8;
+ deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
+ png_ptr->zlib_method, png_ptr->zlib_window_bits,
+ png_ptr->zlib_mem_level, png_ptr->zlib_strategy);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+
+ png_ptr->mode = PNG_HAVE_IHDR;
+}
+
+/* write the palette. We are careful not to trust png_color to be in the
+ * correct order for PNG, so people can redefine it to any convenient
+ * structure.
+ */
+void /* PRIVATE */
+png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_PLTE;
+#endif
+ png_uint_32 i;
+ png_colorp pal_ptr;
+ png_byte buf[3];
+
+ png_debug(1, "in png_write_PLTE\n");
+ if ((
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) &&
+#endif
+ num_pal == 0) || num_pal > 256)
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_error(png_ptr, "Invalid number of colors in palette");
+ }
+ else
+ {
+ png_warning(png_ptr, "Invalid number of colors in palette");
+ return;
+ }
+ }
+
+ if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
+ {
+ png_warning(png_ptr,
+ "Ignoring request to write a PLTE chunk in grayscale PNG");
+ return;
+ }
+
+ png_ptr->num_palette = (png_uint_16)num_pal;
+ png_debug1(3, "num_palette = %d\n", png_ptr->num_palette);
+
+ png_write_chunk_start(png_ptr, (png_bytep)png_PLTE, num_pal * 3);
+#ifndef PNG_NO_POINTER_INDEXING
+ for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
+ {
+ buf[0] = pal_ptr->red;
+ buf[1] = pal_ptr->green;
+ buf[2] = pal_ptr->blue;
+ png_write_chunk_data(png_ptr, buf, (png_size_t)3);
+ }
+#else
+ /* This is a little slower but some buggy compilers need to do this instead */
+ pal_ptr=palette;
+ for (i = 0; i < num_pal; i++)
+ {
+ buf[0] = pal_ptr[i].red;
+ buf[1] = pal_ptr[i].green;
+ buf[2] = pal_ptr[i].blue;
+ png_write_chunk_data(png_ptr, buf, (png_size_t)3);
+ }
+#endif
+ png_write_chunk_end(png_ptr);
+ png_ptr->mode |= PNG_HAVE_PLTE;
+}
+
+/* write an IDAT chunk */
+void /* PRIVATE */
+png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_IDAT;
+#endif
+ png_debug(1, "in png_write_IDAT\n");
+ png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length);
+ png_ptr->mode |= PNG_HAVE_IDAT;
+}
+
+/* write an IEND chunk */
+void /* PRIVATE */
+png_write_IEND(png_structp png_ptr)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_IEND;
+#endif
+ png_debug(1, "in png_write_IEND\n");
+ png_write_chunk(png_ptr, (png_bytep)png_IEND, NULL, (png_size_t)0);
+ png_ptr->mode |= PNG_HAVE_IEND;
+}
+
+#if defined(PNG_WRITE_gAMA_SUPPORTED)
+/* write a gAMA chunk */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+void /* PRIVATE */
+png_write_gAMA(png_structp png_ptr, double file_gamma)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_gAMA;
+#endif
+ png_uint_32 igamma;
+ png_byte buf[4];
+
+ png_debug(1, "in png_write_gAMA\n");
+ /* file_gamma is saved in 1/100,000ths */
+ igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5);
+ png_save_uint_32(buf, igamma);
+ png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
+}
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+void /* PRIVATE */
+png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_gAMA;
+#endif
+ png_byte buf[4];
+
+ png_debug(1, "in png_write_gAMA\n");
+ /* file_gamma is saved in 1/100,000ths */
+ png_save_uint_32(buf, (png_uint_32)file_gamma);
+ png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
+}
+#endif
+#endif
+
+#if defined(PNG_WRITE_sRGB_SUPPORTED)
+/* write a sRGB chunk */
+void /* PRIVATE */
+png_write_sRGB(png_structp png_ptr, int srgb_intent)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_sRGB;
+#endif
+ png_byte buf[1];
+
+ png_debug(1, "in png_write_sRGB\n");
+ if(srgb_intent >= PNG_sRGB_INTENT_LAST)
+ png_warning(png_ptr,
+ "Invalid sRGB rendering intent specified");
+ buf[0]=(png_byte)srgb_intent;
+ png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1);
+}
+#endif
+
+#if defined(PNG_WRITE_iCCP_SUPPORTED)
+/* write an iCCP chunk */
+void /* PRIVATE */
+png_write_iCCP(png_structp png_ptr, png_charp name, int compression_type,
+ png_charp profile, int profile_len)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_iCCP;
+#endif
+ png_size_t name_len;
+ png_charp new_name;
+ compression_state comp;
+
+ png_debug(1, "in png_write_iCCP\n");
+ if (name == NULL || (name_len = png_check_keyword(png_ptr, name,
+ &new_name)) == 0)
+ {
+ png_warning(png_ptr, "Empty keyword in iCCP chunk");
+ return;
+ }
+
+ if (compression_type != PNG_COMPRESSION_TYPE_BASE)
+ png_warning(png_ptr, "Unknown compression type in iCCP chunk");
+
+ if (profile == NULL)
+ profile_len = 0;
+
+ if (profile_len)
+ profile_len = png_text_compress(png_ptr, profile, (png_size_t)profile_len,
+ PNG_COMPRESSION_TYPE_BASE, &comp);
+
+ /* make sure we include the NULL after the name and the compression type */
+ png_write_chunk_start(png_ptr, (png_bytep)png_iCCP,
+ (png_uint_32)name_len+profile_len+2);
+ new_name[name_len+1]=0x00;
+ png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 2);
+
+ if (profile_len)
+ png_write_compressed_data_out(png_ptr, &comp);
+
+ png_write_chunk_end(png_ptr);
+ png_free(png_ptr, new_name);
+}
+#endif
+
+#if defined(PNG_WRITE_sPLT_SUPPORTED)
+/* write a sPLT chunk */
+void /* PRIVATE */
+png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_sPLT;
+#endif
+ png_size_t name_len;
+ png_charp new_name;
+ png_byte entrybuf[10];
+ int entry_size = (spalette->depth == 8 ? 6 : 10);
+ int palette_size = entry_size * spalette->nentries;
+ png_sPLT_entryp ep;
+#ifdef PNG_NO_POINTER_INDEXING
+ int i;
+#endif
+
+ png_debug(1, "in png_write_sPLT\n");
+ if (spalette->name == NULL || (name_len = png_check_keyword(png_ptr,
+ spalette->name, &new_name))==0)
+ {
+ png_warning(png_ptr, "Empty keyword in sPLT chunk");
+ return;
+ }
+
+ /* make sure we include the NULL after the name */
+ png_write_chunk_start(png_ptr, (png_bytep)png_sPLT,
+ (png_uint_32)(name_len + 2 + palette_size));
+ png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 1);
+ png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, 1);
+
+ /* loop through each palette entry, writing appropriately */
+#ifndef PNG_NO_POINTER_INDEXING
+ for (ep = spalette->entries; ep<spalette->entries+spalette->nentries; ep++)
+ {
+ if (spalette->depth == 8)
+ {
+ entrybuf[0] = (png_byte)ep->red;
+ entrybuf[1] = (png_byte)ep->green;
+ entrybuf[2] = (png_byte)ep->blue;
+ entrybuf[3] = (png_byte)ep->alpha;
+ png_save_uint_16(entrybuf + 4, ep->frequency);
+ }
+ else
+ {
+ png_save_uint_16(entrybuf + 0, ep->red);
+ png_save_uint_16(entrybuf + 2, ep->green);
+ png_save_uint_16(entrybuf + 4, ep->blue);
+ png_save_uint_16(entrybuf + 6, ep->alpha);
+ png_save_uint_16(entrybuf + 8, ep->frequency);
+ }
+ png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size);
+ }
+#else
+ ep=spalette->entries;
+ for (i=0; i>spalette->nentries; i++)
+ {
+ if (spalette->depth == 8)
+ {
+ entrybuf[0] = (png_byte)ep[i].red;
+ entrybuf[1] = (png_byte)ep[i].green;
+ entrybuf[2] = (png_byte)ep[i].blue;
+ entrybuf[3] = (png_byte)ep[i].alpha;
+ png_save_uint_16(entrybuf + 4, ep[i].frequency);
+ }
+ else
+ {
+ png_save_uint_16(entrybuf + 0, ep[i].red);
+ png_save_uint_16(entrybuf + 2, ep[i].green);
+ png_save_uint_16(entrybuf + 4, ep[i].blue);
+ png_save_uint_16(entrybuf + 6, ep[i].alpha);
+ png_save_uint_16(entrybuf + 8, ep[i].frequency);
+ }
+ png_write_chunk_data(png_ptr, entrybuf, entry_size);
+ }
+#endif
+
+ png_write_chunk_end(png_ptr);
+ png_free(png_ptr, new_name);
+}
+#endif
+
+#if defined(PNG_WRITE_sBIT_SUPPORTED)
+/* write the sBIT chunk */
+void /* PRIVATE */
+png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_sBIT;
+#endif
+ png_byte buf[4];
+ png_size_t size;
+
+ png_debug(1, "in png_write_sBIT\n");
+ /* make sure we don't depend upon the order of PNG_COLOR_8 */
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ png_byte maxbits;
+
+ maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 :
+ png_ptr->usr_bit_depth);
+ if (sbit->red == 0 || sbit->red > maxbits ||
+ sbit->green == 0 || sbit->green > maxbits ||
+ sbit->blue == 0 || sbit->blue > maxbits)
+ {
+ png_warning(png_ptr, "Invalid sBIT depth specified");
+ return;
+ }
+ buf[0] = sbit->red;
+ buf[1] = sbit->green;
+ buf[2] = sbit->blue;
+ size = 3;
+ }
+ else
+ {
+ if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
+ {
+ png_warning(png_ptr, "Invalid sBIT depth specified");
+ return;
+ }
+ buf[0] = sbit->gray;
+ size = 1;
+ }
+
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
+ {
+ png_warning(png_ptr, "Invalid sBIT depth specified");
+ return;
+ }
+ buf[size++] = sbit->alpha;
+ }
+
+ png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size);
+}
+#endif
+
+#if defined(PNG_WRITE_cHRM_SUPPORTED)
+/* write the cHRM chunk */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+void /* PRIVATE */
+png_write_cHRM(png_structp png_ptr, double white_x, double white_y,
+ double red_x, double red_y, double green_x, double green_y,
+ double blue_x, double blue_y)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_cHRM;
+#endif
+ png_byte buf[32];
+ png_uint_32 itemp;
+
+ png_debug(1, "in png_write_cHRM\n");
+ /* each value is saved in 1/100,000ths */
+ if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 ||
+ white_x + white_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM white point specified");
+#if !defined(PNG_NO_CONSOLE_IO)
+ fprintf(stderr,"white_x=%f, white_y=%f\n",white_x, white_y);
+#endif
+ return;
+ }
+ itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
+ png_save_uint_32(buf, itemp);
+ itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
+ png_save_uint_32(buf + 4, itemp);
+
+ if (red_x < 0 || red_x > 0.8 || red_y < 0 || red_y > 0.8 ||
+ red_x + red_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM red point specified");
+ return;
+ }
+ itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
+ png_save_uint_32(buf + 8, itemp);
+ itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
+ png_save_uint_32(buf + 12, itemp);
+
+ if (green_x < 0 || green_x > 0.8 || green_y < 0 || green_y > 0.8 ||
+ green_x + green_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM green point specified");
+ return;
+ }
+ itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
+ png_save_uint_32(buf + 16, itemp);
+ itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
+ png_save_uint_32(buf + 20, itemp);
+
+ if (blue_x < 0 || blue_x > 0.8 || blue_y < 0 || blue_y > 0.8 ||
+ blue_x + blue_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM blue point specified");
+ return;
+ }
+ itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
+ png_save_uint_32(buf + 24, itemp);
+ itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
+ png_save_uint_32(buf + 28, itemp);
+
+ png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
+}
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+void /* PRIVATE */
+png_write_cHRM_fixed(png_structp png_ptr, png_fixed_point white_x,
+ png_fixed_point white_y, png_fixed_point red_x, png_fixed_point red_y,
+ png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x,
+ png_fixed_point blue_y)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_cHRM;
+#endif
+ png_byte buf[32];
+
+ png_debug(1, "in png_write_cHRM\n");
+ /* each value is saved in 1/100,000ths */
+ if (white_x > 80000L || white_y > 80000L || white_x + white_y > 100000L)
+ {
+ png_warning(png_ptr, "Invalid fixed cHRM white point specified");
+#if !defined(PNG_NO_CONSOLE_IO)
+ fprintf(stderr,"white_x=%ld, white_y=%ld\n",white_x, white_y);
+#endif
+ return;
+ }
+ png_save_uint_32(buf, (png_uint_32)white_x);
+ png_save_uint_32(buf + 4, (png_uint_32)white_y);
+
+ if (red_x > 80000L || red_y > 80000L || red_x + red_y > 100000L)
+ {
+ png_warning(png_ptr, "Invalid cHRM fixed red point specified");
+ return;
+ }
+ png_save_uint_32(buf + 8, (png_uint_32)red_x);
+ png_save_uint_32(buf + 12, (png_uint_32)red_y);
+
+ if (green_x > 80000L || green_y > 80000L || green_x + green_y > 100000L)
+ {
+ png_warning(png_ptr, "Invalid fixed cHRM green point specified");
+ return;
+ }
+ png_save_uint_32(buf + 16, (png_uint_32)green_x);
+ png_save_uint_32(buf + 20, (png_uint_32)green_y);
+
+ if (blue_x > 80000L || blue_y > 80000L || blue_x + blue_y > 100000L)
+ {
+ png_warning(png_ptr, "Invalid fixed cHRM blue point specified");
+ return;
+ }
+ png_save_uint_32(buf + 24, (png_uint_32)blue_x);
+ png_save_uint_32(buf + 28, (png_uint_32)blue_y);
+
+ png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
+}
+#endif
+#endif
+
+#if defined(PNG_WRITE_tRNS_SUPPORTED)
+/* write the tRNS chunk */
+void /* PRIVATE */
+png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
+ int num_trans, int color_type)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_tRNS;
+#endif
+ png_byte buf[6];
+
+ png_debug(1, "in png_write_tRNS\n");
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)
+ {
+ png_warning(png_ptr,"Invalid number of transparent colors specified");
+ return;
+ }
+ /* write the chunk out as it is */
+ png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans, (png_size_t)num_trans);
+ }
+ else if (color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ /* one 16 bit value */
+ if(tran->gray >= (1 << png_ptr->bit_depth))
+ {
+ png_warning(png_ptr,
+ "Ignoring attempt to write tRNS chunk out-of-range for bit_depth");
+ return;
+ }
+ png_save_uint_16(buf, tran->gray);
+ png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2);
+ }
+ else if (color_type == PNG_COLOR_TYPE_RGB)
+ {
+ /* three 16 bit values */
+ png_save_uint_16(buf, tran->red);
+ png_save_uint_16(buf + 2, tran->green);
+ png_save_uint_16(buf + 4, tran->blue);
+ if(png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
+ {
+ png_warning(png_ptr,
+ "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8");
+ return;
+ }
+ png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6);
+ }
+ else
+ {
+ png_warning(png_ptr, "Can't write tRNS with an alpha channel");
+ }
+}
+#endif
+
+#if defined(PNG_WRITE_bKGD_SUPPORTED)
+/* write the background chunk */
+void /* PRIVATE */
+png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_bKGD;
+#endif
+ png_byte buf[6];
+
+ png_debug(1, "in png_write_bKGD\n");
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ (png_ptr->num_palette ||
+ (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) &&
+#endif
+ back->index > png_ptr->num_palette)
+ {
+ png_warning(png_ptr, "Invalid background palette index");
+ return;
+ }
+ buf[0] = back->index;
+ png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1);
+ }
+ else if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ png_save_uint_16(buf, back->red);
+ png_save_uint_16(buf + 2, back->green);
+ png_save_uint_16(buf + 4, back->blue);
+ if(png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
+ {
+ png_warning(png_ptr,
+ "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8");
+ return;
+ }
+ png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6);
+ }
+ else
+ {
+ if(back->gray >= (1 << png_ptr->bit_depth))
+ {
+ png_warning(png_ptr,
+ "Ignoring attempt to write bKGD chunk out-of-range for bit_depth");
+ return;
+ }
+ png_save_uint_16(buf, back->gray);
+ png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2);
+ }
+}
+#endif
+
+#if defined(PNG_WRITE_hIST_SUPPORTED)
+/* write the histogram */
+void /* PRIVATE */
+png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_hIST;
+#endif
+ int i;
+ png_byte buf[3];
+
+ png_debug(1, "in png_write_hIST\n");
+ if (num_hist > (int)png_ptr->num_palette)
+ {
+ png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist,
+ png_ptr->num_palette);
+ png_warning(png_ptr, "Invalid number of histogram entries specified");
+ return;
+ }
+
+ png_write_chunk_start(png_ptr, (png_bytep)png_hIST, (png_uint_32)(num_hist * 2));
+ for (i = 0; i < num_hist; i++)
+ {
+ png_save_uint_16(buf, hist[i]);
+ png_write_chunk_data(png_ptr, buf, (png_size_t)2);
+ }
+ png_write_chunk_end(png_ptr);
+}
+#endif
+
+#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
+ defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
+/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
+ * and if invalid, correct the keyword rather than discarding the entire
+ * chunk. The PNG 1.0 specification requires keywords 1-79 characters in
+ * length, forbids leading or trailing whitespace, multiple internal spaces,
+ * and the non-break space (0x80) from ISO 8859-1. Returns keyword length.
+ *
+ * The new_key is allocated to hold the corrected keyword and must be freed
+ * by the calling routine. This avoids problems with trying to write to
+ * static keywords without having to have duplicate copies of the strings.
+ */
+png_size_t /* PRIVATE */
+png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key)
+{
+ png_size_t key_len;
+ png_charp kp, dp;
+ int kflag;
+ int kwarn=0;
+
+ png_debug(1, "in png_check_keyword\n");
+ *new_key = NULL;
+
+ if (key == NULL || (key_len = png_strlen(key)) == 0)
+ {
+ png_warning(png_ptr, "zero length keyword");
+ return ((png_size_t)0);
+ }
+
+ png_debug1(2, "Keyword to be checked is '%s'\n", key);
+
+ *new_key = (png_charp)png_malloc(png_ptr, (png_uint_32)(key_len + 2));
+
+ /* Replace non-printing characters with a blank and print a warning */
+ for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++)
+ {
+ if (*kp < 0x20 || (*kp > 0x7E && (png_byte)*kp < 0xA1))
+ {
+#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
+ char msg[40];
+
+ sprintf(msg, "invalid keyword character 0x%02X", *kp);
+ png_warning(png_ptr, msg);
+#else
+ png_warning(png_ptr, "invalid character in keyword");
+#endif
+ *dp = ' ';
+ }
+ else
+ {
+ *dp = *kp;
+ }
+ }
+ *dp = '\0';
+
+ /* Remove any trailing white space. */
+ kp = *new_key + key_len - 1;
+ if (*kp == ' ')
+ {
+ png_warning(png_ptr, "trailing spaces removed from keyword");
+
+ while (*kp == ' ')
+ {
+ *(kp--) = '\0';
+ key_len--;
+ }
+ }
+
+ /* Remove any leading white space. */
+ kp = *new_key;
+ if (*kp == ' ')
+ {
+ png_warning(png_ptr, "leading spaces removed from keyword");
+
+ while (*kp == ' ')
+ {
+ kp++;
+ key_len--;
+ }
+ }
+
+ png_debug1(2, "Checking for multiple internal spaces in '%s'\n", kp);
+
+ /* Remove multiple internal spaces. */
+ for (kflag = 0, dp = *new_key; *kp != '\0'; kp++)
+ {
+ if (*kp == ' ' && kflag == 0)
+ {
+ *(dp++) = *kp;
+ kflag = 1;
+ }
+ else if (*kp == ' ')
+ {
+ key_len--;
+ kwarn=1;
+ }
+ else
+ {
+ *(dp++) = *kp;
+ kflag = 0;
+ }
+ }
+ *dp = '\0';
+ if(kwarn)
+ png_warning(png_ptr, "extra interior spaces removed from keyword");
+
+ if (key_len == 0)
+ {
+ png_free(png_ptr, *new_key);
+ *new_key=NULL;
+ png_warning(png_ptr, "Zero length keyword");
+ }
+
+ if (key_len > 79)
+ {
+ png_warning(png_ptr, "keyword length must be 1 - 79 characters");
+ new_key[79] = '\0';
+ key_len = 79;
+ }
+
+ return (key_len);
+}
+#endif
+
+#if defined(PNG_WRITE_tEXt_SUPPORTED)
+/* write a tEXt chunk */
+void /* PRIVATE */
+png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
+ png_size_t text_len)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_tEXt;
+#endif
+ png_size_t key_len;
+ png_charp new_key;
+
+ png_debug(1, "in png_write_tEXt\n");
+ if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
+ {
+ png_warning(png_ptr, "Empty keyword in tEXt chunk");
+ return;
+ }
+
+ if (text == NULL || *text == '\0')
+ text_len = 0;
+ else
+ text_len = png_strlen(text);
+
+ /* make sure we include the 0 after the key */
+ png_write_chunk_start(png_ptr, (png_bytep)png_tEXt, (png_uint_32)key_len+text_len+1);
+ /*
+ * We leave it to the application to meet PNG-1.0 requirements on the
+ * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of
+ * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them.
+ * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
+ */
+ png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
+ if (text_len)
+ png_write_chunk_data(png_ptr, (png_bytep)text, text_len);
+
+ png_write_chunk_end(png_ptr);
+ png_free(png_ptr, new_key);
+}
+#endif
+
+#if defined(PNG_WRITE_zTXt_SUPPORTED)
+/* write a compressed text chunk */
+void /* PRIVATE */
+png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
+ png_size_t text_len, int compression)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_zTXt;
+#endif
+ png_size_t key_len;
+ char buf[1];
+ png_charp new_key;
+ compression_state comp;
+
+ png_debug(1, "in png_write_zTXt\n");
+
+ if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
+ {
+ png_warning(png_ptr, "Empty keyword in zTXt chunk");
+ return;
+ }
+
+ if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE)
+ {
+ png_write_tEXt(png_ptr, new_key, text, (png_size_t)0);
+ png_free(png_ptr, new_key);
+ return;
+ }
+
+ text_len = png_strlen(text);
+
+ png_free(png_ptr, new_key);
+
+ /* compute the compressed data; do it now for the length */
+ text_len = png_text_compress(png_ptr, text, text_len, compression,
+ &comp);
+
+ /* write start of chunk */
+ png_write_chunk_start(png_ptr, (png_bytep)png_zTXt, (png_uint_32)
+ (key_len+text_len+2));
+ /* write key */
+ png_write_chunk_data(png_ptr, (png_bytep)key, key_len + 1);
+ buf[0] = (png_byte)compression;
+ /* write compression */
+ png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1);
+ /* write the compressed data */
+ png_write_compressed_data_out(png_ptr, &comp);
+
+ /* close the chunk */
+ png_write_chunk_end(png_ptr);
+}
+#endif
+
+#if defined(PNG_WRITE_iTXt_SUPPORTED)
+/* write an iTXt chunk */
+void /* PRIVATE */
+png_write_iTXt(png_structp png_ptr, int compression, png_charp key,
+ png_charp lang, png_charp lang_key, png_charp text)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_iTXt;
+#endif
+ png_size_t lang_len, key_len, lang_key_len, text_len;
+ png_charp new_lang, new_key;
+ png_byte cbuf[2];
+ compression_state comp;
+
+ png_debug(1, "in png_write_iTXt\n");
+
+ if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
+ {
+ png_warning(png_ptr, "Empty keyword in iTXt chunk");
+ return;
+ }
+ if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang,
+ &new_lang))==0)
+ {
+ png_warning(png_ptr, "Empty language field in iTXt chunk");
+ return;
+ }
+ lang_key_len = png_strlen(lang_key);
+ text_len = png_strlen(text);
+
+ if (text == NULL || *text == '\0')
+ text_len = 0;
+
+ /* compute the compressed data; do it now for the length */
+ text_len = png_text_compress(png_ptr, text, text_len, compression-2,
+ &comp);
+
+ /* make sure we include the compression flag, the compression byte,
+ * and the NULs after the key, lang, and lang_key parts */
+
+ png_write_chunk_start(png_ptr, (png_bytep)png_iTXt,
+ (png_uint_32)(
+ 5 /* comp byte, comp flag, terminators for key, lang and lang_key */
+ + key_len
+ + lang_len
+ + lang_key_len
+ + text_len));
+
+ /*
+ * We leave it to the application to meet PNG-1.0 requirements on the
+ * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of
+ * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them.
+ * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
+ */
+ png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
+
+ /* set the compression flag */
+ if (compression == PNG_ITXT_COMPRESSION_NONE || \
+ compression == PNG_TEXT_COMPRESSION_NONE)
+ cbuf[0] = 0;
+ else /* compression == PNG_ITXT_COMPRESSION_zTXt */
+ cbuf[0] = 1;
+ /* set the compression method */
+ cbuf[1] = 0;
+ png_write_chunk_data(png_ptr, cbuf, 2);
+
+ png_write_chunk_data(png_ptr, (png_bytep)new_lang, lang_len + 1);
+ png_write_chunk_data(png_ptr, (png_bytep)lang_key, lang_key_len+1);
+ png_write_chunk_data(png_ptr, '\0', 1);
+
+ png_write_compressed_data_out(png_ptr, &comp);
+
+ png_write_chunk_end(png_ptr);
+ png_free(png_ptr, new_key);
+ png_free(png_ptr, new_lang);
+}
+#endif
+
+#if defined(PNG_WRITE_oFFs_SUPPORTED)
+/* write the oFFs chunk */
+void /* PRIVATE */
+png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset,
+ int unit_type)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_oFFs;
+#endif
+ png_byte buf[9];
+
+ png_debug(1, "in png_write_oFFs\n");
+ if (unit_type >= PNG_OFFSET_LAST)
+ png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");
+
+ png_save_int_32(buf, x_offset);
+ png_save_int_32(buf + 4, y_offset);
+ buf[8] = (png_byte)unit_type;
+
+ png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9);
+}
+#endif
+
+#if defined(PNG_WRITE_pCAL_SUPPORTED)
+/* write the pCAL chunk (described in the PNG extensions document) */
+void /* PRIVATE */
+png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
+ png_int_32 X1, int type, int nparams, png_charp units, png_charpp params)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_pCAL;
+#endif
+ png_size_t purpose_len, units_len, total_len;
+ png_uint_32p params_len;
+ png_byte buf[10];
+ png_charp new_purpose;
+ int i;
+
+ png_debug1(1, "in png_write_pCAL (%d parameters)\n", nparams);
+ if (type >= PNG_EQUATION_LAST)
+ png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
+
+ purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1;
+ png_debug1(3, "pCAL purpose length = %d\n", (int)purpose_len);
+ units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
+ png_debug1(3, "pCAL units length = %d\n", (int)units_len);
+ total_len = purpose_len + units_len + 10;
+
+ params_len = (png_uint_32p)png_malloc(png_ptr, (png_uint_32)(nparams
+ *sizeof(png_uint_32)));
+
+ /* Find the length of each parameter, making sure we don't count the
+ null terminator for the last parameter. */
+ for (i = 0; i < nparams; i++)
+ {
+ params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1);
+ png_debug2(3, "pCAL parameter %d length = %lu\n", i, params_len[i]);
+ total_len += (png_size_t)params_len[i];
+ }
+
+ png_debug1(3, "pCAL total length = %d\n", (int)total_len);
+ png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len);
+ png_write_chunk_data(png_ptr, (png_bytep)new_purpose, purpose_len);
+ png_save_int_32(buf, X0);
+ png_save_int_32(buf + 4, X1);
+ buf[8] = (png_byte)type;
+ buf[9] = (png_byte)nparams;
+ png_write_chunk_data(png_ptr, buf, (png_size_t)10);
+ png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len);
+
+ png_free(png_ptr, new_purpose);
+
+ for (i = 0; i < nparams; i++)
+ {
+ png_write_chunk_data(png_ptr, (png_bytep)params[i],
+ (png_size_t)params_len[i]);
+ }
+
+ png_free(png_ptr, params_len);
+ png_write_chunk_end(png_ptr);
+}
+#endif
+
+#if defined(PNG_WRITE_sCAL_SUPPORTED)
+/* write the sCAL chunk */
+#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
+void /* PRIVATE */
+png_write_sCAL(png_structp png_ptr, int unit, double width,double height)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_sCAL;
+#endif
+ png_size_t total_len;
+ char wbuf[32], hbuf[32];
+
+ png_debug(1, "in png_write_sCAL\n");
+
+#if defined(_WIN32_WCE)
+/* sprintf() function is not supported on WindowsCE */
+ {
+ wchar_t wc_buf[32];
+ swprintf(wc_buf, TEXT("%12.12e"), width);
+ WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, wbuf, 32, NULL, NULL);
+ swprintf(wc_buf, TEXT("%12.12e"), height);
+ WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, hbuf, 32, NULL, NULL);
+ }
+#else
+ sprintf(wbuf, "%12.12e", width);
+ sprintf(hbuf, "%12.12e", height);
+#endif
+ total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
+
+ png_debug1(3, "sCAL total length = %d\n", (int)total_len);
+ png_write_chunk_start(png_ptr, (png_bytep)png_sCAL, (png_uint_32)total_len);
+ png_write_chunk_data(png_ptr, (png_bytep)&unit, 1);
+ png_write_chunk_data(png_ptr, (png_bytep)wbuf, png_strlen(wbuf)+1);
+ png_write_chunk_data(png_ptr, (png_bytep)hbuf, png_strlen(hbuf));
+
+ png_write_chunk_end(png_ptr);
+}
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+void /* PRIVATE */
+png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width,
+ png_charp height)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_sCAL;
+#endif
+ png_size_t total_len;
+ char wbuf[32], hbuf[32];
+
+ png_debug(1, "in png_write_sCAL_s\n");
+
+ png_strcpy(wbuf,(const char *)width);
+ png_strcpy(hbuf,(const char *)height);
+ total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
+
+ png_debug1(3, "sCAL total length = %d\n", total_len);
+ png_write_chunk_start(png_ptr, (png_bytep)png_sCAL, (png_uint_32)total_len);
+ png_write_chunk_data(png_ptr, (png_bytep)&unit, 1);
+ png_write_chunk_data(png_ptr, (png_bytep)wbuf, png_strlen(wbuf)+1);
+ png_write_chunk_data(png_ptr, (png_bytep)hbuf, png_strlen(hbuf));
+
+ png_write_chunk_end(png_ptr);
+}
+#endif
+#endif
+#endif
+
+#if defined(PNG_WRITE_pHYs_SUPPORTED)
+/* write the pHYs chunk */
+void /* PRIVATE */
+png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
+ png_uint_32 y_pixels_per_unit,
+ int unit_type)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_pHYs;
+#endif
+ png_byte buf[9];
+
+ png_debug(1, "in png_write_pHYs\n");
+ if (unit_type >= PNG_RESOLUTION_LAST)
+ png_warning(png_ptr, "Unrecognized unit type for pHYs chunk");
+
+ png_save_uint_32(buf, x_pixels_per_unit);
+ png_save_uint_32(buf + 4, y_pixels_per_unit);
+ buf[8] = (png_byte)unit_type;
+
+ png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9);
+}
+#endif
+
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+/* Write the tIME chunk. Use either png_convert_from_struct_tm()
+ * or png_convert_from_time_t(), or fill in the structure yourself.
+ */
+void /* PRIVATE */
+png_write_tIME(png_structp png_ptr, png_timep mod_time)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_tIME;
+#endif
+ png_byte buf[7];
+
+ png_debug(1, "in png_write_tIME\n");
+ if (mod_time->month > 12 || mod_time->month < 1 ||
+ mod_time->day > 31 || mod_time->day < 1 ||
+ mod_time->hour > 23 || mod_time->second > 60)
+ {
+ png_warning(png_ptr, "Invalid time specified for tIME chunk");
+ return;
+ }
+
+ png_save_uint_16(buf, mod_time->year);
+ buf[2] = mod_time->month;
+ buf[3] = mod_time->day;
+ buf[4] = mod_time->hour;
+ buf[5] = mod_time->minute;
+ buf[6] = mod_time->second;
+
+ png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7);
+}
+#endif
+
+/* initializes the row writing capability of libpng */
+void /* PRIVATE */
+png_write_start_row(png_structp png_ptr)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+
+ /* start of interlace block */
+ int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+
+ /* offset to next interlace block */
+ int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+
+ /* start of interlace block in the y direction */
+ int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
+
+ /* offset to next interlace block in the y direction */
+ int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
+#endif
+
+ png_size_t buf_size;
+
+ png_debug(1, "in png_write_start_row\n");
+ buf_size = (png_size_t)(((png_ptr->width * png_ptr->usr_channels *
+ png_ptr->usr_bit_depth + 7) >> 3) + 1);
+
+ /* set up row buffer */
+ png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
+ png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
+
+ /* set up filtering buffer, if using this filter */
+ if (png_ptr->do_filter & PNG_FILTER_SUB)
+ {
+ png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
+ }
+
+ /* We only need to keep the previous row if we are using one of these. */
+ if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
+ {
+ /* set up previous row buffer */
+ png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
+ png_memset(png_ptr->prev_row, 0, buf_size);
+
+ if (png_ptr->do_filter & PNG_FILTER_UP)
+ {
+ png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
+ }
+
+ if (png_ptr->do_filter & PNG_FILTER_AVG)
+ {
+ png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
+ }
+
+ if (png_ptr->do_filter & PNG_FILTER_PAETH)
+ {
+ png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
+ }
+ }
+
+#ifdef PNG_WRITE_INTERLACING_SUPPORTED
+ /* if interlaced, we need to set up width and height of pass */
+ if (png_ptr->interlaced)
+ {
+ if (!(png_ptr->transformations & PNG_INTERLACE))
+ {
+ png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
+ png_pass_ystart[0]) / png_pass_yinc[0];
+ png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
+ png_pass_start[0]) / png_pass_inc[0];
+ }
+ else
+ {
+ png_ptr->num_rows = png_ptr->height;
+ png_ptr->usr_width = png_ptr->width;
+ }
+ }
+ else
+#endif
+ {
+ png_ptr->num_rows = png_ptr->height;
+ png_ptr->usr_width = png_ptr->width;
+ }
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+}
+
+/* Internal use only. Called when finished processing a row of data. */
+void /* PRIVATE */
+png_write_finish_row(png_structp png_ptr)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+
+ /* start of interlace block */
+ int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+
+ /* offset to next interlace block */
+ int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+
+ /* start of interlace block in the y direction */
+ int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
+
+ /* offset to next interlace block in the y direction */
+ int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
+#endif
+
+ int ret;
+
+ png_debug(1, "in png_write_finish_row\n");
+ /* next row */
+ png_ptr->row_number++;
+
+ /* see if we are done */
+ if (png_ptr->row_number < png_ptr->num_rows)
+ return;
+
+#ifdef PNG_WRITE_INTERLACING_SUPPORTED
+ /* if interlaced, go to next pass */
+ if (png_ptr->interlaced)
+ {
+ png_ptr->row_number = 0;
+ if (png_ptr->transformations & PNG_INTERLACE)
+ {
+ png_ptr->pass++;
+ }
+ else
+ {
+ /* loop until we find a non-zero width or height pass */
+ do
+ {
+ png_ptr->pass++;
+ if (png_ptr->pass >= 7)
+ break;
+ png_ptr->usr_width = (png_ptr->width +
+ png_pass_inc[png_ptr->pass] - 1 -
+ png_pass_start[png_ptr->pass]) /
+ png_pass_inc[png_ptr->pass];
+ png_ptr->num_rows = (png_ptr->height +
+ png_pass_yinc[png_ptr->pass] - 1 -
+ png_pass_ystart[png_ptr->pass]) /
+ png_pass_yinc[png_ptr->pass];
+ if (png_ptr->transformations & PNG_INTERLACE)
+ break;
+ } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
+
+ }
+
+ /* reset the row above the image for the next pass */
+ if (png_ptr->pass < 7)
+ {
+ if (png_ptr->prev_row != NULL)
+ png_memset(png_ptr->prev_row, 0,
+ (png_size_t) (((png_uint_32)png_ptr->usr_channels *
+ (png_uint_32)png_ptr->usr_bit_depth *
+ png_ptr->width + 7) >> 3) + 1);
+ return;
+ }
+ }
+#endif
+
+ /* if we get here, we've just written the last row, so we need
+ to flush the compressor */
+ do
+ {
+ /* tell the compressor we are done */
+ ret = deflate(&png_ptr->zstream, Z_FINISH);
+ /* check for an error */
+ if (ret == Z_OK)
+ {
+ /* check to see if we need more room */
+ if (!(png_ptr->zstream.avail_out))
+ {
+ png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ }
+ }
+ else if (ret != Z_STREAM_END)
+ {
+ if (png_ptr->zstream.msg != NULL)
+ png_error(png_ptr, png_ptr->zstream.msg);
+ else
+ png_error(png_ptr, "zlib error");
+ }
+ } while (ret != Z_STREAM_END);
+
+ /* write any extra space */
+ if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
+ {
+ png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
+ png_ptr->zstream.avail_out);
+ }
+
+ deflateReset(&png_ptr->zstream);
+}
+
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+/* Pick out the correct pixels for the interlace pass.
+ * The basic idea here is to go through the row with a source
+ * pointer and a destination pointer (sp and dp), and copy the
+ * correct pixels for the pass. As the row gets compacted,
+ * sp will always be >= dp, so we should never overwrite anything.
+ * See the default: case for the easiest code to understand.
+ */
+void /* PRIVATE */
+png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+
+ /* start of interlace block */
+ int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+
+ /* offset to next interlace block */
+ int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+#endif
+
+ png_debug(1, "in png_do_write_interlace\n");
+ /* we don't have to do anything on the last pass (6) */
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL && pass < 6)
+#else
+ if (pass < 6)
+#endif
+ {
+ /* each pixel depth is handled separately */
+ switch (row_info->pixel_depth)
+ {
+ case 1:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int shift;
+ int d;
+ int value;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ dp = row;
+ d = 0;
+ shift = 7;
+ for (i = png_pass_start[pass]; i < row_width;
+ i += png_pass_inc[pass])
+ {
+ sp = row + (png_size_t)(i >> 3);
+ value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
+ d |= (value << shift);
+
+ if (shift == 0)
+ {
+ shift = 7;
+ *dp++ = (png_byte)d;
+ d = 0;
+ }
+ else
+ shift--;
+
+ }
+ if (shift != 7)
+ *dp = (png_byte)d;
+ break;
+ }
+ case 2:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int shift;
+ int d;
+ int value;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ dp = row;
+ shift = 6;
+ d = 0;
+ for (i = png_pass_start[pass]; i < row_width;
+ i += png_pass_inc[pass])
+ {
+ sp = row + (png_size_t)(i >> 2);
+ value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
+ d |= (value << shift);
+
+ if (shift == 0)
+ {
+ shift = 6;
+ *dp++ = (png_byte)d;
+ d = 0;
+ }
+ else
+ shift -= 2;
+ }
+ if (shift != 6)
+ *dp = (png_byte)d;
+ break;
+ }
+ case 4:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int shift;
+ int d;
+ int value;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ dp = row;
+ shift = 4;
+ d = 0;
+ for (i = png_pass_start[pass]; i < row_width;
+ i += png_pass_inc[pass])
+ {
+ sp = row + (png_size_t)(i >> 1);
+ value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;
+ d |= (value << shift);
+
+ if (shift == 0)
+ {
+ shift = 4;
+ *dp++ = (png_byte)d;
+ d = 0;
+ }
+ else
+ shift -= 4;
+ }
+ if (shift != 4)
+ *dp = (png_byte)d;
+ break;
+ }
+ default:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+ png_size_t pixel_bytes;
+
+ /* start at the beginning */
+ dp = row;
+ /* find out how many bytes each pixel takes up */
+ pixel_bytes = (row_info->pixel_depth >> 3);
+ /* loop through the row, only looking at the pixels that
+ matter */
+ for (i = png_pass_start[pass]; i < row_width;
+ i += png_pass_inc[pass])
+ {
+ /* find out where the original pixel is */
+ sp = row + (png_size_t)i * pixel_bytes;
+ /* move the pixel */
+ if (dp != sp)
+ png_memcpy(dp, sp, pixel_bytes);
+ /* next pixel */
+ dp += pixel_bytes;
+ }
+ break;
+ }
+ }
+ /* set new row width */
+ row_info->width = (row_info->width +
+ png_pass_inc[pass] - 1 -
+ png_pass_start[pass]) /
+ png_pass_inc[pass];
+ row_info->rowbytes = ((row_info->width *
+ row_info->pixel_depth + 7) >> 3);
+ }
+}
+#endif
+
+/* This filters the row, chooses which filter to use, if it has not already
+ * been specified by the application, and then writes the row out with the
+ * chosen filter.
+ */
+#define PNG_MAXSUM (~((png_uint_32)0) >> 1)
+#define PNG_HISHIFT 10
+#define PNG_LOMASK ((png_uint_32)0xffffL)
+#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
+void /* PRIVATE */
+png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
+{
+ png_bytep prev_row, best_row, row_buf;
+ png_uint_32 mins, bpp;
+ png_byte filter_to_do = png_ptr->do_filter;
+ png_uint_32 row_bytes = row_info->rowbytes;
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ int num_p_filters = (int)png_ptr->num_prev_filters;
+#endif
+
+ png_debug(1, "in png_write_find_filter\n");
+ /* find out how many bytes offset each pixel is */
+ bpp = (row_info->pixel_depth + 7) / 8;
+
+ prev_row = png_ptr->prev_row;
+ best_row = row_buf = png_ptr->row_buf;
+ mins = PNG_MAXSUM;
+
+ /* The prediction method we use is to find which method provides the
+ * smallest value when summing the absolute values of the distances
+ * from zero, using anything >= 128 as negative numbers. This is known
+ * as the "minimum sum of absolute differences" heuristic. Other
+ * heuristics are the "weighted minimum sum of absolute differences"
+ * (experimental and can in theory improve compression), and the "zlib
+ * predictive" method (not implemented yet), which does test compressions
+ * of lines using different filter methods, and then chooses the
+ * (series of) filter(s) that give minimum compressed data size (VERY
+ * computationally expensive).
+ *
+ * GRR 980525: consider also
+ * (1) minimum sum of absolute differences from running average (i.e.,
+ * keep running sum of non-absolute differences & count of bytes)
+ * [track dispersion, too? restart average if dispersion too large?]
+ * (1b) minimum sum of absolute differences from sliding average, probably
+ * with window size <= deflate window (usually 32K)
+ * (2) minimum sum of squared differences from zero or running average
+ * (i.e., ~ root-mean-square approach)
+ */
+
+
+ /* We don't need to test the 'no filter' case if this is the only filter
+ * that has been chosen, as it doesn't actually do anything to the data.
+ */
+ if ((filter_to_do & PNG_FILTER_NONE) &&
+ filter_to_do != PNG_FILTER_NONE)
+ {
+ png_bytep rp;
+ png_uint_32 sum = 0;
+ png_uint_32 i;
+ int v;
+
+ for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
+ {
+ v = *rp;
+ sum += (v < 128) ? v : 256 - v;
+ }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ png_uint_32 sumhi, sumlo;
+ int j;
+ sumlo = sum & PNG_LOMASK;
+ sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */
+
+ /* Reduce the sum if we match any of the previous rows */
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
+ {
+ sumlo = (sumlo * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ /* Factor in the cost of this filter (this is here for completeness,
+ * but it makes no sense to have a "cost" for the NONE filter, as
+ * it has the minimum possible computational cost - none).
+ */
+ sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
+ PNG_COST_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
+ PNG_COST_SHIFT;
+
+ if (sumhi > PNG_HIMASK)
+ sum = PNG_MAXSUM;
+ else
+ sum = (sumhi << PNG_HISHIFT) + sumlo;
+ }
+#endif
+ mins = sum;
+ }
+
+ /* sub filter */
+ if (filter_to_do == PNG_FILTER_SUB)
+ /* it's the only filter so no testing is needed */
+ {
+ png_bytep rp, lp, dp;
+ png_uint_32 i;
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
+ i++, rp++, dp++)
+ {
+ *dp = *rp;
+ }
+ for (lp = row_buf + 1; i < row_bytes;
+ i++, rp++, lp++, dp++)
+ {
+ *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
+ }
+ best_row = png_ptr->sub_row;
+ }
+
+ else if (filter_to_do & PNG_FILTER_SUB)
+ {
+ png_bytep rp, dp, lp;
+ png_uint_32 sum = 0, lmins = mins;
+ png_uint_32 i;
+ int v;
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ /* We temporarily increase the "minimum sum" by the factor we
+ * would reduce the sum of this filter, so that we can do the
+ * early exit comparison without scaling the sum each time.
+ */
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 lmhi, lmlo;
+ lmlo = lmins & PNG_LOMASK;
+ lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
+ {
+ lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
+ PNG_COST_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
+ PNG_COST_SHIFT;
+
+ if (lmhi > PNG_HIMASK)
+ lmins = PNG_MAXSUM;
+ else
+ lmins = (lmhi << PNG_HISHIFT) + lmlo;
+ }
+#endif
+
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
+ i++, rp++, dp++)
+ {
+ v = *dp = *rp;
+
+ sum += (v < 128) ? v : 256 - v;
+ }
+ for (lp = row_buf + 1; i < row_info->rowbytes;
+ i++, rp++, lp++, dp++)
+ {
+ v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
+ }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 sumhi, sumlo;
+ sumlo = sum & PNG_LOMASK;
+ sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
+ {
+ sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
+ PNG_COST_SHIFT;
+ sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
+ PNG_COST_SHIFT;
+
+ if (sumhi > PNG_HIMASK)
+ sum = PNG_MAXSUM;
+ else
+ sum = (sumhi << PNG_HISHIFT) + sumlo;
+ }
+#endif
+
+ if (sum < mins)
+ {
+ mins = sum;
+ best_row = png_ptr->sub_row;
+ }
+ }
+
+ /* up filter */
+ if (filter_to_do == PNG_FILTER_UP)
+ {
+ png_bytep rp, dp, pp;
+ png_uint_32 i;
+
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
+ pp = prev_row + 1; i < row_bytes;
+ i++, rp++, pp++, dp++)
+ {
+ *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
+ }
+ best_row = png_ptr->up_row;
+ }
+
+ else if (filter_to_do & PNG_FILTER_UP)
+ {
+ png_bytep rp, dp, pp;
+ png_uint_32 sum = 0, lmins = mins;
+ png_uint_32 i;
+ int v;
+
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 lmhi, lmlo;
+ lmlo = lmins & PNG_LOMASK;
+ lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
+ {
+ lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
+ PNG_COST_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
+ PNG_COST_SHIFT;
+
+ if (lmhi > PNG_HIMASK)
+ lmins = PNG_MAXSUM;
+ else
+ lmins = (lmhi << PNG_HISHIFT) + lmlo;
+ }
+#endif
+
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
+ pp = prev_row + 1; i < row_bytes; i++)
+ {
+ v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
+ }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 sumhi, sumlo;
+ sumlo = sum & PNG_LOMASK;
+ sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
+ {
+ sumlo = (sumlo * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
+ PNG_COST_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
+ PNG_COST_SHIFT;
+
+ if (sumhi > PNG_HIMASK)
+ sum = PNG_MAXSUM;
+ else
+ sum = (sumhi << PNG_HISHIFT) + sumlo;
+ }
+#endif
+
+ if (sum < mins)
+ {
+ mins = sum;
+ best_row = png_ptr->up_row;
+ }
+ }
+
+ /* avg filter */
+ if (filter_to_do == PNG_FILTER_AVG)
+ {
+ png_bytep rp, dp, pp, lp;
+ png_uint_32 i;
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
+ pp = prev_row + 1; i < bpp; i++)
+ {
+ *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
+ }
+ for (lp = row_buf + 1; i < row_bytes; i++)
+ {
+ *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
+ & 0xff);
+ }
+ best_row = png_ptr->avg_row;
+ }
+
+ else if (filter_to_do & PNG_FILTER_AVG)
+ {
+ png_bytep rp, dp, pp, lp;
+ png_uint_32 sum = 0, lmins = mins;
+ png_uint_32 i;
+ int v;
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 lmhi, lmlo;
+ lmlo = lmins & PNG_LOMASK;
+ lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)
+ {
+ lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
+ PNG_COST_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
+ PNG_COST_SHIFT;
+
+ if (lmhi > PNG_HIMASK)
+ lmins = PNG_MAXSUM;
+ else
+ lmins = (lmhi << PNG_HISHIFT) + lmlo;
+ }
+#endif
+
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
+ pp = prev_row + 1; i < bpp; i++)
+ {
+ v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+ }
+ for (lp = row_buf + 1; i < row_bytes; i++)
+ {
+ v = *dp++ =
+ (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
+ }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 sumhi, sumlo;
+ sumlo = sum & PNG_LOMASK;
+ sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
+ {
+ sumlo = (sumlo * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
+ PNG_COST_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
+ PNG_COST_SHIFT;
+
+ if (sumhi > PNG_HIMASK)
+ sum = PNG_MAXSUM;
+ else
+ sum = (sumhi << PNG_HISHIFT) + sumlo;
+ }
+#endif
+
+ if (sum < mins)
+ {
+ mins = sum;
+ best_row = png_ptr->avg_row;
+ }
+ }
+
+ /* Paeth filter */
+ if (filter_to_do == PNG_FILTER_PAETH)
+ {
+ png_bytep rp, dp, pp, cp, lp;
+ png_uint_32 i;
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
+ pp = prev_row + 1; i < bpp; i++)
+ {
+ *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
+ }
+
+ for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ b = *pp++;
+ c = *cp++;
+ a = *lp++;
+
+ p = b - c;
+ pc = a - c;
+
+#ifdef PNG_USE_ABS
+ pa = abs(p);
+ pb = abs(pc);
+ pc = abs(p + pc);
+#else
+ pa = p < 0 ? -p : p;
+ pb = pc < 0 ? -pc : pc;
+ pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+#endif
+
+ p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
+
+ *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
+ }
+ best_row = png_ptr->paeth_row;
+ }
+
+ else if (filter_to_do & PNG_FILTER_PAETH)
+ {
+ png_bytep rp, dp, pp, cp, lp;
+ png_uint_32 sum = 0, lmins = mins;
+ png_uint_32 i;
+ int v;
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 lmhi, lmlo;
+ lmlo = lmins & PNG_LOMASK;
+ lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
+ {
+ lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
+ PNG_COST_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
+ PNG_COST_SHIFT;
+
+ if (lmhi > PNG_HIMASK)
+ lmins = PNG_MAXSUM;
+ else
+ lmins = (lmhi << PNG_HISHIFT) + lmlo;
+ }
+#endif
+
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
+ pp = prev_row + 1; i < bpp; i++)
+ {
+ v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+ }
+
+ for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ b = *pp++;
+ c = *cp++;
+ a = *lp++;
+
+#ifndef PNG_SLOW_PAETH
+ p = b - c;
+ pc = a - c;
+#ifdef PNG_USE_ABS
+ pa = abs(p);
+ pb = abs(pc);
+ pc = abs(p + pc);
+#else
+ pa = p < 0 ? -p : p;
+ pb = pc < 0 ? -pc : pc;
+ pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+#endif
+ p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
+#else /* PNG_SLOW_PAETH */
+ p = a + b - c;
+ pa = abs(p - a);
+ pb = abs(p - b);
+ pc = abs(p - c);
+ if (pa <= pb && pa <= pc)
+ p = a;
+ else if (pb <= pc)
+ p = b;
+ else
+ p = c;
+#endif /* PNG_SLOW_PAETH */
+
+ v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
+ }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 sumhi, sumlo;
+ sumlo = sum & PNG_LOMASK;
+ sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
+ {
+ sumlo = (sumlo * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
+ PNG_COST_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
+ PNG_COST_SHIFT;
+
+ if (sumhi > PNG_HIMASK)
+ sum = PNG_MAXSUM;
+ else
+ sum = (sumhi << PNG_HISHIFT) + sumlo;
+ }
+#endif
+
+ if (sum < mins)
+ {
+ best_row = png_ptr->paeth_row;
+ }
+ }
+
+ /* Do the actual writing of the filtered row data from the chosen filter. */
+
+ png_write_filtered_row(png_ptr, best_row);
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ /* Save the type of filter we picked this time for future calculations */
+ if (png_ptr->num_prev_filters > 0)
+ {
+ int j;
+ for (j = 1; j < num_p_filters; j++)
+ {
+ png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
+ }
+ png_ptr->prev_filters[j] = best_row[0];
+ }
+#endif
+}
+
+
+/* Do the actual writing of a previously filtered row. */
+void /* PRIVATE */
+png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
+{
+ png_debug(1, "in png_write_filtered_row\n");
+ png_debug1(2, "filter = %d\n", filtered_row[0]);
+ /* set up the zlib input buffer */
+
+ png_ptr->zstream.next_in = filtered_row;
+ png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
+ /* repeat until we have compressed all the data */
+ do
+ {
+ int ret; /* return of zlib */
+
+ /* compress the data */
+ ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
+ /* check for compression errors */
+ if (ret != Z_OK)
+ {
+ if (png_ptr->zstream.msg != NULL)
+ png_error(png_ptr, png_ptr->zstream.msg);
+ else
+ png_error(png_ptr, "zlib error");
+ }
+
+ /* see if it is time to write another IDAT */
+ if (!(png_ptr->zstream.avail_out))
+ {
+ /* write the IDAT and reset the zlib output buffer */
+ png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ }
+ /* repeat until all data has been compressed */
+ } while (png_ptr->zstream.avail_in);
+
+ /* swap the current and previous rows */
+ if (png_ptr->prev_row != NULL)
+ {
+ png_bytep tptr;
+
+ tptr = png_ptr->prev_row;
+ png_ptr->prev_row = png_ptr->row_buf;
+ png_ptr->row_buf = tptr;
+ }
+
+ /* finish row - updates counters and flushes zlib if last row */
+ png_write_finish_row(png_ptr);
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+ png_ptr->flush_rows++;
+
+ if (png_ptr->flush_dist > 0 &&
+ png_ptr->flush_rows >= png_ptr->flush_dist)
+ {
+ png_write_flush(png_ptr);
+ }
+#endif
+}
+#endif /* PNG_WRITE_SUPPORTED */
#AUTOHEADER = @AUTOHEADER@ --localdir=$(top_srcdir)/config
CGI_LIB_DIR = $(top_srcdir)/@CGI_LIB_DIR@
-GD_LIB_DIR = $(top_srcdir)/@GD_LIB_DIR@
+FREETYPE_LIB_DIR = $(top_srcdir)/@FREETYPE_LIB_DIR@
+ART_LIB_DIR = $(top_srcdir)/@ART_LIB_DIR@
PNG_LIB_DIR = $(top_srcdir)/@PNG_LIB_DIR@
ZLIB_LIB_DIR = $(top_srcdir)/@ZLIB_LIB_DIR@
-INCLUDES = -I$(CGI_LIB_DIR) -I$(GD_LIB_DIR) -I$(PNG_LIB_DIR) -I$(ZLIB_LIB_DIR)
-
-#COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) $(CFLAGS_EXTRA)
-#LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) $(CFLAGS_EXTRA)
-#LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(CFLAGS_EXTRA) $(LDFLAGS) -o $@
+INCLUDES = -I$(CGI_LIB_DIR) -I$(ART_LIB_DIR) \
+ -I$(PNG_LIB_DIR) -I$(ZLIB_LIB_DIR) -I$(FREETYPE_LIB_DIR)/include
RRD_C_FILES = \
- gdpng.c \
getopt.c \
getopt1.c \
gifsize.c \
rrd_rpncalc.c \
rrd_tune.c \
rrd_update.c \
+ rrd_gfx.c rrd_gfx.h \
getopt.h ntconfig.h parsetime.h rrd_format.h rrd_tool.h rrd.h rrd_hw.h rrd_rpncalc.h
# Build two libraries. One is a public one that gets installed in
RRD_LIBS = \
$(CGI_LIB_DIR)/librrd_cgi.la \
- $(GD_LIB_DIR)/librrd_gd.la \
+ $(FREETYPE_LIB_DIR)/librrd_freetype.la \
+ $(ART_LIB_DIR)/librrd_art.la \
$(PNG_LIB_DIR)/librrd_png.la \
$(ZLIB_LIB_DIR)/librrd_z.la
librrd_private_la_SOURCES = $(RRD_C_FILES)
librrd_la_LIBADD = $(RRD_LIBS)
-librrd_la_LDFLAGS = -version-info 0:0:0
+librrd_la_LDFLAGS = -version-info 1:2:0
include_HEADERS = rrd.h
* least every ds_mrhb seconds,
* otherwise it is regarded dead and
* will be set to UNKNOWN */
- DS_min_val, /* the processed input of a ds must */
+ DS_min_val, /* the processed input of a ds must */
DS_max_val, /* be between max_val and min_val
* both can be set to UNKNOWN if you
* do not care. Data outside the limits
CF_MINIMUM,
CF_MAXIMUM,
CF_LAST,
- CF_HWPREDICT,
+ CF_HWPREDICT,
/* An array of predictions using the seasonal
* Holt-Winters algorithm. Requires an RRA of type
* CF_SEASONAL for this data source. */
--- /dev/null
+/****************************************************************************
+ * RRDtool 1.1.x Copyright Tobias Oetiker, 1997 - 2002
+ ****************************************************************************
+ * rrd_gfx.c graphics wrapper for rrdtool
+ **************************************************************************/
+
+/* #define DEBUG */
+
+#ifdef DEBUG
+# define DPRINT(x) (void)(printf x, printf("\n"))
+#else
+# define DPRINT(x)
+#endif
+
+#include <png.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#include "rrd_gfx.h"
+
+/* lines are better drawn on the pixle than between pixles */
+#define LINEOFFSET 0.5
+
+static
+gfx_node_t *gfx_new_node( gfx_canvas_t *canvas,enum gfx_en type){
+ gfx_node_t *node = art_new(gfx_node_t,1);
+ if (node == NULL) return NULL;
+ node->type = type;
+ node->color = 0x0; /* color of element 0xRRGGBBAA alpha 0xff is solid*/
+ node->size =0.0; /* font size, line width */
+ node->path = NULL; /* path */
+ node->points = 0;
+ node->points_max =0;
+ node->svp = NULL; /* svp */
+ node->filename = NULL; /* font or image filename */
+ node->text = NULL;
+ node->x = 0.0;
+ node->y = 0.0; /* position */
+ node->halign = GFX_H_NULL; /* text alignement */
+ node->valign = GFX_V_NULL; /* text alignement */
+ node->tabwidth = 0.0;
+ node->next = NULL;
+ if (canvas->lastnode != NULL){
+ canvas->lastnode->next = node;
+ }
+ if (canvas->firstnode == NULL){
+ canvas->firstnode = node;
+ }
+ canvas->lastnode = node;
+ return node;
+}
+
+gfx_canvas_t *gfx_new_canvas (void) {
+ gfx_canvas_t *canvas = art_new(gfx_canvas_t,1);
+ canvas->firstnode = NULL;
+ canvas->lastnode = NULL;
+ return canvas;
+}
+
+/* create a new line */
+gfx_node_t *gfx_new_line(gfx_canvas_t *canvas,
+ double x0, double y0,
+ double x1, double y1,
+ double width, gfx_color_t color){
+
+ gfx_node_t *node;
+ ArtVpath *vec;
+ node = gfx_new_node(canvas,GFX_LINE);
+ if (node == NULL) return NULL;
+ vec = art_new(ArtVpath, 3);
+ if (vec == NULL) return NULL;
+ vec[0].code = ART_MOVETO_OPEN; vec[0].x=x0+LINEOFFSET; vec[0].y=y0+LINEOFFSET;
+ vec[1].code = ART_LINETO; vec[1].x=x1+LINEOFFSET; vec[1].y=y1+LINEOFFSET;
+ vec[2].code = ART_END;
+
+ node->points = 3;
+ node->points_max = 3;
+ node->color = color;
+ node->size = width;
+ node->path = vec;
+ return node;
+}
+
+/* create a new area */
+gfx_node_t *gfx_new_area (gfx_canvas_t *canvas,
+ double x0, double y0,
+ double x1, double y1,
+ double x2, double y2,
+ gfx_color_t color) {
+
+ gfx_node_t *node;
+ ArtVpath *vec;
+ node = gfx_new_node(canvas,GFX_AREA);
+ if (node == NULL) return NULL;
+ vec = art_new(ArtVpath, 5);
+ if (vec == NULL) return NULL;
+ vec[0].code = ART_MOVETO; vec[0].x=x0; vec[0].y=y0;
+ vec[1].code = ART_LINETO; vec[1].x=x1; vec[1].y=y1;
+ vec[2].code = ART_LINETO; vec[2].x=x2; vec[2].y=y2;
+ vec[3].code = ART_LINETO; vec[3].x=x0; vec[3].y=y0;
+ vec[4].code = ART_END;
+
+ node->points = 5;
+ node->points_max = 5;
+ node->color = color;
+ node->path = vec;
+
+ return node;
+}
+
+/* add a point to a line or to an area */
+int gfx_add_point (gfx_node_t *node,
+ double x, double y){
+ if (node == NULL) return 1;
+ if (node->type == GFX_AREA) {
+ double x0 = node->path[0].x;
+ double y0 = node->path[0].y;
+ node->points -= 2;
+ art_vpath_add_point (&(node->path),
+ &(node->points),
+ &(node->points_max),
+ ART_LINETO,
+ x,y);
+ art_vpath_add_point (&(node->path),
+ &(node->points),
+ &(node->points_max),
+ ART_LINETO,
+ x0,y0);
+ art_vpath_add_point (&(node->path),
+ &(node->points),
+ &(node->points_max),
+ ART_END,
+ 0,0);
+ } else if (node->type == GFX_LINE) {
+ node->points -= 1;
+ art_vpath_add_point (&(node->path),
+ &(node->points),
+ &(node->points_max),
+ ART_LINETO,
+ x+LINEOFFSET,y+LINEOFFSET);
+ art_vpath_add_point (&(node->path),
+ &(node->points),
+ &(node->points_max),
+ ART_END,
+ 0,0);
+
+ } else {
+ /* can only add point to areas and lines */
+ return 1;
+ }
+ return 0;
+}
+
+
+
+/* create a text node */
+gfx_node_t *gfx_new_text (gfx_canvas_t *canvas,
+ double x, double y, gfx_color_t color,
+ char* font, double size,
+ double tabwidth, double angle,
+ enum gfx_h_align_en h_align,
+ enum gfx_v_align_en v_align,
+ char* text){
+ gfx_node_t *node = gfx_new_node(canvas,GFX_TEXT);
+ if (angle != 0.0){
+ /* currently we only support 0 and 270 */
+ angle = 270.0;
+ }
+
+ node->text = strdup(text);
+ node->size = size;
+ node->filename = strdup(font);
+ node->x = x;
+ node->y = y;
+ node->color = color;
+ node->tabwidth = tabwidth;
+ node->halign = h_align;
+ node->valign = v_align;
+ return node;
+}
+
+double gfx_get_text_width ( double start, char* font, double size,
+ double tabwidth, char* text){
+
+ FT_GlyphSlot slot;
+ FT_UInt previous=0;
+ FT_UInt glyph_index=0;
+ FT_Bool use_kerning;
+ int error;
+ FT_Face face;
+ FT_Library library=NULL;
+ double text_width=0;
+ FT_Init_FreeType( &library );
+ error = FT_New_Face( library, font, 0, &face );
+ if ( error ) return -1;
+ error = FT_Set_Char_Size(face, size*64,size*64, 100,100);
+ if ( error ) return -1;
+
+ use_kerning = FT_HAS_KERNING(face);
+ slot = face->glyph;
+ for(;*text;text++) {
+ previous = glyph_index;
+ glyph_index = FT_Get_Char_Index( face, *text);
+
+ if (use_kerning && previous && glyph_index){
+ FT_Vector delta;
+ FT_Get_Kerning( face, previous, glyph_index,
+ 0, &delta );
+ text_width += (double)delta.x / 64.0;
+
+ }
+ error = FT_Load_Glyph( face, glyph_index, 0 );
+ if (! previous) {
+ text_width -= (double)slot->metrics.horiBearingX / 64.0; /* add just char width */
+ }
+ text_width += (double)slot->metrics.horiAdvance / 64.0;
+ }
+ text_width -= (double)slot->metrics.horiAdvance / 64.0; /* remove last step */
+ text_width += (double)slot->metrics.width / 64.0; /* add just char width */
+ text_width += (double)slot->metrics.horiBearingX / 64.0; /* add just char width */
+ return text_width;
+}
+
+
+
+
+static int gfx_save_png (art_u8 *buffer, FILE *fp,
+ long width, long height, long bytes_per_pixel);
+/* render grafics into png image */
+int gfx_render_png (gfx_canvas_t *canvas,
+ art_u32 width, art_u32 height,
+ double zoom,
+ gfx_color_t background, FILE *fp){
+
+
+ FT_Library library;
+ gfx_node_t *node = canvas->firstnode;
+ art_u8 red = background >> 24, green = (background >> 16) & 0xff;
+ art_u8 blue = (background >> 8) & 0xff, alpha = ( background & 0xff );
+ unsigned long pys_width = width * zoom;
+ unsigned long pys_height = height * zoom;
+ const int bytes_per_pixel = 3;
+ unsigned long rowstride = pys_width*bytes_per_pixel; /* bytes per pixel */
+ art_u8 *buffer = art_new (art_u8, rowstride*pys_height);
+ art_rgb_run_alpha (buffer, red, green, blue, alpha, pys_width*pys_height);
+ FT_Init_FreeType( &library );
+ while(node){
+ switch (node->type) {
+ case GFX_LINE:
+ case GFX_AREA: {
+ ArtVpath *vec;
+ double dst[6];
+ ArtSVP *svp;
+ art_affine_scale(dst,zoom,zoom);
+ vec = art_vpath_affine_transform(node->path,dst);
+ if(node->type == GFX_LINE){
+ svp = art_svp_vpath_stroke ( vec, ART_PATH_STROKE_JOIN_ROUND,
+ ART_PATH_STROKE_CAP_ROUND,
+ node->size*zoom,1,1);
+ } else {
+ svp = art_svp_from_vpath ( vec );
+ }
+ art_free(vec);
+ art_rgb_svp_alpha (svp ,0,0, pys_width, pys_height,
+ node->color, buffer, rowstride, NULL);
+ art_free(svp);
+ break;
+ }
+ case GFX_TEXT: {
+ int error;
+ float text_width=0.0, text_height = 0.0;
+ unsigned char *text;
+ art_u8 fcolor[3],falpha;
+ FT_Face face;
+ FT_GlyphSlot slot;
+ FT_UInt previous=0;
+ FT_UInt glyph_index=0;
+ FT_Bool use_kerning;
+
+ float pen_x = 0.0 , pen_y = 0.0;
+ /* double x,y; */
+ long ix,iy,iz;
+
+ fcolor[0] = node->color >> 24;
+ fcolor[1] = (node->color >> 16) & 0xff;
+ fcolor[2] = (node->color >> 8) & 0xff;
+ falpha = node->color & 0xff;
+ error = FT_New_Face( library,
+ (char *)node->filename,
+ 0,
+ &face );
+ use_kerning = FT_HAS_KERNING(face);
+
+ if ( error ) break;
+ error = FT_Set_Char_Size(face, /* handle to face object */
+ (long)(node->size*64),
+ (long)(node->size*64),
+ (long)(100*zoom),
+ (long)(100*zoom));
+ pen_x = node->x * zoom;
+ pen_y = node->y * zoom;
+ slot = face->glyph;
+
+ for(text=(unsigned char *)node->text;*text;text++) {
+ previous = glyph_index;
+ glyph_index = FT_Get_Char_Index( face, *text);
+
+ if (use_kerning && previous && glyph_index){
+ FT_Vector delta;
+ FT_Get_Kerning( face, previous, glyph_index,
+ 0, &delta );
+ text_width += (double)delta.x / 64.0;
+
+ }
+ error = FT_Load_Glyph( face, glyph_index, 0 );
+ if (previous == 0){
+ pen_x -= (double)slot->metrics.horiBearingX / 64.0; /* adjust pos for first char */
+ text_width -= (double)slot->metrics.horiBearingX / 64.0; /* add just char width */
+ }
+ if ( text_height < (double)slot->metrics.horiBearingY / 64.0 ) {
+ text_height = (double)slot->metrics.horiBearingY / 64.0;
+ }
+ text_width += (double)slot->metrics.horiAdvance / 64.0;
+ }
+ text_width -= (double)slot->metrics.horiAdvance / 64.0; /* remove last step */
+ text_width += (double)slot->metrics.width / 64.0; /* add just char width */
+ text_width += (double)slot->metrics.horiBearingX / 64.0; /* add just char width */
+
+ switch(node->halign){
+ case GFX_H_RIGHT: pen_x -= text_width; break;
+ case GFX_H_CENTER: pen_x -= text_width / 2.0; break;
+ case GFX_H_LEFT: break;
+ }
+
+ switch(node->valign){
+ case GFX_V_TOP: pen_y += text_height; break;
+ case GFX_V_CENTER: pen_y += text_height / 2.0; break;
+ case GFX_V_BOTTOM: break;
+ }
+
+ glyph_index=0;
+ for(text=(unsigned char *)node->text;*text;text++) {
+ int gr;
+ previous = glyph_index;
+ glyph_index = FT_Get_Char_Index( face, *text);
+
+ if (use_kerning && previous && glyph_index){
+ FT_Vector delta;
+ FT_Get_Kerning( face, previous, glyph_index,
+ 0, &delta );
+ pen_x += (double)delta.x / 64.0;
+
+ }
+ error = FT_Load_Glyph( face, glyph_index, FT_LOAD_RENDER );
+ gr = slot->bitmap.num_grays -1;
+ for (iy=0; iy < slot->bitmap.rows; iy++){
+ long buf_y = iy+(pen_y+0.5)-slot->bitmap_top;
+ if (buf_y < 0 || buf_y >= pys_height) continue;
+ buf_y *= rowstride;
+ for (ix=0;ix < slot->bitmap.width;ix++){
+ long buf_x = ix + (pen_x + 0.5) + (double)slot->bitmap_left ;
+ art_u8 font_alpha;
+
+ if (buf_x < 0 || buf_x >= pys_width) continue;
+ buf_x *= bytes_per_pixel ;
+ font_alpha = *(slot->bitmap.buffer + iy * slot->bitmap.width + ix);
+ font_alpha = (art_u8)((double)font_alpha / gr * falpha);
+ for (iz = 0; iz < 3; iz++){
+ art_u8 *orig = buffer + buf_y + buf_x + iz;
+ *orig = (art_u8)((double)*orig / gr * ( gr - font_alpha) +
+ (double)fcolor[iz] / gr * (font_alpha));
+ }
+ }
+ }
+ pen_x += (double)slot->metrics.horiAdvance / 64.0;
+ }
+ }
+ }
+ node = node->next;
+ }
+ gfx_save_png(buffer,fp , pys_width,pys_height,bytes_per_pixel);
+ art_free(buffer);
+ return 0;
+}
+
+/* free memory used by nodes this will also remove memory required for
+ associated paths and svcs ... but not for text strings */
+int
+gfx_destroy (gfx_canvas_t *canvas){
+ gfx_node_t *next,*node = canvas->firstnode;
+ while(node){
+ next = node->next;
+ art_free(node->path);
+ art_free(node->svp);
+ free(node->text);
+ free(node->filename);
+ art_free(node);
+ node = next;
+ }
+ return 0;
+}
+
+static int gfx_save_png (art_u8 *buffer, FILE *fp, long width, long height, long bytes_per_pixel){
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+ int i;
+ png_bytep *row_pointers;
+ int rowstride = width * bytes_per_pixel;
+ png_text text[2];
+
+ if (fp == NULL)
+ return (1);
+
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
+ if (png_ptr == NULL)
+ {
+ return (1);
+ }
+ row_pointers = (png_bytepp)png_malloc(png_ptr,
+ height*sizeof(png_bytep));
+
+ info_ptr = png_create_info_struct(png_ptr);
+
+ if (info_ptr == NULL)
+ {
+ png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+ return (1);
+ }
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ /* If we get here, we had a problem writing the file */
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ return (1);
+ }
+
+ png_init_io(png_ptr, fp);
+ png_set_IHDR (png_ptr, info_ptr,width, height,
+ 8, PNG_COLOR_TYPE_RGB,
+ PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_DEFAULT);
+
+ text[0].key = "Software";
+ text[0].text = "RRDtool, Tobias Oetiker <tobi@oetike.ch>, http://tobi.oetiker.ch";
+ text[0].compression = PNG_TEXT_COMPRESSION_NONE;
+ png_set_text (png_ptr, info_ptr, text, 1);
+
+ /* Write header data */
+ png_write_info (png_ptr, info_ptr);
+
+ for (i = 0; i < height; i++)
+ row_pointers[i] = (png_bytep) (buffer + i*rowstride);
+
+ png_write_image(png_ptr, row_pointers);
+ png_write_end(png_ptr, info_ptr);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ return 1;
+}
--- /dev/null
+/****************************************************************************
+ * RRDtool 1.1.x Copyright Tobias Oetiker, 1997 - 2001
+ ****************************************************************************
+ * rrd_gfx.h generic graphics adapter library
+ ****************************************************************************/
+
+#ifndef RRD_GFX_H
+#define RRD_GFX_H
+#define LIBART_COMPILATION
+#include <libart.h>
+
+enum gfx_en { GFX_LINE=0,GFX_AREA,GFX_TEXT };
+enum gfx_h_align_en { GFX_H_NULL=0, GFX_H_LEFT, GFX_H_RIGHT, GFX_H_CENTER };
+enum gfx_v_align_en { GFX_V_NULL=0, GFX_V_TOP, GFX_V_BOTTOM, GFX_V_CENTER };
+typedef unsigned long gfx_color_t;
+
+typedef struct gfx_node_t {
+ enum gfx_en type; /* type of graph element */
+ gfx_color_t color; /* color of element 0xRRGGBBAA alpha 0xff is solid*/
+ double size; /* font size, line width */
+ ArtVpath *path; /* path */
+ int points;
+ int points_max;
+ ArtSVP *svp; /* svp */
+ char *filename; /* font or image filename */
+ char *text;
+ double x,y; /* position */
+ enum gfx_h_align_en halign; /* text alignement */
+ enum gfx_v_align_en valign; /* text alignement */
+ double tabwidth;
+ struct gfx_node_t *next;
+} gfx_node_t;
+
+
+typedef struct gfx_canvas_t
+{
+ struct gfx_node_t *firstnode;
+ struct gfx_node_t *lastnode;
+} gfx_canvas_t;
+
+
+gfx_canvas_t *gfx_new_canvas (void);
+
+/* create a new line */
+gfx_node_t *gfx_new_line (gfx_canvas_t *canvas,
+ double x0, double y0,
+ double x1, double y1,
+ double width, gfx_color_t color);
+
+/* create a new area */
+gfx_node_t *gfx_new_area (gfx_canvas_t *canvas,
+ double x0, double y0,
+ double x1, double y1,
+ double x2, double y2,
+ gfx_color_t color);
+
+/* add a point to a line or to an area */
+int gfx_add_point (gfx_node_t *node, double x, double y);
+
+
+/* create a text node */
+gfx_node_t *gfx_new_text (gfx_canvas_t *canvas,
+ double x, double y, gfx_color_t color,
+ char* font, double size,
+ double tabwidth, double angle,
+ enum gfx_h_align_en h_align,
+ enum gfx_v_align_en v_align,
+ char* text);
+
+/* measure width of a text string */
+double gfx_get_text_width ( double start, char* font, double size,
+ double tabwidth, char* text);
+
+
+
+/* turn graph into a png image */
+int gfx_render_png (gfx_canvas_t *canvas,
+ art_u32 width, art_u32 height,
+ double zoom,
+ gfx_color_t background, FILE *fo);
+
+
+/* free memory used by nodes this will also remove memory required for
+ node chain and associated material */
+int gfx_destroy (gfx_canvas_t *canvas);
+
+#endif
+
+
+
#include "rrd_tool.h"
#endif
-#include <gd.h>
-#include <gdlucidan10.h>
-#include <gdlucidab12.h>
#include <sys/stat.h>
#ifdef WIN32
#include <io.h>
#include "rrd_graph.h"
#include "rrd_graph_helper.h"
-#define SmallFont gdLucidaNormal10
-#define LargeFont gdLucidaBold12
+/* some constant definitions */
-/* #define DEBUG */
-#ifdef DEBUG
-# define DPRINT(x) (void)(printf x, printf("\n"))
-#else
-# define DPRINT(x)
+#ifndef RRD_DEFAULT_FONT
+#define RRD_DEFAULT_FONT "/usr/openwin/lib/X11/fonts/TrueType/Arial.ttf"
+/* #define RRD_DEFAULT_FONT "/usr/share/fonts/truetype/Arial.ttf" */
#endif
+
+text_prop_t text_prop[] = {
+ { 10.0, RRD_DEFAULT_FONT }, /* default */
+ { 12.0, RRD_DEFAULT_FONT }, /* title */
+ { 8.0, RRD_DEFAULT_FONT }, /* axis */
+ { 10.0, RRD_DEFAULT_FONT }, /* unit */
+ { 10.0, RRD_DEFAULT_FONT } /* legend */
+};
+
xlab_t xlab[] = {
{0, TMT_SECOND,30, TMT_MINUTE,5, TMT_MINUTE,5, 0,"%H:%M"},
{2, TMT_MINUTE,1, TMT_MINUTE,5, TMT_MINUTE,5, 0,"%H:%M"},
{0.0, {0,0,0,0}}};
-
-col_trip_t graph_col[] = { /* default colors */
- {255,255,255,-1}, /* canvas */
- {245,245,245,-1}, /* background */
- {200,200,200,-1}, /* shade A */
- {150,150,150,-1}, /* shade B */
- {140,140,140,-1}, /* grid */
- {130,30,30,-1}, /* major grid */
- {0,0,0,-1}, /* font */
- {0,0,0,-1}, /* frame */
- {255,0,0,-1} /*arrow*/
+gfx_color_t graph_col[] = /* default colors */
+{ 0xFFFFFFFF, /* canvas */
+ 0xF0F0F0FF, /* background */
+ 0xD0D0D0FF, /* shade A */
+ 0xA0A0A0FF, /* shade B */
+ 0x909090FF, /* grid */
+ 0xE05050FF, /* major grid */
+ 0x000000FF, /* font */
+ 0x000000FF, /* frame */
+ 0xFF0000FF /* arrow */
};
-/* translate time values into x coordinates */
-/*#define xtr(x) (int)((double)im->xorigin \
- + ((double) im->xsize / (double)(im->end - im->start) ) \
- * ((double)(x) - im->start)+0.5) */
+/* #define DEBUG */
+
+#ifdef DEBUG
+# define DPRINT(x) (void)(printf x, printf("\n"))
+#else
+# define DPRINT(x)
+#endif
+
+
/* initialize with xtr(im,0); */
int
xtr(image_desc_t *im,time_t mytime){
}
/* translate data values into y coordinates */
-
-/* #define ytr(x) (int)((double)im->yorigin \
- - ((double) im->ysize / (im->maxval - im->minval) ) \
- * ((double)(x) - im->minval)+0.5) */
int
ytr(image_desc_t *im, double value){
static double pixie;
conv_if(COMMENT,GF_COMMENT)
conv_if(HRULE,GF_HRULE)
conv_if(VRULE,GF_VRULE)
- conv_if(LINE1,GF_LINE1)
- conv_if(LINE2,GF_LINE2)
- conv_if(LINE3,GF_LINE3)
+ conv_if(LINE,GF_LINE)
conv_if(AREA,GF_AREA)
conv_if(STACK,GF_STACK)
- conv_if(TICK,GF_TICK)
+ conv_if(TICK,GF_TICK)
conv_if(DEF,GF_DEF)
conv_if(CDEF,GF_CDEF)
conv_if(VDEF,GF_VDEF)
return -1;
}
+enum text_prop_en text_prop_conv(char *string){
+
+ conv_if(DEFAULT,TEXT_PROP_DEFAULT)
+ conv_if(TITLE,TEXT_PROP_TITLE)
+ conv_if(AXIS,TEXT_PROP_AXIS)
+ conv_if(UNIT,TEXT_PROP_UNIT)
+ conv_if(LEGEND,TEXT_PROP_LEGEND)
+ return -1;
+}
+
+
#undef conv_if
/* memory for the processed data */
for(i=0;i<im->gdes_c;i++){
- if((im->gdes[i].gf==GF_LINE1) ||
- (im->gdes[i].gf==GF_LINE2) ||
- (im->gdes[i].gf==GF_LINE3) ||
+ if((im->gdes[i].gf==GF_LINE) ||
(im->gdes[i].gf==GF_AREA) ||
(im->gdes[i].gf==GF_TICK) ||
(im->gdes[i].gf==GF_STACK)){
for(ii=0;ii<im->gdes_c;ii++){
double value;
switch(im->gdes[ii].gf){
- case GF_LINE1:
- case GF_LINE2:
- case GF_LINE3:
+ case GF_LINE:
case GF_AREA:
case GF_TICK:
paintval = 0.0;
}
-void gator( gdImagePtr gif, int x, int y){
-
-/* this function puts the name of the author and the tool into the
- graph. Remove if you must, but please note, that it is here,
- because I would like people who look at rrdtool generated graphs to
- see what was used to do it. No obviously you can also add a credit
- line to your webpage or printed document, this is fine with me. But
- as I have no control over this, I added the little tag in here.
-*/
-
-/* the fact that the text of what gets put into the graph is not
- visible in the function, has lead some to think this is for
- obfuscation reasons. While this is a nice side effect (I addmit),
- it is not the prime reason. The prime reason is, that the font
- used, is so small, that I had to hand edit the characters to ensure
- readability. I could thus not use the normal gd functions to write,
- but had to embed a slightly compressed bitmap version into the code.
-*/
-
- int li[]={0,0,1, 0,4,5, 0,8,9, 0,12,14, 0,17,17, 0,21,21,
- 0,24,24, 0,34,34, 0,40,42, 0,45,45, 0,48,49, 0,52,54,
- 0,61,61, 0,64,66, 0,68,70, 0,72,74, 0,76,76, 0,78,78,
- 0,80,82, 0,84,85,
- 1,0,0, 1,2,2, 1,4,4, 1,6,6, 1,8,8, 1,10,10,
- 1,13,13, 1,16,16, 1,18,18, 1,20,20, 1,22,22, 1,24,24,
- 1,34,34, 1,41,41, 1,44,44, 1,46,46, 1,48,48, 1,50,50,
- 1,53,53, 1,60,60, 1,62,62, 1,64,64, 1,69,69, 1,73,73,
- 1,76,76, 1,78,78, 1,80,80, 1,84,84, 1,86,86,
- 2,0,1, 2,4,5, 2,8,8, 2,10,10, 2,13,13, 2,16,16,
- 2,18,18, 2,20,20, 2,22,22, 2,24,24, 2,33,33, 2,41,41,
- 2,44,44, 2,46,46, 2,48,49, 2,53,53, 2,60,60, 2,62,62,
- 2,64,65, 2,69,69, 2,73,73, 2,76,77, 2,80,81, 2,84,85,
- 3,0,0, 3,2,2, 3,4,4, 3,6,6, 3,8,8, 3,10,10,
- 3,13,13, 3,16,16, 3,18,18, 3,20,20, 3,22,22, 3,24,24,
- 3,32,32, 3,41,41, 3,44,44, 3,46,46, 3,48,48, 3,50,50,
- 3,53,53, 3,60,60, 3,62,62, 3,64,64, 3,69,69, 3,73,73,
- 3,76,76, 3,78,78, 3,80,80, 3,84,84, 3,86,86,
- 4,0,0, 4,2,2, 4,4,4, 4,6,6, 4,8,9, 4,13,13,
- 4,17,17, 4,21,21, 4,24,26, 4,32,32, 4,41,41, 4,45,45,
- 4,48,49, 4,52,54, 4,61,61, 4,64,66, 4,69,69, 4,72,74,
- 4,76,76, 4,78,78, 4,80,82, 4,84,84};
- int i,ii;
- for(i=0; i<DIM(li); i=i+3)
- for(ii=y+li[i+1]; ii<=y+li[i+2];ii++)
- gdImageSetPixel(gif,x-li[i],ii,graph_col[GRC_GRID].i);
-}
-
/* calculate values required for PRINT and GPRINT functions */
}
break;
case GF_COMMENT:
- case GF_LINE1:
- case GF_LINE2:
- case GF_LINE3:
+ case GF_LINE:
case GF_AREA:
case GF_TICK:
case GF_STACK:
leg_place(image_desc_t *im)
{
/* graph labels */
- int interleg = SmallFont->w*2;
- int box = SmallFont->h*1.2;
- int border = SmallFont->w*2;
+ int interleg = im->text_prop[TEXT_PROP_LEGEND].size*2.0;
+ int box =im->text_prop[TEXT_PROP_LEGEND].size*1.5;
+ int border = im->text_prop[TEXT_PROP_LEGEND].size*2.0;
int fill=0, fill_last;
int leg_c = 0;
int leg_x = border, leg_y = im->ygif;
im->gdes[i].gf != GF_COMMENT) {
fill += box;
}
- fill += leg_cc * SmallFont->w;
+ fill += gfx_get_text_width(fill+border,im->text_prop[TEXT_PROP_LEGEND].font,
+ im->text_prop[TEXT_PROP_LEGEND].size,
+ im->tabwidth,
+ im->gdes[i].legend);
leg_c++;
} else {
legspace[i]=0;
leg_x = border;
if (leg_c >= 2 && prt_fctn == 'j') {
glue = (im->xgif - fill - 2* border) / (leg_c-1);
- /* if (glue > 2 * SmallFont->w) glue = 0; */
} else {
glue = 0;
}
for(ii=mark;ii<=i;ii++){
if(im->gdes[ii].legend[0]=='\0')
continue;
- im->gdes[ii].legloc.x = leg_x;
- im->gdes[ii].legloc.y = leg_y;
- leg_x = leg_x
- + strlen(im->gdes[ii].legend)*SmallFont->w
- + legspace[ii]
- + glue;
+ im->gdes[ii].leg_x = leg_x;
+ im->gdes[ii].leg_y = leg_y;
+ leg_x +=
+ gfx_get_text_width(leg_x,im->text_prop[TEXT_PROP_LEGEND].font,
+ im->text_prop[TEXT_PROP_LEGEND].size,
+ im->tabwidth,
+ im->gdes[i].legend)
+ + legspace[ii]
+ + glue;
if (im->gdes[ii].gf != GF_GPRINT &&
im->gdes[ii].gf != GF_COMMENT)
leg_x += box;
}
- leg_y = leg_y + SmallFont->h*1.2;
- if (prt_fctn == 's') leg_y -= SmallFont->h *0.5;
+ leg_y = leg_y + im->text_prop[TEXT_PROP_LEGEND].size*1.2;
+ if (prt_fctn == 's') leg_y -= im->text_prop[TEXT_PROP_LEGEND].size*1.2;
fill = 0;
leg_c = 0;
mark = ii;
int
-horizontal_grid(gdImagePtr gif, image_desc_t *im)
+horizontal_grid(gfx_canvas_t *canvas, image_desc_t *im)
{
double range;
double scaledrange;
double gridstep;
double scaledstep;
char graph_label[100];
- gdPoint polyPoints[4];
+ double x0,x1,y0,y1;
int labfact,gridind;
- int styleMinor[2],styleMajor[2];
int decimals, fractionals;
char labfmt[64];
return 0;
}
- styleMinor[0] = graph_col[GRC_GRID].i;
- styleMinor[1] = gdTransparent;
-
- styleMajor[0] = graph_col[GRC_MGRID].i;
- styleMajor[1] = gdTransparent;
-
/* find grid spaceing */
pixel=1;
if(isnan(im->ygridstep)){
}
for(i=0; i<4;i++) {
- if (pixel * ylab[gridind].lfac[i] >= 2 * SmallFont->h) {
- labfact = ylab[gridind].lfac[i];
- break;
- }
+ if (pixel * ylab[gridind].lfac[i] >= 2 * im->text_prop[TEXT_PROP_AXIS].size) {
+ labfact = ylab[gridind].lfac[i];
+ break;
+ }
}
gridstep = ylab[gridind].grid * im->magfact;
labfact = im->ylabfact;
}
- polyPoints[0].x=im->xorigin;
- polyPoints[1].x=im->xorigin+im->xsize;
+ x0=im->xorigin;
+ x1=im->xorigin+im->xsize;
+
sgrid = (int)( im->minval / gridstep - 1);
egrid = (int)( im->maxval / gridstep + 1);
scaledstep = gridstep/im->magfact;
for (i = sgrid; i <= egrid; i++){
- polyPoints[0].y=ytr(im,gridstep*i);
- if ( polyPoints[0].y >= im->yorigin-im->ysize
- && polyPoints[0].y <= im->yorigin) {
+ y0=ytr(im,gridstep*i);
+ if ( y0 >= im->yorigin-im->ysize
+ && y0 <= im->yorigin){
if(i % labfact == 0){
if (i==0 || im->symbol == ' ') {
if(scaledstep < 1){
}
}
- gdImageString(gif, SmallFont,
- (polyPoints[0].x - (strlen(graph_label) *
- SmallFont->w)-7),
- polyPoints[0].y - SmallFont->h/2+1,
- (unsigned char *)graph_label, graph_col[GRC_FONT].i);
-
- gdImageSetStyle(gif, styleMajor, 2);
-
- gdImageLine(gif, polyPoints[0].x-2,polyPoints[0].y,
- polyPoints[0].x+2,polyPoints[0].y,graph_col[GRC_MGRID].i);
- gdImageLine(gif, polyPoints[1].x-2,polyPoints[0].y,
- polyPoints[1].x+2,polyPoints[0].y,graph_col[GRC_MGRID].i);
+ gfx_new_text ( canvas,
+ x0-im->text_prop[TEXT_PROP_AXIS].size/1.5, y0,
+ im->graph_col[GRC_FONT],
+ im->text_prop[TEXT_PROP_AXIS].font,
+ im->text_prop[TEXT_PROP_AXIS].size,
+ im->tabwidth, 0.0, GFX_H_RIGHT, GFX_V_CENTER,
+ graph_label );
+ gfx_new_line ( canvas,
+ x0-2,y0,
+ x1+2,y0,
+ MGRIDWIDTH, im->graph_col[GRC_MGRID] );
+
} else {
- gdImageSetStyle(gif, styleMinor, 2);
- gdImageLine(gif, polyPoints[0].x-1,polyPoints[0].y,
- polyPoints[0].x+1,polyPoints[0].y,graph_col[GRC_GRID].i);
- gdImageLine(gif, polyPoints[1].x-1,polyPoints[0].y,
- polyPoints[1].x+1,polyPoints[0].y,graph_col[GRC_GRID].i);
+ gfx_new_line ( canvas,
+ x0-1,y0,
+ x1+1,y0,
+ GRIDWIDTH, im->graph_col[GRC_GRID] );
+
}
- gdImageLine(gif, polyPoints[0].x,polyPoints[0].y,
- polyPoints[1].x,polyPoints[0].y,gdStyled);
}
}
-/* if(im->minval * im->maxval < 0){
- polyPoints[0].y=ytr(0);
- gdImageLine(gif, polyPoints[0].x,polyPoints[0].y,
- polyPoints[1].x,polyPoints[0].y,graph_col[GRC_MGRID].i);
- } */
-
return 1;
}
/* logaritmic horizontal grid */
int
-horizontal_log_grid(gdImagePtr gif, image_desc_t *im)
+horizontal_log_grid(gfx_canvas_t *canvas, image_desc_t *im)
{
double pixpex;
int ii,i;
int minoridx=0, majoridx=0;
char graph_label[100];
- gdPoint polyPoints[4];
- int styleMinor[2],styleMajor[2];
+ double x0,x1,y0,y1;
double value, pixperstep, minstep;
/* find grid spaceing */
}
pixperstep = pixpex * minstep;
if(pixperstep > 5){minoridx = i;}
- if(pixperstep > 2 * SmallFont->h){majoridx = i;}
+ if(pixperstep > 2 * im->text_prop[TEXT_PROP_LEGEND].size){majoridx = i;}
}
- styleMinor[0] = graph_col[GRC_GRID].i;
- styleMinor[1] = gdTransparent;
-
- styleMajor[0] = graph_col[GRC_MGRID].i;
- styleMajor[1] = gdTransparent;
-
- polyPoints[0].x=im->xorigin;
- polyPoints[1].x=im->xorigin+im->xsize;
+ x0=im->xorigin;
+ x1=im->xorigin+im->xsize;
/* paint minor grid */
for (value = pow((double)10, log10(im->minval)
- fmod(log10(im->minval),log10(yloglab[minoridx][0])));
if (value < im->minval) continue;
i=0;
while(yloglab[minoridx][++i] > 0){
- polyPoints[0].y = ytr(im,value * yloglab[minoridx][i]);
- if (polyPoints[0].y <= im->yorigin - im->ysize) break;
- gdImageSetStyle(gif, styleMinor, 2);
- gdImageLine(gif, polyPoints[0].x-1,polyPoints[0].y,
- polyPoints[0].x+1,polyPoints[0].y,graph_col[GRC_GRID].i);
- gdImageLine(gif, polyPoints[1].x-1,polyPoints[0].y,
- polyPoints[1].x+1,polyPoints[0].y,graph_col[GRC_GRID].i);
-
- gdImageLine(gif, polyPoints[0].x,polyPoints[0].y,
- polyPoints[1].x,polyPoints[0].y,gdStyled);
+ y0 = ytr(im,value * yloglab[minoridx][i]);
+ if (y0 <= im->yorigin - im->ysize) break;
+ gfx_new_line ( canvas,
+ x0-1,y0,
+ x1+1,y0,
+ GRIDWIDTH, im->graph_col[GRC_GRID] );
}
}
if (value < im->minval) continue;
i=0;
while(yloglab[majoridx][++i] > 0){
- polyPoints[0].y = ytr(im,value * yloglab[majoridx][i]);
- if (polyPoints[0].y <= im->yorigin - im->ysize) break;
- gdImageSetStyle(gif, styleMajor, 2);
- gdImageLine(gif, polyPoints[0].x-2,polyPoints[0].y,
- polyPoints[0].x+2,polyPoints[0].y,graph_col[GRC_MGRID].i);
- gdImageLine(gif, polyPoints[1].x-2,polyPoints[0].y,
- polyPoints[1].x+2,polyPoints[0].y,graph_col[GRC_MGRID].i);
-
- gdImageLine(gif, polyPoints[0].x,polyPoints[0].y,
- polyPoints[1].x,polyPoints[0].y,gdStyled);
- sprintf(graph_label,"%3.0e",value * yloglab[majoridx][i]);
- gdImageString(gif, SmallFont,
- (polyPoints[0].x - (strlen(graph_label) *
- SmallFont->w)-7),
- polyPoints[0].y - SmallFont->h/2+1,
- (unsigned char *)graph_label, graph_col[GRC_FONT].i);
+ y0 = ytr(im,value * yloglab[majoridx][i]);
+ if (y0 <= im->yorigin - im->ysize) break;
+ gfx_new_line ( canvas,
+ x0-2,y0,
+ x1+2,y0,
+ MGRIDWIDTH, im->graph_col[GRC_MGRID] );
+
+ sprintf(graph_label,"%3.0e",value * yloglab[majoridx][i]);
+ gfx_new_text ( canvas,
+ x0-im->text_prop[TEXT_PROP_AXIS].size/1.5, y0,
+ im->graph_col[GRC_FONT],
+ im->text_prop[TEXT_PROP_AXIS].font,
+ im->text_prop[TEXT_PROP_AXIS].size,
+ im->tabwidth,0.0, GFX_H_RIGHT, GFX_V_CENTER,
+ graph_label );
}
}
return 1;
void
vertical_grid(
- gdImagePtr gif,
+ gfx_canvas_t *canvas,
image_desc_t *im )
{
int xlab_sel; /* which sort of label and grid ? */
time_t ti, tilab;
long factor;
char graph_label[100];
- gdPoint polyPoints[4]; /* points for filled graph and more*/
-
- /* style for grid lines */
- int styleDotted[4];
+ double x0,y0,y1; /* points for filled graph and more*/
+
-
/* the type of time grid is determined by finding
the number of seconds per pixel in the graph */
}
/* y coords are the same for every line ... */
- polyPoints[0].y = im->yorigin;
- polyPoints[1].y = im->yorigin-im->ysize;
+ y0 = im->yorigin;
+ y1 = im->yorigin-im->ysize;
+
/* paint the minor grid */
for(ti = find_first_time(im->start,
){
/* are we inside the graph ? */
if (ti < im->start || ti > im->end) continue;
- polyPoints[0].x = xtr(im,ti);
- styleDotted[0] = graph_col[GRC_GRID].i;
- styleDotted[1] = gdTransparent;
-
- gdImageSetStyle(gif, styleDotted, 2);
-
- gdImageLine(gif, polyPoints[0].x,polyPoints[0].y,
- polyPoints[0].x,polyPoints[1].y,gdStyled);
- gdImageLine(gif, polyPoints[0].x,polyPoints[0].y-1,
- polyPoints[0].x,polyPoints[0].y+1,graph_col[GRC_GRID].i);
- gdImageLine(gif, polyPoints[0].x,polyPoints[1].y-1,
- polyPoints[0].x,polyPoints[1].y+1,graph_col[GRC_GRID].i);
+ x0 = xtr(im,ti);
+ gfx_new_line(canvas,x0,y0+1, x0,y1-1,GRIDWIDTH, im->graph_col[GRC_GRID]);
+
}
/* paint the major grid */
){
/* are we inside the graph ? */
if (ti < im->start || ti > im->end) continue;
- polyPoints[0].x = xtr(im,ti);
- styleDotted[0] = graph_col[GRC_MGRID].i;
- styleDotted[1] = gdTransparent;
- gdImageSetStyle(gif, styleDotted, 2);
-
- gdImageLine(gif, polyPoints[0].x,polyPoints[0].y,
- polyPoints[0].x,polyPoints[1].y,gdStyled);
- gdImageLine(gif, polyPoints[0].x,polyPoints[0].y-2,
- polyPoints[0].x,polyPoints[0].y+2,graph_col[GRC_MGRID].i);
- gdImageLine(gif, polyPoints[0].x,polyPoints[1].y-2,
- polyPoints[0].x,polyPoints[1].y+2,graph_col[GRC_MGRID].i);
+ x0 = xtr(im,ti);
+ gfx_new_line(canvas,x0,y0+2, x0,y1-2,MGRIDWIDTH, im->graph_col[GRC_MGRID]);
+
}
/* paint the labels below the graph */
for(ti = find_first_time(im->start,
ti <= im->end;
ti = find_next_time(ti,im->xlab_user.labtm,im->xlab_user.labst)
){
- int gr_pos,width;
tilab= ti + im->xlab_user.precis/2; /* correct time for the label */
#if HAVE_STRFTIME
#else
# error "your libc has no strftime I guess we'll abort the exercise here."
#endif
- width=strlen(graph_label) * SmallFont->w;
- gr_pos=xtr(im,tilab) - width/2;
- if (gr_pos >= im->xorigin
- && gr_pos + width <= im->xorigin+im->xsize)
- gdImageString(gif, SmallFont,
- gr_pos, polyPoints[0].y+4,
- (unsigned char *)graph_label, graph_col[GRC_FONT].i);
+ gfx_new_text ( canvas,
+ xtr(im,tilab), y0+im->text_prop[TEXT_PROP_AXIS].size/1.5,
+ im->graph_col[GRC_FONT],
+ im->text_prop[TEXT_PROP_AXIS].font,
+ im->text_prop[TEXT_PROP_AXIS].size,
+ im->tabwidth, 0.0, GFX_H_CENTER, GFX_V_TOP,
+ graph_label );
+
}
}
void
axis_paint(
- image_desc_t *im,
- gdImagePtr gif
- )
+ image_desc_t *im,
+ gfx_canvas_t *canvas
+ )
{
/* draw x and y axis */
- gdImageLine(gif, im->xorigin+im->xsize,im->yorigin,
- im->xorigin+im->xsize,im->yorigin-im->ysize,
- graph_col[GRC_GRID].i);
-
- gdImageLine(gif, im->xorigin,im->yorigin-im->ysize,
- im->xorigin+im->xsize,im->yorigin-im->ysize,
- graph_col[GRC_GRID].i);
-
- gdImageLine(gif, im->xorigin-4,im->yorigin,
- im->xorigin+im->xsize+4,im->yorigin,
- graph_col[GRC_FONT].i);
-
- gdImageLine(gif, im->xorigin,im->yorigin,
- im->xorigin,im->yorigin-im->ysize,
- graph_col[GRC_GRID].i);
+ gfx_new_line ( canvas, im->xorigin+im->xsize,im->yorigin,
+ im->xorigin+im->xsize,im->yorigin-im->ysize,
+ GRIDWIDTH, im->graph_col[GRC_GRID]);
+
+ gfx_new_line ( canvas, im->xorigin,im->yorigin-im->ysize,
+ im->xorigin+im->xsize,im->yorigin-im->ysize,
+ GRIDWIDTH, im->graph_col[GRC_GRID]);
+
+ gfx_new_line ( canvas, im->xorigin-4,im->yorigin,
+ im->xorigin+im->xsize+4,im->yorigin,
+ MGRIDWIDTH, im->graph_col[GRC_GRID]);
+
+ gfx_new_line ( canvas, im->xorigin,im->yorigin+4,
+ im->xorigin,im->yorigin-im->ysize-4,
+ MGRIDWIDTH, im->graph_col[GRC_GRID]);
+
/* arrow for X axis direction */
- gdImageLine(gif, im->xorigin+im->xsize+4, im->yorigin-3, im->xorigin+im->xsize+4, im->yorigin+3,graph_col[GRC_ARROW].i);
- gdImageLine(gif, im->xorigin+im->xsize+4, im->yorigin-3, im->xorigin+im->xsize+9, im->yorigin,graph_col[GRC_ARROW].i);
- gdImageLine(gif, im->xorigin+im->xsize+4, im->yorigin+3, im->xorigin+im->xsize+9, im->yorigin,graph_col[GRC_ARROW].i);
-
- /* gdImageLine(gif, im->xorigin+im->xsize-1, im->yorigin-3, im->xorigin+im->xsize-1, im->yorigin+3,graph_col[GRC_MGRID].i);
- gdImageLine(gif, im->xorigin+im->xsize, im->yorigin-2, im->xorigin+im->xsize, im->yorigin+2,graph_col[GRC_MGRID].i);
- gdImageLine(gif, im->xorigin+im->xsize+1, im->yorigin-2, im->xorigin+im->xsize+1, im->yorigin+2,graph_col[GRC_MGRID].i);
- gdImageLine(gif, im->xorigin+im->xsize+2, im->yorigin-2, im->xorigin+im->xsize+2, im->yorigin+2,graph_col[GRC_MGRID].i);
- gdImageLine(gif, im->xorigin+im->xsize+3, im->yorigin-1, im->xorigin+im->xsize+3, im->yorigin+1,graph_col[GRC_MGRID].i);
- gdImageLine(gif, im->xorigin+im->xsize+4, im->yorigin-1, im->xorigin+im->xsize+4, im->yorigin+1,graph_col[GRC_MGRID].i);
- gdImageLine(gif, im->xorigin+im->xsize+5, im->yorigin, im->xorigin+im->xsize+5, im->yorigin,graph_col[GRC_MGRID].i); */
-
-
-
+ gfx_new_area ( canvas,
+ im->xorigin+im->xsize+4, im->yorigin-3,
+ im->xorigin+im->xsize+4, im->yorigin+3,
+ im->xorigin+im->xsize+9, im->yorigin,
+ im->graph_col[GRC_ARROW]);
+
+
+
}
void
grid_paint(
image_desc_t *im,
- gdImagePtr gif
+ gfx_canvas_t *canvas
+
)
{
long i;
int boxH=8, boxV=8;
int res=0;
- gdPoint polyPoints[4]; /* points for filled graph and more*/
+ double x0,x1,x2,x3,y0,y1,y2,y3; /* points for filled graph and more*/
+ gfx_node_t *node;
+
/* draw 3d border */
- gdImageLine(gif,0,0,im->xgif-1,0,graph_col[GRC_SHADEA].i);
- gdImageLine(gif,1,1,im->xgif-2,1,graph_col[GRC_SHADEA].i);
- gdImageLine(gif,0,0,0,im->ygif-1,graph_col[GRC_SHADEA].i);
- gdImageLine(gif,1,1,1,im->ygif-2,graph_col[GRC_SHADEA].i);
- gdImageLine(gif,im->xgif-1,0,im->xgif-1,im->ygif-1,graph_col[GRC_SHADEB].i);
- gdImageLine(gif,0,im->ygif-1,im->xgif-1,im->ygif-1,graph_col[GRC_SHADEB].i);
- gdImageLine(gif,im->xgif-2,1,im->xgif-2,im->ygif-2,graph_col[GRC_SHADEB].i);
- gdImageLine(gif,1,im->ygif-2,im->xgif-2,im->ygif-2,graph_col[GRC_SHADEB].i);
-
-
+ node = gfx_new_area (canvas, 0,im->ygif, 0,0, im->xgif, 0,im->graph_col[GRC_SHADEA]);
+ gfx_add_point( node , im->xgif - 2, 2 );
+ gfx_add_point( node , 2,2 );
+ gfx_add_point( node , 2,im->ygif-2 );
+ gfx_add_point( node , 0,im->ygif );
+
+ node = gfx_new_area (canvas, 0,im->ygif, im->xgif,im->ygif, im->xgif,0,im->graph_col[GRC_SHADEB]);
+ gfx_add_point( node , im->xgif - 2, 2 );
+ gfx_add_point( node , im->xgif-2,im->ygif-2 );
+ gfx_add_point( node , 2,im->ygif-2 );
+ gfx_add_point( node , 0,im->ygif );
+
+
if (im->draw_x_grid == 1 )
- vertical_grid(gif, im);
+ vertical_grid(canvas, im);
if (im->draw_y_grid == 1){
if(im->logarithmic){
- res = horizontal_log_grid(gif,im);
+ res = horizontal_log_grid(canvas,im);
} else {
- res = horizontal_grid(gif,im);
+ res = horizontal_grid(canvas,im);
}
/* dont draw horizontal grid if there is no min and max val */
if (! res ) {
char *nodata = "No Data found";
- gdImageString(gif, LargeFont,
- im->xgif/2
- - (strlen(nodata)*LargeFont->w)/2,
- (2*im->yorigin-im->ysize) / 2,
- (unsigned char *)nodata, graph_col[GRC_FONT].i);
+ gfx_new_text(canvas,im->xgif/2, (2*im->yorigin-im->ysize) / 2,
+ im->graph_col[GRC_FONT],
+ im->text_prop[TEXT_PROP_AXIS].font,
+ im->text_prop[TEXT_PROP_AXIS].size,
+ im->tabwidth, 0.0, GFX_H_CENTER, GFX_V_CENTER,
+ nodata );
}
}
/* yaxis description */
- gdImageStringUp(gif, SmallFont,
- 7,
- (im->yorigin - im->ysize/2
- +(strlen(im->ylegend)*SmallFont->w)/2 ),
- (unsigned char *)im->ylegend, graph_col[GRC_FONT].i);
-
-
+ gfx_new_text( canvas,
+ 7, (im->yorigin - im->ysize/2),
+ im->graph_col[GRC_FONT],
+ im->text_prop[TEXT_PROP_AXIS].font,
+ im->text_prop[TEXT_PROP_AXIS].size, im->tabwidth, 270.0,
+ GFX_H_CENTER, GFX_V_CENTER,
+ im->ylegend);
+
/* graph title */
- gdImageString(gif, LargeFont,
- im->xgif/2
- - (strlen(im->title)*LargeFont->w)/2,
- 8,
- (unsigned char *)im->title, graph_col[GRC_FONT].i);
-
- /* graph labels */
- if( !(im->extra_flags & NOLEGEND) ) {
+ gfx_new_text( canvas,
+ im->xgif/2, im->text_prop[TEXT_PROP_TITLE].size*1.5,
+ im->graph_col[GRC_FONT],
+ im->text_prop[TEXT_PROP_TITLE].font,
+ im->text_prop[TEXT_PROP_TITLE].size, im->tabwidth, 0.0,
+ GFX_H_CENTER, GFX_V_CENTER,
+ im->title);
+
+ /* graph labels */
+ if( !(im->extra_flags & NOLEGEND) ) {
for(i=0;i<im->gdes_c;i++){
- if(im->gdes[i].legend[0] =='\0')
- continue;
-
- if(im->gdes[i].gf != GF_GPRINT && im->gdes[i].gf != GF_COMMENT){
+ if(im->gdes[i].legend[0] =='\0')
+ continue;
+
+ if(im->gdes[i].gf != GF_GPRINT && im->gdes[i].gf != GF_COMMENT){
+ x0 = im->gdes[i].leg_x;
+ y0 = im->gdes[i].leg_y+1.0;
+ x1 = x0+boxH;
+ x2 = x0+boxH;
+ x3 = x0;
+ y1 = y0;
+ y2 = y0+boxV;
+ y3 = y0+boxV;
+ node = gfx_new_area(canvas, x0,y0,x1,y1,x2,y2 ,im->gdes[i].col);
+ gfx_add_point ( node, x3, y3 );
+ gfx_add_point ( node, x0, y0 );
+ node = gfx_new_line(canvas, x0,y0,x1,y1 ,GRIDWIDTH, im->graph_col[GRC_FRAME]);
+ gfx_add_point ( node, x2, y2 );
+ gfx_add_point ( node, x3, y3 );
+ gfx_add_point ( node, x0, y0 );
- polyPoints[0].x = im->gdes[i].legloc.x;
- polyPoints[0].y = im->gdes[i].legloc.y+1;
- polyPoints[1].x = polyPoints[0].x+boxH;
- polyPoints[2].x = polyPoints[0].x+boxH;
- polyPoints[3].x = polyPoints[0].x;
- polyPoints[1].y = polyPoints[0].y;
- polyPoints[2].y = polyPoints[0].y+boxV;
- polyPoints[3].y = polyPoints[0].y+boxV;
- gdImageFilledPolygon(gif,polyPoints,4,im->gdes[i].col.i);
- gdImagePolygon(gif,polyPoints,4,graph_col[GRC_FRAME].i);
-
- gdImageString(gif, SmallFont,
- polyPoints[0].x+boxH+6,
- polyPoints[0].y-1,
- (unsigned char *)im->gdes[i].legend,
- graph_col[GRC_FONT].i);
- } else {
- polyPoints[0].x = im->gdes[i].legloc.x;
- polyPoints[0].y = im->gdes[i].legloc.y;
+ gfx_new_text ( canvas, x0+boxH+6, (y0+y2) / 2.0,
+ im->graph_col[GRC_FONT],
+ im->text_prop[TEXT_PROP_AXIS].font,
+ im->text_prop[TEXT_PROP_AXIS].size,
+ im->tabwidth,0.0, GFX_H_LEFT, GFX_V_CENTER,
+ im->gdes[i].legend );
- gdImageString(gif, SmallFont,
- polyPoints[0].x,
- polyPoints[0].y,
- (unsigned char *)im->gdes[i].legend,
- graph_col[GRC_FONT].i);
- }
+ } else {
+ x0 = im->gdes[i].leg_x;
+ y0 = im->gdes[i].leg_y;
+
+ gfx_new_text ( canvas, x0, (y0+y2) / 2.0,
+ im->graph_col[GRC_FONT],
+ im->text_prop[TEXT_PROP_AXIS].font,
+ im->text_prop[TEXT_PROP_AXIS].size,
+ im->tabwidth,0.0, GFX_H_LEFT, GFX_V_BOTTOM,
+ im->gdes[i].legend );
+
+ }
}
- }
-
-
- gator(gif, (int) im->xgif-5, 5);
-
+ }
}
-gdImagePtr
-MkLineBrush(image_desc_t *im,long cosel, enum gf_en typsel){
- gdImagePtr brush;
- int pen;
- switch (typsel){
- case GF_LINE1:
- brush=gdImageCreate(1,1);
- break;
- case GF_LINE2:
- brush=gdImageCreate(2,2);
- break;
- case GF_LINE3:
- brush=gdImageCreate(3,3);
- break;
- default:
- return NULL;
- }
-
- gdImageColorTransparent(brush,
- gdImageColorAllocate(brush, 0, 0, 0));
-
- pen = gdImageColorAllocate(brush,
- im->gdes[cosel].col.red,
- im->gdes[cosel].col.green,
- im->gdes[cosel].col.blue);
-
- switch (typsel){
- case GF_LINE1:
- gdImageSetPixel(brush,0,0,pen);
- break;
- case GF_LINE2:
- gdImageSetPixel(brush,0,0,pen);
- gdImageSetPixel(brush,0,1,pen);
- gdImageSetPixel(brush,1,0,pen);
- gdImageSetPixel(brush,1,1,pen);
- break;
- case GF_LINE3:
- gdImageSetPixel(brush,1,0,pen);
- gdImageSetPixel(brush,0,1,pen);
- gdImageSetPixel(brush,1,1,pen);
- gdImageSetPixel(brush,2,1,pen);
- gdImageSetPixel(brush,1,2,pen);
- break;
- default:
- return NULL;
- }
- return brush;
-}
/*****************************************************
* lazy check make sure we rely need to create this graph
*****************************************************/
return size;
}
+
/* draw that picture thing ... */
int
graph_paint(image_desc_t *im, char ***calcpr)
{
- int i,ii;
- int lazy = lazy_check(im);
- FILE *fo;
-
- /* gif stuff */
- gdImagePtr gif,brush;
-
- double areazero = 0.0;
- enum gf_en stack_gf = GF_PRINT;
- graph_desc_t *lastgdes = NULL;
- gdPoint canvas[4], back[4]; /* points for canvas*/
-
- /* if we are lazy and there is nothing to PRINT ... quit now */
- if (lazy && im->prt_c==0) return 0;
-
- /* pull the data from the rrd files ... */
-
- if(data_fetch(im)==-1)
- return -1;
-
- /* evaluate VDEF and CDEF operations ... */
- if(data_calc(im)==-1)
- return -1;
-
- /* calculate and PRINT and GPRINT definitions. We have to do it at
- * this point because it will affect the length of the legends
- * if there are no graph elements we stop here ...
- * if we are lazy, try to quit ...
- */
- i=print_calc(im,calcpr);
- if(i<0) return -1;
- if(i==0 || lazy) return 0;
-
- /* get actual drawing data and find min and max values*/
- if(data_proc(im)==-1)
- return -1;
-
- if(!im->logarithmic){si_unit(im);} /* identify si magnitude Kilo, Mega Giga ? */
-
- if(!im->rigid && ! im->logarithmic)
- expand_range(im); /* make sure the upper and lower limit are
- sensible values */
-
- /* init xtr and ytr */
- /* determine the actual size of the gif to draw. The size given
- on the cmdline is the graph area. But we need more as we have
- draw labels and other things outside the graph area */
-
-
- im->xorigin = 10 + 9 * SmallFont->w+SmallFont->h;
- xtr(im,0);
-
- im->yorigin = 14 + im->ysize;
- ytr(im,DNAN);
-
- if(im->title[0] != '\0')
- im->yorigin += (LargeFont->h+4);
-
- im->xgif=20+im->xsize + im->xorigin;
- im->ygif= im->yorigin+2*SmallFont->h;
-
- /* determine where to place the legends onto the graphics.
- and set im->ygif to match space requirements for text */
- if(leg_place(im)==-1)
- return -1;
-
- gif=gdImageCreate(im->xgif,im->ygif);
-
- gdImageInterlace(gif, im->interlaced);
-
- /* allocate colors for the screen elements */
- for(i=0;i<DIM(graph_col);i++)
- /* check for user override values */
- if(im->graph_col[i].red != -1)
- graph_col[i].i =
- gdImageColorAllocate( gif,
- im->graph_col[i].red,
- im->graph_col[i].green,
- im->graph_col[i].blue);
- else
- graph_col[i].i =
- gdImageColorAllocate( gif,
- graph_col[i].red,
- graph_col[i].green,
- graph_col[i].blue);
-
-
- /* allocate colors for the graph */
- for(i=0;i<im->gdes_c;i++)
- /* only for elements which have a color defined */
- if (im->gdes[i].col.red != -1)
- im->gdes[i].col.i =
- gdImageColorAllocate(gif,
- im->gdes[i].col.red,
- im->gdes[i].col.green,
- im->gdes[i].col.blue);
-
-
- /* the actual graph is created by going through the individual
- graph elements and then drawing them */
-
- back[0].x = 0;
- back[0].y = 0;
- back[1].x = back[0].x+im->xgif;
- back[1].y = back[0].y;
- back[2].x = back[1].x;
- back[2].y = back[0].y+im->ygif;
- back[3].x = back[0].x;
- back[3].y = back[2].y;
-
- gdImageFilledPolygon(gif,back,4,graph_col[GRC_BACK].i);
-
- canvas[0].x = im->xorigin;
- canvas[0].y = im->yorigin;
- canvas[1].x = canvas[0].x+im->xsize;
- canvas[1].y = canvas[0].y;
- canvas[2].x = canvas[1].x;
- canvas[2].y = canvas[0].y-im->ysize;
- canvas[3].x = canvas[0].x;
- canvas[3].y = canvas[2].y;
-
- gdImageFilledPolygon(gif,canvas,4,graph_col[GRC_CANVAS].i);
-
- if (im->minval > 0.0)
- areazero = im->minval;
- if (im->maxval < 0.0)
- areazero = im->maxval;
-
- axis_paint(im,gif);
-
- for(i=0;i<im->gdes_c;i++){
-
- switch(im->gdes[i].gf){
- case GF_CDEF:
- case GF_VDEF:
- case GF_DEF:
- case GF_PRINT:
- case GF_GPRINT:
- case GF_COMMENT:
- case GF_HRULE:
- case GF_VRULE:
- break;
- case GF_TICK:
- for (ii = 0; ii < im->xsize; ii++)
- {
- if (!isnan(im->gdes[i].p_data[ii]) &&
- im->gdes[i].p_data[ii] > 0.0)
- {
- /* generate a tick */
- gdImageLine(gif, im -> xorigin + ii,
- im -> yorigin - (im -> gdes[i].yrule * im -> ysize),
- im -> xorigin + ii,
- im -> yorigin,
- im -> gdes[i].col.i);
- }
- }
- break;
- case GF_LINE1:
- case GF_LINE2:
- case GF_LINE3:
- case GF_AREA:
- stack_gf = im->gdes[i].gf;
- case GF_STACK:
- /* fix data points at oo and -oo */
- for(ii=0;ii<im->xsize;ii++){
- if (isinf(im->gdes[i].p_data[ii])){
- if (im->gdes[i].p_data[ii] > 0) {
- im->gdes[i].p_data[ii] = im->maxval ;
- } else {
- im->gdes[i].p_data[ii] = im->minval ;
- }
-
- }
- }
+ int i,ii;
+ int lazy = lazy_check(im);
+ FILE *fo;
+ gfx_canvas_t *canvas;
+ gfx_node_t *node;
+
+ double areazero = 0.0;
+ enum gf_en stack_gf = GF_PRINT;
+ graph_desc_t *lastgdes = NULL;
+
+ /* if we are lazy and there is nothing to PRINT ... quit now */
+ if (lazy && im->prt_c==0) return 0;
+
+ /* pull the data from the rrd files ... */
+
+ if(data_fetch(im)==-1)
+ return -1;
+
+ /* evaluate VDEF and CDEF operations ... */
+ if(data_calc(im)==-1)
+ return -1;
+
+ /* calculate and PRINT and GPRINT definitions. We have to do it at
+ * this point because it will affect the length of the legends
+ * if there are no graph elements we stop here ...
+ * if we are lazy, try to quit ...
+ */
+ i=print_calc(im,calcpr);
+ if(i<0) return -1;
+ if(i==0 || lazy) return 0;
+
+ /* get actual drawing data and find min and max values*/
+ if(data_proc(im)==-1)
+ return -1;
+
+ if(!im->logarithmic){si_unit(im);} /* identify si magnitude Kilo, Mega Giga ? */
+
+ if(!im->rigid && ! im->logarithmic)
+ expand_range(im); /* make sure the upper and lower limit are
+ sensible values */
+
+ /* init xtr and ytr */
+ /* determine the actual size of the gif to draw. The size given
+ on the cmdline is the graph area. But we need more as we have
+ draw labels and other things outside the graph area */
+
+
+ im->xorigin = 10 + 9 * im->text_prop[TEXT_PROP_LEGEND].size;
+
+ xtr(im,0);
+
+ im->yorigin = 10 + im->ysize;
+
+ ytr(im,DNAN);
+
+ if(im->title[0] != '\0')
+ im->yorigin += im->text_prop[TEXT_PROP_TITLE].size*3+4;
+
+ im->xgif=20+im->xsize + im->xorigin;
+ im->ygif= im->yorigin+2* im->text_prop[TEXT_PROP_LEGEND].size;
+
+ /* determine where to place the legends onto the graphics.
+ and set im->ygif to match space requirements for text */
+ if(leg_place(im)==-1)
+ return -1;
- if (im->gdes[i].col.i != -1){
- /* GF_LINE and frined */
- if(stack_gf == GF_LINE1 || stack_gf == GF_LINE2 || stack_gf == GF_LINE3 ){
- brush = MkLineBrush(im,i,stack_gf);
- gdImageSetBrush(gif, brush);
- for(ii=1;ii<im->xsize;ii++){
- if (isnan(im->gdes[i].p_data[ii-1]) ||
- isnan(im->gdes[i].p_data[ii]))
- continue;
- gdImageLine(gif,
- ii+im->xorigin-1,ytr(im,im->gdes[i].p_data[ii-1]),
+ canvas=gfx_new_canvas();
+
+ /* the actual graph is created by going through the individual
+ graph elements and then drawing them */
+
+ node=gfx_new_area ( canvas,
+ 0, 0,
+ im->xgif, 0,
+ im->xgif, im->ygif,
+ im->graph_col[GRC_BACK]);
+
+ gfx_add_point(node,0, im->ygif);
+
+ node=gfx_new_area ( canvas,
+ im->xorigin, im->yorigin,
+ im->xorigin + im->xsize, im->yorigin,
+ im->xorigin + im->xsize, im->yorigin-im->ysize,
+ im->graph_col[GRC_CANVAS]);
+
+ gfx_add_point(node,im->xorigin, im->yorigin - im->ysize);
+
+
+ if (im->minval > 0.0)
+ areazero = im->minval;
+ if (im->maxval < 0.0)
+ areazero = im->maxval;
+
+ axis_paint(im,canvas);
+
+
+ for(i=0;i<im->gdes_c;i++){
+ switch(im->gdes[i].gf){
+ case GF_CDEF:
+ case GF_VDEF:
+ case GF_DEF:
+ case GF_PRINT:
+ case GF_GPRINT:
+ case GF_COMMENT:
+ case GF_HRULE:
+ case GF_VRULE:
+ break;
+ case GF_TICK:
+ for (ii = 0; ii < im->xsize; ii++)
+ {
+ if (!isnan(im->gdes[i].p_data[ii]) &&
+ im->gdes[i].p_data[ii] > 0.0)
+ {
+ /* generate a tick */
+ gfx_new_line(canvas, im -> xorigin + ii,
+ im -> yorigin - (im -> gdes[i].yrule * im -> ysize),
+ im -> xorigin + ii,
+ im -> yorigin,
+ 1.0,
+ im -> gdes[i].col );
+ }
+ }
+ break;
+ case GF_LINE:
+ case GF_AREA:
+ stack_gf = im->gdes[i].gf;
+ case GF_STACK:
+ /* fix data points at oo and -oo */
+ for(ii=0;ii<im->xsize;ii++){
+ if (isinf(im->gdes[i].p_data[ii])){
+ if (im->gdes[i].p_data[ii] > 0) {
+ im->gdes[i].p_data[ii] = im->maxval ;
+ } else {
+ im->gdes[i].p_data[ii] = im->minval ;
+ }
+
+ }
+ } /* for */
+
+ if (im->gdes[i].col != 0x0){
+ /* GF_LINE and friend */
+ if(stack_gf == GF_LINE ){
+ node = NULL;
+ for(ii=1;ii<im->xsize;ii++){
+ if ( ! isnan(im->gdes[i].p_data[ii-1])
+ && ! isnan(im->gdes[i].p_data[ii])){
+ if (node == NULL){
+ node = gfx_new_line(canvas,
+ ii-1+im->xorigin,ytr(im,im->gdes[i].p_data[ii-1]),
ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]),
- gdBrushed);
-
- }
- gdImageDestroy(brush);
+ im->gdes[i].linewidth,
+ im->gdes[i].col);
+ } else {
+ gfx_add_point(node,ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]));
+ }
+ } else {
+ node = NULL;
+ }
+ }
+ } else {
+ int area_start=-1;
+ node = NULL;
+ for(ii=1;ii<im->xsize;ii++){
+ /* open an area */
+ if ( ! isnan(im->gdes[i].p_data[ii-1])
+ && ! isnan(im->gdes[i].p_data[ii])){
+ if (node == NULL){
+ float ybase = 0.0;
+ if (im->gdes[i].gf == GF_STACK) {
+ ybase = ytr(im,lastgdes->p_data[ii-1]);
+ } else {
+ ybase = ytr(im,areazero);
}
- else
- /* GF_AREA STACK type*/
- if (im->gdes[i].gf == GF_STACK )
- for(ii=0;ii<im->xsize;ii++){
- if(isnan(im->gdes[i].p_data[ii])){
- im->gdes[i].p_data[ii] = lastgdes->p_data[ii];
- continue;
- }
-
- if (lastgdes->p_data[ii] == im->gdes[i].p_data[ii]){
- continue;
- }
- gdImageLine(gif,
- ii+im->xorigin,ytr(im,lastgdes->p_data[ii]),
- ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]),
- im->gdes[i].col.i);
- }
-
- else /* simple GF_AREA */
- for(ii=0;ii<im->xsize;ii++){
- if (isnan(im->gdes[i].p_data[ii])) {
- im->gdes[i].p_data[ii] = 0;
- continue;
- }
- gdImageLine(gif,
- ii+im->xorigin,ytr(im,areazero),
- ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]),
- im->gdes[i].col.i);
- }
- }
- lastgdes = &(im->gdes[i]);
- break;
- }
- }
+ area_start = ii-1;
+ node = gfx_new_area(canvas,
+ ii-1+im->xorigin,ybase,
+ ii-1+im->xorigin,ytr(im,im->gdes[i].p_data[ii-1]),
+ ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]),
+ im->gdes[i].col
+ );
+ } else {
+ gfx_add_point(node,ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]));
+ }
+ }
+
+ if ( node != NULL && (ii+1==im->xsize || isnan(im->gdes[i].p_data[ii]) )){
+ /* GF_AREA STACK type*/
+ if (im->gdes[i].gf == GF_STACK ) {
+ int iii;
+ for (iii=ii-1;iii>area_start;iii--){
+ gfx_add_point(node,iii+im->xorigin,ytr(im,lastgdes->p_data[iii]));
+ }
+ } else {
+ gfx_add_point(node,ii+im->xorigin,ytr(im,areazero));
+ };
+ node=NULL;
+ };
+ }
+ } /* else GF_LINE */
+ } /* if color != 0x0 */
+ /* make sure we do not run into trouble when stacking on NaN */
+ for(ii=0;ii<im->xsize;ii++){
+ if (isnan(im->gdes[i].p_data[ii])) {
+ double ybase = 0.0;
+ if (lastgdes) {
+ ybase = ytr(im,lastgdes->p_data[ii-1]);
+ };
+ if (isnan(ybase) || !lastgdes ){
+ ybase = ytr(im,areazero);
+ }
+ im->gdes[i].p_data[ii] = ybase;
+ }
+ }
+ lastgdes = &(im->gdes[i]);
+ break;
+ } /* switch */
+ }
+ grid_paint(im,canvas);
+
+ /* the RULES are the last thing to paint ... */
+ for(i=0;i<im->gdes_c;i++){
- grid_paint(im,gif);
-
- /* the RULES are the last thing to paint ... */
- for(i=0;i<im->gdes_c;i++){
-
- switch(im->gdes[i].gf){
- case GF_HRULE:
- if(isnan(im->gdes[i].yrule)) { /* fetch variable */
- im->gdes[i].yrule = im->gdes[im->gdes[i].vidx].vf.val;
- };
- if(im->gdes[i].yrule >= im->minval
- && im->gdes[i].yrule <= im->maxval)
- gdImageLine(gif,
- im->xorigin,ytr(im,im->gdes[i].yrule),
- im->xorigin+im->xsize,ytr(im,im->gdes[i].yrule),
- im->gdes[i].col.i);
- break;
- case GF_VRULE:
- if(im->gdes[i].xrule == 0) { /* fetch variable */
- im->gdes[i].xrule = im->gdes[im->gdes[i].vidx].vf.when;
- };
- if(im->gdes[i].xrule >= im->start
- && im->gdes[i].xrule <= im->end)
- gdImageLine(gif,
- xtr(im,im->gdes[i].xrule),im->yorigin,
- xtr(im,im->gdes[i].xrule),im->yorigin-im->ysize,
- im->gdes[i].col.i);
- break;
- default:
- break;
- }
+ switch(im->gdes[i].gf){
+ case GF_HRULE:
+ printf("DEBUG: HRULE at %f\n",im->gdes[i].yrule);
+ if(isnan(im->gdes[i].yrule)) { /* fetch variable */
+ im->gdes[i].yrule = im->gdes[im->gdes[i].vidx].vf.val;
+ };
+ if(im->gdes[i].yrule >= im->minval
+ && im->gdes[i].yrule <= im->maxval)
+ gfx_new_line(canvas,
+ im->xorigin,ytr(im,im->gdes[i].yrule),
+ im->xorigin+im->xsize,ytr(im,im->gdes[i].yrule),
+ 1.0,im->gdes[i].col);
+ break;
+ case GF_VRULE:
+ if(im->gdes[i].xrule == 0) { /* fetch variable */
+ im->gdes[i].xrule = im->gdes[im->gdes[i].vidx].vf.when;
+ };
+ if(im->gdes[i].xrule >= im->start
+ && im->gdes[i].xrule <= im->end)
+ gfx_new_line(canvas,
+ xtr(im,im->gdes[i].xrule),im->yorigin,
+ xtr(im,im->gdes[i].xrule),im->yorigin-im->ysize,
+ 1.0,im->gdes[i].col);
+ break;
+ default:
+ break;
}
+ }
- if (strcmp(im->graphfile,"-")==0) {
+
+ if (strcmp(im->graphfile,"-")==0) {
#ifdef WIN32
- /* Change translation mode for stdout to BINARY */
- _setmode( _fileno( stdout ), O_BINARY );
+ /* Change translation mode for stdout to BINARY */
+ _setmode( _fileno( stdout ), O_BINARY );
#endif
- fo = stdout;
- } else {
- if ((fo = fopen(im->graphfile,"wb")) == NULL) {
- rrd_set_error("Opening '%s' for write: %s",im->graphfile, strerror(errno));
- return (-1);
- }
- }
- switch (im->imgformat) {
- case IF_GIF:
- gdImageGif(gif, fo);
- break;
- case IF_PNG:
- gdImagePng(gif, fo);
- break;
+ fo = stdout;
+ } else {
+ if ((fo = fopen(im->graphfile,"wb")) == NULL) {
+ rrd_set_error("Opening '%s' for write: %s",im->graphfile,
+ strerror(errno));
+ return (-1);
}
- if (strcmp(im->graphfile,"-") != 0)
- fclose(fo);
- gdImageDestroy(gif);
-
- return 0;
+ }
+ switch (im->imgformat) {
+ case IF_GIF:
+ break;
+ case IF_PNG:
+ gfx_render_png (canvas,im->xgif,im->ygif,im->zoom,0x0,fo);
+ break;
+ }
+ if (strcmp(im->graphfile,"-") != 0)
+ fclose(fo);
+
+ gfx_destroy(canvas);
+ return 0;
}
im->gdes[im->gdes_c-1].data_first=0;
im->gdes[im->gdes_c-1].p_data=NULL;
im->gdes[im->gdes_c-1].rpnp=NULL;
- im->gdes[im->gdes_c-1].col.red = -1;
- im->gdes[im->gdes_c-1].col.i=-1;
+ im->gdes[im->gdes_c-1].col = 0x0;
im->gdes[im->gdes_c-1].legend[0]='\0';
im->gdes[im->gdes_c-1].rrd[0]='\0';
im->gdes[im->gdes_c-1].ds=-1;
filename--;
}
- sprintf((*prdata)[0],im.imginfo,filename,im.xgif,im.ygif);
+ sprintf((*prdata)[0],im.imginfo,filename,(long)(im.zoom*im.xgif),(long)(im.zoom*im.ygif));
}
im_free(&im);
return 0;
im->prt_c = 0;
im->gdes_c = 0;
im->gdes = NULL;
+ im->zoom = 1.0;
im->imgformat = IF_GIF; /* we default to GIF output */
for(i=0;i<DIM(graph_col);i++)
- im->graph_col[i].red=-1;
+ im->graph_col[i]=graph_col[i];
+
+ for(i=0;i<DIM(text_prop);i++){
+ im->text_prop[i].size = text_prop[i].size;
+ im->text_prop[i].font = text_prop[i].font;
+ }
}
void
time_t start_tmp=0,end_tmp=0;
long long_tmp;
struct time_value start_tv, end_tv;
- unsigned int col_red,col_green,col_blue;
+ gfx_color_t color;
parsetime("end-24h", &start_tv);
parsetime("now", &end_tv);
{"base", required_argument, 0, 'b'},
{"logarithmic",no_argument, 0, 'o'},
{"color", required_argument, 0, 'c'},
+ {"font", required_argument, 0, 'n'},
{"title", required_argument, 0, 't'},
{"imginfo", required_argument, 0, 'f'},
{"imgformat", required_argument, 0, 'a'},
{"lazy", no_argument, 0, 'z'},
+ {"zoom", required_argument, 0, 'm'},
{"no-legend", no_argument, 0, 'g'},
{"alt-y-grid", no_argument, 0, 257 },
{"alt-autoscale", no_argument, 0, 258 },
opt = getopt_long(argc, argv,
- "s:e:x:y:v:w:h:iu:l:rb:oc:t:f:a:z:g",
+ "s:e:x:y:v:w:h:iu:l:rb:oc:n:m:t:f:a:z:g",
long_options, &option_index);
if (opt == EOF)
if (isnan(im->minval))
im->minval=1;
break;
- case 'c':
- if(sscanf(optarg,
- "%10[A-Z]#%2x%2x%2x",
- col_nam,&col_red,&col_green,&col_blue) == 4){
- int ci;
- if((ci=grc_conv(col_nam)) != -1){
- im->graph_col[ci].red=col_red;
- im->graph_col[ci].green=col_green;
- im->graph_col[ci].blue=col_blue;
- } else {
- rrd_set_error("invalid color name '%s'",col_nam);
- }
- } else {
- rrd_set_error("invalid color def format");
+ case 'c':
+ if(sscanf(optarg,
+ "%10[A-Z]#%8x",
+ col_nam,&color) == 2){
+ int ci;
+ if((ci=grc_conv(col_nam)) != -1){
+ im->graph_col[ci]=color;
+ } else {
+ rrd_set_error("invalid color name '%s'",col_nam);
+ }
+ } else {
+ rrd_set_error("invalid color def format");
+ return -1;
+ }
+ break;
+ case 'n':{
+ char *prop = "";
+ double size = 1;
+ char *font = "dummy";
+
+ if(sscanf(optarg,
+ "%10[A-Z]:%lf:%s",
+ prop,&size,font) == 3){
+ int sindex;
+ if((sindex=text_prop_conv(prop)) != -1){
+ im->text_prop[sindex].size=size;
+ im->text_prop[sindex].font=font;
+
+ } else {
+ rrd_set_error("invalid color name '%s'",col_nam);
+ }
+ } else {
+ rrd_set_error("invalid text property format");
+ return;
+ }
+ break;
+ }
+ case 'm':
+ im->zoom= atof(optarg);
+ if (im->zoom <= 0.0) {
+ rrd_set_error("zoom factor must be > 0");
return;
}
- break;
+ break;
case 't':
strncpy(im->title,optarg,150);
im->title[150]='\0';
char *line;
char funcname[10],vname[MAX_VNAME_LEN+1],sep[1];
double d;
+ double linewidth;
int j,k,l,m;
/* Each command is one element from *argv[], we call this "line".
** function:string for COMMENT
*/
argstart=0;
+
sscanf(line, "%10[A-Z0-9]:%n", funcname,&argstart);
if (argstart==0) {
rrd_set_error("Cannot parse function in line: %s",line);
im_free(im);
return;
}
- if ((gdp->gf=gf_conv(funcname))==-1) {
- rrd_set_error("'%s' is not a valid function name",funcname);
- im_free(im);
- return;
- }
+ if(sscanf(funcname,"LINE%lf",&linewidth)){
+ im->gdes[im->gdes_c-1].gf = GF_LINE;
+ im->gdes[im->gdes_c-1].linewidth = linewidth;
+ } else {
+ if ((gdp->gf=gf_conv(funcname))==-1) {
+ rrd_set_error("'%s' is not a valid function name",funcname);
+ im_free(im);
+ return;
+ }
+ }
/* If the error string is set, we exit at the end of the switch */
switch (gdp->gf) {
rrd_set_error("STACK must follow another graphing element");
break;
}
- case GF_LINE1:
- case GF_LINE2:
- case GF_LINE3:
+ case GF_LINE:
case GF_AREA:
case GF_TICK:
j=k=0;
} else {
int n=0;
char *rest;
- unsigned int R,G,B,A;
+ gfx_color_t col;
rest=strstr(color,":");
if (rest!=NULL)
switch (n) {
case 7:
- sscanf(color,"#%2x%2x%2x%n",&R,&G,&B,&n);
- A=255;
+ sscanf(color,"#%6x%n",&col,&n);
+ col = (col << 8) + 0xff /* shift left by 8 */;
if (n!=7) rrd_set_error("Color problem in %s",err);
break;
case 9:
- sscanf(color,"#%2x%2x%2x%2x%n",&R,&G,&B,&A,&n);
+ sscanf(color,"#%8x%n",&col,&n);
if (n==9) break;
default:
rrd_set_error("Color problem in %s",err);
}
if (rrd_test_error()) return 0;
- gdp->col.red = R;
- gdp->col.green = G;
- gdp->col.blue = B;
-/* gdp->col.alpha = A; */
-if (n==9) printf("WARNING: alpha channel not yet supported\n");
+ gdp->col = col;
return n;
}
}
#include "rrd_tool.h"
#include "rrd_rpncalc.h"
+#include "rrd_gfx.h"
#define MAX_VNAME_LEN 29
#define DEF_NAM_FMT "%29[_A-Za-z0-9]"
enum grc_en {GRC_CANVAS=0,GRC_BACK,GRC_SHADEA,GRC_SHADEB,
GRC_GRID,GRC_MGRID,GRC_FONT,GRC_FRAME,GRC_ARROW,__GRC_END__};
+#define MGRIDWIDTH 0.6
+#define GRIDWIDTH 0.4
-enum gf_en {GF_PRINT=0,GF_GPRINT,GF_COMMENT,GF_HRULE,GF_VRULE,GF_LINE1,
- GF_LINE2,GF_LINE3,GF_AREA,GF_STACK,GF_TICK,
+enum gf_en {GF_PRINT=0,GF_GPRINT,GF_COMMENT,GF_HRULE,GF_VRULE,GF_LINE,
+ GF_AREA,GF_STACK,GF_TICK,
GF_DEF, GF_CDEF, GF_VDEF};
enum if_en {IF_GIF=0,IF_PNG=1};
,VDEF_FIRST /* first non-unknown value and time */
,VDEF_LAST /* last non-unknown value and time */
};
+enum text_prop_en { TEXT_PROP_DEFAULT=0, /* default settings */
+ TEXT_PROP_TITLE, /* properties for the title */
+ TEXT_PROP_AXIS, /* for the numbers next to the axis */
+ TEXT_PROP_UNIT, /* for the vertical unit description */
+ TEXT_PROP_LEGEND, /* fot the legend below the graph */
+ TEXT_PROP_LAST };
+
+typedef struct text_prop_t {
+ double size;
+ char * font;
+} text_prop_t;
+
+
typedef struct vdef_t {
enum vdef_op_en op;
double param; /* parameter for function, if applicable */
time_t when; /* timestamp, if applicable */
} vdef_t;
-typedef struct col_trip_t {
- int red; /* red = -1 is no color */
- int green;
- int blue;
- int i; /* color index assigned in gif image i=-1 is unasigned*/
-} col_trip_t;
-
-
typedef struct xlab_t {
long minsec; /* minimum sec per pix */
enum tmt_en gridtm; /* grid interval in what ?*/
char *stst; /* strftime string*/
} xlab_t;
-#if 0
-xlab_t xlab[] = {
- {0, TMT_SECOND,30, TMT_MINUTE,5, TMT_MINUTE,5, 0,"%H:%M"},
- {2, TMT_MINUTE,1, TMT_MINUTE,5, TMT_MINUTE,5, 0,"%H:%M"},
- {5, TMT_MINUTE,2, TMT_MINUTE,10, TMT_MINUTE,10, 0,"%H:%M"},
- {10, TMT_MINUTE,5, TMT_MINUTE,20, TMT_MINUTE,20, 0,"%H:%M"},
- {30, TMT_MINUTE,10, TMT_HOUR,1, TMT_HOUR,1, 0,"%H:%M"},
- {60, TMT_MINUTE,30, TMT_HOUR,2, TMT_HOUR,2, 0,"%H:%M"},
- {180, TMT_HOUR,1, TMT_HOUR,6, TMT_HOUR,6, 0,"%H:%M"},
- /*{300, TMT_HOUR,3, TMT_HOUR,12, TMT_HOUR,12, 12*3600,"%a %p"}, this looks silly*/
- {600, TMT_HOUR,6, TMT_DAY,1, TMT_DAY,1, 24*3600,"%a"},
- {1800, TMT_HOUR,12, TMT_DAY,1, TMT_DAY,2, 24*3600,"%a"},
- {3600, TMT_DAY,1, TMT_WEEK,1, TMT_WEEK,1, 7*24*3600,"Week %W"},
- {3*3600, TMT_WEEK,1, TMT_MONTH,1, TMT_WEEK,2, 7*24*3600,"Week %W"},
- {6*3600, TMT_MONTH,1, TMT_MONTH,1, TMT_MONTH,1, 30*24*3600,"%b"},
- {48*3600, TMT_MONTH,1, TMT_MONTH,3, TMT_MONTH,3, 30*24*3600,"%b"},
- {10*24*3600, TMT_YEAR,1, TMT_YEAR,1, TMT_YEAR,1, 365*24*3600,"%y"},
- {-1,TMT_MONTH,0,TMT_MONTH,0,TMT_MONTH,0,0,""}
-};
-
-/* sensible logarithmic y label intervals ...
- the first element of each row defines the possible starting points on the
- y axis ... the other specify the */
-
-double yloglab[][12]= {{ 1e9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 1e3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 1e1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- /* { 1e1, 1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, */
- { 1e1, 1, 2.5, 5, 7.5, 0, 0, 0, 0, 0, 0, 0 },
- { 1e1, 1, 2, 4, 6, 8, 0, 0, 0, 0, 0, 0 },
- { 1e1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }};
-
-#endif
-
/* sensible y label intervals ...*/
typedef struct ylab_t {
int lfac[4]; /* associated label spacing*/
} ylab_t;
-#if 0
-ylab_t ylab[]= {
- {0.1, {1,2, 5,10}},
- {0.2, {1,5,10,20}},
- {0.5, {1,2, 4,10}},
- {1.0, {1,2, 5,10}},
- {2.0, {1,5,10,20}},
- {5.0, {1,2, 4,10}},
- {10.0, {1,2, 5,10}},
- {20.0, {1,5,10,20}},
- {50.0, {1,2, 4,10}},
- {100.0, {1,2, 5,10}},
- {200.0, {1,5,10,20}},
- {500.0, {1,2, 4,10}},
- {0.0, {0,0,0,0}}};
-
-
-
-col_trip_t graph_col[] = { /* default colors */
- {255,255,255,-1}, /* canvas */
- {245,245,245,-1}, /* background */
- {200,200,200,-1}, /* shade A */
- {150,150,150,-1}, /* shade B */
- {140,140,140,-1}, /* grid */
- {130,30,30,-1}, /* major grid */
- {0,0,0,-1}, /* font */
- {0,0,0,-1}, /* frame */
- {255,0,0,-1} /*arrow*/
-};
-
-#endif
/* this structure describes the elements which can make up a graph.
because they are quite diverse, not all elements will use all the
char ds_nam[DS_NAM_SIZE]; /* data source name */
long ds; /* data source number */
enum cf_en cf; /* consolidation function */
- col_trip_t col; /* graph color */
- char format[FMT_LEG_LEN+5]; /* format for PRINT AND GPRINT */
- char legend[FMT_LEG_LEN+5]; /* legend*/
- gdPoint legloc; /* location of legend */
+ gfx_color_t col; /* graph color */
+ char format[FMT_LEG_LEN+5]; /* format for PRINT AND GPRINT */
+ char legend[FMT_LEG_LEN+5]; /* legend*/
+ double leg_x,leg_y; /* location of legend */
double yrule; /* value for y rule line and for VDEF */
time_t xrule; /* time for x rule line and for VDEF */
vdef_t vf; /* instruction for VDEF function */
char **ds_namv; /* name of datasources in the fetch. */
rrd_value_t *data; /* the raw data drawn from the rrd */
rrd_value_t *p_data; /* processed data, xsize elments */
-
+ double linewidth; /* linewideth */
} graph_desc_t;
typedef struct image_desc_t {
char graphfile[MAXPATH]; /* filename for graphic */
long xsize,ysize; /* graph area size in pixels */
- col_trip_t graph_col[__GRC_END__]; /* real colors for the graph */
+ double zoom; /* zoom for graph */
+ gfx_color_t graph_col[__GRC_END__]; /* real colors for the graph */
+ text_prop_t text_prop[TEXT_PROP_LAST]; /* text properties */
char ylegend[200]; /* legend along the yaxis */
char title[200]; /* title for graph */
int draw_x_grid; /* no x-grid at all */
double ygridstep; /* user defined step for y grid */
int ylabfact; /* every how many y grid shall a label be written ? */
-
+ double tabwidth; /* tabwdith */
time_t start,end; /* what time does the graph cover */
- unsigned long step; /* any preference for the default step ? */
+ unsigned long step; /* any preference for the default step ? */
rrd_value_t minval,maxval; /* extreme values in the data */
int rigid; /* do not expand range even with
values outside */
- char* imginfo; /* construct an <IMG ... tag and return
+ char* imginfo; /* construct an <IMG ... tag and return
as first retval */
int lazy; /* only update the gif if there is reasonable
probablility that the existing one is out of date */
int logarithmic; /* scale the yaxis logarithmic */
- enum if_en imgformat; /* image format */
+ enum if_en imgformat; /* image format */
/* status information */
enum if_en if_conv(char *);
enum tmt_en tmt_conv(char *);
enum grc_en grc_conv(char *);
+enum grc_en text_prop_conv(char *);
int im_free(image_desc_t *);
void auto_scale( image_desc_t *, double *, char **, double *);
void si_unit( image_desc_t *);
int data_proc( image_desc_t *);
time_t find_first_time( time_t, enum tmt_en, long);
time_t find_next_time( time_t, enum tmt_en, long);
-void gator( gdImagePtr, int, int);
int print_calc(image_desc_t *, char ***);
int leg_place(image_desc_t *);
-int horizontal_grid(gdImagePtr, image_desc_t *);
-int horizontal_log_grid(gdImagePtr, image_desc_t *);
-void vertical_grid( gdImagePtr, image_desc_t *);
-void axis_paint( image_desc_t *, gdImagePtr);
-void grid_paint( image_desc_t *, gdImagePtr);
-gdImagePtr MkLineBrush(image_desc_t *,long, enum gf_en);
+int horizontal_grid(gfx_canvas_t *,image_desc_t *);
+int horizontal_log_grid(gfx_canvas_t *, image_desc_t *);
+void vertical_grid(gfx_canvas_t *, image_desc_t *);
+void axis_paint( image_desc_t *, gfx_canvas_t *);
+void grid_paint( image_desc_t *, gfx_canvas_t *);
int lazy_check(image_desc_t *);
int graph_paint(image_desc_t *, char ***);
int gdes_alloc(image_desc_t *);
"\t\t[-u|--upper-limit value] [-z|--lazy]\n"
"\t\t[-l|--lower-limit value] [-r|--rigid]\n"
"\t\t[-g|--no-legend]\n"
+ "\t\t[--font FONTTAG:size:font]\n"
+ "\t\t[--zoom factor]\n"
"\t\t[--alt-autoscale]\n"
"\t\t[--alt-autoscale-max]\n"
"\t\t[--units-exponent value]\n"
"\t\t[--step seconds]\n"
"\t\t[-f|--imginfo printfstr]\n"
"\t\t[-a|--imgformat GIF|PNG]\n"
- "\t\t[-c|--color COLORTAG#rrggbb] [-t|--title string]\n"
+ "\t\t[-c|--color COLORTAG#rrggbb[aa]] [-t|--title string]\n"
"\t\t[DEF:vname=rrd:ds-name:CF]\n"
"\t\t[CDEF:vname=rpn-expression]\n"
"\t\t[PRINT:vname:CF:format]\n"
"\t\t[GPRINT:vname:CF:format]\n"
- "\t\t[HRULE:value#rrggbb[:legend]]\n"
- "\t\t[VRULE:value#rrggbb[:legend]]\n"
- "\t\t[LINE{1|2|3}:vname[#rrggbb[:legend]]]\n"
- "\t\t[AREA:vname[#rrggbb[:legend]]]\n"
- "\t\t[STACK:vname[#rrggbb[:legend]]]\n\n";
+ "\t\t[HRULE:value#rrggbb[aa][:legend]]\n"
+ "\t\t[VRULE:value#rrggbb[aa][:legend]]\n"
+ "\t\t[LINE{1|2|3}:vname[#rrggbb[aa][:legend]]]\n"
+ "\t\t[AREA:vname[#rrggbb[aa][:legend]]]\n"
+ "\t\t[STACK:vname[#rrggbb[aa][:legend]]]\n\n";
char help_tune[] =
" * tune - Modify some basic properties of an RRD\n\n"
info_t *rrd_info(int, char **);
/* HELPER FUNCTIONS */
+
int GifSize(FILE *, long *, long *);
int PngSize(FILE *, long *, long *);
int PngSize(FILE *, long *, long *);
-#include <gd.h>
-void gdImagePng(gdImagePtr im, FILE *out);
-
int rrd_create_fn(char *file_name, rrd_t *rrd);
int rrd_fetch_fn(char *filename, enum cf_en cf_idx,
time_t *start,time_t *end,