diff --git a/.gitignore b/.gitignore index 27f4c56..8d5fb30 100644 --- a/.gitignore +++ b/.gitignore @@ -25,5 +25,4 @@ /pdfio-*.zip* /testpdfio /testpdfio-*.pdf -/testttf /x64 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..6efb9fa --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "ttf"] + path = ttf + url = https://github.com/michaelrsweet/ttf.git diff --git a/CHANGES.md b/CHANGES.md index 0ef03cb..1e6057d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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. diff --git a/Makefile.in b/Makefile.in index 73398db..f88c1e0 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 diff --git a/configure b/configure index 51b150a..fc59956 100755 --- a/configure +++ b/configure @@ -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;} diff --git a/configure.ac b/configure.ac index e8c909d..b86199b 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/pdfio.pc.in b/pdfio.pc.in index 7196046..edbca55 100644 --- a/pdfio.pc.in +++ b/pdfio.pc.in @@ -11,3 +11,4 @@ Cflags: @PKGCONFIG_CFLAGS@ Libs: @PKGCONFIG_LIBS@ Libs.private: @PKGCONFIG_LIBS_PRIVATE@ Requires: @PKGCONFIG_REQUIRES@ +Requires.private: @PKGCONFIG_REQUIRES_PRIVATE@ diff --git a/testttf.c b/testttf.c deleted file mode 100644 index db4455f..0000000 --- a/testttf.c +++ /dev/null @@ -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 -#include -#include -#include -#include -#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); -} diff --git a/ttf b/ttf new file mode 160000 index 0000000..efbdbf3 --- /dev/null +++ b/ttf @@ -0,0 +1 @@ +Subproject commit efbdbf30747c3e66bec9782ca77ed36260723510 diff --git a/ttf.c b/ttf.c deleted file mode 100644 index fa02b1c..0000000 --- a/ttf.c +++ /dev/null @@ -1,2280 +0,0 @@ -// -// Implementation 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. -// - -#ifdef _WIN32 -# define _CRT_SECURE_NO_WARNINGS 1 -#endif // _WIN32 - -#include "ttf.h" -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 -# include -# include - -// -// Microsoft renames the POSIX functions to _name, and introduces -// a broken compatibility layer using the original names. As a result, -// random crashes can occur when, for example, strdup() allocates memory -// from a different heap than used by malloc() and free(). -// -// To avoid moronic problems like this, we #define the POSIX function -// names to the corresponding non-standard Microsoft names. -// - -# define access _access -# define close _close -# define fileno _fileno -# define lseek(f,o,w) (off_t)_lseek((f),(long)(o),(w)) -# define mkdir(d,p) _mkdir(d) -# define open _open -# define read(f,b,s) _read((f),(b),(unsigned)(s)) -# define rmdir _rmdir -# define snprintf _snprintf -# define strdup _strdup -# define unlink _unlink -# define vsnprintf _vsnprintf -# define write(f,b,s) _write((f),(b),(unsigned)(s)) - -// -// Map various parameters for POSIX... -// - -# define F_OK 00 -# define W_OK 02 -# define R_OK 04 -# define O_BINARY _O_BINARY -# define O_RDONLY _O_RDONLY -# define O_WRONLY _O_WRONLY -# define O_CREAT _O_CREAT -# define O_TRUNC _O_TRUNC - -typedef __int64 ssize_t; // POSIX type not present on Windows... @private@ - -#else -# include -# define O_BINARY 0 -#endif // _WIN32 - - -// -// DEBUG is typically defined for debug builds. TTF_DEBUG maps to fprintf when -// DEBUG is defined and is a no-op otherwise... -// - -#ifdef DEBUG -# define TTF_DEBUG(...) fprintf(stderr, __VA_ARGS__) -#else -# define TTF_DEBUG(...) -#endif // DEBUG - - -// -// TTF_FORMAT_ARGS tells the compiler to validate printf-style format -// arguments, producing warnings when there are issues... -// - -#if defined(__has_extension) || defined(__GNUC__) -# define TTF_FORMAT_ARGS(a,b) __attribute__ ((__format__(__printf__, a, b))) -#else -# define TTF_FORMAT_ARGS(a,b) -#endif // __has_extension || __GNUC__ - - -// -// Constants... -// - -#define TTF_FONT_MAX_CHAR 262144 // Maximum number of character values -#define TTF_FONT_MAX_GROUPS 65536 // Maximum number of sub-groups -#define TTF_FONT_MAX_NAMES 16777216// Maximum size of names table we support - - -// -// TTF/OFF tag constants... -// - -#define TTF_OFF_cmap 0x636d6170 // Character to glyph mapping -#define TTF_OFF_head 0x68656164 // Font header -#define TTF_OFF_hhea 0x68686561 // Horizontal header -#define TTF_OFF_hmtx 0x686d7478 // Horizontal metrics -#define TTF_OFF_maxp 0x6d617870 // Maximum profile -#define TTF_OFF_name 0x6e616d65 // Naming table -#define TTF_OFF_OS_2 0x4f532f32 // OS/2 and Windows specific metrics -#define TTF_OFF_post 0x706f7374 // PostScript information - -#define TTF_OFF_Unicode 0 // Unicode platform ID - -#define TTF_OFF_Mac 1 // Macintosh platform ID -#define TTF_OFF_Mac_Roman 0 // Macintosh Roman encoding ID -#define TTF_OFF_Mac_USEnglish 0 // Macintosh US English language ID - -#define TTF_OFF_Windows 3 // Windows platform ID -#define TTF_OFF_Windows_English 9 // Windows English language ID base -#define TTF_OFF_Windows_UCS2 1 // Windows UCS-2 encoding -#define TTF_OFF_Windows_UCS4 10 // Windows UCS-4 encoding - -#define TTF_OFF_Copyright 0 // Copyright naming string -#define TTF_OFF_FontFamily 1 // Font family naming string ("Arial") -#define TTF_OFF_FontSubfamily 2 // Font sub-family naming string ("Bold") -#define TTF_OFF_FontFullName 4 // Font full name ("Arial Bold") -#define TTF_OFF_FontVersion 5 // Font version number -#define TTF_OFF_PostScriptName 6 // Font PostScript name - - -// -// Local types... -// - -typedef struct _ttf_metric_s //*** Font metric information ****/ -{ - short width, // Advance width - left_bearing; // Left side bearing -} _ttf_metric_t; - -typedef struct _ttf_off_dir_s // OFF/TTF directory entry -{ - unsigned tag; // Table identifier - unsigned checksum; // Checksum of table - unsigned offset; // Offset from the beginning of the file - unsigned length; // Length -} _ttf_off_dir_t; - -typedef struct _ttf_off_table_s // OFF/TTF offset table -{ - int num_entries; // Number of table entries - _ttf_off_dir_t *entries; // Table entries -} _ttf_off_table_t; - -typedef struct _ttf_off_name_s // OFF/TTF name string -{ - unsigned short platform_id, // Platform identifier - encoding_id, // Encoding identifier - language_id, // Language identifier - name_id, // Name identifier - length, // Length of string - offset; // Offset from start of storage area -} _ttf_off_name_t; - -typedef struct _ttf_off_names_s // OFF/TTF naming table -{ - int num_names; // Number of names - _ttf_off_name_t *names; // Names - unsigned char *storage; // Storage area - unsigned storage_size; // Size of storage area -} _ttf_off_names_t; - -typedef size_t (*_ttf_read_cb_t)(ttf_t *font, void *buffer, size_t bytes); - // Font read callback, returns number of bytes read -typedef bool (*_ttf_seek_cb_t)(ttf_t *font, size_t offset); - // Font seek callback, returns `true` on success - -struct _ttf_s -{ - _ttf_read_cb_t read_cb; // Read callback - _ttf_seek_cb_t seek_cb; // Seek callback - int file_fd; // File descriptor for ttfCreate - const char *data; // Font data for ttfCreateData - size_t data_size; // Size of font data for ttfCreateData - size_t data_offset; // Offset within input - size_t idx; // Font number in file - ttf_err_cb_t err_cb; // Error callback, if any - void *err_data; // Error callback data - _ttf_off_table_t table; // Offset table - _ttf_off_names_t names; // Names - size_t num_fonts; // Number of fonts in this file - char *copyright; // Copyright string - char *family; // Font family string - char *postscript_name; // PostScript name string - char *version; // Font version string - bool is_fixed; // Is this a fixed-width font? - int max_char, // Last character in font - min_char; // First character in font - size_t num_cmap; // Number of entries in glyph map - int *cmap; // Unicode character to glyph map - _ttf_metric_t *widths[TTF_FONT_MAX_CHAR / 256]; - // Character metrics (sparse array) - float units; // Width units - short ascent, // Maximum ascent above baseline - descent, // Maximum descent below baseline - cap_height, // "A" height - x_height, // "x" height - x_max, // Bounding box - x_min, - y_max, - y_min, - weight; // Font weight - float italic_angle; // Angle of italic text - ttf_stretch_t stretch; // Font stretch value - ttf_style_t style; // Font style -}; - -typedef struct _ttf_off_cmap4_s // Format 4 cmap table -{ - unsigned short startCode, // First character - endCode, // Last character - idRangeOffset; // Offset for range (modulo 65536) - short idDelta; // Delta for range (modulo 65536) -} _ttf_off_cmap4_t; - -typedef struct _ttf_off_cmap12_s // Format 12 cmap table -{ - unsigned startCharCode, // First character - endCharCode, // Last character - startGlyphID; // Glyph index for the first character -} _ttf_off_cmap12_t; - -typedef struct _ttf_off_cmap13_s // Format 13 cmap table -{ - unsigned startCharCode, // First character - endCharCode, // Last character - glyphID; // Glyph index for all characters -} _ttf_off_cmap13_t; - -typedef struct _ttf_off_head_s // Font header -{ - unsigned short unitsPerEm; // Units for widths/coordinates - short xMin, // Bounding box of all glyphs - yMin, - xMax, - yMax; - unsigned short macStyle; // Mac style bits -} _ttf_off_head_t; - -#define TTF_OFF_macStyle_Bold 0x01 -#define TTF_OFF_macStyle_Italic 0x02 -#define TTF_OFF_macStyle_Underline 0x04 -#define TTF_OFF_macStyle_Outline 0x08 -#define TTF_OFF_macStyle_Shadow 0x10 -#define TTF_OFF_macStyle_Condensed 0x20 -#define TTF_OFF_macStyle_Extended 0x40 - -typedef struct _ttf_off_hhea_s // Horizontal header -{ - short ascender, // Ascender - descender; // Descender - unsigned short numberOfHMetrics; // Number of horizontal metrics -} _ttf_off_hhea_t; - -typedef struct _ttf_off_os_2_s // OS/2 information -{ - unsigned short usWeightClass, // Font weight - usWidthClass, // Font weight - fsType; // Type bits - short sTypoAscender, // Ascender - sTypoDescender, // Descender - sxHeight, // xHeight - sCapHeight; // CapHeight -} _ttf_off_os_2_t; - -typedef struct _ttf_off_post_s // PostScript information -{ - float italicAngle; // Italic angle - unsigned isFixedPitch; // Fixed-width font? -} _ttf_off_post_t; - - -// -// Local functions... -// - -static char *copy_name(ttf_t *font, unsigned name_id); -static ttf_t *create_font(const char *filename, const void *data, size_t datasize, size_t idx, ttf_err_cb_t err_cb, void *err_data); -static void errorf(ttf_t *font, const char *message, ...) TTF_FORMAT_ARGS(2,3); -static size_t fd_read_cb(ttf_t *font, void *buffer, size_t bytes); -static bool fd_seek_cb(ttf_t *font, size_t offset); -static size_t mem_read_cb(ttf_t *font, void *buffer, size_t bytes); -static bool mem_seek_cb(ttf_t *font, size_t offset); -static bool read_cmap(ttf_t *font); -static bool read_head(ttf_t *font, _ttf_off_head_t *head); -static bool read_hhea(ttf_t *font, _ttf_off_hhea_t *hhea); -static _ttf_metric_t *read_hmtx(ttf_t *font, _ttf_off_hhea_t *hhea); -static int read_maxp(ttf_t *font); -static bool read_names(ttf_t *font); -static bool read_os_2(ttf_t *font, _ttf_off_os_2_t *os_2); -static bool read_post(ttf_t *font, _ttf_off_post_t *post); -static int read_short(ttf_t *font); -static bool read_table(ttf_t *font); -static unsigned read_ulong(ttf_t *font); -static int read_ushort(ttf_t *font); -static unsigned seek_table(ttf_t *font, unsigned tag, unsigned offset, bool required); - - -// -// 'ttfCreate()' - Create a new font object for the named font file. -// -// This function creates a new font object for the named TrueType or OpenType -// font file or collection. The "filename" argument specifies the name of the -// file to read. -// -// The "idx" argument specifies the font to load from a collection - the first -// font is number `0`. Once created, you can call the @link ttfGetNumFonts@ -// function to determine whether the loaded font file is a collection with more -// than one font. -// -// The "err_cb" and "err_data" arguments specify a callback function and data -// pointer for receiving error messages. If `NULL`, errors are sent to the -// `stderr` file. The callback function receives the data pointer and a text -// message string, for example: -// -// ``` -// void my_err_cb(void *err_data, const char *message) -// { -// fprintf(stderr, "ERROR: %s\n", message); -// } -// ``` -// - -ttf_t * // O - New font object -ttfCreate(const char *filename, // I - Filename - size_t idx, // I - Font number to create in collection (0-based) - ttf_err_cb_t err_cb, // I - Error callback or `NULL` to log to stderr - void *err_data) // I - Error callback data -{ - TTF_DEBUG("ttfCreate(filename=\"%s\", idx=%u, err_cb=%p, err_data=%p)\n", filename, (unsigned)idx, (void *)err_cb, err_data); - - // Range check input.. - if (!filename) - { - errno = EINVAL; - return (NULL); - } - - // Open and return the font... - return (create_font(filename, /*data*/NULL, /*datasize*/0, idx, err_cb, err_data)); -} - - -// -// 'ttfCreateData()' - Create a new font object from a memory buffer. -// -// This function creates a new font object from a memory buffer. The "data" -// argument specifies a pointer to the first byte of data and the "datasize" -// argument specifies the length of the memory buffer in bytes. -// -// > Note: The caller is responsible for ensuring that the memory buffer is -// > available until the font object is deleted with @link ttfDelete@. -// -// The "idx" argument specifies the font to load from a collection - the first -// font is number `0`. Once created, you can call the @link ttfGetNumFonts@ -// function to determine whether the loaded font file is a collection with more -// than one font. -// -// The "err_cb" and "err_data" arguments specify a callback function and data -// pointer for receiving error messages. If `NULL`, errors are sent to the -// `stderr` file. The callback function receives the data pointer and a text -// message string, for example: -// -// ``` -// void my_err_cb(void *err_data, const char *message) -// { -// fprintf(stderr, "ERROR: %s\n", message); -// } -// ``` -// - -ttf_t * // O - New font object -ttfCreateData(const void *data, // I - Buffer - size_t datasize, // I - Size of buffer in bytes - size_t idx, // I - Font number to create in collection (0-based) - ttf_err_cb_t err_cb, // I - Error callback or `NULL` to log to stderr - void *err_data) // I - Error callback data -{ - TTF_DEBUG("ttfCreateData(data=%p, datasize=%lu, idx=%u, err_cb=%p, err_data=%p)\n", data, (unsigned long)datasize, (unsigned)idx, (void *)err_cb, err_data); - - // Range check input.. - if (!data || datasize == 0) - { - errno = EINVAL; - return (NULL); - } - - // Open and return the font... - return (create_font(/*filename*/NULL, data, datasize, idx, err_cb, err_data)); -} - - -// -// 'ttfDelete()' - Free all memory used for a font family object. -// - -void -ttfDelete(ttf_t *font) // I - Font -{ - int i; // Looping var - - - // Range check input... - if (!font) - return; - - // Close the font file... - if (font->file_fd >= 0) - close(font->file_fd); - - // Free all memory used... - free(font->copyright); - free(font->family); - free(font->postscript_name); - free(font->version); - - free(font->table.entries); - free(font->names.names); - free(font->names.storage); - - free(font->cmap); - - for (i = 0; i < 256; i ++) - free(font->widths[i]); - - free(font); -} - - -// -// 'ttfGetAscent()' - Get the maximum height of non-accented characters. -// - -int // O - Ascent in 1000ths -ttfGetAscent(ttf_t *font) // I - Font -{ - return (font ? (int)(1000 * font->ascent / font->units) : 0); -} - - -// -// 'ttfGetBounds()' - Get the bounds of all characters in a font. -// -// This function gets the bounds of all characters in a font. The "bounds" -// argument is a pointer to a `ttf_rect_t` structure that will be filled with -// the limits for characters in the font scaled to a 1000x1000 unit square. -// - -ttf_rect_t * // O - Bounds or `NULL` on error -ttfGetBounds(ttf_t *font, // I - Font - ttf_rect_t *bounds) // I - Bounds buffer -{ - // Range check input... - if (!font || !bounds) - { - if (bounds) - memset(bounds, 0, sizeof(ttf_rect_t)); - - return (NULL); - } - - bounds->left = 1000.0f * font->x_min / font->units; - bounds->right = 1000.0f * font->x_max / font->units; - bounds->bottom = 1000.0f * font->y_min / font->units; - bounds->top = 1000.0f * font->y_max / font->units; - - return (bounds); -} - - -// -// 'ttfGetCapHeight()' - Get the height of capital letters. -// - -int // O - Capital letter height in 1000ths -ttfGetCapHeight(ttf_t *font) // I - Font -{ - return (font ? (int)(1000 * font->cap_height / font->units) : 0); -} - - -// -// 'ttfGetCMap()' - Get the Unicode to glyph mapping table. -// - -const int * // O - CMap table -ttfGetCMap(ttf_t *font, // I - Font - size_t *num_cmap) // O - Number of entries in table -{ - // Range check input... - if (!font || !num_cmap) - { - if (num_cmap) - *num_cmap = 0; - - return (NULL); - } - - *num_cmap = font->num_cmap; - return (font->cmap); -} - - -// -// 'ttfGetCopyright()' - Get the copyright text for a font. -// - -const char * // O - Copyright text -ttfGetCopyright(ttf_t *font) // I - Font -{ - return (font ? font->copyright : NULL); -} - - -// -// 'ttfGetDescent()' - Get the maximum depth of non-accented characters. -// - -int // O - Descent in 1000ths -ttfGetDescent(ttf_t *font) // I - Font -{ - return (font ? (int)(1000 * font->descent / font->units) : 0); -} - - -// -// 'ttfGetExtents()' - Get the extents of a UTF-8 string. -// -// This function computes the extents of the UTF-8 string "s" when rendered -// using the specified font "font" and size "size". The "extents" argument is -// a pointer to a `ttf_rect_t` structure that is filled with the extents of a -// simple rendering of the string with no kerning or rewriting applied. The -// values are scaled using the specified font size. -// - -ttf_rect_t * // O - Pointer to extents or `NULL` on error -ttfGetExtents( - ttf_t *font, // I - Font - float size, // I - Font size - const char *s, // I - String - ttf_rect_t *extents) // O - Extents of the string -{ - bool first = true; // First character? - int ch, // Current character - width = 0; // Width - _ttf_metric_t *widths; // Widths - - - TTF_DEBUG("ttfGetExtents(font=%p, size=%.2f, s=\"%s\", extents=%p)\n", (void *)font, size, s, (void *)extents); - - // Make sure extents is zeroed out... - if (extents) - memset(extents, 0, sizeof(ttf_rect_t)); - - // Range check input... - if (!font || size <= 0.0f || !s || !extents) - return (NULL); - - // Loop through the string... - while (*s) - { - // Get the next Unicode character... - if ((*s & 0xe0) == 0xc0 && (s[1] & 0xc0) == 0x80) - { - // Two byte UTF-8 - ch = ((*s & 0x1f) << 6) | (s[1] & 0x3f); - s += 2; - } - else if ((*s & 0xf0) == 0xe0 && (s[1] & 0xc0) == 0x80 && (s[2] & 0xc0) == 0x80) - { - // Three byte UTF-8 - ch = ((*s & 0x0f) << 12) | ((s[1] & 0x3f) << 6) | (s[2] & 0x3f); - s += 3; - } - else if ((*s & 0xf8) == 0xf0 && (s[1] & 0xc0) == 0x80 && (s[2] & 0xc0) == 0x80 && (s[3] & 0xc0) == 0x80) - { - // Four byte UTF-8 - ch = ((*s & 0x07) << 18) | ((s[1] & 0x3f) << 12) | ((s[2] & 0x3f) << 6) | (s[3] & 0x3f); - s += 4; - } - else if (*s & 0x80) - { - // Invalid UTF-8 - errorf(font, "Invalid UTF-8 sequence starting with 0x%02X.", *s & 255); - return (NULL); - } - else - { - // ASCII... - ch = *s++; - } - - // Find its width... - if (ch < TTF_FONT_MAX_CHAR && (widths = font->widths[ch / 256]) != NULL) - { - if (first) - { - extents->left = -widths[ch & 255].left_bearing / font->units; - first = false; - } - - width += widths[ch & 255].width; - } - else if ((widths = font->widths[0]) != NULL) - { - // Use the ".notdef" (0) glyph width... - if (first) - { - extents->left = -widths[0].left_bearing / font->units; - first = false; - } - - width += widths[0].width; - } - } - - // Calculate the bounding box for the text and return... - TTF_DEBUG("ttfGetExtents: width=%d\n", width); - - extents->bottom = size * font->y_min / font->units; - extents->right = size * width / font->units + extents->left; - extents->top = size * font->y_max / font->units; - - return (extents); -} - - -// -// 'ttfGetFamily()' - Get the family name of a font. -// - -const char * // O - Family name -ttfGetFamily(ttf_t *font) // I - Font -{ - return (font ? font->family : NULL); -} - - -// -// 'ttfGetItalicAngle()' - Get the italic angle. -// - -float // O - Angle in degrees -ttfGetItalicAngle(ttf_t *font) // I - Font -{ - return (font ? font->italic_angle : 0.0f); -} - - -// -// 'ttfGetMaxChar()' - Get the last character in the font. -// - -int // O - Last character in font -ttfGetMaxChar(ttf_t *font) // I - Font -{ - return (font ? font->max_char : 0); -} - - -// -// 'ttfGetMinChar()' - Get the first character in the font. -// - -int // O - First character in font -ttfGetMinChar(ttf_t *font) // I - Font -{ - return (font ? font->min_char : 0); -} - - -// -// 'ttfGetNumFonts()' - Get the number of fonts in this collection. -// - -size_t // O - Number of fonts -ttfGetNumFonts(ttf_t *font) // I - Font -{ - return (font ? font->num_fonts : 0); -} - - -// -// 'ttfGetPostScriptName()' - Get the PostScript name of a font. -// - -const char * // O - PostScript name -ttfGetPostScriptName( - ttf_t *font) // I - Font -{ - return (font ? font->postscript_name : NULL); -} - - -// -// 'ttfGetStretch()' - Get the font "stretch" value... -// - -ttf_stretch_t // O - Stretch value -ttfGetStretch(ttf_t *font) // I - Font -{ - return (font ? font->stretch : TTF_STRETCH_NORMAL); -} - - -// -// 'ttfGetStyle()' - Get the font style. -// - -ttf_style_t // O - Style -ttfGetStyle(ttf_t *font) // I - Font -{ - return (font ? font->style : TTF_STYLE_NORMAL); -} - - -// -// 'ttfGetVersion()' - Get the version number of a font. -// - -const char * // O - Version number -ttfGetVersion(ttf_t *font) // I - Font -{ - return (font ? font->version : NULL); -} - - -// -// 'ttfGetWeight()' - Get the weight of a font. -// - -ttf_weight_t // O - Weight -ttfGetWeight(ttf_t *font) // I - Font -{ - return (font ? (ttf_weight_t)font->weight : TTF_WEIGHT_400); -} - - -// -// 'ttfGetWidth()' - Get the width of a single character. -// - -int // O - Width in 1000ths -ttfGetWidth(ttf_t *font, // I - Font - int ch) // I - Unicode character -{ - int bin = ch >> 8; // Bin in widths array - - - // Range check input... - if (!font || ch < ' ' || ch == 0x7f) - return (0); - - if (font->widths[bin]) - return ((int)(1000.0f * font->widths[bin][ch & 255].width / font->units)); - else if (font->widths[0]) // .notdef - return ((int)(1000.0f * font->widths[0][0].width / font->units)); - else - return (0); -} - - -// -// 'ttfGetXHeight()' - Get the height of lowercase letters. -// - -int // O - Lowercase letter height in 1000ths -ttfGetXHeight(ttf_t *font) // I - Font -{ - return (font ? (int)(1000 * font->x_height / font->units) : 0); -} - - -// -// 'ttfIsFixedPitch()' - Determine whether a font is fixedpitch. -// - -bool // O - `true` if fixed pitch, `false` otherwise -ttfIsFixedPitch(ttf_t *font) // I - Font -{ - return (font ? font->is_fixed : false); -} - - -// -// 'copy_name()' - Copy a name string from a font. -// - -static char * // O - Name string or `NULL` -copy_name(ttf_t *font, // I - Font - unsigned name_id) // I - Name identifier -{ - int i; // Looping var - _ttf_off_name_t *name; // Current name - - - for (i = font->names.num_names, name = font->names.names; i > 0; i --, name ++) - { - if (name->name_id == name_id && - ((name->platform_id == TTF_OFF_Mac && name->language_id == TTF_OFF_Mac_USEnglish) || - (name->platform_id == TTF_OFF_Windows && (name->language_id & 0xff) == TTF_OFF_Windows_English))) - { - char temp[1024], // Temporary string buffer - *tempptr, // Pointer into temporary string - *storptr; // Pointer into storage - int chars, // Length of string to copy in characters - bpc; // Bytes per character - - if ((unsigned)(name->offset + name->length) > font->names.storage_size) - { - TTF_DEBUG("copy_name: offset(%d)+length(%d) > storage_size(%d)\n", name->offset, name->length, font->names.storage_size); - continue; - } - - if (name->platform_id == TTF_OFF_Windows && name->encoding_id == TTF_OFF_Windows_UCS2) - { - storptr = (char *)font->names.storage + name->offset; - chars = name->length / 2; - bpc = 2; - } - else if (name->platform_id == TTF_OFF_Windows && name->encoding_id == TTF_OFF_Windows_UCS4) - { - storptr = (char *)font->names.storage + name->offset; - chars = name->length / 4; - bpc = 4; - } - else - { - storptr = (char *)font->names.storage + name->offset; - chars = name->length; - bpc = 1; - } - - for (tempptr = temp; chars > 0; storptr += bpc, chars --) - { - int ch; // Current character - - // Convert to Unicode... - if (bpc == 1) - ch = *storptr; - else if (bpc == 2) - ch = ((storptr[0] & 255) << 8) | (storptr[1] & 255); - else - ch = ((storptr[0] & 255) << 24) | ((storptr[1] & 255) << 16) | ((storptr[2] & 255) << 8) | (storptr[3] & 255); - - // Convert to UTF-8... - if (ch < 0x80) - { - // ASCII... - if (tempptr < (temp + sizeof(temp) - 1)) - *tempptr++ = (char)ch; - else - break; - } - else if (ch < 0x400) - { - // Two byte UTF-8 - if (tempptr < (temp + sizeof(temp) - 2)) - { - *tempptr++ = (char)(0xc0 | (ch >> 6)); - *tempptr++ = (char)(0x80 | (ch & 0x3f)); - } - else - break; - } - else if (ch < 0x10000) - { - // Three byte UTF-8 - if (tempptr < (temp + sizeof(temp) - 3)) - { - *tempptr++ = (char)(0xe0 | (ch >> 12)); - *tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f)); - *tempptr++ = (char)(0x80 | (ch & 0x3f)); - } - else - break; - } - else - { - // Four byte UTF-8 - if (tempptr < (temp + sizeof(temp) - 4)) - { - *tempptr++ = (char)(0xf0 | (ch >> 18)); - *tempptr++ = (char)(0x80 | ((ch >> 12) & 0x3f)); - *tempptr++ = (char)(0x80 | ((ch >> 6) & 0x3f)); - *tempptr++ = (char)(0x80 | (ch & 0x3f)); - } - else - break; - } - } - - *tempptr = '\0'; - - TTF_DEBUG("copy_name: name_id(%d) = \"%s\"\n", name_id, temp); - - return (strdup(temp)); - } - } - - TTF_DEBUG("copy_name: No English name string for %d.\n", name_id); -#ifdef DEBUG - for (i = font->names.num_names, name = font->names.names; i > 0; i --, name ++) - { - if (name->name_id == name_id) - TTF_DEBUG("copy_name: Found name_id=%d, platform_id=%d, language_id=%d(0x%04x)\n", name_id, name->platform_id, name->language_id, name->language_id); - } -#endif // DEBUG - - return (NULL); -} - - -// -// 'create_font()' - Create a font object from the file or data. -// - -static ttf_t * -create_font(const char *filename, // I - Filename of `NULL` - const void *data, // I - Data pointer or `NULL` - size_t datasize, // I - Size of data or 0 - size_t idx, // I - Font index - ttf_err_cb_t err_cb, // I - Error callback function - void *err_data) // I - Error callback data -{ - ttf_t *font = NULL; // New font object - size_t i; // Looping var - _ttf_metric_t *widths = NULL; // Glyph metrics - _ttf_off_head_t head; // head table - _ttf_off_hhea_t hhea; // hhea table - _ttf_off_os_2_t os_2; // OS/2 table - _ttf_off_post_t post; // PostScript table - - - TTF_DEBUG("create_font(filename=\"%s\", data=%p, datasize=%lu, idx=%u, err_cb=%p, err_data=%p)\n", filename, data, (unsigned long)datasize, (unsigned)idx, (void *)err_cb, err_data); - - // Allocate memory... - if ((font = (ttf_t *)calloc(1, sizeof(ttf_t))) == NULL) - return (NULL); - - font->idx = idx; - font->err_cb = err_cb; - font->err_data = err_data; - - if (filename) - { - // Open the font file... - if ((font->file_fd = open(filename, O_RDONLY | O_BINARY)) < 0) - { - errorf(font, "Unable to open '%s': %s", filename, strerror(errno)); - goto error; - } - - TTF_DEBUG("create_font: file_fd=%d\n", font->file_fd); - - font->read_cb = fd_read_cb; - font->seek_cb = fd_seek_cb; - } - else - { - // Read from memory... - font->file_fd = -1; - font->data = (const char *)data; - font->data_size = datasize; - font->read_cb = mem_read_cb; - font->seek_cb = mem_seek_cb; - } - - // Read the table of contents and the identifying names... - if (!read_table(font)) - goto error; - - TTF_DEBUG("create_font: num_entries=%d\n", font->table.num_entries); - - if (!read_names(font)) - goto error; - - TTF_DEBUG("create_font: num_names=%d\n", font->names.num_names); - - // Copy key font meta data strings... - font->copyright = copy_name(font, TTF_OFF_Copyright); - font->family = copy_name(font, TTF_OFF_FontFamily); - font->postscript_name = copy_name(font, TTF_OFF_PostScriptName); - font->version = copy_name(font, TTF_OFF_FontVersion); - - if (read_post(font, &post)) - { - font->italic_angle = post.italicAngle; - font->is_fixed = post.isFixedPitch != 0; - } - - TTF_DEBUG("create_font: copyright=\"%s\"\n", font->copyright); - TTF_DEBUG("create_font: family=\"%s\"\n", font->family); - TTF_DEBUG("create_font: postscript_name=\"%s\"\n", font->postscript_name); - TTF_DEBUG("create_font: version=\"%s\"\n", font->version); - TTF_DEBUG("create_font: italic_angle=%g\n", font->italic_angle); - TTF_DEBUG("create_font: is_fixed=%s\n", font->is_fixed ? "true" : "false"); - - if (!read_cmap(font)) - goto error; - - if (!read_head(font, &head)) - goto error; - - font->units = (float)head.unitsPerEm; - font->x_max = head.xMax; - font->x_min = head.xMin; - font->y_max = head.yMax; - font->y_min = head.yMin; - - if (head.macStyle & TTF_OFF_macStyle_Italic) - { - if (font->postscript_name && strstr(font->postscript_name, "Oblique")) - font->style = TTF_STYLE_OBLIQUE; - else - font->style = TTF_STYLE_ITALIC; - } - else - font->style = TTF_STYLE_NORMAL; - - if (!read_hhea(font, &hhea)) - goto error; - - font->ascent = hhea.ascender; - font->descent = hhea.descender; - - if (read_maxp(font) < 0) - goto error; - - if (hhea.numberOfHMetrics > 0) - { - if ((widths = read_hmtx(font, &hhea)) == NULL) - goto error; - } - else - { - errorf(font, "Number of horizontal metrics is 0."); - goto error; - } - - if (read_os_2(font, &os_2)) - { - // Copy key values from OS/2 table... - static const ttf_stretch_t stretches[] = - { - TTF_STRETCH_ULTRA_CONDENSED, // ultra-condensed - TTF_STRETCH_EXTRA_CONDENSED, // extra-condensed - TTF_STRETCH_CONDENSED, // condensed - TTF_STRETCH_SEMI_CONDENSED, // semi-condensed - TTF_STRETCH_NORMAL, // normal - TTF_STRETCH_SEMI_EXPANDED, // semi-expanded - TTF_STRETCH_EXPANDED, // expanded - TTF_STRETCH_EXTRA_EXPANDED, // extra-expanded - TTF_STRETCH_ULTRA_EXPANDED // ultra-expanded - }; - - if (os_2.usWidthClass >= 1 && os_2.usWidthClass <= (int)(sizeof(stretches) / sizeof(stretches[0]))) - font->stretch = stretches[os_2.usWidthClass - 1]; - - font->weight = (short)os_2.usWeightClass; - font->cap_height = os_2.sCapHeight; - font->x_height = os_2.sxHeight; - } - else - { - // Default key values since there isn't an OS/2 table... - TTF_DEBUG("create_font: Unable to read OS/2 table.\n"); - - font->weight = 400; - } - - if (font->cap_height == 0) - font->cap_height = font->ascent; - - if (font->x_height == 0) - font->x_height = 3 * font->ascent / 5; - - // Build a sparse glyph widths table... - font->min_char = -1; - - for (i = 0; i < font->num_cmap; i ++) - { - if (font->cmap[i] >= 0) - { - int bin = (int)i / 256, // Sub-array bin - glyph = font->cmap[i]; // Glyph index - - // Update min/max... - if (font->min_char < 0) - font->min_char = (int)i; - - font->max_char = (int)i; - - // Allocate a sub-array as needed... - if (!font->widths[bin]) - font->widths[bin] = (_ttf_metric_t *)calloc(256, sizeof(_ttf_metric_t)); - - // Copy the width of the specified glyph or the last one if we are past - // the end of the table... - if (glyph >= hhea.numberOfHMetrics) - font->widths[bin][i & 255] = widths[hhea.numberOfHMetrics - 1]; - else - font->widths[bin][i & 255] = widths[glyph]; - } - -#ifdef DEBUG - if (i >= ' ' && i < 127 && font->widths[0]) - TTF_DEBUG("create_font: width['%c']=%d(%d)\n", (char)i, font->widths[0][i].width, font->widths[0][i].left_bearing); -#endif // DEBUG - } - - // Cleanup and return the font... - free(widths); - - return (font); - - // If we get here something bad happened... - error: - - free(widths); - ttfDelete(font); - - return (NULL); -} - - -// -// 'errorf()' - Show an error message. -// - -static void -errorf(ttf_t *font, // I - Font - const char *message, // I - `printf`-style message string - ...) // I - Addition arguments as needed -{ - va_list ap; // Argument pointer - char buffer[2048]; // Message buffer - - - // Format the message... - va_start(ap, message); - vsnprintf(buffer, sizeof(buffer), message, ap); - va_end(ap); - - // If an error callback is set, sent the message there. Otherwise write it - // to stderr... - if (font && font->err_cb) - (font->err_cb)(font->err_data, buffer); - else - fprintf(stderr, "%s\n", message); -} - - -// -// 'fd_read_cb()' - Read from a file. -// - -static size_t // O - Number of bytes read -fd_read_cb(ttf_t *font, // I - Font - void *buffer, // I - Read buffer - size_t bytes) // I - Number of bytes to read -{ - ssize_t rbytes; // Bytes read - - - if ((rbytes = read(font->file_fd, buffer, bytes)) < 0) - return (0); - - return ((size_t)rbytes); -} - - -// -// 'fd_seek_cb()' - Seek in a file. -// - -static bool // O - `true` on success, `false` on failure -fd_seek_cb(ttf_t *font, // I - Font - size_t offset) // I - Offset in data -{ - return (lseek(font->file_fd, (off_t)offset, SEEK_SET) == (off_t)offset); -} - - -// -// 'mem_read_cb()' - Read from a memory buffer. -// - -static size_t // O - Number of bytes read -mem_read_cb(ttf_t *font, // I - Font - void *buffer, // I - Read buffer - size_t bytes) // I - Number of bytes to read -{ - size_t rbytes; // Bytes to copy - - - if (font->data_offset >= font->data_size) - return (0); - - if ((rbytes = font->data_size - font->data_offset) > bytes) - rbytes = bytes; - - memcpy(buffer, font->data + font->data_offset, rbytes); - font->data_offset += rbytes; - - return (rbytes); -} - - -// -// 'mem_seek_cb()' - Seek in a memory buffer. -// - -static bool // O - `true` on success, `false` on error -mem_seek_cb(ttf_t *font, // I - Font - size_t offset) // I - Offset in data -{ - if (offset >= font->data_size) - { - errno = ENXIO; - return (false); - } - - font->data_offset = offset; - - return (true); -} - - -// -// 'read_cmap()' - Read the cmap table, getting the Unicode mapping table. -// - -static bool // O - `true` on success, `false` on error -read_cmap(ttf_t *font) // I - Font -{ - unsigned length; // Length of cmap table - int i, // Looping var - temp, // Temporary value - num_tables, // Number of cmap tables - platform_id, // Platform identifier (Windows or Mac) - encoding_id, // Encoding identifier (varies) - cformat; // Formap of cmap data - unsigned clength, // Length of cmap data - coffset = 0, // Offset to cmap data - roman_offset = 0; // MacRoman offset - int *cmapptr; // Pointer into cmap -#if 0 - const int *unimap = NULL; // Unicode character map, if any - static const int romanmap[256] = // MacRoman to Unicode map - { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, - 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, - 0xC4, 0xC5, 0xC7, 0xC9, 0xD1, 0xD6, 0xDC, 0xE1, - 0xE0, 0xE2, 0xE4, 0xE3, 0xE5, 0xE7, 0xE9, 0xE8, - 0xEA, 0xEB, 0xED, 0xEC, 0xEE, 0xEF, 0xF1, 0xF3, - 0xF2, 0xF4, 0xF6, 0xF5, 0xFA, 0xF9, 0xFB, 0xFC, - 0x2020, 0xB0, 0xA2, 0xA3, 0xA7, 0x2022, 0xB6, 0xDF, - 0xAE, 0xA9, 0x2122, 0xB4, 0xA8, 0x2260, 0xC6, 0xD8, - 0x221E, 0xB1, 0x2264, 0x2265, 0xA5, 0xB5, 0x2202, 0x2211, - 0x220F, 0x3C0, 0x222B, 0xAA, 0xBA, 0x3A9, 0xE6, 0xF8, - 0xBF, 0xA1, 0xAC, 0x221A, 0x192, 0x2248, 0x2206, 0xAB, - 0xBB, 0x2026, 0xA0, 0xC0, 0xC3, 0xD5, 0x152, 0x153, - 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0xF7, 0x25CA, - 0xFF, 0x178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02, - 0x2021, 0xB7, 0x201A, 0x201E, 0x2030, 0xC2, 0xCA, 0xC1, - 0xCB, 0xC8, 0xCD, 0xCE, 0xCF, 0xCC, 0xD3, 0xD4, - 0xF8FF, 0xD2, 0xDA, 0xDB, 0xD9, 0x131, 0x2C6, 0x2DC, - 0xAF, 0x2D8, 0x2D9, 0x2DA, 0xB8, 0x2DD, 0x2DB, 0x2C7 - }; -#endif /* 0 */ - - - // Find the cmap table... - if (seek_table(font, TTF_OFF_cmap, 0, true) == 0) - return (false); - - if ((temp = read_ushort(font)) != 0) - { - errorf(font, "Unknown cmap version %d.", temp); - return (false); - } - - if ((num_tables = read_ushort(font)) < 1) - { - errorf(font, "No cmap tables to read."); - return (false); - } - - TTF_DEBUG("read_cmap: num_tables=%d\n", num_tables); - - // Find a Unicode table we can use... - for (i = 0; i < num_tables; i ++) - { - platform_id = read_ushort(font); - encoding_id = read_ushort(font); - coffset = read_ulong(font); - - TTF_DEBUG("read_cmap: table[%d].platform_id=%d, encoding_id=%d, coffset=%u\n", i, platform_id, encoding_id, coffset); - - if (platform_id == TTF_OFF_Unicode || (platform_id == TTF_OFF_Windows && encoding_id == TTF_OFF_Windows_UCS2)) - break; - - if (platform_id == TTF_OFF_Mac && encoding_id == TTF_OFF_Mac_Roman) - roman_offset = coffset; - } - - if (i >= num_tables) - { - if (roman_offset) - { - TTF_DEBUG("read_cmap: Using MacRoman cmap table.\n"); - coffset = roman_offset; - } - else - { - errorf(font, "No usable cmap table."); - return (false); - } - } - - if ((length = seek_table(font, TTF_OFF_cmap, coffset, true)) == 0) - return (false); - - if ((cformat = read_ushort(font)) < 0) - { - errorf(font, "Unable to read cmap table format at offset %u.", coffset); - return (false); - } - - TTF_DEBUG("read_cmap: cformat=%d\n", cformat); - - switch (cformat) - { - case 0 : - { - // Format 0: Byte encoding table. - // - // This is a simple 8-bit mapping. - size_t j; // Looping var - unsigned char bmap[256]; // Byte map buffer - - if ((unsigned)read_ushort(font) == (unsigned)-1) - { - errorf(font, "Unable to read cmap table length at offset %u.", coffset); - return (false); - } - - /* language = */ read_ushort(font); - - if (length > (256 + 6) || length < 7) - { - errorf(font, "Bad cmap table length at offset %u.", coffset); - return (false); - } - - font->num_cmap = length - 6; - - if ((font->cmap = (int *)malloc(font->num_cmap * sizeof(int))) == NULL) - { - errorf(font, "Unable to allocate cmap table."); - return (false); - } - - if ((font->read_cb)(font, bmap, font->num_cmap) != font->num_cmap) - { - errorf(font, "Unable to read cmap table length at offset %u.", coffset); - return (false); - } - - // Copy into the actual cmap table... - for (j = 0; j < font->num_cmap; j ++) - font->cmap[j] = bmap[j]; - } - break; - - case 4 : - { - // Format 4: Segment mapping to delta values. - // - // This is an overly complicated linear way of encoding a sparse - // mapping table. And it uses 1-based indexing with modulo - // arithmetic... - int ch, // Current character - seg, // Current segment - glyph, // Current glyph - segCount, // Number of segments - numGlyphIdArray,// Number of glyph IDs - *glyphIdArray; // Glyph IDs - _ttf_off_cmap4_t *segments, // Segment data - *segment; // This segment - - - // Read the table... - if ((clength = (unsigned)read_ushort(font)) == (unsigned)-1) - { - errorf(font, "Unable to read cmap table length at offset %u.", coffset); - return (false); - } - - TTF_DEBUG("read_cmap: clength=%u\n", clength); - - /* language = */ read_ushort(font); - segCount = read_ushort(font) / 2; - /* searchRange = */ read_ushort(font); - /* entrySelectoed = */ read_ushort(font); - /* rangeShift = */ read_ushort(font); - - TTF_DEBUG("read_cmap: segCount=%d\n", segCount); - - if (segCount < 2) - { - errorf(font, "Bad cmap table."); - return (false); - } - - numGlyphIdArray = ((int)clength - 8 * segCount - 16) / 2; - segments = (_ttf_off_cmap4_t *)calloc((size_t)segCount, sizeof(_ttf_off_cmap4_t)); - glyphIdArray = (int *)calloc((size_t)numGlyphIdArray, sizeof(int)); - - if (!segments || !glyphIdArray) - { - errorf(font, "Unable to allocate memory for cmap."); - free(segments); - free(glyphIdArray); - return (false); - } - - TTF_DEBUG("read_cmap: numGlyphIdArray=%d\n", numGlyphIdArray); - - for (i = 0; i < segCount; i ++) - segments[i].endCode = (unsigned short)read_ushort(font); - - /* reservedPad = */ read_ushort(font); - - for (i = 0; i < segCount; i ++) - segments[i].startCode = (unsigned short)read_ushort(font); - - for (i = 0; i < segCount; i ++) - segments[i].idDelta = (short)read_short(font); - - for (i = 0; i < segCount; i ++) - segments[i].idRangeOffset = (unsigned short)read_ushort(font); - - for (i = 0; i < numGlyphIdArray; i ++) - glyphIdArray[i] = read_ushort(font); - - for (i = 0, segment = segments; i < segCount; i ++, segment ++) - { - TTF_DEBUG("read_cmap: segment[%d].startCode=%d, endCode=%d, idDelta=%d, idRangeOffset=%d\n", i, segment->startCode, segment->endCode, segment->idDelta, segment->idRangeOffset); - - if (segment->startCode > segment->endCode) - { - errorf(font, "Bad cmap table segment %u to %u.", segments->startCode, segment->endCode); - free(segments); - free(glyphIdArray); - return (false); - } - - // Based on the end code of the segment table, allocate space for the - // uncompressed cmap table... - if (segment->endCode >= font->num_cmap) - font->num_cmap = segment->endCode + 1; - } - -#ifdef DEBUG - for (i = 0; i < numGlyphIdArray; i ++) - TTF_DEBUG("read_cmap: glyphIdArray[%d]=%d\n", i, glyphIdArray[i]); -#endif /* DEBUG */ - - if (font->num_cmap == 0 || font->num_cmap > TTF_FONT_MAX_CHAR) - { - errorf(font, "Invalid cmap table with %u characters.", (unsigned)font->num_cmap); - free(segments); - free(glyphIdArray); - return (false); - } - - font->cmap = cmapptr = (int *)malloc(font->num_cmap * sizeof(int)); - - if (!font->cmap) - { - errorf(font, "Unable to allocate memory for cmap."); - free(segments); - free(glyphIdArray); - return (false); - } - - memset(cmapptr, -1, font->num_cmap * sizeof(int)); - - // Now loop through the segments and assign glyph indices from the - // array... - for (seg = segCount, segment = segments; seg > 0; seg --, segment ++) - { - for (ch = segment->startCode; ch <= segment->endCode; ch ++) - { - if (segment->idRangeOffset) - { - // Use an "obscure indexing trick" (words from the spec, not - // mine) to look up the glyph index... - temp = (int)(segment->idRangeOffset / 2 - segCount + (ch - segment->startCode) + (segment - segments)); - - TTF_DEBUG("read_cmap: ch=%d, temp=%d\n", ch, temp); - if (temp < 0 || temp >= numGlyphIdArray) - glyph = -1; - else - glyph = (glyphIdArray[temp] + segment->idDelta) & 65535; - } - else - { - // Just use idDelta to compute a glyph index... - glyph = (ch + segment->idDelta) & 65535; - } - - cmapptr[ch] = glyph; - } - } - - // Free the segment data... - free(segments); - free(glyphIdArray); - } - break; - - case 12 : - { - // Format 12: Segmented coverage - // - // A simple sparse linear segment mapping format. - unsigned ch, // Current character - gidx, // Current group - nGroups; // Number of groups - _ttf_off_cmap12_t *groups, // Groups - *group; // This group - - // Read the table... - /* reserved */ read_ushort(font); - - if (read_ulong(font) == 0) - { - errorf(font, "Unable to read cmap table length at offset %u.", coffset); - return (false); - } - - /* language = */ read_ulong(font); - nGroups = read_ulong(font); - - TTF_DEBUG("read_cmap: nGroups=%u\n", nGroups); - - if (nGroups > TTF_FONT_MAX_GROUPS) - { - errorf(font, "Invalid cmap table with %u groups.", nGroups); - return (false); - } - - if ((groups = (_ttf_off_cmap12_t *)calloc(nGroups, sizeof(_ttf_off_cmap12_t))) == NULL) - { - errorf(font, "Unable to allocate memory for cmap."); - return (false); - } - - for (gidx = 0, group = groups, font->num_cmap = 0; gidx < nGroups; gidx ++, group ++) - { - group->startCharCode = read_ulong(font); - group->endCharCode = read_ulong(font); - group->startGlyphID = read_ulong(font); - TTF_DEBUG("read_cmap: [%u] startCharCode=%u, endCharCode=%u, startGlyphID=%u\n", gidx, group->startCharCode, group->endCharCode, group->startGlyphID); - - if (group->startCharCode > group->endCharCode || group->startCharCode >= TTF_FONT_MAX_CHAR || group->endCharCode >= TTF_FONT_MAX_CHAR) - { - errorf(font, "Bad cmap table segment %u to %u.", group->startCharCode, group->endCharCode); - free(groups); - return (false); - } - - if (group->endCharCode >= font->num_cmap) - font->num_cmap = group->endCharCode + 1; - } - - // Based on the end code of the segent table, allocate space for the - // uncompressed cmap table... - TTF_DEBUG("read_cmap: num_cmap=%u\n", (unsigned)font->num_cmap); - - if (font->num_cmap == 0 || font->num_cmap > TTF_FONT_MAX_CHAR) - { - errorf(font, "Invalid cmap table with %u characters.", (unsigned)font->num_cmap); - free(groups); - return (false); - } - - font->cmap = cmapptr = (int *)malloc(font->num_cmap * sizeof(int)); - - if (!font->cmap) - { - errorf(font, "Unable to allocate memory for cmap."); - free(groups); - return (false); - } - - memset(cmapptr, -1, font->num_cmap * sizeof(int)); - - // Now loop through the groups and assign glyph indices from the - // array... - for (gidx = 0, group = groups; gidx < nGroups; gidx ++, group ++) - { - for (ch = group->startCharCode; ch <= group->endCharCode && ch < font->num_cmap; ch ++) - cmapptr[ch] = (int)(group->startGlyphID + ch - group->startCharCode); - } - - // Free the group data... - free(groups); - } - break; - - case 13 : - { - // Format 13: Many-to-one range mappings - // - // Typically used for fonts of last resort where multiple characters - // map to the same glyph. - unsigned ch, // Current character - gidx, // Current group - nGroups; // Number of groups - _ttf_off_cmap13_t *groups, // Groups - *group; // This group - - // Read the table... - /* reserved */ read_ushort(font); - - if (read_ulong(font) == 0) - { - errorf(font, "Unable to read cmap table length at offset %u.", coffset); - return (false); - } - - /* language = */ read_ulong(font); - nGroups = read_ulong(font); - - TTF_DEBUG("read_cmap: nGroups=%u\n", nGroups); - - if (nGroups > TTF_FONT_MAX_GROUPS) - { - errorf(font, "Invalid cmap table with %u groups.", nGroups); - return (false); - } - - if ((groups = (_ttf_off_cmap13_t *)calloc(nGroups, sizeof(_ttf_off_cmap13_t))) == NULL) - { - errorf(font, "Unable to allocate memory for cmap."); - return (false); - } - - for (gidx = 0, group = groups, font->num_cmap = 0; gidx < nGroups; gidx ++, group ++) - { - group->startCharCode = read_ulong(font); - group->endCharCode = read_ulong(font); - group->glyphID = read_ulong(font); - TTF_DEBUG("read_cmap: [%u] startCharCode=%u, endCharCode=%u, glyphID=%u\n", gidx, group->startCharCode, group->endCharCode, group->glyphID); - - if (group->startCharCode > group->endCharCode || group->startCharCode >= TTF_FONT_MAX_CHAR || group->endCharCode >= TTF_FONT_MAX_CHAR) - { - errorf(font, "Bad cmap table segment %u to %u.", group->startCharCode, group->endCharCode); - free(groups); - return (false); - } - - if (group->endCharCode >= font->num_cmap) - font->num_cmap = group->endCharCode + 1; - } - - // Based on the end code of the segent table, allocate space for the - // uncompressed cmap table... - TTF_DEBUG("read_cmap: num_cmap=%u\n", (unsigned)font->num_cmap); - - if (font->num_cmap == 0 || font->num_cmap > TTF_FONT_MAX_CHAR) - { - errorf(font, "Invalid cmap table with %u characters.", (unsigned)font->num_cmap); - free(groups); - return (false); - } - - font->cmap = cmapptr = (int *)malloc(font->num_cmap * sizeof(int)); - - if (!font->cmap) - { - errorf(font, "Unable to allocate cmap."); - free(groups); - return (false); - } - - memset(cmapptr, -1, font->num_cmap * sizeof(int)); - - // Now loop through the groups and assign glyph indices from the - // array... - for (gidx = 0, group = groups; gidx < nGroups; gidx ++, group ++) - { - for (ch = group->startCharCode; ch <= group->endCharCode && ch < font->num_cmap; ch ++) - cmapptr[ch] = (int)group->glyphID; - } - - // Free the group data... - free(groups); - } - break; - - default : - errorf(font, "Format %d cmap tables are not yet supported.", cformat); - return (false); - } - -#ifdef DEBUG - cmapptr = font->cmap; - for (i = 0; i < (int)font->num_cmap && i < 127; i ++) - { - if (cmapptr[i] >= 0) - TTF_DEBUG("read_cmap; cmap[%d]=%d\n", i, cmapptr[i]); - } -#endif // DEBUG - - return (true); -} - - -// -// 'read_head()' - Read the head table. -// - -static bool // O - `true` on success, `false` on error -read_head(ttf_t *font, // I - Font - _ttf_off_head_t *head) // O - head table data -{ - memset(head, 0, sizeof(_ttf_off_head_t)); - - if (seek_table(font, TTF_OFF_head, 0, true) == 0) - return (false); - - /* majorVersion */ read_ushort(font); - /* minorVersion */ read_ushort(font); - /* fontRevision */ read_ulong(font); - /* checkSumAdjustment */ read_ulong(font); - /* magicNumber */ read_ulong(font); - /* flags */ read_ushort(font); - head->unitsPerEm = (unsigned short)read_ushort(font); - /* created */ read_ulong(font); read_ulong(font); - /* modified */ read_ulong(font); read_ulong(font); - head->xMin = (short)read_short(font); - head->yMin = (short)read_short(font); - head->xMax = (short)read_short(font); - head->yMax = (short)read_short(font); - head->macStyle = (unsigned short)read_ushort(font); - - return (true); -} - - -// -// 'read_hhea()' - Read the hhea table. -// - -static bool // O - `true` on success, `false` on error -read_hhea(ttf_t *font, // I - Font - _ttf_off_hhea_t *hhea) // O - hhea table data -{ - int temp; // Temporary read value - - - memset(hhea, 0, sizeof(_ttf_off_hhea_t)); - - if (seek_table(font, TTF_OFF_hhea, 0, true) == 0) - return (false); - - /* majorVersion */ read_ushort(font); - /* minorVersion */ read_ushort(font); - hhea->ascender = (short)read_short(font); - hhea->descender = (short)read_short(font); - /* lineGap */ read_short(font); - /* advanceWidthMax */ read_ushort(font); - /* minLeftSideBearing */ read_short(font); - /* minRightSideBearing */ read_short(font); - /* mMaxExtent */ read_short(font); - /* caretSlopeRise */ read_short(font); - /* caretSlopeRun */ read_short(font); - /* caretOffset */ read_short(font); - /* (reserved) */ read_short(font); - /* (reserved) */ read_short(font); - /* (reserved) */ read_short(font); - /* (reserved) */ read_short(font); - /* metricDataFormat */ read_short(font); - if ((temp = read_ushort(font)) < 0) - return (false); - else - hhea->numberOfHMetrics = (unsigned short)temp; - - return (true); -} - - -// -// 'read_hmtx()' - Read the horizontal metrics from the font. -// - -static _ttf_metric_t * // O - Array of glyph metrics -read_hmtx(ttf_t *font, // I - Font - _ttf_off_hhea_t *hhea) // O - hhea table data -{ - unsigned length; // Length of hmtx table - unsigned i; // Looping var - _ttf_metric_t *widths; // Glyph metrics array - - - if ((length = seek_table(font, TTF_OFF_hmtx, 0, true)) == 0) - return (NULL); - - if (length < (unsigned)(4 * hhea->numberOfHMetrics)) - { - errorf(font, "Length of hhea table is only %u, expected at least %d.", length, 4 * hhea->numberOfHMetrics); - return (NULL); - } - - if ((widths = (_ttf_metric_t *)calloc((size_t)hhea->numberOfHMetrics, sizeof(_ttf_metric_t))) == NULL) - return (NULL); - - for (i = 0; i < hhea->numberOfHMetrics; i ++) - { - widths[i].width = (short)read_ushort(font); - widths[i].left_bearing = (short)read_short(font); - - TTF_DEBUG("read_hmtx: widths[%d].width=%d, .left_bearing=%d\n", i, widths[i].width, widths[i].left_bearing); - } - - return (widths); -} - - -// -// 'read_maxp()' - Read the number of glyphs in the font. -// - -static int // O - Number of glyphs or -1 on error -read_maxp(ttf_t *font) // I - Font -{ - // All we care about is the number of glyphs, so just grab that... - if (seek_table(font, TTF_OFF_maxp, 4, true) == 0) - return (-1); - else - return (read_ushort(font)); -} - - -// -// 'read_names()' - Read the name strings from a font. -// - -static bool // O - `true` on success, `false` on error -read_names(ttf_t *font) // I - Font -{ - unsigned length; // Length of names table - int i, // Looping var - format, // Name table format - offset; // Offset to storage - _ttf_off_name_t *name; // Current name - - - // Find the name table... - if ((length = seek_table(font, TTF_OFF_name, 0, true)) == 0) - return (false); - - if ((format = read_ushort(font)) < 0 || format > 1) - { - errorf(font, "Unsupported name table format %d.", format); - return (false); - } - - TTF_DEBUG("read_names: format=%d\n", format); - - if ((font->names.num_names = read_ushort(font)) < 1) - return (false); - - if ((font->names.names = (_ttf_off_name_t *)calloc((size_t)font->names.num_names, sizeof(_ttf_off_name_t))) == NULL) - return (false); - - if ((offset = read_ushort(font)) < 0 || (unsigned)offset >= length) - return (false); - - font->names.storage_size = length - (unsigned)offset; - if (font->names.storage_size > TTF_FONT_MAX_NAMES) - { - errorf(font, "Name table too large - %u bytes.", (unsigned)font->names.storage_size); - return (false); - } - - if ((font->names.storage = malloc(font->names.storage_size)) == NULL) - return (false); - - memset(font->names.storage, 'A', font->names.storage_size); - - for (i = font->names.num_names, name = font->names.names; i > 0; i --, name ++) - { - name->platform_id = (unsigned short)read_ushort(font); - name->encoding_id = (unsigned short)read_ushort(font); - name->language_id = (unsigned short)read_ushort(font); - name->name_id = (unsigned short)read_ushort(font); - name->length = (unsigned short)read_ushort(font); - name->offset = (unsigned short)read_ushort(font); - - TTF_DEBUG("name->platform_id=%d, encoding_id=%d, language_id=%d(0x%04x), name_id=%d, length=%d, offset=%d\n", name->platform_id, name->encoding_id, name->language_id, name->language_id, name->name_id, name->length, name->offset); - } - - if (format == 1) - { - // Skip language_id table... - int count = read_ushort(font); // Number of language IDs - - TTF_DEBUG("read_names: Skipping language_id table...\n"); - - while (count > 0) - { - /* length = */read_ushort(font); - /* offset = */read_ushort(font); - count --; - } - } - - length -= (unsigned)offset; - - if ((font->read_cb)(font, font->names.storage, length) == 0) - { - errorf(font, "Unable to read name table: %s", strerror(errno)); - return (false); - } - - return (true); -} - - -// -// 'read_os_2()' - Read the OS/2 table. -// - -static bool // O - `true` on success, `false` on error -read_os_2(ttf_t *font, // I - Font - _ttf_off_os_2_t *os_2) // O - OS/2 table -{ - int version; // OS/2 table version - unsigned char panose[10]; // panose value - - - memset(os_2, 0, sizeof(_ttf_off_os_2_t)); - - // Find the OS/2 table... - if (seek_table(font, TTF_OFF_OS_2, 0, false) == 0) - return (false); - - if ((version = read_ushort(font)) < 0) - return (false); - - TTF_DEBUG("read_names: version=%d\n", version); - - /* xAvgCharWidth */ read_short(font); - os_2->usWeightClass = (unsigned short)read_ushort(font); - os_2->usWidthClass = (unsigned short)read_ushort(font); - os_2->fsType = (unsigned short)read_ushort(font); - /* ySubscriptXSize */ read_short(font); - /* ySubscriptYSize */ read_short(font); - /* ySubscriptXOffset */ read_short(font); - /* ySubscriptYOffset */ read_short(font); - /* ySuperscriptXSize */ read_short(font); - /* ySuperscriptYSize */ read_short(font); - /* ySuperscriptXOffset */ read_short(font); - /* ySuperscriptYOffset */ read_short(font); - /* yStrikeoutSize */ read_short(font); - /* yStrikeoutOffset */ read_short(font); - /* sFamilyClass */ read_short(font); - /* panose[10] */ - if ((font->read_cb)(font, panose, sizeof(panose)) != sizeof(panose)) - return (false); - /* ulUnicodeRange1 */ read_ulong(font); - /* ulUnicodeRange2 */ read_ulong(font); - /* ulUnicodeRange3 */ read_ulong(font); - /* ulUnicodeRange4 */ read_ulong(font); - /* achVendID */ read_ulong(font); read_ulong(font); - read_ulong(font); read_ulong(font); - /* fsSelection */ read_ushort(font); - /* usFirstCharIndex */ read_ushort(font); - /* usLastCharIndex */ read_ushort(font); - os_2->sTypoAscender = (short)read_short(font); - os_2->sTypoDescender = (short)read_short(font); - /* sTypoLineGap */ read_short(font); - /* usWinAscent */ read_ushort(font); - /* usWinDescent */ read_ushort(font); - - if (version >= 4) - { - /* ulCodePageRange1 */ read_ulong(font); - /* ulCodePageRange2 */ read_ulong(font); - os_2->sxHeight = (short)read_short(font); - os_2->sCapHeight = (short)read_short(font); - } - - return (true); -} - - -// -// 'read_post()' - Read the PostScript table. -// - -static bool // O - `true` on success, `false` otherwise -read_post(ttf_t *font, // I - Font - _ttf_off_post_t *post) // I - PostScript table -{ - memset(post, 0, sizeof(_ttf_off_post_t)); - - if (seek_table(font, TTF_OFF_post, 0, false) == 0) - return (false); - - /* version = */read_ulong(font); - post->italicAngle = (int)read_ulong(font) / 65536.0f; - /* underlinePosition = */read_ushort(font); - /* underlineThickness = */read_ushort(font); - post->isFixedPitch = read_ulong(font); - - return (true); -} - - -// -// 'read_short()' - Read a 16-bit signed integer. -// - -static int // O - 16-bit signed integer value or EOF -read_short(ttf_t *font) // I - Font -{ - unsigned char buffer[2]; // Read buffer - - - if ((font->read_cb)(font, buffer, sizeof(buffer)) != sizeof(buffer)) - return (EOF); - else if (buffer[0] & 0x80) - return (((buffer[0] << 8) | buffer[1]) - 65536); - else - return ((buffer[0] << 8) | buffer[1]); -} - - -// -// 'read_table()' - Read an OFF/TTF offset table. -// - -static bool // O - `true` on success, `false` on error -read_table(ttf_t *font) // I - Font -{ - int i; // Looping var - unsigned temp; // Temporary value - _ttf_off_dir_t *current; // Current table entry - - - // Read the table header: - // - // Fixed sfnt version (should be 0x10000 for version 1.0) - // USHORT numTables - // USHORT searchRange - // USHORT entrySelector - // USHORT rangeShift - /* sfnt version */ - if ((temp = read_ulong(font)) != 0x10000 && temp != 0x4f54544f && temp != 0x74746366) - { - errorf(font, "Invalid font file."); - return (false); - } - - if (temp == 0x74746366) - { - // Font collection, get the number of fonts and then seek to the start of - // the offset table for the desired font... - size_t idx; // Current index - - TTF_DEBUG("read_table: Font collection\n"); - - /* Version */ - if ((temp = read_ulong(font)) != 0x10000 && temp != 0x20000) - { - errorf(font, "Unsupported font collection version %f.", temp / 65536.0); - return (false); - } - - TTF_DEBUG("read_table: Collection version=%f\n", temp / 65536.0); - - /* numFonts */ - if ((temp = read_ulong(font)) == 0) - { - errorf(font, "No fonts in collection."); - return (false); - } - - font->num_fonts = (size_t)temp; - - TTF_DEBUG("read_table: numFonts=%u\n", temp); - - if (font->idx >= font->num_fonts) - return (false); - - /* OffsetTable */ - temp = read_ulong(font); - for (idx = font->idx; idx > 0; idx --) - temp = read_ulong(font); - - TTF_DEBUG("read_table: Offset for font %u is %u.\n", (unsigned)font->idx, temp); - - if (!(font->seek_cb)(font, temp + 4)) - { - errorf(font, "Unable to seek to font %u: %s", (unsigned)font->idx, strerror(errno)); - return (false); - } - } - else - { - // Not a collection so just one font... - font->num_fonts = 1; - } - - // numTables - if ((font->table.num_entries = read_ushort(font)) <= 0) - { - errorf(font, "Unable to read font tables."); - return (false); - } - - TTF_DEBUG("read_table: num_entries=%u\n", (unsigned)font->table.num_entries); - - // searchRange - if (read_ushort(font) < 0) - { - errorf(font, "Unable to read font tables."); - return (false); - } - - // entrySelector - if (read_ushort(font) < 0) - { - errorf(font, "Unable to read font tables."); - return (false); - } - - // rangeShift - if (read_ushort(font) < 0) - { - errorf(font, "Unable to read font tables."); - return (false); - } - - /* - * Read the table entries... - */ - - if ((font->table.entries = calloc((size_t)font->table.num_entries, sizeof(_ttf_off_dir_t))) == NULL) - { - errorf(font, "Unable to allocate memory for font tables."); - return (false); - } - - for (i = font->table.num_entries, current = font->table.entries; i > 0; i --, current ++) - { - current->tag = read_ulong(font); - current->checksum = read_ulong(font); - current->offset = read_ulong(font); - current->length = read_ulong(font); - - TTF_DEBUG("read_table: [%d] tag='%c%c%c%c' checksum=%u offset=%u length=%u\n", i, (current->tag >> 24) & 255, (current->tag >> 16) & 255, (current->tag >> 8) & 255, current->tag & 255, current->checksum, current->offset, current->length); - } - - return (true); -} - - -// -// 'read_ulong()' - Read a 32-bit unsigned integer. -// - -static unsigned // O - 32-bit unsigned integer value or EOF -read_ulong(ttf_t *font) // I - Font -{ - unsigned char buffer[4]; // Read buffer - - - if ((font->read_cb)(font, buffer, sizeof(buffer)) != sizeof(buffer)) - return ((unsigned)EOF); - else - return ((unsigned)((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3])); -} - - -// -// 'read_ushort()' - Read a 16-bit unsigned integer. -// - -static int // O - 16-bit unsigned integer value or EOF -read_ushort(ttf_t *font) // I - Font -{ - unsigned char buffer[2]; // Read buffer - - - if ((font->read_cb)(font, buffer, sizeof(buffer)) != sizeof(buffer)) - return (EOF); - else - return ((buffer[0] << 8) | buffer[1]); -} - - -// -// 'seek_table()' - Seek to a specific table in a font. -// - -static unsigned // O - Length of table or 0 if not found -seek_table(ttf_t *font, // I - Font - unsigned tag, // I - Tag to find - unsigned offset, // I - Additional offset - bool required) // I - Required table? -{ - int i; // Looping var - _ttf_off_dir_t *current; // Current entry - - - // Look up the tag in the table... - for (i = font->table.num_entries, current = font->table.entries; i > 0; i --, current ++) - { - if (current->tag == tag) - { - // Found it, seek and return... - if ((font->seek_cb)(font, current->offset + offset)) - { - // Successful seek... - return (current->length - offset); - } - else - { - // Seek failed... - errorf(font, "Unable to seek to %c%c%c%c table: %s", (tag >> 24) & 255, (tag >> 16) & 255, (tag >> 8) & 255, tag & 255, strerror(errno)); - return (0); - } - } - } - - // Not found, return 0... - if (required) - errorf(font, "%c%c%c%c table not found.", (tag >> 24) & 255, (tag >> 16) & 255, (tag >> 8) & 255, tag & 255); - - return (0); -} diff --git a/ttf.h b/ttf.h deleted file mode 100644 index ca519d5..0000000 --- a/ttf.h +++ /dev/null @@ -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 -# include -# include -# 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