Update to fonttosfnt 1.2.0.

Includes work done by chrisz@ to fix issues for recent pango versions.
tested with st and gvim and OK chrisz@
This commit is contained in:
matthieu 2020-10-23 11:17:04 +00:00
parent eec02f95fe
commit f3f39cb65b
13 changed files with 469 additions and 190 deletions

View File

@ -1,3 +1,135 @@
commit 91af80a0aa18c969cd90668eed80bcbfc1e40661
Author: Peter Hutterer <peter.hutterer@who-t.net>
Date: Wed Oct 21 16:36:30 2020 +1000
Bump to 1.2.0
commit ca9ad454496bebbc37125959d049cf2173c07c2a
Author: Christopher Zimmermann <madroach@gmerlin.de>
Date: Sun Aug 16 21:56:15 2020 +0200
use PIXEL_SIZE to calculate lineGap
commit 0447b81053d4ccaa1e1b0087bf6076abae431cae
Author: Christopher Zimmermann <madroach@gmerlin.de>
Date: Fri Jul 31 00:07:26 2020 +0200
fix sign of sTypoDescender
commit 747c58aa17b9adc016aed0caab049417a20f0b22
Author: Christopher Zimmermann <madroach@gmerlin.de>
Date: Thu Jul 30 22:46:50 2020 +0200
calculate capHeight and xHeight as recommended
commit 64e7f386baf69fa6857047fc8ad9b4cd9a8185f1
Author: Christopher Zimmermann <madroach@gmerlin.de>
Date: Thu Jul 30 21:34:59 2020 +0200
move metrics calculation to write.c
commit 19412d9ac3fb7f00346273cfe914601c844f5872
Author: Christopher Zimmermann <madroach@gmerlin.de>
Date: Sat Jul 18 08:39:01 2020 +0200
Add warnings when wrapping multiple fonts and on PCF fonts
commit 1fa97fdc6dc900728be8523be89096b4cb117d4d
Author: Christopher Zimmermann <madroach@gmerlin.de>
Date: Sun Jul 12 15:36:18 2020 +0200
provide version 5 OS/2 table
this was an attempt to fix linespacing, which did not help, but
would still keep it around to avoid double efforts.
commit facf71184163d50adf0b8fccffcaffa18b7bd277
Author: Christopher Zimmermann <madroach@gmerlin.de>
Date: Sun Jul 12 15:12:59 2020 +0200
use design metrics in eblc instead of calculated metrics
This will probably not work for a font providing multiple strikes.
But .bdf fonts don't provide multiple strikes (or do they?!?)
I don't know about .pcf fonts, but I would recommend against running fonttosfnt
on .pcf fonts because bdf2pcf seems to loose some attributes during conversion.
commit 9fb05de7d6c57d045b4a88516f3c28cf3cf98722
Author: Christopher Zimmermann <madroach@gmerlin.de>
Date: Tue Jul 7 21:02:56 2020 +0200
use more properties according to XLFD
commit 58cbf737557f34744b950668e3354ec2f2dae766
Author: Christopher Zimmermann <madroach@gmerlin.de>
Date: Mon Jul 6 22:50:23 2020 +0200
use standard C rounding functions
commit f8fa7919397659fb0ac5dade75152343d57f20ce
Author: Christopher Zimmermann <madroach@gmerlin.de>
Date: Tue Jun 16 18:43:12 2020 +0200
correctly set OS2 fsSelection for italic and bold fonts
commit 1df352c9e862686692ac053b838d76a36d721805
Author: Christopher Zimmermann <madroach@gmerlin.de>
Date: Mon Jun 15 14:08:49 2020 +0200
truncate foundry if there is no known abbreviation.
Honestly I have no idea why the foundry needs to fit in four bytes.
But anyway truncation might indeed be better then "UNKN" ?
Anyone more knowledgeable than me out there?
commit 8532812f1eddfadc0bcfad220b283bf5990bba10
Author: Christopher Zimmermann <madroach@gmerlin.de>
Date: Sun May 31 08:02:24 2020 +0200
use zero lineGap, sTypoDescender should be negative
According to
https://simoncozens.github.io/fonts-and-layout/opentype.html#vertical-metrics-hhea-and-os2
sTypoDescender should be negative and lineGap should be zero.
commit de8068f9c4251fb6cb9407c07bf245e1937270bc
Author: Christopher Zimmermann <madroach@gmerlin.de>
Date: Sun May 31 07:58:10 2020 +0200
don't add arbitrary number to the glypth metrics
This caused pango to calculate wrong, too large font extents and in
consequence gvim used too large character cells.
commit 7096c58f3fe3b6c79508cb16daac5c5bb2f042e7
Author: Peng Wu <pwu@redhat.com>
Date: Thu Jun 11 14:09:35 2020 +0800
Guess Regular style for Medium Weight
X Logical Font Description recognize "Medium" as "Regular".
Update the faceWeight function to change style from "Medium" to "Regular".
commit 81a61c049e6de80120531f0770b22e7637c9acb9
Author: rnhmjoj <rnhmjoj@inventati.org>
Date: Fri Feb 7 17:47:52 2020 +0100
Fix uninitialised memory write
If macTime() fails write zeros instead of unitialized memory to
the date fields.
commit 51e8117654fb092ae5412d7aa184bfc6b498c954
Author: rnhmjoj <rnhmjoj@inventati.org>
Date: Fri Feb 7 17:46:54 2020 +0100
Fix incorrect error handling in macTime()
mktime() and time() return (time_t -1) to signal an error.
Checking for negative values will incorrectly assume an error
happened for any calendar date before the unix epoch.
commit 1d757ff6fa30079790fc44b141f6d0e4d5411f13
Author: Peter Hutterer <peter.hutterer@who-t.net>
Date: Mon Jan 6 12:55:31 2020 +1000

View File

@ -306,6 +306,7 @@ pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@

View File

@ -19,9 +19,9 @@ You have another version of autoconf. It may work, but is not guaranteed to.
If you have problems, you may need to regenerate the build system entirely.
To do so, use the procedure documented by the package, typically 'autoreconf'.])])
dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
dnl serial 11 (pkg-config-0.29.1)
dnl
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
# serial 12 (pkg-config-0.29.2)
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
dnl
@ -62,7 +62,7 @@ dnl
dnl See the "Since" comment for each macro you use to see what version
dnl of the macros you require.
m4_defun([PKG_PREREQ],
[m4_define([PKG_MACROS_VERSION], [0.29.1])
[m4_define([PKG_MACROS_VERSION], [0.29.2])
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
])dnl PKG_PREREQ
@ -163,7 +163,7 @@ AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
pkg_failed=no
AC_MSG_CHECKING([for $1])
AC_MSG_CHECKING([for $2])
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
@ -173,7 +173,7 @@ and $1[]_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.])
if test $pkg_failed = yes; then
AC_MSG_RESULT([no])
AC_MSG_RESULT([no])
_PKG_SHORT_ERRORS_SUPPORTED
if test $_pkg_short_errors_supported = yes; then
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
@ -194,7 +194,7 @@ installed software in a non-standard prefix.
_PKG_TEXT])[]dnl
])
elif test $pkg_failed = untried; then
AC_MSG_RESULT([no])
AC_MSG_RESULT([no])
m4_default([$4], [AC_MSG_FAILURE(
[The pkg-config script could not be found or is too old. Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full

View File

@ -3,7 +3,7 @@
scriptversion=2018-03-07.03; # UTC
# Copyright (C) 1999-2018 Free Software Foundation, Inc.
# Copyright (C) 1999-2020 Free Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify
@ -53,7 +53,7 @@ func_file_conv ()
MINGW*)
file_conv=mingw
;;
CYGWIN*)
CYGWIN* | MSYS*)
file_conv=cygwin
;;
*)
@ -67,7 +67,7 @@ func_file_conv ()
mingw/*)
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
;;
cygwin/*)
cygwin/* | msys/*)
file=`cygpath -m "$file" || echo "$file"`
;;
wine/*)

View File

@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for fonttosfnt 1.1.0.
# Generated by GNU Autoconf 2.69 for fonttosfnt 1.2.0.
#
# Report bugs to <https://gitlab.freedesktop.org/xorg/app/fonttosfnt/issues>.
#
@ -581,8 +581,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='fonttosfnt'
PACKAGE_TARNAME='fonttosfnt'
PACKAGE_VERSION='1.1.0'
PACKAGE_STRING='fonttosfnt 1.1.0'
PACKAGE_VERSION='1.2.0'
PACKAGE_STRING='fonttosfnt 1.2.0'
PACKAGE_BUGREPORT='https://gitlab.freedesktop.org/xorg/app/fonttosfnt/issues'
PACKAGE_URL=''
@ -731,6 +731,7 @@ infodir
docdir
oldincludedir
includedir
runstatedir
localstatedir
sharedstatedir
sysconfdir
@ -811,6 +812,7 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@ -1063,6 +1065,15 @@ do
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
-runstatedir | --runstatedir | --runstatedi | --runstated \
| --runstate | --runstat | --runsta | --runst | --runs \
| --run | --ru | --r)
ac_prev=runstatedir ;;
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
| --run=* | --ru=* | --r=*)
runstatedir=$ac_optarg ;;
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@ -1200,7 +1211,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
libdir localedir mandir
libdir localedir mandir runstatedir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
@ -1313,7 +1324,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures fonttosfnt 1.1.0 to adapt to many kinds of systems.
\`configure' configures fonttosfnt 1.2.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1353,6 +1364,7 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@ -1383,7 +1395,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of fonttosfnt 1.1.0:";;
short | recursive ) echo "Configuration of fonttosfnt 1.2.0:";;
esac
cat <<\_ACEOF
@ -1492,7 +1504,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
fonttosfnt configure 1.1.0
fonttosfnt configure 1.2.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@ -1816,7 +1828,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by fonttosfnt $as_me 1.1.0, which was
It was created by fonttosfnt $as_me 1.2.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@ -2645,7 +2657,7 @@ fi
# Define the identity of the package.
PACKAGE='fonttosfnt'
VERSION='1.1.0'
VERSION='1.2.0'
cat >>confdefs.h <<_ACEOF
@ -10513,8 +10525,8 @@ fi
# Checks for pkg-config packages
pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for FONTTOSFNT" >&5
$as_echo_n "checking for FONTTOSFNT... " >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for xproto freetype2 fontenc" >&5
$as_echo_n "checking for xproto freetype2 fontenc... " >&6; }
if test -n "$FONTTOSFNT_CFLAGS"; then
pkg_cv_FONTTOSFNT_CFLAGS="$FONTTOSFNT_CFLAGS"
@ -10554,7 +10566,7 @@ fi
if test $pkg_failed = yes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@ -10581,7 +10593,7 @@ Alternatively, you may set the environment variables FONTTOSFNT_CFLAGS
and FONTTOSFNT_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details." "$LINENO" 5
elif test $pkg_failed = untried; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
@ -11144,7 +11156,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by fonttosfnt $as_me 1.1.0, which was
This file was extended by fonttosfnt $as_me 1.2.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -11210,7 +11222,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
fonttosfnt config.status 1.1.0
fonttosfnt config.status 1.2.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"

View File

@ -23,7 +23,7 @@ dnl Process this file with autoconf to create configure.
# Initialize Autoconf
AC_PREREQ([2.60])
AC_INIT(fonttosfnt,[1.1.0], [https://gitlab.freedesktop.org/xorg/app/fonttosfnt/issues],fonttosfnt)
AC_INIT(fonttosfnt,[1.2.0], [https://gitlab.freedesktop.org/xorg/app/fonttosfnt/issues],fonttosfnt)
AC_CONFIG_SRCDIR([Makefile.am])
AC_CONFIG_HEADERS([config.h])

View File

@ -106,6 +106,12 @@ main(int argc, char **argv)
font = makeFont();
if(argc - i > 1)
fprintf(stderr,
"You are requesting to put more than one font into a single OpenType font.\n"
"This is not recommended. The global font metrics will not match every font face.\n"
"The creation of an OpenType font collection is recommended.\n");
if(i == argc) {
rc = readFile(NULL, font);
if(rc != 0)

View File

@ -29,6 +29,7 @@ THE SOFTWARE.
#endif
#include <stdarg.h>
#include <math.h>
#include <ft2build.h>
#include FT_FREETYPE_H
@ -69,17 +70,15 @@ extern int reencode_flag;
#define UNITS_PER_EM 2048
#define EPSILON 0.000000001
#define FLOOR(x) ((x) < 0.0 ? -(int)(-(x)) : (x))
#define CEIL(x) FLOOR((x) + 1.0 - EPSILON)
#define UNDEF 0x80000000
/* Convert a fixed-point value into FUnits */
#define FONT_UNITS(x) \
FLOOR(((double)(x)) / TWO_SIXTEENTH * UNITS_PER_EM + 0.5)
round(((double)(x)) / TWO_SIXTEENTH * UNITS_PER_EM)
#define FONT_UNITS_FLOOR(x) \
FLOOR(((double)(x)) / TWO_SIXTEENTH * UNITS_PER_EM)
floor(((double)(x)) / TWO_SIXTEENTH * UNITS_PER_EM)
#define FONT_UNITS_CEIL(x) \
CEIL(((double)(x)) / TWO_SIXTEENTH * UNITS_PER_EM)
ceil(((double)(x)) / TWO_SIXTEENTH * UNITS_PER_EM)
typedef struct _FontNameEntry {
int nid; /* name id */
@ -87,6 +86,23 @@ typedef struct _FontNameEntry {
char *value;
} FontNameEntryRec, *FontNameEntryPtr;
typedef struct _Metrics {
int height;
int size;
int maxX;
int minX;
int maxY;
int minY;
int xHeight;
int capHeight;
int maxAwidth;
int awidth;
int ascent;
int descent;
int underlinePosition;
int underlineThickness;
} MetricsRec, *MetricsPtr;
typedef struct _Font {
int numNames;
struct _FontNameEntry *names;
@ -94,8 +110,8 @@ typedef struct _Font {
int weight; /* as in the OS/2 table */
int width; /* as in the OS/2 table */
int italicAngle; /* degrees c-clockwise from the vertical */
int underlinePosition;
int underlineThickness;
MetricsRec pxMetrics;
MetricsRec metrics;
unsigned foundry;
struct _Strike *strikes;
} FontRec, *FontPtr;
@ -152,9 +168,9 @@ CmapPtr makeCmap(FontPtr);
int findIndex(CmapPtr, int);
int findCode(CmapPtr, int);
BitmapPtr strikeBitmapIndex(StrikePtr, CmapPtr, int);
void strikeMetrics(StrikePtr, int*, int*, int*, int*, int*);
int strikeMaxWidth(StrikePtr);
int glyphMetrics(FontPtr, int, int*, int*, int*, int*, int*);
void fontMetrics(FontPtr, int*, int*, int*, int*, int*);
void fontMetrics(FontPtr);
int maxIndex(CmapPtr);
int readFile(char *filename, FontPtr);
@ -174,6 +190,7 @@ int macTime(int *, unsigned *);
unsigned faceFoundry(FT_Face);
char *faceEncoding(FT_Face);
int faceFlags(FT_Face);
int faceIntProp(FT_Face, const char *);
int faceWeight(FT_Face);
int faceWidth(FT_Face);
int faceItalicAngle(FT_Face);

View File

@ -222,6 +222,7 @@ pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@

View File

@ -29,6 +29,7 @@ THE SOFTWARE.
#include FT_FREETYPE_H
#include FT_MODULE_H
#include FT_BDF_H
#include FT_FONT_FORMATS_H
#include "X11/Xos.h"
#include "fonttosfnt.h"
#include "X11/fonts/fontenc.h"
@ -102,7 +103,7 @@ readFile(char *filename, FontPtr font)
BitmapPtr bitmap;
int symbol = 0;
int force_unicode = 1;
char *encoding_name = NULL;
const char *encoding_name, *file_format;
FontMapPtr mapping = NULL;
FontMapReversePtr reverse = NULL;
@ -133,6 +134,15 @@ readFile(char *filename, FontPtr font)
return -1;
}
file_format = FT_Get_Font_Format(face);
if(strcmp(file_format, "BDF") != 0)
fprintf(stderr,
"font file %s is of format %s.\n"
"It's recommended to convert directly from a BDF font.\n"
"Some font properties may get lost when converting via a PCF font.\n",
filename ? filename : "<stdin>",
file_format);
/* FreeType will insist on encodings which are simple subsets of unicode
* to be read as unicode regardless of what we call them. */
for(j = 0; j < face->num_charmaps; ++j) {
@ -258,30 +268,6 @@ readFile(char *filename, FontPtr font)
i++;
#endif
font->numNames = i;
font->flags = faceFlags(face) | (symbol ? FACE_SYMBOL : 0);
font->weight = faceWeight(face);
font->width = faceWidth(face);
font->foundry = faceFoundry(face);
font->italicAngle = faceItalicAngle(face);
rc = FT_Get_BDF_Property(face, "UNDERLINE_POSITION", &prop);
if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
font->underlinePosition =
(double)prop.u.integer / face->available_sizes[0].height *
TWO_SIXTEENTH;
else
font->underlinePosition =
- 1.5 / face->available_sizes[0].height * TWO_SIXTEENTH;
rc = FT_Get_BDF_Property(face, "UNDERLINE_THICKNESS", &prop);
if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
font->underlineThickness =
(double)prop.u.integer / face->available_sizes[0].height *
TWO_SIXTEENTH;
else
font->underlineThickness =
1.0 / face->available_sizes[0].height * TWO_SIXTEENTH;
}
if(face->num_fixed_sizes == 0) {
@ -304,6 +290,20 @@ readFile(char *filename, FontPtr font)
return -1;
}
font->flags = faceFlags(face) | (symbol ? FACE_SYMBOL : 0);
font->weight = faceWeight(face);
font->width = faceWidth(face);
font->foundry = faceFoundry(face);
font->italicAngle = faceItalicAngle(face);
font->pxMetrics.height = face->available_sizes[0].height;
font->pxMetrics.size = faceIntProp(face, "PIXEL_SIZE");
font->pxMetrics.xHeight = faceIntProp(face, "X_HEIGHT");
font->pxMetrics.capHeight = faceIntProp(face, "CAP_HEIGHT");
font->pxMetrics.ascent = faceIntProp(face, "FONT_ASCENT");
font->pxMetrics.descent = faceIntProp(face, "FONT_DESCENT");
font->pxMetrics.underlinePosition = faceIntProp(face, "UNDERLINE_POSITION");
font->pxMetrics.underlineThickness = faceIntProp(face, "UNDERLINE_THICKNESS");
for(int i = 0; i < face->num_fixed_sizes; i++) {
if(verbose_flag)
fprintf(stderr, "size %d: %dx%d\n",

View File

@ -42,8 +42,32 @@ makeFont(void)
font->weight = 500;
font->width = 5;
font->italicAngle = 0;
font->underlinePosition = - TWO_SIXTEENTH;
font->underlineThickness = TWO_SIXTEENTH;
font->pxMetrics.height = UNDEF;
font->pxMetrics.maxX = UNDEF;
font->pxMetrics.minX = UNDEF;
font->pxMetrics.maxY = UNDEF;
font->pxMetrics.minY = UNDEF;
font->pxMetrics.xHeight = UNDEF;
font->pxMetrics.capHeight = UNDEF;
font->pxMetrics.maxAwidth = UNDEF;
font->pxMetrics.awidth = UNDEF;
font->pxMetrics.ascent = UNDEF;
font->pxMetrics.descent = UNDEF;
font->pxMetrics.underlinePosition = UNDEF;
font->pxMetrics.underlineThickness = UNDEF;
font->metrics.height = UNDEF;
font->metrics.maxX = UNDEF;
font->metrics.minX = UNDEF;
font->metrics.maxY = UNDEF;
font->metrics.minY = UNDEF;
font->metrics.xHeight = UNDEF;
font->metrics.capHeight = UNDEF;
font->metrics.maxAwidth = UNDEF;
font->metrics.awidth = UNDEF;
font->metrics.ascent = UNDEF;
font->metrics.descent = UNDEF;
font->metrics.underlinePosition = UNDEF;
font->metrics.underlineThickness = UNDEF;
font->foundry = makeName("UNKN");
font->strikes = NULL;
return font;
@ -401,19 +425,12 @@ strikeBitmapIndex(StrikePtr strike, CmapPtr cmap, int index)
return STRIKE_BITMAP(strike, code);
}
void
strikeMetrics(StrikePtr strike,
int *width_max_return,
int *x_min_return, int *y_min_return,
int *x_max_return, int *y_max_return)
int
strikeMaxWidth(StrikePtr strike)
{
BitmapPtr bitmap;
int i;
int width_max = 0;
int x_min = 10000;
int y_min = 10000;
int x_max = -10000;
int y_max = -10000;
for(i = 0; i < FONT_CODES; i++) {
bitmap = STRIKE_BITMAP(strike, i);
@ -421,21 +438,9 @@ strikeMetrics(StrikePtr strike,
continue;
if(bitmap->advanceWidth > width_max)
width_max = bitmap->advanceWidth;
if(bitmap->horiBearingX < x_min)
x_min = bitmap->horiBearingX;
if(bitmap->horiBearingY > y_max)
y_max = bitmap->horiBearingY;
if(bitmap->horiBearingX + bitmap->width > x_max)
x_max = bitmap->horiBearingX + bitmap->width;
if(bitmap->horiBearingY - bitmap->height < y_min)
y_min = bitmap->horiBearingY - bitmap->height;
}
if(width_max_return) *width_max_return = width_max;
if(x_min_return) *x_min_return = x_min;
if(y_min_return) *y_min_return = y_min;
if(x_max_return) *x_max_return = x_max;
if(y_max_return) *y_max_return = y_max;
return width_max;
}
int
@ -453,7 +458,7 @@ glyphMetrics(FontPtr font, int code,
if(bitmap) {
if(width_return)
*width_return =
(((float)bitmap->advanceWidth + 0.5) / strike->sizeX) *
(((float)bitmap->advanceWidth) / strike->sizeX) *
TWO_SIXTEENTH;
if(x_min_return)
*x_min_return =
@ -463,17 +468,13 @@ glyphMetrics(FontPtr font, int code,
*y_min_return =
(((float)bitmap->horiBearingY - bitmap->height)
/ strike->sizeY) * TWO_SIXTEENTH;
/* For the following two, 0.9 instead of 0.5 might make
more sense. However, using different rounding rules
for x_max and awidth causes problems for detecting
charcell fonts. */
if(x_max_return)
*x_max_return =
(((float)bitmap->horiBearingX + bitmap->width + 0.5)
(((float)bitmap->horiBearingX + bitmap->width)
/ strike->sizeX) * TWO_SIXTEENTH;
if(y_max_return)
*y_max_return =
(((float)bitmap->horiBearingY + 0.5) / strike->sizeY) *
(((float)bitmap->horiBearingY) / strike->sizeY) *
TWO_SIXTEENTH;
return 1;
}
@ -482,33 +483,3 @@ glyphMetrics(FontPtr font, int code,
return -1;
}
void
fontMetrics(FontPtr font,
int *max_awidth_return,
int *min_x_return, int *min_y_return,
int *max_x_return, int *max_y_return)
{
int i, rc;
int max_awidth = 0;
int min_x = 10000 * 65536, min_y = 10000 * 65536;
int max_x = -10000 * 65536, max_y = -10000 * 65536;
for(i = 0; i < FONT_CODES; i++) {
int awidth, x0, y0, x1, y1;
rc = glyphMetrics(font, i, &awidth, &x0, &y0, &x1, &y1);
if(rc < 0)
continue;
if(awidth > max_awidth)
max_awidth = awidth;
if(x0 < min_x) min_x = x0;
if(y0 < min_y) min_y = y0;
if(x1 > max_x) max_x = x1;
if(y1 > max_y) max_y = y1;
}
if(max_awidth_return) *max_awidth_return = max_awidth;
if(min_x_return) *min_x_return = min_x;
if(min_y_return) *min_y_return = min_y;
if(max_x_return) *max_x_return = max_x;
if(max_y_return) *max_y_return = max_y;
}

View File

@ -213,10 +213,10 @@ macTime(int *hi, unsigned *lo)
tm.tm_isdst = -1;
macEpoch = mktime_gmt(&tm);
if(macEpoch < 0) return -1;
if(macEpoch == -1) return -1;
current = time(NULL);
if(current < 0)
if(current == -1)
return -1;
if(current < macEpoch) {
@ -280,8 +280,11 @@ faceFoundry(FT_Face face)
return makeName("URW ");
else if(strcasecmp(prop.u.atom, "y&y") == 0)
return makeName("Y&Y ");
else
return makeName("UNKN");
else {
char buf[5];
snprintf(buf, sizeof(buf), "%-4s", prop.u.atom);
return makeName(buf);
}
}
/* For now */
return makeName("UNKN");
@ -302,7 +305,7 @@ faceWeight(FT_Face face)
else if(strcasecmp(prop.u.atom, "light") == 0)
return 300;
else if(strcasecmp(prop.u.atom, "medium") == 0)
return 500;
return 400;
else if(strcasecmp(prop.u.atom, "semibold") == 0)
return 600;
else if(strcasecmp(prop.u.atom, "bold") == 0)
@ -312,9 +315,9 @@ faceWeight(FT_Face face)
else if(strcasecmp(prop.u.atom, "black") == 0)
return 900;
else
return 500;
return 400;
} else
return 500; /* for now */
return 400; /* for now */
}
int
@ -388,6 +391,19 @@ faceFlags(FT_Face face)
return flags;
}
int
faceIntProp(FT_Face face, const char *name)
{
int rc;
BDF_PropertyRec prop;
rc = FT_Get_BDF_Property(face, name, &prop);
if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
return prop.u.integer;
else
return UNDEF;
}
char *
faceEncoding(FT_Face face)
{

View File

@ -61,7 +61,6 @@ static int writemaxp(FILE*, FontPtr);
static int writename(FILE*, FontPtr);
static int writepost(FILE*, FontPtr);
int max_awidth, min_x, min_y, max_x, max_y;
static CmapPtr current_cmap = NULL;
static int numglyphs, nummetrics;
static int write_error_occurred, read_error_occurred;
@ -206,6 +205,117 @@ readULONG(FILE *out)
return ntohl(val);
}
void
fontMetrics(FontPtr font)
{
int i, rc;
double sumAwidth = 0;
unsigned count = 0;
font->metrics.maxAwidth = 0;
font->metrics.maxX = -10000 * TWO_SIXTEENTH;
font->metrics.maxY = -10000 * TWO_SIXTEENTH;
font->metrics.minX = 10000 * TWO_SIXTEENTH;
font->metrics.minY = 10000 * TWO_SIXTEENTH;
for(i = 0; i < FONT_CODES; i++) {
int awidth, x0, y0, x1, y1;
rc = glyphMetrics(font, i, &awidth, &x0, &y0, &x1, &y1);
if(rc < 0)
continue;
if(awidth > font->metrics.maxAwidth) font->metrics.maxAwidth = awidth;
if(x0 < font->metrics.minX) font->metrics.minX = x0;
if(y0 < font->metrics.minY) font->metrics.minY = y0;
if(x1 > font->metrics.maxX) font->metrics.maxX = x1;
if(y1 > font->metrics.maxY) font->metrics.maxY = y1;
if(awidth > 0) {
sumAwidth += awidth;
count++;
}
}
if (count) font->metrics.awidth = sumAwidth / count;
font->metrics.height = TWO_SIXTEENTH;
if(font->pxMetrics.size == UNDEF) {
font->pxMetrics.size = font->pxMetrics.height;
font->metrics.size = font->metrics.height;
}
font->metrics.size = font->pxMetrics.size
* TWO_SIXTEENTH / font->pxMetrics.height;
if(font->pxMetrics.ascent == UNDEF) {
font->metrics.ascent = font->metrics.maxY;
font->pxMetrics.ascent =
font->metrics.ascent
* font->pxMetrics.height / TWO_SIXTEENTH;
}
else
font->metrics.ascent =
font->pxMetrics.ascent
* TWO_SIXTEENTH / font->pxMetrics.height;
if(font->pxMetrics.descent == UNDEF) {
font->metrics.descent = font->metrics.minY;
font->pxMetrics.descent =
font->metrics.descent
* font->pxMetrics.height / TWO_SIXTEENTH;
}
else
font->metrics.descent =
font->pxMetrics.descent
* TWO_SIXTEENTH / font->pxMetrics.height;
if(font->pxMetrics.capHeight == UNDEF) {
if(glyphMetrics(font, 'X', NULL, NULL, NULL, NULL, &font->metrics.capHeight) != 1)
font->metrics.capHeight = font->metrics.ascent;
font->pxMetrics.capHeight =
font->metrics.capHeight * font->pxMetrics.height / TWO_SIXTEENTH;
}
else
font->metrics.capHeight =
font->pxMetrics.capHeight
* TWO_SIXTEENTH / font->pxMetrics.height;
if(font->pxMetrics.xHeight == UNDEF) {
if(glyphMetrics(font, 'x', NULL, NULL, NULL, NULL, &font->metrics.xHeight) != 1)
font->metrics.xHeight = font->metrics.capHeight * 2 / 3;
font->pxMetrics.xHeight =
font->metrics.xHeight * font->pxMetrics.height / TWO_SIXTEENTH;
}
else
font->metrics.xHeight =
font->pxMetrics.xHeight
* TWO_SIXTEENTH / font->pxMetrics.height;
if(font->pxMetrics.underlinePosition == UNDEF)
font->metrics.underlinePosition = - font->metrics.descent * 2;
else {
fprintf(stderr, "Setting underlinePosition. pxMetrics.underlinePosition is %d. height is %d\n",
font->pxMetrics.underlinePosition, font->pxMetrics.height);
font->metrics.underlinePosition =
font->pxMetrics.underlinePosition
* TWO_SIXTEENTH / font->pxMetrics.height;
}
if(font->pxMetrics.underlineThickness == UNDEF)
/* make sure thickness is at least one pixel. */
/* TODO: this could be refined according to
* X Logical Font Description Conventions (xlfd.txt)
* by also considering the font weight. */
font->metrics.underlineThickness =
TWO_SIXTEENTH
/ (font->pxMetrics.height < 9 ? font->pxMetrics.height : 9);
else
font->metrics.underlineThickness =
font->pxMetrics.underlineThickness
* TWO_SIXTEENTH / font->pxMetrics.height;
}
int
writeFile(char *filename, FontPtr font)
{
@ -219,8 +329,6 @@ writeFile(char *filename, FontPtr font)
int offset[15], length[15];
StrikePtr strike;
fontMetrics(font, &max_awidth, &min_x, &min_y, &max_x, &max_y);
out = fopen(filename, "wb+");
if(out == NULL)
return -1;
@ -231,6 +339,8 @@ writeFile(char *filename, FontPtr font)
return -1;
}
fontMetrics(font);
write_error_occurred = 0;
read_error_occurred = 0;
@ -434,8 +544,8 @@ fixupChecksum(FILE *out, int full_length, int head_position)
static int
writehead(FILE* out, FontPtr font)
{
int time_hi;
unsigned time_lo;
int time_hi = 0;
unsigned time_lo = 0;
macTime(&time_hi, &time_lo);
@ -451,10 +561,12 @@ writehead(FILE* out, FontPtr font)
writeLONG(out, time_hi); /* modified */
writeULONG(out, time_lo);
writeUSHORT(out, FONT_UNITS_FLOOR(min_x));
writeUSHORT(out, FONT_UNITS_FLOOR(min_y));
writeUSHORT(out, FONT_UNITS_CEIL(max_x));
writeUSHORT(out, FONT_UNITS_CEIL(max_y));
/* bounding box for all glyphs */
writeUSHORT(out, FONT_UNITS_FLOOR(font->metrics.minX));
writeUSHORT(out, FONT_UNITS_FLOOR(font->metrics.minY));
writeUSHORT(out, FONT_UNITS_CEIL(font->metrics.maxX));
writeUSHORT(out, FONT_UNITS_CEIL(font->metrics.maxY));
writeUSHORT(out, font->flags); /* macStyle */
writeUSHORT(out, 1); /* lowestRecPPEM */
writeSHORT(out, 0); /* fontDirectionHint */
@ -549,27 +661,6 @@ writeEBDT(FILE* out, FontPtr font)
return 0;
}
static int
writeSbitLineMetrics(FILE *out, StrikePtr strike, int num, int den)
{
int width_max, x_min, y_min, x_max, y_max;
strikeMetrics(strike, &width_max, &x_min, &y_min, &x_max, &y_max);
writeCHAR(out, y_max); /* ascender */
writeCHAR(out, y_min); /* descender */
writeBYTE(out, width_max); /* widthMax */
writeCHAR(out, num); /* caretSlopeNumerator */
writeCHAR(out, den); /* caretSlopeDenominator */
writeCHAR(out, 0); /* caretOffset */
writeCHAR(out, 0); /* minOriginSB */
writeCHAR(out, 0); /* minAdvanceSB */
writeCHAR(out, 0); /* maxBeforeBL */
writeCHAR(out, 0); /* minAfterBL */
writeCHAR(out, 0); /* pad1 */
writeCHAR(out, 0); /* pad2 */
return 0;
}
static int
writeEBLC(FILE* out, FontPtr font)
{
@ -599,8 +690,20 @@ writeEBLC(FILE* out, FontPtr font)
writeULONG(out, 0xDEADFACE); /* indexTablesSize */
writeULONG(out, 0xDEADFACE); /* numberOfIndexSubTables */
writeULONG(out, 0); /* colorRef */
writeSbitLineMetrics(out, strike, num, den);
writeSbitLineMetrics(out, strike, num, den);
for (i = 0; i <= 1; i++) {
writeCHAR(out, font->pxMetrics.ascent); /* ascender */
writeCHAR(out, -font->pxMetrics.descent); /* descender */
writeBYTE(out, strikeMaxWidth(strike)); /* widthMax */
writeCHAR(out, num); /* caretSlopeNumerator */
writeCHAR(out, den); /* caretSlopeDenominator */
writeCHAR(out, 0); /* caretOffset */
writeCHAR(out, 0); /* minOriginSB */
writeCHAR(out, 0); /* minAdvanceSB */
writeCHAR(out, 0); /* maxBeforeBL */
writeCHAR(out, 0); /* minAfterBL */
writeCHAR(out, 0); /* pad1 */
writeCHAR(out, 0); /* pad2 */
}
writeUSHORT(out, 0); /* startGlyphIndex */
writeUSHORT(out, 0xFFFD); /* endGlyphIndex */
writeBYTE(out, strike->sizeX); /* ppemX */
@ -648,9 +751,6 @@ writeEBLC(FILE* out, FontPtr font)
/* actual indexSubTables */
strike = font->strikes;
while(strike) {
int vertAdvance, y_min, y_max;
strikeMetrics(strike, NULL, NULL, &y_min, NULL, &y_max);
vertAdvance = y_max - y_min;
table = strike->indexSubTables;
while(table) {
int location;
@ -718,7 +818,7 @@ writeEBLC(FILE* out, FontPtr font)
writeBYTE(out, bitmap->advanceWidth);
writeCHAR(out, bitmap->horiBearingX); /* vertBearingX */
writeCHAR(out, bitmap->horiBearingY); /* vertBearingY */
writeBYTE(out, vertAdvance); /* vertAdvance */
writeBYTE(out, font->metrics.maxAwidth); /* vertAdvance */
} else {
for(i = table->firstGlyphIndex;
i <= table->lastGlyphIndex; i++) {
@ -849,13 +949,15 @@ writehhea(FILE* out, FontPtr font)
degreesToFraction(font->italicAngle, &num, &den);
writeULONG(out, 0x00010000); /* version */
writeSHORT(out, FONT_UNITS_CEIL(max_y)); /* ascender */
writeSHORT(out, FONT_UNITS_FLOOR(min_y)); /* descender */
writeSHORT(out, FONT_UNITS(TWO_SIXTEENTH / 20)); /* lineGap */
writeUSHORT(out, FONT_UNITS(max_awidth)); /* advanceWidthMax */
writeSHORT(out, FONT_UNITS_FLOOR(min_x)); /* minLeftSideBearing */
writeSHORT(out, FONT_UNITS_FLOOR(min_x)); /* minRightSideBearing */
writeSHORT(out, FONT_UNITS_CEIL(max_x)); /* xMaxExtent */
writeSHORT(out, FONT_UNITS_CEIL(font->metrics.ascent)); /* ascender */
writeSHORT(out, -FONT_UNITS_CEIL(font->metrics.descent)); /* descender */
writeSHORT(out, FONT_UNITS(font->metrics.size - font->metrics.ascent - font->metrics.descent)); /* lineGap */
writeUSHORT(out, FONT_UNITS(font->metrics.maxAwidth)); /* advanceWidthMax */
/* TODO: the next three are not calculated according to spec, are they ?
* https://docs.microsoft.com/en-us/typography/opentype/spec/hhea */
writeSHORT(out, FONT_UNITS_FLOOR(font->metrics.minX)); /* minLeftSideBearing */
writeSHORT(out, FONT_UNITS_FLOOR(font->metrics.minX)); /* minRightSideBearing */
writeSHORT(out, FONT_UNITS_CEIL(font->metrics.maxX)); /* xMaxExtent */
writeSHORT(out, den); /* caretSlopeRise */
writeSHORT(out, num); /* caretSlopeRun */
writeSHORT(out, 0); /* reserved */
@ -974,8 +1076,8 @@ writepost(FILE* out, FontPtr font)
writeULONG(out, 0x00030000); /* FormatType */
writeULONG(out, font->italicAngle); /* italicAngle */
writeSHORT(out, FONT_UNITS(font->underlinePosition));
writeSHORT(out, FONT_UNITS(font->underlineThickness));
writeSHORT(out, FONT_UNITS(font->metrics.underlinePosition));
writeSHORT(out, FONT_UNITS(font->metrics.underlineThickness));
writeULONG(out, fixed_pitch); /* isFixedPitch */
writeULONG(out, 0); /* minMemType42 */
writeULONG(out, 0); /* maxMemType42 */
@ -989,8 +1091,8 @@ writeOS2(FILE* out, FontPtr font)
{
int i;
writeUSHORT(out, 0x0001);
writeSHORT(out, FONT_UNITS(max_awidth / 2)); /* xAvgCharWidth; */
writeUSHORT(out, 5); /* version */
writeSHORT(out, FONT_UNITS(font->metrics.awidth)); /* xAvgCharWidth; */
writeUSHORT(out, font->weight); /* usWeightClass; */
writeUSHORT(out, font->width); /* usWidthClass; */
writeSHORT(out, 0); /* fsType; */
@ -1002,7 +1104,7 @@ writeOS2(FILE* out, FontPtr font)
writeSHORT(out, UNITS_PER_EM / 5); /* ySuperscriptYSize; */
writeSHORT(out, 0); /* ySuperscriptXOffset; */
writeSHORT(out, UNITS_PER_EM / 5); /* ySuperscriptYOffset; */
writeSHORT(out, FONT_UNITS(font->underlineThickness));
writeSHORT(out, FONT_UNITS(font->metrics.underlineThickness));
/* yStrikeoutSize; */
writeSHORT(out, UNITS_PER_EM / 4); /* yStrikeoutPosition; */
writeSHORT(out, 0); /* sFamilyClass; */
@ -1013,17 +1115,38 @@ writeOS2(FILE* out, FontPtr font)
writeULONG(out, 0x03FF); /* ulUnicodeRange3; */
writeULONG(out, 0U); /* ulUnicodeRange4; */
writeULONG(out, font->foundry); /* achVendID[4]; */
writeUSHORT(out, 0x0040); /* fsSelection; */
i = 0;
if (font->flags & FACE_ITALIC)
i |= 1 << 0;
if (font->flags & FACE_BOLD)
i |= 1 << 5;
if (!i)
i |= 1 << 6;
#ifndef NO_TYPO_METRICS
i |= 1 << 7; /* USE_TYPO_METRICS instead usWin metrics for line spacing. */
#endif
writeUSHORT(out, i); /* fsSelection; */
writeUSHORT(out, 0x20); /* usFirstCharIndex; */
writeUSHORT(out, 0xFFFD); /* usLastCharIndex; */
writeUSHORT(out, FONT_UNITS_CEIL(max_y)); /* sTypoAscender; */
writeUSHORT(out, -FONT_UNITS_FLOOR(min_y)); /* sTypoDescender; */
writeUSHORT(out, FONT_UNITS(max_y - min_y));
/* sTypoLineGap; */
writeUSHORT(out, FONT_UNITS_CEIL(max_y)); /* usWinAscent; */
writeUSHORT(out, -FONT_UNITS_FLOOR(min_y)); /* usWinDescent; */
writeULONG(out, 3); /* ulCodePageRange1; */
writeULONG(out, 0); /* ulCodePageRange2; */
writeUSHORT(out, FONT_UNITS_CEIL(font->metrics.ascent)); /* sTypoAscender; */
writeSHORT(out, -FONT_UNITS_CEIL(font->metrics.descent)); /* sTypoDescender; */
writeSHORT(out, FONT_UNITS(font->metrics.size - font->metrics.ascent - font->metrics.descent)); /* sTypoLineGap */
#ifdef NO_TYPO_METRICS
writeUSHORT(out, FONT_UNITS_CEIL(font->metrics.ascent)); /* usWinAscent; */
writeUSHORT(out, FONT_UNITS_CEIL(font->metrics.descent)); /* usWinDescent; */
#else
writeUSHORT(out, FONT_UNITS_CEIL(font->metrics.maxY)); /* usWinAscent; */
writeUSHORT(out, -FONT_UNITS_FLOOR(font->metrics.minY)); /* usWinDescent; */
#endif
writeULONG(out, 3); /* ulCodePageRange1; */
writeULONG(out, 0); /* ulCodePageRange2; */
writeSHORT(out, FONT_UNITS_CEIL(font->metrics.xHeight)); /* sxHeight; */
writeSHORT(out, FONT_UNITS_CEIL(font->metrics.capHeight)); /* sCapHeight; */
writeUSHORT(out, 0); /* usDefaultChar; */
writeUSHORT(out, 20); /* usBreakChar; */
writeUSHORT(out, 0); /* usMaxContext; */
writeUSHORT(out, 0); /* usLowerOpticalPointSize; */
writeUSHORT(out, 0xffff); /* usUpperOpticalPointSize; */
return 0;
}
@ -1061,11 +1184,11 @@ writePCLT(FILE* out, FontPtr font)
writeULONG(out, 0x00010000); /* version */
writeULONG(out, 0); /* FontNumber */
writeUSHORT(out, FONT_UNITS(max_awidth)); /* pitch */
writeUSHORT(out, FONT_UNITS(max_y)); /* xHeight */
writeUSHORT(out, FONT_UNITS(font->metrics.maxAwidth)); /* pitch */
writeUSHORT(out, FONT_UNITS(font->metrics.xHeight)); /* xHeight */
writeUSHORT(out, style); /* style */
writeUSHORT(out, 6 << 12); /* TypeFamily */
writeUSHORT(out, FONT_UNITS(max_y)); /* CapHeight */
writeUSHORT(out, FONT_UNITS(font->metrics.xHeight)); /* CapHeight */
writeUSHORT(out, 0); /* SymbolSet */
writeCHARs(out, name, 16); /* TypeFace */
writeBYTEs(out, charComplement, 8); /* CharacterComplement */