Change to using external TTF library, when available, otherwise local copy.

Fix pkgconfig file.
This commit is contained in:
Michael R Sweet
2025-12-21 20:28:26 -05:00
parent f6f3191a8d
commit 7ac8669057
11 changed files with 240 additions and 2820 deletions

1
.gitignore vendored
View File

@@ -25,5 +25,4 @@
/pdfio-*.zip*
/testpdfio
/testpdfio-*.pdf
/testttf
/x64

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "ttf"]
path = ttf
url = https://github.com/michaelrsweet/ttf.git

View File

@@ -5,6 +5,7 @@ Changes in PDFio
v1.7.0 - YYYY-MM-DD
-------------------
- Now use TTF 1.1 or later for font support.
v1.6.1 - YYYY-MM-DD
@@ -17,6 +18,7 @@ v1.6.1 - YYYY-MM-DD
indirect reference (Issue #139)
- Fixed character range checking in a TTF support function.
- Fixed some clang warnings.
- Fixed the generated pkg-config file.

View File

@@ -69,6 +69,8 @@ top_srcdir = @top_srcdir@
BUILDROOT = $(DSTROOT)$(RPM_BUILD_ROOT)$(DESTDIR)
TTFDIR = @TTFDIR@
# Build commands...
.SUFFIXES: .c .h .o
@@ -99,17 +101,14 @@ PUBOBJS = \
pdfio-token.o \
pdfio-value.o
LIBOBJS = \
$(PUBOBJS) \
ttf.o
$(PUBOBJS)
OBJS = \
$(LIBOBJS) \
testpdfio.o \
testttf.o
testpdfio.o
TARGETS = \
$(LIBPDFIO) \
$(LIBPDFIO_STATIC) \
testpdfio \
testttf
testpdfio
DOCFILES = \
doc/pdfio.html \
doc/pdfio-512.png \
@@ -135,16 +134,30 @@ EXAMPLES = \
# Make everything
all: $(TARGETS)
all:
if test "x$(TTFDIR)" != x; then \
echo Making all in $(TTFDIR)...; \
(cd $(TTFDIR); $(MAKE) $(MFLAGS) all) || exit 1; \
fi
$(MAKE) $(MFLAGS) $(TARGETS)
# Clean everything
clean:
if test "x$(TTFDIR)" != x; then \
echo Cleaning in $(TTFDIR)...; \
(cd $(TTFDIR); $(MAKE) $(MFLAGS) clean) || exit 1; \
fi
echo Cleaning build files...
rm -f $(TARGETS) $(OBJS)
# Install everything
install: $(TARGETS)
if test "x$(TTFDIR)" != x; then \
echo Installing in $(TTFDIR)...; \
(cd $(TTFDIR); $(MAKE) $(MFLAGS) install) || exit 1; \
fi
echo Installing header files to $(BUILDROOT)$(includedir)...
$(INSTALL) -d -m 755 $(BUILDROOT)$(includedir)
for file in $(PUBHEADERS); do \
@@ -232,18 +245,10 @@ testpdfio: testpdfio.o libpdfio.a
$(CC) $(LDFLAGS) -o $@ testpdfio.o libpdfio.a $(LIBS)
# TTF test program
testttf: ttf.o testttf.o
echo Linking $@...
$(CC) $(LDFLAGS) -o testttf ttf.o testttf.o $(LIBS)
# Dependencies
$(OBJS): pdfio.h pdfio-private.h Makefile
pdfio-content.o: pdfio-content.h ttf.h
pdfio-content.o: pdfio-content.h
testpdfio.o: test.h
testttf.o: ttf.h
ttf.o: ttf.h
# Make documentation using Codedoc <https://www.msweet.org/codedoc>

194
configure vendored
View File

@@ -647,13 +647,16 @@ ac_includes_default="\
#endif"
ac_header_c_list=
enable_option_checking=no
ac_subst_vars='LTLIBOBJS
LIBOBJS
WARNINGS
CSFLAGS
LIBPDFIO_STATIC
LIBPDFIO
PKGCONFIG_LIBPNG
TTFDIR
subdirs
PKGCONFIG_REQUIRES_PRIVATE
PKGCONFIG_REQUIRES
PKGCONFIG_LIBS_PRIVATE
PKGCONFIG_LIBS
@@ -747,7 +750,7 @@ CFLAGS
LDFLAGS
LIBS
CPPFLAGS'
ac_subdirs_all='ttf'
# Initialize some variables set by options.
ac_init_help=
@@ -4138,13 +4141,44 @@ fi
PKGCONFIG_CFLAGS="-I\${includedir}"
PKGCONFIG_LIBS="-L\${libdir} -lpdfio"
PKGCONFIG_LIBS_PRIVATE="-lm"
PKGCONFIG_REQUIRES="zlib"
PKGCONFIG_REQUIRES=""
PKGCONFIG_REQUIRES_PRIVATE="ttf"
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ttf library" >&5
printf %s "checking for ttf library... " >&6; }
if $PKGCONFIG --exists ttf
then :
# Use installed TTF library...
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }
CPPFLAGS="$CPPFLAGS $($PKGCONFIG --cflags ttf)"
TTFDIR=""
LIBS="$($PKGCONFIG --libs ttf) $LIBS"
else $as_nop
# Use embedded TTF library...
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using embedded version" >&5
printf "%s\n" "no, using embedded version" >&6; }
CPPFLAGS="$CPPFLAGS -Ittf"
TTFDIR="ttf"
LIBS="-Lttf \`PKG_CONFIG_PATH=ttf $PKGCONFIG --libs ttf\` $LIBS"
subdirs="$subdirs ttf"
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for zlib via pkg-config" >&5
printf %s "checking for zlib via pkg-config... " >&6; }
if $PKGCONFIG --exists zlib
@@ -4154,6 +4188,7 @@ then :
printf "%s\n" "yes" >&6; }
CPPFLAGS="$($PKGCONFIG --cflags zlib) $CPPFLAGS"
LIBS="$($PKGCONFIG --libs zlib) $LIBS"
PKGCONFIG_REQUIRES_PRIVATE="$PKGCONFIG_REQUIRES_PRIVATE, zlib"
else $as_nop
@@ -4216,11 +4251,11 @@ then :
fi
PKGCONFIG_REQUIRES=""
PKGCONFIG_LIBS_PRIVATE="-lz $PKGCONFIG_LIBS_PRIVATE"
fi
# Check whether --enable-libpng was given.
if test ${enable_libpng+y}
then :
@@ -4228,9 +4263,6 @@ then :
fi
PKGCONFIG_LIBPNG=""
if test "x$PKGCONFIG" != x -a x$enable_libpng != xno
then :
@@ -4246,8 +4278,7 @@ printf "%s\n" "#define HAVE_LIBPNG 1" >>confdefs.h
CPPFLAGS="$($PKGCONFIG --cflags libpng16) -DHAVE_LIBPNG=1 $CPPFLAGS"
LIBS="$($PKGCONFIG --libs libpng16) -lz $LIBS"
PKGCONFIG_LIBS_PRIVATE="$($PKGCONFIG --libs libpng16) $PKGCONFIG_LIBS_PRIVATE"
PKGCONFIG_REQUIRES="libpng >= 1.6,$PKGCONFIG_REQUIRES"
PKGCONFIG_REQUIRES_PRIVATE="libpng >= 1.6, $PKGCONFIG_REQUIRES_PRIVATE"
else $as_nop
@@ -4314,6 +4345,8 @@ else $as_nop
LIBPDFIO_STATIC=""
PKGCONFIG_LIBS="$PKGCONFIG_LIBS $PKGCONFIG_LIBS_PRIVATE"
PKGCONFIG_LIBS_PRIVATE=""
PKGCONFIG_REQUIRES="$PKGCONFIG_REQUIRES_PRIVATE"
PKGCONFIG_REQUIRES_PRIVATE=""
fi
@@ -5718,6 +5751,149 @@ if test "$no_create" != yes; then
# would make configure fail if this is the last instruction.
$ac_cs_success || as_fn_exit 1
fi
#
# CONFIG_SUBDIRS section.
#
if test "$no_recursion" != yes; then
# Remove --cache-file, --srcdir, and --disable-option-checking arguments
# so they do not pile up.
ac_sub_configure_args=
ac_prev=
eval "set x $ac_configure_args"
shift
for ac_arg
do
if test -n "$ac_prev"; then
ac_prev=
continue
fi
case $ac_arg in
-cache-file | --cache-file | --cache-fil | --cache-fi \
| --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
ac_prev=cache_file ;;
-cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
| --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \
| --c=*)
;;
--config-cache | -C)
;;
-srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
ac_prev=srcdir ;;
-srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
;;
-prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
ac_prev=prefix ;;
-prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
;;
--disable-option-checking)
;;
*)
case $ac_arg in
*\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
esac
as_fn_append ac_sub_configure_args " '$ac_arg'" ;;
esac
done
# Always prepend --prefix to ensure using the same prefix
# in subdir configurations.
ac_arg="--prefix=$prefix"
case $ac_arg in
*\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
esac
ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args"
# Pass --silent
if test "$silent" = yes; then
ac_sub_configure_args="--silent $ac_sub_configure_args"
fi
# Always prepend --disable-option-checking to silence warnings, since
# different subdirs can have different --enable and --with options.
ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args"
ac_popdir=`pwd`
for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue
# Do not complain, so a configure script can configure whichever
# parts of a large source tree are present.
test -d "$srcdir/$ac_dir" || continue
ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)"
printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5
printf "%s\n" "$ac_msg" >&6
as_dir="$ac_dir"; as_fn_mkdir_p
ac_builddir=.
case "$ac_dir" in
.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
*)
ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'`
# A ".." for each directory in $ac_dir_suffix.
ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
case $ac_top_builddir_sub in
"") ac_top_builddir_sub=. ac_top_build_prefix= ;;
*) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
esac ;;
esac
ac_abs_top_builddir=$ac_pwd
ac_abs_builddir=$ac_pwd$ac_dir_suffix
# for backward compatibility:
ac_top_builddir=$ac_top_build_prefix
case $srcdir in
.) # We are building in place.
ac_srcdir=.
ac_top_srcdir=$ac_top_builddir_sub
ac_abs_top_srcdir=$ac_pwd ;;
[\\/]* | ?:[\\/]* ) # Absolute name.
ac_srcdir=$srcdir$ac_dir_suffix;
ac_top_srcdir=$srcdir
ac_abs_top_srcdir=$srcdir ;;
*) # Relative name.
ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
ac_top_srcdir=$ac_top_build_prefix$srcdir
ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
esac
ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
cd "$ac_dir"
# Check for configure.gnu first; this name is used for a wrapper for
# Metaconfig's "Configure" on case-insensitive file systems.
if test -f "$ac_srcdir/configure.gnu"; then
ac_sub_configure=$ac_srcdir/configure.gnu
elif test -f "$ac_srcdir/configure"; then
ac_sub_configure=$ac_srcdir/configure
else
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5
printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2;}
ac_sub_configure=
fi
# The recursion is here.
if test -n "$ac_sub_configure"; then
# Make the cache file name correct relative to the subdirectory.
case $cache_file in
[\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;;
*) # Relative name.
ac_sub_cache_file=$ac_top_build_prefix$cache_file ;;
esac
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5
printf "%s\n" "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;}
# The eval makes quoting arguments work.
eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \
--cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" ||
as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5
fi
cd "$ac_popdir"
done
fi
if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}

View File

@@ -119,11 +119,32 @@ AC_PATH_TOOL([PKGCONFIG], [pkg-config])
PKGCONFIG_CFLAGS="-I\${includedir}"
PKGCONFIG_LIBS="-L\${libdir} -lpdfio"
PKGCONFIG_LIBS_PRIVATE="-lm"
PKGCONFIG_REQUIRES="zlib"
PKGCONFIG_REQUIRES=""
PKGCONFIG_REQUIRES_PRIVATE="ttf"
AC_SUBST([PKGCONFIG_CFLAGS])
AC_SUBST([PKGCONFIG_LIBS])
AC_SUBST([PKGCONFIG_LIBS_PRIVATE])
AC_SUBST([PKGCONFIG_REQUIRES])
AC_SUBST([PKGCONFIG_REQUIRES_PRIVATE])
dnl TTF library for font support...
AC_MSG_CHECKING([for ttf library])
AS_IF([$PKGCONFIG --exists ttf], [
# Use installed TTF library...
AC_MSG_RESULT([yes])
CPPFLAGS="$CPPFLAGS $($PKGCONFIG --cflags ttf)"
TTFDIR=""
LIBS="$($PKGCONFIG --libs ttf) $LIBS"
], [
# Use embedded TTF library...
AC_MSG_RESULT([no, using embedded version])
CPPFLAGS="$CPPFLAGS -Ittf"
TTFDIR="ttf"
LIBS="-Lttf \`PKG_CONFIG_PATH=ttf $PKGCONFIG --libs ttf\` $LIBS"
AC_CONFIG_SUBDIRS([ttf])
])
AC_SUBST([TTFDIR])
dnl ZLIB
@@ -132,6 +153,7 @@ AS_IF([$PKGCONFIG --exists zlib], [
AC_MSG_RESULT([yes])
CPPFLAGS="$($PKGCONFIG --cflags zlib) $CPPFLAGS"
LIBS="$($PKGCONFIG --libs zlib) $LIBS"
PKGCONFIG_REQUIRES_PRIVATE="$PKGCONFIG_REQUIRES_PRIVATE, zlib"
],[
AC_MSG_RESULT([no])
AC_CHECK_HEADER([zlib.h])
@@ -141,16 +163,13 @@ AS_IF([$PKGCONFIG --exists zlib], [
AC_MSG_ERROR([Sorry, this software requires zlib 1.1 or higher.])
])
PKGCONFIG_REQUIRES=""
PKGCONFIG_LIBS_PRIVATE="-lz $PKGCONFIG_LIBS_PRIVATE"
])
dnl libpng...
AC_ARG_ENABLE([libpng], AS_HELP_STRING([--enable-libpng], [use libpng for pdfioFileCreateImageObjFromFile, default=auto]))
PKGCONFIG_LIBPNG=""
AC_SUBST([PKGCONFIG_LIBPNG])
AS_IF([test "x$PKGCONFIG" != x -a x$enable_libpng != xno], [
AC_MSG_CHECKING([for libpng-1.6.x])
AS_IF([$PKGCONFIG --exists libpng16], [
@@ -158,8 +177,7 @@ AS_IF([test "x$PKGCONFIG" != x -a x$enable_libpng != xno], [
AC_DEFINE([HAVE_LIBPNG], 1, [Have PNG library?])
CPPFLAGS="$($PKGCONFIG --cflags libpng16) -DHAVE_LIBPNG=1 $CPPFLAGS"
LIBS="$($PKGCONFIG --libs libpng16) -lz $LIBS"
PKGCONFIG_LIBS_PRIVATE="$($PKGCONFIG --libs libpng16) $PKGCONFIG_LIBS_PRIVATE"
PKGCONFIG_REQUIRES="libpng >= 1.6,$PKGCONFIG_REQUIRES"
PKGCONFIG_REQUIRES_PRIVATE="libpng >= 1.6, $PKGCONFIG_REQUIRES_PRIVATE"
], [
AC_MSG_RESULT([no]);
AS_IF([test x$enable_libpng = xyes], [
@@ -192,6 +210,8 @@ AS_IF([test x$enable_shared = xyes], [
LIBPDFIO_STATIC=""
PKGCONFIG_LIBS="$PKGCONFIG_LIBS $PKGCONFIG_LIBS_PRIVATE"
PKGCONFIG_LIBS_PRIVATE=""
PKGCONFIG_REQUIRES="$PKGCONFIG_REQUIRES_PRIVATE"
PKGCONFIG_REQUIRES_PRIVATE=""
])
AC_SUBST([LIBPDFIO])

View File

@@ -11,3 +11,4 @@ Cflags: @PKGCONFIG_CFLAGS@
Libs: @PKGCONFIG_LIBS@
Libs.private: @PKGCONFIG_LIBS_PRIVATE@
Requires: @PKGCONFIG_REQUIRES@
Requires.private: @PKGCONFIG_REQUIRES_PRIVATE@

396
testttf.c
View File

@@ -1,396 +0,0 @@
//
// Unit test program for TTF library
//
// https://github.com/michaelrsweet/ttf
//
// Copyright © 2018-2025 by Michael R Sweet.
//
// Licensed under Apache License v2.0. See the file "LICENSE" for more
// information.
//
// Usage:
//
// ./testttf [FILENAME]
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include "ttf.h"
//
// Local functions...
//
static void error_cb(void *data, const char *message);
static int test_font(const char *filename);
//
// 'main()' - Main entry for unit tests.
//
int // O - Exit status
main(int argc, // I - Number of command-line arguments
char *argv[]) // I - Command-line arguments
{
int i; // Looping var
int errors = 0; // Number of errors
if (argc > 1)
{
for (i = 1; i < argc; i ++)
errors += test_font(argv[i]);
}
else
{
// Test with the bundled TrueType files...
errors += test_font("testfiles/OpenSans-Bold.ttf");
errors += test_font("testfiles/OpenSans-Regular.ttf");
errors += test_font("testfiles/NotoSansJP-Regular.otf");
}
if (!errors)
puts("\nALL TESTS PASSED");
else
printf("\n%d TEST(S) FAILED\n", errors);
return (errors);
}
//
// 'error_cb()' - Error callback.
//
static void
error_cb(void *data, // I - User data (not used)
const char *message) // I - Message string
{
fprintf(stderr, "FAIL (%s)\n", message);
}
//
// 'test_font()' - Test a font file.
//
static int // O - Number of errors
test_font(const char *filename) // I - Font filename
{
int i, // Looping var
errors = 0; // Number of errors
ttf_t *font; // Font
struct stat fileinfo; // Font file information
FILE *fp = NULL; // File pointer
void *data = NULL; // Memory buffer for font file
const char *value; // Font (string) value
int intvalue; // Font (integer) value
float realvalue; // Font (real) value
char psname[1024]; // Postscript font name
ttf_rect_t bounds; // Bounds
ttf_rect_t extents; // Extents
size_t num_fonts; // Number of fonts
ttf_style_t style; // Font style
ttf_weight_t weight; // Font weight
static const char * const stretches[] =
{ // Font stretch strings
"TTF_STRETCH_NORMAL", // normal
"TTF_STRETCH_ULTRA_CONDENSED", // ultra-condensed
"TTF_STRETCH_EXTRA_CONDENSED", // extra-condensed
"TTF_STRETCH_CONDENSED", // condensed
"TTF_STRETCH_SEMI_CONDENSED", // semi-condensed
"TTF_STRETCH_SEMI_EXPANDED", // semi-expanded
"TTF_STRETCH_EXPANDED", // expanded
"TTF_STRETCH_EXTRA_EXPANDED", // extra-expanded
"TTF_STRETCH_ULTRA_EXPANDED" // ultra-expanded
};
static const char * const strings[] = // Test strings
{
"Hello, World!", // English
"مرحبا بالعالم!", // Arabic
"Bonjour le monde!", // French
"Γειά σου Κόσμε!", // Greek
"שלום עולם!", // Hebrew
"Привет мир!", // Russian
"こんにちは世界!" // Japanese
};
static const char * const styles[] = // Font style names
{
"TTF_STYLE_NORMAL",
"TTF_STYLE_ITALIC",
"TTF_STYLE_OBLIQUE"
};
printf("ttfCreate(\"%s\"): ", filename);
fflush(stdout);
if ((font = ttfCreate(filename, 0, error_cb, NULL)) != NULL)
puts("PASS");
else
errors ++;
fputs("ttfGetAscent: ", stdout);
if ((intvalue = ttfGetAscent(font)) > 0)
{
printf("PASS (%d)\n", intvalue);
}
else
{
printf("FAIL (%d)\n", intvalue);
errors ++;
}
fputs("ttfGetBounds: ", stdout);
if (ttfGetBounds(font, &bounds))
{
printf("PASS (%g %g %g %g)\n", bounds.left, bounds.bottom, bounds.right, bounds.top);
}
else
{
puts("FAIL");
errors ++;
}
fputs("ttfGetCapHeight: ", stdout);
if ((intvalue = ttfGetCapHeight(font)) > 0)
{
printf("PASS (%d)\n", intvalue);
}
else
{
printf("FAIL (%d)\n", intvalue);
errors ++;
}
fputs("ttfGetCopyright: ", stdout);
if ((value = ttfGetCopyright(font)) != NULL)
{
printf("PASS (%s)\n", value);
}
else
{
puts("WARNING (no copyright found)");
}
for (i = 0; i < (int)(sizeof(strings) / sizeof(strings[0])); i ++)
{
printf("ttfGetExtents(\"%s\"): ", strings[i]);
if (ttfGetExtents(font, 12.0f, strings[i], &extents))
{
printf("PASS (%.1f %.1f %.1f %.1f)\n", extents.left, extents.bottom, extents.right, extents.top);
}
else
{
puts("FAIL");
errors ++;
}
}
fputs("ttfGetFamily: ", stdout);
if ((value = ttfGetFamily(font)) != NULL)
{
printf("PASS (%s)\n", value);
}
else
{
puts("FAIL");
errors ++;
}
fputs("ttfGetItalicAngle: ", stdout);
if ((realvalue = ttfGetItalicAngle(font)) >= -180.0 && realvalue <= 180.0)
{
printf("PASS (%g)\n", realvalue);
}
else
{
printf("FAIL (%g)\n", realvalue);
errors ++;
}
fputs("ttfGetNumFonts: ", stdout);
if ((num_fonts = ttfGetNumFonts(font)) > 0)
{
printf("PASS (%u)\n", (unsigned)num_fonts);
}
else
{
puts("FAIL");
errors ++;
}
fputs("ttfGetPostScriptName: ", stdout);
if ((value = ttfGetPostScriptName(font)) != NULL)
{
printf("PASS (%s)\n", value);
strncpy(psname, value, sizeof(psname) - 1);
psname[sizeof(psname) - 1] = '\0';
}
else
{
puts("FAIL");
errors ++;
}
fputs("ttfGetStretch: ", stdout);
if ((intvalue = (int)ttfGetStretch(font)) >= TTF_STRETCH_NORMAL && intvalue <= TTF_STRETCH_ULTRA_EXPANDED)
{
printf("PASS (%s)\n", stretches[intvalue]);
}
else
{
printf("FAIL (%d)\n", intvalue);
errors ++;
}
fputs("ttfGetStyle: ", stdout);
if ((style = ttfGetStyle(font)) >= TTF_STYLE_NORMAL && style <= TTF_STYLE_ITALIC)
{
printf("PASS (%s)\n", styles[style]);
}
else
{
puts("FAIL");
errors ++;
}
fputs("ttfGetVersion: ", stdout);
if ((value = ttfGetVersion(font)) != NULL)
{
printf("PASS (%s)\n", value);
}
else
{
puts("FAIL");
errors ++;
}
fputs("ttfGetWeight: ", stdout);
if ((weight = ttfGetWeight(font)) >= 0)
{
printf("PASS (%u)\n", (unsigned)weight);
}
else
{
puts("FAIL");
errors ++;
}
fputs("ttfGetWidth(' '): ", stdout);
if ((intvalue = ttfGetWidth(font, ' ')) > 0)
{
printf("PASS (%d)\n", intvalue);
}
else
{
printf("FAIL (%d)\n", intvalue);
errors ++;
}
fputs("ttfGetXHeight: ", stdout);
if ((intvalue = ttfGetXHeight(font)) > 0)
{
printf("PASS (%d)\n", intvalue);
}
else
{
printf("FAIL (%d)\n", intvalue);
errors ++;
}
fputs("ttfIsFixedPitch: ", stdout);
if (ttfIsFixedPitch(font))
puts("PASS (true)");
else
puts("PASS (false)");
ttfDelete(font);
font = NULL;
// Now copy the font to memory and open it that way...
printf("fopen(\"%s\", \"rb\"): ", filename);
if ((fp = fopen(filename, "rb")) == NULL)
{
printf("FAIL (%s)\n", strerror(errno));
errors ++;
}
else
{
printf("PASS (%d)\n", fileno(fp));
printf("fstat(%d): ", fileno(fp));
if (fstat(fileno(fp), &fileinfo))
{
printf("FAIL (%s)\n", strerror(errno));
errors ++;
}
else
{
printf("PASS (%lu bytes)\n", (unsigned long)fileinfo.st_size);
fputs("malloc(): ", stdout);
if ((data = malloc((size_t)fileinfo.st_size)) == NULL)
{
printf("FAIL (%s)\n", strerror(errno));
errors ++;
}
else
{
puts("PASS");
fputs("fread(): ", stdout);
if (fread(data, (size_t)fileinfo.st_size, 1, fp) != 1)
{
printf("FAIL (%s)\n", strerror(errno));
errors ++;
}
else
{
puts("PASS");
fputs("ttfCreateData(): ", stdout);
if ((font = ttfCreateData(data, (size_t)fileinfo.st_size, /*idx*/0, error_cb, /*err_data*/NULL)) == NULL)
{
puts("FAIL");
errors ++;
}
else
{
puts("PASS");
fputs("ttfGetPostScriptName: ", stdout);
if ((value = ttfGetPostScriptName(font)) != NULL)
{
if (!strcmp(value, psname))
{
printf("PASS (%s)\n", value);
}
else
{
printf("FAIL (got \"%s\", expected \"%s\")\n", value, psname);
errors ++;
}
}
else
{
puts("FAIL");
errors ++;
}
}
}
}
}
if (fp)
fclose(fp);
free(data);
ttfDelete(font);
}
return (errors);
}

1
ttf Submodule

Submodule ttf added at efbdbf3074

2280
ttf.c

File diff suppressed because it is too large Load Diff

111
ttf.h
View File

@@ -1,111 +0,0 @@
//
// Header file for TTF library
//
// https://github.com/michaelrsweet/ttf
//
// Copyright © 2018-2025 by Michael R Sweet.
//
// Licensed under Apache License v2.0. See the file "LICENSE" for more
// information.
//
#ifndef TTF_H
# define TTF_H
# include <stddef.h>
# include <stdbool.h>
# include <sys/types.h>
# ifdef __cplusplus
extern "C" {
# endif // __cplusplus
//
// Types...
//
typedef struct _ttf_s ttf_t; // Font object
typedef void (*ttf_err_cb_t)(void *data, const char *message);
// Font error callback
typedef enum ttf_stretch_e // Font stretch
{
TTF_STRETCH_NORMAL, // normal
TTF_STRETCH_ULTRA_CONDENSED, // ultra-condensed
TTF_STRETCH_EXTRA_CONDENSED, // extra-condensed
TTF_STRETCH_CONDENSED, // condensed
TTF_STRETCH_SEMI_CONDENSED, // semi-condensed
TTF_STRETCH_SEMI_EXPANDED, // semi-expanded
TTF_STRETCH_EXPANDED, // expanded
TTF_STRETCH_EXTRA_EXPANDED, // extra-expanded
TTF_STRETCH_ULTRA_EXPANDED // ultra-expanded
} ttf_stretch_t;
typedef enum ttf_style_e // Font style
{
TTF_STYLE_NORMAL, // Normal font
TTF_STYLE_ITALIC, // Italic font
TTF_STYLE_OBLIQUE // Oblique (angled) font
} ttf_style_t;
typedef enum ttf_variant_e // Font variant
{
TTF_VARIANT_NORMAL, // Normal font
TTF_VARIANT_SMALL_CAPS // Font whose lowercase letters are small capitals
} ttf_variant_t;
typedef enum ttf_weight_e // Font weight
{
TTF_WEIGHT_100 = 100, // Weight 100 (Thin)
TTF_WEIGHT_200 = 200, // Weight 200 (Extra/Ultra-Light)
TTF_WEIGHT_300 = 300, // Weight 300 (Light)
TTF_WEIGHT_400 = 400, // Weight 400 (Normal/Regular)
TTF_WEIGHT_500 = 500, // Weight 500 (Medium)
TTF_WEIGHT_600 = 600, // Weight 600 (Semi/Demi-Bold)
TTF_WEIGHT_700 = 700, // Weight 700 (Bold)
TTF_WEIGHT_800 = 800, // Weight 800 (Extra/Ultra-Bold)
TTF_WEIGHT_900 = 900 // Weight 900 (Black/Heavy)
} ttf_weight_t;
typedef struct ttf_rect_s // Bounding rectangle
{
float left; // Left offset
float top; // Top offset
float right; // Right offset
float bottom; // Bottom offset
} ttf_rect_t;
//
// Functions...
//
extern ttf_t *ttfCreate(const char *filename, size_t idx, ttf_err_cb_t err_cb, void *err_data);
extern ttf_t *ttfCreateData(const void *data, size_t data_size, size_t idx, ttf_err_cb_t err_cb, void *err_data);
extern void ttfDelete(ttf_t *font);
extern int ttfGetAscent(ttf_t *font);
extern ttf_rect_t *ttfGetBounds(ttf_t *font, ttf_rect_t *bounds);
extern const int *ttfGetCMap(ttf_t *font, size_t *num_cmap);
extern int ttfGetCapHeight(ttf_t *font);
extern const char *ttfGetCopyright(ttf_t *font);
extern int ttfGetDescent(ttf_t *font);
extern ttf_rect_t *ttfGetExtents(ttf_t *font, float size, const char *s, ttf_rect_t *extents);
extern const char *ttfGetFamily(ttf_t *font);
extern float ttfGetItalicAngle(ttf_t *font);
extern int ttfGetMaxChar(ttf_t *font);
extern int ttfGetMinChar(ttf_t *font);
extern size_t ttfGetNumFonts(ttf_t *font);
extern const char *ttfGetPostScriptName(ttf_t *font);
extern ttf_stretch_t ttfGetStretch(ttf_t *font);
extern ttf_style_t ttfGetStyle(ttf_t *font);
extern const char *ttfGetVersion(ttf_t *font);
extern int ttfGetWidth(ttf_t *font, int ch);
extern ttf_weight_t ttfGetWeight(ttf_t *font);
extern int ttfGetXHeight(ttf_t *font);
extern bool ttfIsFixedPitch(ttf_t *font);
# ifdef __cplusplus
}
# endif // __cplusplus
#endif // !TTF_H