summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-25 19:29:02 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-25 19:29:02 +0000
commita46389d96c54351cd95614f1e5eae495f51957f0 (patch)
tree1354ccf9481f6196a5b128dd6da82401ccfd1364
Initial revision
-rw-r--r--env.c151
-rw-r--r--fonttosfnt.c117
-rw-r--r--fonttosfnt.h178
-rw-r--r--fonttosfnt.man76
-rw-r--r--read.c310
-rw-r--r--struct.c514
-rw-r--r--util.c409
-rw-r--r--write.c1078
8 files changed, 2833 insertions, 0 deletions
diff --git a/env.c b/env.c
new file mode 100644
index 0000000..5d4e567
--- /dev/null
+++ b/env.c
@@ -0,0 +1,151 @@
+/*
+ * Provide setenv() and unsetenv() on platforms that don't have them.
+ * From FreeBSD's libc.
+ */
+
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $XFree86: xc/programs/fonttosfnt/env.c,v 1.1 2003/07/08 15:39:49 tsi Exp $ */
+
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+extern char **environ;
+
+extern int setenv(const char *name, const char *value, int overwrite);
+extern void unsetenv(const char *name);
+
+static char *
+findenv(const char *name, int *offset)
+{
+ int len, i;
+ const char *np;
+ char **p, *cp;
+
+ if (name == NULL || environ == NULL)
+ return NULL;
+
+ for (np = name; *np && *np != '='; ++np)
+ continue;
+ len = np - name;
+ for (p = environ; (cp = *p) != NULL; ++p) {
+ for (np = name, i = len; i && *cp; i--)
+ if (*cp++ != *np++)
+ break;
+ if (i == 0 && *cp++ == '=') {
+ *offset = p - environ;
+ return cp;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * setenv --
+ * Set the value of the environmental variable "name" to be
+ * "value". If overwrite is set, replace any current value.
+ */
+
+int
+setenv(const char *name, const char *value, int overwrite)
+{
+ static char **alloced; /* if allocated space before */
+ char *c;
+ int l_value, offset;
+
+ if (*value == '=') /* no '=' in value */
+ ++value;
+ l_value = strlen(value);
+ if ((c = findenv(name, &offset))) { /* find if already exists */
+ if (!overwrite)
+ return 0;
+ if (strlen(c) >= l_value) { /* old larger; copy over */
+ while ((*c++ = *value++))
+ ;
+ return 0;
+ }
+ } else { /* create new slot */
+ int cnt;
+ char **p;
+
+ for (p = environ, cnt = 0; *p; ++p, ++cnt)
+ ;
+ if (alloced == environ) { /* just increase size */
+ p = (char **)realloc((char *)environ,
+ sizeof(char *) * (cnt + 2));
+ if (!p)
+ return -1;
+ alloced = environ = p;
+ } else { /* get new space */
+ /* copy old entries into it */
+ p = malloc(sizeof(char *) * (cnt + 2));
+ if (!p)
+ return -1;
+ memcpy(p, environ, cnt * sizeof(char *));
+ alloced = environ = p;
+ }
+ environ[cnt + 1] = NULL;
+ offset = cnt;
+ }
+ for (c = (char *)name; *c && *c != '='; ++c) /* no '=' in name */
+ ;
+ if (!(environ[offset] = /* name + '=' + value */
+ malloc((int)(c - name) + l_value + 2)))
+ return -1;
+ for (c = environ[offset]; (*c = *name++) && *c != '='; ++c)
+ ;
+ for (*c++ = '='; (*c++ = *value++); )
+ ;
+ return 0;
+}
+
+/*
+ * unsetenv(name) --
+ * Delete environmental variable "name".
+ */
+
+void
+unsetenv(const char *name)
+{
+ char **p;
+ int offset;
+
+ while (findenv(name, &offset)) /* if set multiple times */
+ for (p = &environ[offset];; ++p)
+ if (!(*p = *(p + 1)))
+ break;
+}
+
diff --git a/fonttosfnt.c b/fonttosfnt.c
new file mode 100644
index 0000000..375fdb3
--- /dev/null
+++ b/fonttosfnt.c
@@ -0,0 +1,117 @@
+/*
+Copyright (c) 2002-2003 by Juliusz Chroboczek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+/* $XFree86: xc/programs/fonttosfnt/fonttosfnt.c,v 1.3 2003/07/08 15:39:49 tsi Exp $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "fonttosfnt.h"
+
+int verbose_flag = 0;
+int reencode_flag = 1;
+int glyph_flag = 2;
+int metrics_flag = 1;
+int crop_flag = 1;
+int bit_aligned_flag = 1;
+
+static void
+usage()
+{
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr,
+ "fonttosfnt [ -v ] [ -c ] [ -b ] [ -r ] [ -g n ] [ -m n ] -o font.ttf "
+ "[ -- ] font ...\n");
+}
+
+int
+main(int argc, char **argv)
+{
+ int i;
+ int rc;
+ char *output = NULL;
+ FontPtr font;
+
+ i = 1;
+ while(i < argc) {
+ if(argv[i][0] != '-')
+ break;
+
+ if(argv[i][1] == 'o') {
+ if(argv[i][2] == '\0') {
+ output = sprintf_reliable("%s", argv[i + 1]);
+ i += 2;
+ } else {
+ output = sprintf_reliable("%s", argv[i] + 2);
+ i++;
+ }
+ } else if(strcmp(argv[i], "-v") == 0) {
+ verbose_flag = 1;
+ i++;
+ } else if(strcmp(argv[i], "-c") == 0) {
+ crop_flag = 0;
+ i++;
+ } else if(strcmp(argv[i], "-b") == 0) {
+ bit_aligned_flag = 0;
+ i++;
+ } else if(strcmp(argv[i], "-r") == 0) {
+ reencode_flag = 0;
+ i++;
+ } else if(strcmp(argv[i], "-g") == 0) {
+ if(argc <= i + 1) {
+ usage();
+ exit(1);
+ }
+ glyph_flag = atoi(argv[i + 1]);
+ i += 2;
+ } else if(strcmp(argv[i], "-m") == 0) {
+ if(argc <= i + 1) {
+ usage();
+ exit(1);
+ }
+ metrics_flag = atoi(argv[i + 1]);
+ i += 2;
+ } else if(strcmp(argv[i], "--") == 0) {
+ i++;
+ break;
+ } else {
+ usage();
+ exit(1);
+ }
+ }
+
+ if(output == NULL) {
+ usage();
+ exit(1);
+ }
+
+ font = makeFont();
+
+ while(i < argc) {
+ rc = readFile(argv[i], font);
+ if(rc != 0)
+ exit(1);
+ i++;
+ }
+
+ writeFile(output, font);
+ return 0;
+}
diff --git a/fonttosfnt.h b/fonttosfnt.h
new file mode 100644
index 0000000..128d2cc
--- /dev/null
+++ b/fonttosfnt.h
@@ -0,0 +1,178 @@
+/*
+Copyright (c) 2002-2003 by Juliusz Chroboczek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+/* $XFree86: xc/programs/fonttosfnt/fonttosfnt.h,v 1.5 2003/11/21 05:22:09 dawes Exp $ */
+
+#ifndef _FONTTOSFNT_H_
+#define _FONTTOSFNT_H_ 1
+
+#include <stdarg.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#define ROUND(x) ((double)(int)((x) + 0.5))
+
+extern int verbose_flag;
+extern int glyph_flag;
+extern int metrics_flag;
+extern int crop_flag;
+extern int bit_aligned_flag;
+extern int reencode_flag;
+
+#define FONT_SEGMENT_SIZE 128
+#define FONT_CODES 0x10000
+
+#define FACE_BOLD 1
+#define FACE_ITALIC 2
+#define FACE_SYMBOL 4
+
+#define STRIKE_BITMAP(s, i) \
+ ((s)->bitmaps[(i)/FONT_SEGMENT_SIZE] ? \
+ (s)->bitmaps[(i)/FONT_SEGMENT_SIZE][(i)%FONT_SEGMENT_SIZE] : \
+ NULL)
+
+#define SAME_METRICS(b1, b2) \
+ ((b1)->advanceWidth == (b2)->advanceWidth && \
+ (b1)->horiBearingX == (b2)->horiBearingX && \
+ (b1)->horiBearingY == (b2)->horiBearingY && \
+ (b1)->width == (b2)->width && \
+ (b1)->height == (b2)->height)
+
+/* bit at (x, y) of raster r with stride s */
+#define BITREF(r, s, x, y) \
+ (((r)[(y) * (s) + (x) / 8] & (1 << (7 - (x) % 8))) != 0)
+
+#define ONE_HALF (1 << 15)
+#define TWO_SIXTEENTH (1 << 16)
+
+#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)
+
+/* Convert a fixed-point value into FUnits */
+#define FONT_UNITS(x) \
+ FLOOR(((double)(x)) / TWO_SIXTEENTH * UNITS_PER_EM + 0.5)
+#define FONT_UNITS_FLOOR(x) \
+ FLOOR(((double)(x)) / TWO_SIXTEENTH * UNITS_PER_EM)
+#define FONT_UNITS_CEIL(x) \
+ CEIL(((double)(x)) / TWO_SIXTEENTH * UNITS_PER_EM)
+
+typedef struct _FontNameEntry {
+ int nid; /* name id */
+ int size; /* bytes in value */
+ char *value;
+} FontNameEntryRec, *FontNameEntryPtr;
+
+typedef struct _Font {
+ int numNames;
+ struct _FontNameEntry *names;
+ int flags;
+ 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;
+ unsigned foundry;
+ struct _Strike *strikes;
+} FontRec, *FontPtr;
+
+typedef struct _Strike {
+ int sizeX;
+ int sizeY;
+ struct _Bitmap ***bitmaps;
+ struct _Strike *next;
+ int numSbits;
+ int bitmapSizeTableLocation;
+ int indexSubTableLocation;
+ struct _IndexSubTable *indexSubTables;
+} StrikeRec, *StrikePtr;
+
+typedef struct _Bitmap {
+ int index;
+ int advanceWidth;
+ int horiBearingX;
+ int horiBearingY;
+ int width;
+ int height;
+ int stride;
+ char *raster;
+ int location;
+} BitmapRec, *BitmapPtr;
+
+typedef struct _IndexSubTable {
+ int location;
+ int firstGlyphIndex;
+ int lastGlyphIndex;
+ int constantMetrics;
+ int lastLocation;
+ struct _IndexSubTable *next;
+} IndexSubTableRec, *IndexSubTablePtr;
+
+typedef struct _Cmap {
+ int startCode;
+ int endCode;
+ int index;
+ struct _Cmap *next;
+ int maxindex; /* only in the head segment*/
+ int *inverse;
+} CmapRec, *CmapPtr;
+
+FontPtr makeFont(void);
+StrikePtr makeStrike(FontPtr, int, int);
+BitmapPtr makeBitmap(StrikePtr, int,
+ int, int, int, int, int, int,
+ unsigned char*, int);
+IndexSubTablePtr makeIndexSubTables(StrikePtr, CmapPtr);
+int fontIndex(FontPtr, int);
+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 glyphMetrics(FontPtr, int, int*, int*, int*, int*, int*);
+void fontMetrics(FontPtr, int*, int*, int*, int*, int*);
+int maxIndex(CmapPtr);
+
+int readFile(char *filename, FontPtr);
+int writeFile(char *filename, FontPtr);
+
+/* util.c */
+
+#define PROP_ATOM 1
+#define PROP_INTEGER 2
+#define PROP_CARDINAL 3
+
+char *sprintf_reliable(char *f, ...);
+char *vsprintf_reliable(char *f, va_list args);
+char *makeUTF16(char *);
+unsigned makeName(char*);
+int macTime(int *, unsigned *);
+unsigned faceFoundry(FT_Face);
+char *faceEncoding(FT_Face);
+int faceFlags(FT_Face);
+int faceWeight(FT_Face);
+int faceWidth(FT_Face);
+int faceItalicAngle(FT_Face);
+int degreesToFraction(int, int*, int*);
+
+#endif /* _FONTTOSFNT_H_ */
diff --git a/fonttosfnt.man b/fonttosfnt.man
new file mode 100644
index 0000000..e4c72b1
--- /dev/null
+++ b/fonttosfnt.man
@@ -0,0 +1,76 @@
+.\" $XFree86: xc/programs/fonttosfnt/fonttosfnt.man,v 1.3 2003/07/08 15:39:49 tsi Exp $
+.TH FONTTOSFNT 1 __vendorversion__
+.SH NAME
+fonttosfnt \- Wrap a bitmap font in a sfnt (TrueType) wrapper
+.SH SYNOPSIS
+.B fonttosfnt
+[
+.I options
+]
+.B \-o
+.I file.ttf
+[
+.B \-\-
+]
+.IR font ...
+.SH DESCRIPTION
+Wrap a bitmap font or a set of bitmap fonts in a sfnt (TrueType or
+OpenType) wrapper.
+.SH OPTIONS
+.TP
+.B \-v
+Be verbose.
+.TP
+.B \-c
+Do not crop glyphs. This usually increases file size, but may
+sometimes yield a modest decrease in file size for small character
+cell fonts (terminal fonts).
+.TP
+.B \-b
+Write byte-aligned glyph data. By default, bit-aligned data is
+written, which yields a smaller file size.
+.TP
+.B \-r
+Do not reencode fonts. By default, fonts are reencoded to Unicode
+whenever possible.
+.TP
+.BI \-g " n"
+Set the type of scalable glyphs that we write. If
+.I n
+is 0, no scalable glyphs are written; this is legal but confuses
+most current software. If
+.I n
+is 1, a single scalable glyph (the undefined glyph) is written; this
+is recommended, but triggers a bug in current versions of
+.BR FreeType .
+If
+.I n
+is 2 (the default), a sufficiently high number of blank glyphs are
+written, which works with
+.B FreeType
+but increases file size.
+.TP
+.BI \-m " n"
+Set the type of scalable metrics that we write. If
+.I n
+is 0, no scalable metrics are written, which may or may not be legal.
+If
+.I n
+is 1, full metrics for a single glyph are written, and only left
+sidebearing values are written for the other glyphs. If
+.I n
+is 2, scalable metrics for all glyphs are written, which increases
+file size and is not recommended. The default is 1.
+.TP
+.B \-\-
+End of options.
+.SH BUGS
+Some of the font-level values, notably sub- and superscript positions,
+are dummy values.
+.SH SEE ALSO
+X(7), Xserver(1), Xft(3x).
+.I Fonts in XFree86.
+.SH AUTHOR
+.B Fonttosfnt
+was written by Juliusz Chroboczek <jch@xfree86.org> for the XFree86
+project.
diff --git a/read.c b/read.c
new file mode 100644
index 0000000..07d2f2a
--- /dev/null
+++ b/read.c
@@ -0,0 +1,310 @@
+/*
+Copyright (c) 2002 by Juliusz Chroboczek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+/* $XFree86: xc/programs/fonttosfnt/read.c,v 1.4 2003/11/21 05:22:09 dawes Exp $ */
+
+#include <stdio.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_BDF_H
+#include "fonttosfnt.h"
+#include "fontenc.h"
+
+#define FLOOR2(x, y) ((x) >= 0 ? (x) / (y) : -(((-(x)) + (y) - 1) / (y)))
+#define CEIL2(x, y) (FLOOR2((x) + (y) - 1, (y)))
+#define FT_Pos_DOWN(x) (FLOOR2((x),64))
+#define FT_Pos_UP(x) (CEIL2((x), 64))
+
+static int ft_inited = 0;
+static FT_Library ft_library;
+
+static int
+FT_Ensure_Inited()
+{
+ int rc;
+ if(ft_inited)
+ return 0;
+
+ rc = FT_Init_FreeType(&ft_library);
+ if(rc != 0)
+ return rc;
+
+ ft_inited = 1;
+ return 0;
+}
+
+int
+readFile(char *filename, FontPtr font)
+{
+ int i, j, k, index;
+ int rc;
+ FT_Face face;
+ StrikePtr strike;
+ BitmapPtr bitmap;
+ int symbol = 0;
+ char *encoding_name = NULL;
+ FontMapPtr mapping = NULL;
+ FontMapReversePtr reverse = NULL;
+
+
+ rc = FT_Ensure_Inited();
+ if(rc != 0)
+ return rc;
+
+ rc = FT_New_Face(ft_library, filename, 0, &face);
+ if(rc != 0) {
+ fprintf(stderr, "Couldn't open face %s.\n", filename);
+ return -1;
+ }
+
+ encoding_name = faceEncoding(face);
+ if(encoding_name == NULL) {
+ symbol = 1;
+ } else if(strcasecmp(encoding_name, "iso10646-1") != 0) {
+ if(reencode_flag)
+ mapping = FontEncMapFind(encoding_name,
+ FONT_ENCODING_UNICODE, 0, 0, NULL);
+ if(mapping == NULL) {
+ symbol = 1;
+ } else {
+ reverse = FontMapReverse(mapping);
+ if(reverse == NULL) {
+ fprintf(stderr, "Couldn't reverse mapping.\n");
+ return -1;
+ }
+ }
+ }
+
+ if(verbose_flag) {
+ fprintf(stderr, "%s %s %s: %d sizes%s\n",
+ filename, face->family_name, face->style_name,
+ face->num_fixed_sizes,
+ symbol ? " (symbol)" : "");
+ }
+
+ if(font->numNames == 0 && face->style_name && face->family_name) {
+ char *full_name, *unique_name;
+ BDF_PropertyRec prop;
+ int rc, i;
+ if(strcmp(face->style_name, "Regular") == 0)
+ full_name = sprintf_reliable("%s", face->family_name);
+ else
+ full_name = sprintf_reliable("%s %s",
+ face->family_name, face->style_name);
+
+ /* The unique name doesn't actually need to be globally
+ unique; it only needs to be unique among all installed fonts on a
+ Windows system. We don't bother getting it quite right. */
+ if(face->num_fixed_sizes <= 0)
+ unique_name = sprintf_reliable("%s XFree86 bitmap", full_name);
+ else if(face->available_sizes[0].width ==
+ face->available_sizes[0].height)
+ unique_name = sprintf_reliable("%s XFree86 bitmap size %d",
+ full_name,
+ face->available_sizes[0].height);
+ else
+ unique_name = sprintf_reliable("%s XFree86 bitmap size %dx%d",
+ full_name,
+ face->available_sizes[0].width,
+ face->available_sizes[0].height);
+
+ font->names = malloc(10 * sizeof(FontNameEntryRec));
+ if(font->names == NULL) {
+ fprintf(stderr, "Couldn't allocate names.\n");
+ return -1;
+ }
+ i = 0;
+
+ rc = FT_Get_BDF_Property(face, "COPYRIGHT", &prop);
+ if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
+ font->names[i].nid = 0;
+ font->names[i].size = 2 * strlen(prop.u.atom);
+ font->names[i].value = makeUTF16((char*)prop.u.atom);
+ i++;
+ }
+
+ font->names[i].nid = 1;
+ font->names[i].size = 2 * strlen(face->family_name);
+ font->names[i].value = makeUTF16(face->family_name);
+ i++;
+
+ font->names[i].nid = 2;
+ font->names[i].size = 2 * strlen(face->style_name);
+ font->names[i].value = makeUTF16(face->style_name);
+ i++;
+
+ font->names[i].nid = 3;
+ font->names[i].size = 2 * strlen(unique_name);
+ font->names[i].value = makeUTF16(unique_name);
+ i++;
+
+ font->names[i].nid = 4;
+ font->names[i].size = 2 * strlen(full_name);
+ font->names[i].value = makeUTF16(full_name);
+ i++;
+
+ font->names[i].nid = 5;
+ font->names[i].size = 2 * strlen("Version 0.0");
+ font->names[i].value = makeUTF16("Version 0.0");
+ i++;
+
+ rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop);
+ if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
+ font->names[i].nid = 8;
+ font->names[i].size = 2 * strlen(prop.u.atom);
+ font->names[i].value = makeUTF16((char*)prop.u.atom);
+ i++;
+ }
+
+ font->names[i].nid = 10;
+ font->names[i].size = 2 * strlen("XFree86 converted bitmap font");
+ font->names[i].value = makeUTF16("XFree86 converted bitmap font");
+ i++;
+
+ font->names[i].nid = 11;
+ font->names[i].size = 2 * strlen("http://www.xfree86.org");
+ font->names[i].value = makeUTF16("http://www.xfree86.org");
+ i++;
+
+ 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) {
+ fprintf(stderr, "No bitmaps in face.\n");
+ return -1;
+ }
+
+ if(!symbol && !mapping)
+ rc = FT_Select_Charmap(face, ft_encoding_unicode);
+ else
+ rc = FT_Select_Charmap(face, ft_encoding_none);
+ if(rc != 0) {
+ fprintf(stderr, "Couldn't select character map: %x.\n", rc);
+ return -1;
+ }
+
+ for(i = 0; i < face->num_fixed_sizes; i++) {
+ if(verbose_flag)
+ fprintf(stderr, "size %d: %dx%d\n",
+ i,
+ face->available_sizes[i].width,
+ face->available_sizes[i].height);
+
+ rc = FT_Set_Pixel_Sizes(face,
+ face->available_sizes[i].width,
+ face->available_sizes[i].height);
+ if(rc != 0) {
+ fprintf(stderr, "Couldn't set size.\n");
+ return -1;
+ }
+
+ strike = makeStrike(font,
+ face->available_sizes[i].width,
+ face->available_sizes[i].height);
+ if(strike == NULL) {
+ fprintf(stderr, "Couldn't allocate strike.\n");
+ return -1;
+ }
+
+ for(j = 0; j < FONT_CODES; j++) {
+ if(mapping)
+ k = reverse->reverse(j, reverse->data);
+ else
+ k = j;
+ if(k <= 0 && j != 0)
+ continue;
+ index = FT_Get_Char_Index(face, k);
+ if(j != 0 && index == 0)
+ continue;
+ rc = FT_Load_Glyph(face, index,
+ FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
+ if(rc != 0) {
+ fprintf(stderr, "Couldn't load glyph for U+%04X (%d)\n",
+ j, index);
+ continue;
+ }
+ bitmap = makeBitmap(strike, j,
+ FT_Pos_UP(face->glyph->metrics.horiAdvance),
+ FT_Pos_DOWN(face->glyph->metrics.horiBearingX),
+ FT_Pos_DOWN(face->glyph->metrics.horiBearingY),
+ face->glyph->bitmap.width,
+ face->glyph->bitmap.rows,
+ face->glyph->bitmap.pitch,
+ face->glyph->bitmap.buffer,
+ crop_flag);
+
+ if(bitmap == NULL) {
+ fprintf(stderr, "Couldn't create bitmap.\n");
+ return -1;
+ }
+ }
+ }
+
+ FT_Done_Face(face);
+
+ j = 0;
+ for(i = 0; i < FONT_CODES; i++) {
+ int found = 0;
+ strike = font->strikes;
+ while(strike) {
+ bitmap = STRIKE_BITMAP(strike, i);
+ if(bitmap) {
+ bitmap->index = j;
+ found = 1;
+ } else {
+ if(i == 0) {
+ fprintf(stderr,
+ "Warning: no bitmap for the undefined glyph.\n");
+ found = 1;
+ }
+ }
+ strike = strike->next;
+ }
+ if(found)
+ j++;
+ }
+ return 0;
+}
diff --git a/struct.c b/struct.c
new file mode 100644
index 0000000..7622e06
--- /dev/null
+++ b/struct.c
@@ -0,0 +1,514 @@
+/*
+Copyright (c) 2002-2003 by Juliusz Chroboczek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+/* $XFree86: xc/programs/fonttosfnt/struct.c,v 1.4 2003/11/21 05:22:09 dawes Exp $ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include "fonttosfnt.h"
+
+FontPtr
+makeFont()
+{
+ FontPtr font;
+
+ font = malloc(sizeof(FontRec));
+ if(font == NULL)
+ return NULL;
+
+ font->numNames = 0;
+ font->names = NULL;
+ font->flags = 0;
+ font->weight = 500;
+ font->width = 5;
+ font->italicAngle = 0;
+ font->underlinePosition = - TWO_SIXTEENTH;
+ font->underlineThickness = TWO_SIXTEENTH;
+ font->foundry = makeName("UNKN");
+ font->strikes = NULL;
+ return font;
+}
+
+StrikePtr
+makeStrike(FontPtr font, int sizeX, int sizeY)
+{
+ StrikePtr strike, last_strike;
+
+ strike = font->strikes;
+ last_strike = NULL;
+ while(strike) {
+ if(strike->sizeX == sizeX && strike->sizeY == sizeY)
+ return strike;
+ last_strike = strike;
+ strike = strike->next;
+ }
+
+ strike = malloc(sizeof(StrikeRec));
+ if(strike == NULL)
+ return NULL;
+ strike->sizeX = sizeX;
+ strike->sizeY = sizeY;
+ strike->bitmaps =
+ calloc(FONT_CODES / FONT_SEGMENT_SIZE, sizeof(BitmapPtr*));
+ if(strike->bitmaps == NULL) {
+ free(strike);
+ return NULL;
+ }
+ strike->numSbits = 0;
+ strike->next = NULL;
+ strike->bitmapSizeTableLocation = 0xDEADFACE;
+ strike->indexSubTables = NULL;
+ if(last_strike)
+ last_strike->next = strike;
+ else
+ font->strikes = strike;
+ return strike;
+}
+
+BitmapPtr
+makeBitmap(StrikePtr strike, int code,
+ int advanceWidth, int horiBearingX, int horiBearingY,
+ int width, int height, int stride, unsigned char *raster, int crop)
+{
+ BitmapPtr bitmap;
+ int i, j, x, y;
+ int dx, dy, new_width, new_height;
+
+ bitmap = malloc(sizeof(BitmapRec));
+ if(bitmap == NULL)
+ return NULL;
+
+ bitmap->index = -1;
+ bitmap->width = 0;
+ bitmap->height = 0;
+ bitmap->stride = 0;
+ bitmap->raster = NULL;
+ bitmap->location = 0xDEADFACE;
+
+ i = code / FONT_SEGMENT_SIZE;
+ j = code % FONT_SEGMENT_SIZE;
+
+ if(strike->bitmaps[i] == NULL) {
+ strike->bitmaps[i] = calloc(FONT_SEGMENT_SIZE, sizeof(BitmapPtr));
+ }
+ if(strike->bitmaps[i] == NULL) {
+ free(bitmap);
+ return NULL;
+ }
+ if(strike->bitmaps[i][j] != NULL) {
+ if(verbose_flag)
+ fprintf(stderr, "Duplicate bitmap %d.\n", code);
+ free(bitmap);
+ return strike->bitmaps[i][j];
+ }
+
+ dx = 0;
+ dy = 0;
+ new_width = width;
+ new_height = height;
+
+ if(crop) {
+ int empty;
+ while(new_width > 0) {
+ empty = 1;
+ x = new_width - 1;
+ for(y = 0; y < new_height; y++) {
+ if(BITREF(raster, stride, x + dx, y + dy)) {
+ empty = 0;
+ break;
+ }
+ }
+ if(empty)
+ new_width--;
+ else
+ break;
+ }
+ while(new_height > 0) {
+ empty = 1;
+ y = new_height - 1;
+ for(x = 0; x < new_width; x++) {
+ if(BITREF(raster, stride, x + dx, y + dy)) {
+ empty = 0;
+ break;
+ }
+ }
+ if(empty)
+ new_height--;
+ else
+ break;
+ }
+ while(new_width > 0) {
+ empty = 1;
+ x = 0;
+ for(y = 0; y < new_height; y++) {
+ if(BITREF(raster, stride, x + dx, y + dy)) {
+ empty = 0;
+ break;
+ }
+ }
+ if(empty) {
+ dx++;
+ new_width--;
+ } else
+ break;
+ }
+ while(new_height > 0) {
+ empty = 1;
+ y = 0;
+ for(x = 0; x < new_width; x++) {
+ if(BITREF(raster, stride, x + dx, y + dy)) {
+ empty = 0;
+ break;
+ }
+ }
+ if(empty) {
+ dy++;
+ new_height--;
+ } else
+ break;
+ }
+ }
+
+
+ bitmap->advanceWidth = advanceWidth;
+ bitmap->horiBearingX = horiBearingX + dx;
+ bitmap->horiBearingY = horiBearingY - dy;
+ bitmap->width = new_width;
+ bitmap->height = new_height;
+ bitmap->stride = (new_width + 7) / 8;
+
+ bitmap->raster = malloc(bitmap->height * bitmap->stride);
+ if(bitmap->raster == NULL) {
+ free(bitmap);
+ return NULL;
+ }
+ memset(bitmap->raster, 0, bitmap->height * bitmap->stride);
+ for(y = 0; y < new_height; y++) {
+ for(x = 0; x < new_width; x++) {
+ if(BITREF(raster, stride, x + dx, y + dy))
+ bitmap->raster[y * bitmap->stride + x / 8] |=
+ 1 << (7 - (x % 8));
+ }
+ }
+ strike->bitmaps[i][j] = bitmap;
+ strike->numSbits++;
+
+ return bitmap;
+}
+
+IndexSubTablePtr
+makeIndexSubTables(StrikePtr strike, CmapPtr cmap)
+{
+ IndexSubTablePtr table, first, last;
+ BitmapPtr bitmap0, bitmap;
+ int index, n;
+
+ first = NULL;
+ last = NULL;
+
+ /* Assuming that we're writing bit-aligned data, small metrics
+ and short offsets, a constant metrics segment saves 5 bytes
+ per glyph in the EBDT table, and 2 bytes per glyph in the EBLC
+ table. On the other hand, the overhead for a supplementary
+ type 2 indexSubTable is 8 bytes for the indexSubTableArray
+ entry and 20 bytes for the subtable itself. It's worth
+ splitting at 5 glyphs. There's no analogue of a type 2
+ indexSubTable with byte-aligned data, so we don't bother
+ splitting when byte-aligning. */
+ index = 0;
+ while(index < 0xFFFF) {
+ int constantMetrics = 1;
+ bitmap0 = strikeBitmapIndex(strike, cmap, index);
+ if(bitmap0 == NULL) {
+ index++;
+ continue;
+ }
+ n = 1;
+ while((bitmap = strikeBitmapIndex(strike, cmap, index + n)) != NULL) {
+ if(constantMetrics) {
+ if(!SAME_METRICS(bitmap0, bitmap)) {
+ if(bit_aligned_flag && n >= 4)
+ break;
+ else
+ constantMetrics = 0;
+ }
+ } else if(bit_aligned_flag) {
+ BitmapPtr b1 = strikeBitmapIndex(strike, cmap, index + n + 1);
+ BitmapPtr b2 = strikeBitmapIndex(strike, cmap, index + n + 2);
+ BitmapPtr b3 = strikeBitmapIndex(strike, cmap, index + n + 3);
+ BitmapPtr b4 = strikeBitmapIndex(strike, cmap, index + n + 4);
+ if(b1 && b2 && b3 && b4 &&
+ SAME_METRICS(bitmap, b1) &&
+ SAME_METRICS(bitmap, b2) &&
+ SAME_METRICS(bitmap, b3) &&
+ SAME_METRICS(bitmap, b4)) {
+ break;
+ }
+ }
+ n++;
+ }
+ if(n <= 1)
+ constantMetrics = 0;
+
+ table = malloc(sizeof(IndexSubTableRec));
+ table->firstGlyphIndex = index;
+ table->lastGlyphIndex = index + n - 1;
+ table->constantMetrics = constantMetrics;
+ table->location = 0xDEADFACE;
+ table->lastLocation = 0xDEADFACE;
+ table->next = NULL;
+
+ if(first == NULL) {
+ first = table;
+ last = table;
+ } else {
+ last->next = table;
+ last = table;
+ }
+ index += n;
+ }
+ return first;
+}
+
+int
+fontIndex(FontPtr font, int code)
+{
+ StrikePtr strike;
+ BitmapPtr bitmap;
+
+ if(code == 0)
+ return 0;
+ strike = font->strikes;
+ while(strike) {
+ bitmap = STRIKE_BITMAP(strike, code);
+ if(bitmap)
+ return bitmap->index;
+ strike = strike->next;
+ }
+ return -1;
+}
+
+CmapPtr
+makeCmap(FontPtr font)
+{
+ CmapPtr cmap_head = NULL;
+ CmapPtr cmap_last = NULL;
+ CmapPtr cmap;
+ int code, i, index, maxindex = 0;
+
+ code = 0;
+ while(code < FONT_CODES) {
+ index = fontIndex(font, code);
+ if(index < 0) {
+ code++;
+ continue;
+ }
+ i = 1;
+ while(code + i < FONT_CODES &&
+ fontIndex(font, code + i) == index + i) {
+ i++;
+ }
+ cmap = malloc(sizeof(CmapRec));
+ if(cmap == NULL)
+ return NULL;
+ cmap->startCode = code;
+ cmap->endCode = code + i - 1;
+ cmap->index = index;
+ cmap->next = NULL;
+ cmap->maxindex = 0;
+ if(maxindex < index + i - 1)
+ maxindex = index + i - 1;
+ if(cmap_head == NULL)
+ cmap_head = cmap;
+ else
+ cmap_last->next = cmap;
+ cmap_last = cmap;
+
+ code += i;
+ }
+ cmap_head->maxindex = maxindex;
+ cmap_head->inverse = calloc(maxindex + 1, sizeof(int));
+ cmap = cmap_head;
+ while(cmap) {
+ for(i = cmap->index;
+ i <= cmap->endCode - cmap->startCode + cmap->index; i++) {
+ cmap_head->inverse[i] =
+ i - cmap->index + cmap->startCode;
+ }
+ cmap = cmap->next;
+ }
+
+ return cmap_head;
+}
+
+int
+findIndex(CmapPtr cmap_head, int code)
+{
+ CmapPtr cmap;
+ cmap = cmap_head;
+ while(cmap) {
+ if(cmap->endCode > code)
+ return -1;
+ if(cmap->startCode <= code)
+ return cmap->index + code - cmap->startCode;
+ cmap = cmap->next;
+ }
+ return -1;
+}
+
+int
+findCode(CmapPtr cmap_head, int index)
+{
+ if(index < 0 || index > cmap_head->maxindex)
+ return -1;
+ return cmap_head->inverse[index];
+
+}
+
+int
+maxIndex(CmapPtr cmap_head)
+{
+ return cmap_head->maxindex;
+}
+
+BitmapPtr
+strikeBitmapIndex(StrikePtr strike, CmapPtr cmap, int index)
+{
+ int code = findCode(cmap, index);
+ if(code < 0)
+ return NULL;
+
+ 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)
+{
+ 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);
+ if(!bitmap)
+ 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;
+}
+
+int
+glyphMetrics(FontPtr font, int code,
+ int *width_return,
+ int *x_min_return, int *y_min_return,
+ int *x_max_return, int *y_max_return)
+{
+ StrikePtr strike;
+ BitmapPtr bitmap;
+
+ strike = font->strikes;
+ while(strike) {
+ bitmap = STRIKE_BITMAP(strike, code);
+ if(bitmap) {
+ if(width_return)
+ *width_return =
+ (((float)bitmap->advanceWidth + 0.5) / strike->sizeX) *
+ TWO_SIXTEENTH;
+ if(x_min_return)
+ *x_min_return =
+ ((float)bitmap->horiBearingX / strike->sizeX) *
+ TWO_SIXTEENTH;
+ if(y_min_return)
+ *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)
+ / strike->sizeX) * TWO_SIXTEENTH;
+ if(y_max_return)
+ *y_max_return =
+ (((float)bitmap->horiBearingY + 0.5) / strike->sizeY) *
+ TWO_SIXTEENTH;
+ return 1;
+ }
+ strike = strike->next;
+ }
+
+ 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 << 16, min_y = 10000 << 16;
+ int max_x = -10000 << 16, max_y = -10000 << 16;
+ 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;
+}
+
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..0808cdf
--- /dev/null
+++ b/util.c
@@ -0,0 +1,409 @@
+/*
+Copyright (c) 2002-2003 by Juliusz Chroboczek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+/* $XFree86: xc/programs/fonttosfnt/util.c,v 1.8 2003/11/21 05:22:09 dawes Exp $ */
+
+#include <time.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#ifndef __UNIXOS2__
+# include <math.h>
+#else
+# include <float.h>
+#endif
+#include <stdarg.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_BDF_H
+#include "fonttosfnt.h"
+
+#ifdef __GLIBC__
+#define HAVE_TIMEGM
+#define HAVE_TM_GMTOFF
+#endif
+
+#ifdef BSD
+#define HAVE_TM_GMTOFF
+#define GMTOFFMEMBER tm_gmtoff
+#endif
+
+#ifdef SCO
+#define HAVE_TM_GMTOFF
+#define GMTOFFMEMBER tm_tzadj
+#endif
+
+/* That's in POSIX */
+#define HAVE_TZSET
+
+#ifdef NEED_SETENV
+extern int setenv(const char *name, const char *value, int overwrite);
+extern void unsetenv(const char *name);
+#endif
+
+char*
+sprintf_reliable(char *f, ...)
+{
+ char *s;
+ va_list args;
+ va_start(args, f);
+ s = vsprintf_reliable(f, args);
+ va_end(args);
+ return s;
+}
+
+char*
+vsprintf_reliable(char *f, va_list args)
+{
+ int n, size = 12;
+ char *string;
+ while(1) {
+ if(size > 4096)
+ return NULL;
+ string = malloc(size);
+ if(!string)
+ return NULL;
+ n = vsnprintf(string, size, f, args);
+ if(n >= 0 && n < size)
+ return string;
+ else if(n >= size)
+ size = n + 1;
+ else
+ size = size * 3 / 2 + 1;
+ free(string);
+ }
+ /* NOTREACHED */
+}
+
+/* Build a UTF-16 string from a Latin-1 string.
+ Result is not NUL-terminated. */
+char *
+makeUTF16(char *string)
+{
+ int i;
+ int n = strlen(string);
+ char *value = malloc(2 * n);
+ if(!value)
+ return NULL;
+ for(i = 0; i < n; i++) {
+ value[2 * i] = '\0';
+ value[2 * i + 1] = string[i];
+ }
+ return value;
+}
+
+unsigned
+makeName(char *s)
+{
+ return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3];
+}
+
+/* Like mktime(3), but UTC rather than local time */
+#if defined(HAVE_TIMEGM)
+time_t
+mktime_gmt(struct tm *tm)
+{
+ return timegm(tm);
+}
+#elif defined(HAVE_TM_GMTOFF)
+time_t
+mktime_gmt(struct tm *tm)
+{
+ time_t t;
+ struct tm *ltm;
+
+ t = mktime(tm);
+ if(t < 0)
+ return -1;
+ ltm = localtime(&t);
+ if(ltm == NULL)
+ return -1;
+ return t + ltm->GMTOFFMEMBER;
+}
+#elif defined(HAVE_TZSET)
+/* Taken from the Linux timegm(3) man page */
+time_t
+mktime_gmt(struct tm *tm)
+{
+ time_t t;
+ char *tz;
+
+ tz = getenv("TZ");
+ setenv("TZ", "", 1);
+ tzset();
+ t = mktime(tm);
+ if(tz)
+ setenv("TZ", tz, 1);
+ else
+ unsetenv("TZ");
+ tzset();
+ return t;
+}
+#else
+#error no mktime_gmt implementation on this platform
+#endif
+
+/* Return the current time as a signed 64-bit number of seconds since
+ midnight, 1 January 1904. This is apparently when the Macintosh
+ was designed. */
+int
+macTime(int *hi, unsigned *lo)
+{
+ unsigned long diff; /* Not time_t */
+ time_t macEpoch, current;
+ struct tm tm;
+ tm.tm_sec = 0;
+ tm.tm_min = 0;
+ tm.tm_hour = 0;
+ tm.tm_mday = 1;
+ tm.tm_mon = 1;
+ tm.tm_year = 4;
+ tm.tm_isdst = -1;
+
+ macEpoch = mktime_gmt(&tm);
+ if(macEpoch < 0) return -1;
+
+ current = time(NULL);
+ if(current < 0)
+ return -1;
+
+ if(current < macEpoch) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ diff = current - macEpoch;
+#if INT_MAX == LONG_MAX
+ *hi = 0;
+#else
+ *hi = diff >> 32;
+#endif
+ *lo = diff & 0xFFFFFFFF;
+ return 0;
+}
+
+unsigned
+faceFoundry(FT_Face face)
+{
+ int rc;
+ BDF_PropertyRec prop;
+
+ rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop);
+ if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
+ if(strcasecmp(prop.u.atom, "adobe") == 0)
+ return makeName("ADBE");
+ else if(strcasecmp(prop.u.atom, "agfa") == 0)
+ return makeName("AGFA");
+ else if(strcasecmp(prop.u.atom, "altsys") == 0)
+ return makeName("ALTS");
+ else if(strcasecmp(prop.u.atom, "apple") == 0)
+ return makeName("APPL");
+ else if(strcasecmp(prop.u.atom, "arphic") == 0)
+ return makeName("ARPH");
+ else if(strcasecmp(prop.u.atom, "alltype") == 0)
+ return makeName("ATEC");
+ else if(strcasecmp(prop.u.atom, "b&h") == 0)
+ return makeName("B&H ");
+ else if(strcasecmp(prop.u.atom, "bitstream") == 0)
+ return makeName("BITS");
+ else if(strcasecmp(prop.u.atom, "dynalab") == 0)
+ return makeName("DYNA");
+ else if(strcasecmp(prop.u.atom, "ibm") == 0)
+ return makeName("IBM ");
+ else if(strcasecmp(prop.u.atom, "itc") == 0)
+ return makeName("ITC ");
+ else if(strcasecmp(prop.u.atom, "interleaf") == 0)
+ return makeName("LEAF");
+ else if(strcasecmp(prop.u.atom, "impress") == 0)
+ return makeName("IMPR");
+ else if(strcasecmp(prop.u.atom, "larabiefonts") == 0)
+ return makeName("LARA");
+ else if(strcasecmp(prop.u.atom, "linotype") == 0)
+ return makeName("LINO");
+ else if(strcasecmp(prop.u.atom, "monotype") == 0)
+ return makeName("MT ");
+ else if(strcasecmp(prop.u.atom, "microsoft") == 0)
+ return makeName("MS ");
+ else if(strcasecmp(prop.u.atom, "urw") == 0)
+ return makeName("URW ");
+ else if(strcasecmp(prop.u.atom, "y&y") == 0)
+ return makeName("Y&Y ");
+ else
+ return makeName("UNKN");
+ }
+ /* For now */
+ return makeName("UNKN");
+}
+
+
+int
+faceWeight(FT_Face face)
+{
+ int rc;
+ BDF_PropertyRec prop;
+ rc = FT_Get_BDF_Property(face, "WEIGHT_NAME", &prop);
+ if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
+ if(strcasecmp(prop.u.atom, "thin") == 0)
+ return 100;
+ else if(strcasecmp(prop.u.atom, "extralight") == 0)
+ return 200;
+ else if(strcasecmp(prop.u.atom, "light") == 0)
+ return 300;
+ else if(strcasecmp(prop.u.atom, "medium") == 0)
+ return 500;
+ else if(strcasecmp(prop.u.atom, "semibold") == 0)
+ return 600;
+ else if(strcasecmp(prop.u.atom, "bold") == 0)
+ return 700;
+ else if(strcasecmp(prop.u.atom, "extrabold") == 0)
+ return 800;
+ else if(strcasecmp(prop.u.atom, "black") == 0)
+ return 900;
+ else
+ return 500;
+ } else
+ return 500; /* for now */
+}
+
+int
+faceWidth(FT_Face face)
+{
+ int rc;
+ BDF_PropertyRec prop;
+ rc = FT_Get_BDF_Property(face, "SETWIDTH_NAME", &prop);
+ if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
+ if(strcasecmp(prop.u.atom, "ultracondensed") == 0)
+ return 1;
+ else if(strcasecmp(prop.u.atom, "extracondensed") == 0)
+ return 2;
+ else if(strcasecmp(prop.u.atom, "condensed") == 0)
+ return 3;
+ else if(strcasecmp(prop.u.atom, "semicondensed") == 0)
+ return 4;
+ else if(strcasecmp(prop.u.atom, "normal") == 0)
+ return 5;
+ else if(strcasecmp(prop.u.atom, "semiexpanded") == 0)
+ return 6;
+ else if(strcasecmp(prop.u.atom, "expanded") == 0)
+ return 7;
+ else if(strcasecmp(prop.u.atom, "extraexpanded") == 0)
+ return 8;
+ else if(strcasecmp(prop.u.atom, "ultraexpanded") == 0)
+ return 9;
+ else
+ return 5;
+ } else
+ return 5; /* for now */
+}
+
+int
+faceItalicAngle(FT_Face face)
+{
+ int rc;
+ BDF_PropertyRec prop;
+
+ rc = FT_Get_BDF_Property(face, "ITALIC_ANGLE", &prop);
+ if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER) {
+ return (prop.u.integer - 64 * 90) * (TWO_SIXTEENTH / 64);
+ }
+
+ rc = FT_Get_BDF_Property(face, "SLANT", &prop);
+ if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
+ if(strcasecmp(prop.u.atom, "i") == 0 ||
+ strcasecmp(prop.u.atom, "s") == 0)
+ return -30 * TWO_SIXTEENTH;
+ else
+ return 0;
+ } else
+ return 0; /* for now */
+}
+
+int
+faceFlags(FT_Face face)
+{
+ int flags = 0;
+ BDF_PropertyRec prop;
+ int rc;
+
+ if(faceWeight(face) >= 650)
+ flags |= FACE_BOLD;
+ rc = FT_Get_BDF_Property(face, "SLANT", &prop);
+ if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
+ if(strcasecmp(prop.u.atom, "i") == 0 ||
+ strcasecmp(prop.u.atom, "s") == 0)
+ flags |= FACE_ITALIC;
+ }
+ return flags;
+}
+
+char *
+faceEncoding(FT_Face face)
+{
+ BDF_PropertyRec p1, p2;
+ int rc;
+
+ rc = FT_Get_BDF_Property(face, "CHARSET_REGISTRY", &p1);
+ if(rc != 0 || p1.type != BDF_PROPERTY_TYPE_ATOM)
+ return NULL;
+ rc = FT_Get_BDF_Property(face, "CHARSET_ENCODING", &p2);
+ if(rc != 0 || p2.type != BDF_PROPERTY_TYPE_ATOM)
+ return NULL;
+
+ return sprintf_reliable("%s-%s", p1.u.atom, p2.u.atom);
+}
+
+int
+degreesToFraction(int deg, int *num, int *den)
+{
+ double n, d;
+ double rad, val;
+ int i;
+
+ if(deg <= -(60 * TWO_SIXTEENTH) || deg >= (60 * TWO_SIXTEENTH))
+ goto fail;
+
+ rad = (((double)deg) / TWO_SIXTEENTH) / 180.0 * M_PI;
+
+ n = sin(-rad);
+ d = cos(rad);
+
+ if(d < 0.001)
+ goto fail;
+
+ val = atan2(n, d);
+ /* There must be a cleaner way */
+ for(i = 1; i < 10000; i++) {
+ if((int)(d * i) != 0.0 &&
+ fabs(atan2(ROUND(n * i), ROUND(d * i)) - val) < 0.05) {
+ *num = (int)ROUND(n * i);
+ *den = (int)ROUND(d * i);
+ return 0;
+ }
+ }
+
+ fail:
+ *den = 1;
+ *num = 0;
+ return -1;
+}
+
diff --git a/write.c b/write.c
new file mode 100644
index 0000000..9a51d49
--- /dev/null
+++ b/write.c
@@ -0,0 +1,1078 @@
+/*
+Copyright (c) 2002-2003 by Juliusz Chroboczek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+/* $XFree86: xc/programs/fonttosfnt/write.c,v 1.5 2003/10/24 20:38:11 tsi Exp $ */
+
+#if defined(linux) && !defined(_GNU_SOURCE)
+/* for fwrite_unlocked and fread_unlocked */
+#define _GNU_SOURCE 1
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include "X11/Xos.h"
+
+#include "fonttosfnt.h"
+
+#if !defined(I_LOVE_POSIX) && \
+ defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
+#define DO_FWRITE fwrite_unlocked
+#define DO_FREAD fread_unlocked
+#else
+#define DO_FWRITE fwrite
+#define DO_FREAD fread
+#endif
+
+static int writeDir(FILE*, FontPtr, int, unsigned*);
+static int fixupDir(FILE*, FontPtr, int, int*, int*);
+static int fixupChecksum(FILE*, int, int);
+
+static int writeEBDT(FILE*, FontPtr);
+static int writeEBLC(FILE*, FontPtr);
+static int writeOS2(FILE*, FontPtr);
+static int writePCLT(FILE*, FontPtr);
+static int writecmap(FILE*, FontPtr);
+static int writeglyf(FILE*, FontPtr);
+static int writehead(FILE*, FontPtr);
+static int writehhea(FILE*, FontPtr);
+static int writehmtx(FILE*, FontPtr);
+static int writeloca(FILE*, FontPtr);
+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;
+
+/* floor(log2(x)) */
+static int
+log2_floor(int x)
+{
+ int i, j;
+
+ if(x <= 0)
+ abort();
+
+ i = 0;
+ j = 1;
+ while(2 * j < x) {
+ i++;
+ j *= 2;
+ }
+ return i;
+}
+
+/* 2 ** floor(log2(x)) */
+static int
+two_log2_floor(int x)
+{
+ int j;
+
+ if(x <= 0)
+ abort();
+
+ j = 1;
+ while(2 * j < x) {
+ j *= 2;
+ }
+ return j;
+}
+
+static void
+write_error(int rc)
+{
+ /* Real Men program in C and don't use exceptions. */
+ if(write_error_occurred)
+ return;
+ write_error_occurred = 1;
+ if(rc < 0)
+ perror("Couldn't write");
+ else
+ fprintf(stderr, "Short write.\n");
+}
+
+static void
+read_error(int rc)
+{
+ if(read_error_occurred)
+ return;
+ read_error_occurred = 1;
+ if(rc < 0)
+ perror("Couldn't read");
+ else
+ fprintf(stderr, "Short read.\n");
+}
+
+static void
+writeBYTE(FILE *out, unsigned char val)
+{
+ int rc;
+ rc = DO_FWRITE(&val, 1, 1, out);
+ if(rc != 1) write_error(rc);
+}
+
+static void
+writeBYTEs(FILE *out, unsigned char *chars, int n)
+{
+ int rc;
+ rc = DO_FWRITE(chars, 1, n, out);
+ if(rc != n) write_error(rc);
+}
+
+static void
+writeCHAR(FILE *out, char val)
+{
+ int rc;
+ rc = DO_FWRITE(&val, 1, 1, out);
+ if(rc != 1) write_error(rc);
+}
+
+static void
+writeCHARs(FILE *out, char *chars, int n)
+{
+ int rc;
+ rc = DO_FWRITE(chars, 1, n, out);
+ if(rc != n) write_error(rc);
+}
+
+static void
+writeUSHORT(FILE *out, unsigned short val)
+{
+ int rc;
+ val = htons(val);
+ rc = DO_FWRITE(&val, 2, 1, out);
+ if(rc != 1) write_error(rc);
+}
+
+static void
+writeSHORT(FILE *out, short val)
+{
+ int rc;
+ val = htons(val);
+ rc = DO_FWRITE(&val, 2, 1, out);
+ if(rc != 1) write_error(rc);
+}
+
+static void
+writeULONG(FILE *out, unsigned int val)
+{
+ int rc;
+ val = htonl(val);
+ rc = DO_FWRITE(&val, 4, 1, out);
+ if(rc != 1) write_error(rc);
+}
+
+static void
+writeLONG(FILE *out, int val)
+{
+ int rc;
+ val = htonl(val);
+ rc = DO_FWRITE(&val, 4, 1, out);
+ if(rc != 1) write_error(rc);
+}
+
+static unsigned
+readULONG(FILE *out)
+{
+ int rc;
+ unsigned val;
+ rc = DO_FREAD(&val, 4, 1, out);
+ if(rc != 1) {
+ read_error(rc);
+ return 0xDEADBEEF;
+ }
+ return ntohl(val);
+}
+
+int
+writeFile(char *filename, FontPtr font)
+{
+ int rc;
+ FILE *out;
+ unsigned tables[15];
+ int head_position = 0;
+ int full_length;
+ int (*(table_writers[15]))(FILE*, FontPtr);
+ int i, j;
+ 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;
+
+ current_cmap = makeCmap(font);
+ if(current_cmap == NULL) {
+ fprintf(stderr, "Couldn't build cmap.\n");
+ return -1;
+ }
+
+ write_error_occurred = 0;
+ read_error_occurred = 0;
+
+ if(glyph_flag >= 2) {
+ numglyphs = maxIndex(current_cmap) + 1;
+ if(metrics_flag >= 2)
+ nummetrics = numglyphs - 1;
+ else if(metrics_flag >= 1)
+ nummetrics = 1;
+ else
+ nummetrics = 0;
+ } else if(glyph_flag == 1) {
+ numglyphs = 1;
+ nummetrics = (metrics_flag >= 1) ? 1 : 0;
+ } else {
+ numglyphs = 0;
+ nummetrics = 0;
+ }
+
+ strike = font->strikes;
+ while(strike) {
+ strike->indexSubTables = makeIndexSubTables(strike, current_cmap);
+ if(!strike->indexSubTables) {
+ fprintf(stderr, "Couldn't build indexSubTable.\n");
+ return -1;
+ }
+ strike = strike->next;
+ }
+
+ /* These must be sorted lexicographically */
+ i = 0;
+ tables[i] = makeName("EBDT"); table_writers[i] = writeEBDT; i++;
+ tables[i] = makeName("EBLC"); table_writers[i] = writeEBLC; i++;
+ tables[i] = makeName("OS/2"); table_writers[i] = writeOS2; i++;
+ tables[i] = makeName("PCLT"); table_writers[i] = writePCLT; i++;
+ tables[i] = makeName("cmap"); table_writers[i] = writecmap; i++;
+ if(numglyphs >= 1) {
+ tables[i] = makeName("glyf");
+ table_writers[i] = writeglyf; i++;
+ }
+ tables[i] = makeName("head"); table_writers[i] = writehead; i++;
+ tables[i] = makeName("hhea"); table_writers[i] = writehhea; i++;
+ if(nummetrics >= 1) {
+ tables[i] = makeName("hmtx");
+ table_writers[i] = writehmtx; i++;
+ }
+ if(numglyphs >= 1) {
+ tables[i] = makeName("loca");
+ table_writers[i] = writeloca; i++;
+ }
+ tables[i] = makeName("maxp"); table_writers[i] = writemaxp; i++;
+ tables[i] = makeName("name"); table_writers[i] = writename; i++;
+ tables[i] = makeName("post"); table_writers[i] = writepost; i++;
+
+ rc = writeDir(out, font, i, tables);
+ if(rc < 0)
+ goto fail;
+
+ for(j = 0; j < i; j++) {
+ offset[j] = ftell(out);
+ if(offset[j] < 0) {
+ perror("Couldn't compute table offset");
+ goto fail;
+ }
+ if(tables[j] == makeName("head"))
+ head_position = offset[j];
+ rc = table_writers[j](out, font);
+ if(rc < 0 || write_error_occurred || read_error_occurred)
+ goto fail;
+ length[j] = ftell(out) - offset[j];
+ if(length[j] < 0) {
+ perror("Couldn't compute table size");
+ goto fail;
+ }
+ if(length[j] % 4 != 0) {
+ /* Pad -- recommended by the spec, and assumed by
+ computeChecksum. */
+ int k;
+ for(k = 0; k < (4 - length[j] % 4); k++) {
+ /* This must be 0 -- see computeChecksum. */
+ writeBYTE(out, 0);
+ }
+ if(write_error_occurred || read_error_occurred)
+ goto fail;
+ }
+ }
+
+ rc = fixupDir(out, font, i, offset, length);
+ if(rc < 0)
+ goto fail;
+
+ full_length = ftell(out);
+ if(full_length < 0) {
+ perror("Couldn't compute file size");
+ goto fail;
+ }
+ while(full_length % 4 != 0) {
+ /* pad for computeChecksum */
+ writeBYTE(out, 0);
+ full_length++;
+ }
+ if(write_error_occurred || read_error_occurred)
+ goto fail;
+ rc = fixupChecksum(out, full_length, head_position);
+ if(rc < 0)
+ goto fail;
+ fclose(out);
+ return 0;
+
+ fail:
+ unlink(filename);
+ return -1;
+}
+
+static int
+writeDir(FILE *out, FontPtr font, int numTables, unsigned *tables)
+{
+ int i, ti;
+ i = 0; ti = 1;
+ while(2 * ti < numTables) {
+ i++;
+ ti = 2 * ti;
+ }
+
+ writeULONG(out, 0x10000); /* version */
+ writeUSHORT(out, numTables); /* numTables */
+ writeUSHORT(out, 16 * ti); /* searchRange */
+ writeUSHORT(out, i - 1); /* entrySelector */
+ writeUSHORT(out, 16 * (numTables - ti)); /* rangeShift */
+
+ /* see fixupDir */
+ for(i = 0; i < numTables; i++) {
+ writeULONG(out, tables[i]);
+ writeULONG(out, 0xDEADFACE); /* checkSum */
+ writeULONG(out, 0xDEADFACE); /* offset */
+ writeULONG(out, 0xDEADFACE); /* length */
+ }
+ return 0;
+}
+
+static unsigned
+computeChecksum(FILE *out, int offset, int length)
+{
+ int rc;
+ int i;
+ unsigned sum = 0;
+
+ if(offset % 4 != 0) {
+ fprintf(stderr, "Offset %d is not a multiple of 4\n", offset);
+ return ~0;
+ }
+
+ rc = fseek(out, offset, SEEK_SET);
+ if(rc < 0) {
+ perror("Couldn't seek");
+ return ~0;
+ }
+
+ /* This relies on the fact that we always pad tables with zeroes. */
+ for(i = 0; i < length; i += 4) {
+ sum += readULONG(out);
+ }
+ return sum;
+}
+
+static int
+fixupDir(FILE *out, FontPtr font, int numTables, int *offset, int *length)
+{
+ int rc, i;
+ unsigned sum;
+
+ for(i = 0; i < numTables; i++) {
+ sum = computeChecksum(out, offset[i], length[i]);
+ rc = fseek(out, 12 + 16 * i + 4, SEEK_SET);
+ if(rc != 0) {
+ perror("Couldn't seek");
+ return -1;
+ }
+ writeULONG(out, sum);
+ writeULONG(out, offset[i]);
+ writeULONG(out, length[i]);
+ }
+ return 0;
+}
+
+static int
+fixupChecksum(FILE *out, int full_length, int head_position)
+{
+ int rc, checksum;
+ checksum = computeChecksum(out, 0, full_length);
+ rc = fseek(out, head_position + 8, SEEK_SET);
+ if(rc != 0) {
+ perror("Couldn't seek");
+ return -1;
+ }
+ writeULONG(out, 0xB1B0AFBA - checksum); /* checkSumAdjustment */
+ return 0;
+}
+
+
+static int
+writehead(FILE* out, FontPtr font)
+{
+ int time_hi;
+ unsigned time_lo;
+
+ macTime(&time_hi, &time_lo);
+
+ writeULONG(out, 0x00010000);
+ writeULONG(out, 0x00010000); /* fontRevision */
+ writeULONG(out, 0); /* checkSumAdjustment -- filled in later */
+ writeULONG(out,0x5F0F3CF5); /* magicNumber */
+ writeUSHORT(out, 1); /* flags */
+ writeUSHORT(out, UNITS_PER_EM); /* unitsPerEm */
+
+ writeLONG(out, time_hi); /* created */
+ writeULONG(out, time_lo);
+ 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));
+ writeUSHORT(out, font->flags); /* macStyle */
+ writeUSHORT(out, 1); /* lowestRecPPEM */
+ writeSHORT(out, 0); /* fontDirectionHint */
+ writeSHORT(out, 0); /* indexToLocFormat */
+ writeSHORT(out, 0); /* glyphDataFormat */
+ return 0;
+}
+
+static int
+outputRaster(FILE *out, char *raster, int width, int height, int stride,
+ int bit_aligned)
+{
+ int i, j;
+ int len = 0;
+
+ if(!bit_aligned || width % 8 == 0) {
+ for(i = 0; i < height; i++) {
+ writeCHARs(out, raster + i * stride, (width + 7) / 8);
+ len += (width + 7) / 8;
+ }
+ } else {
+ int bit = 0;
+ unsigned char v = 0;
+ for(i = 0; i < height; i++) {
+ for(j = 0; j < width; j++) {
+ if(BITREF(raster, stride, j, i))
+ v |= 1 << (7 - bit);
+ bit++;
+ if(bit >= 8) {
+ writeBYTE(out, v);
+ len++;
+ bit = 0;
+ v = 0;
+ }
+ }
+ }
+ if(bit > 0) {
+ writeBYTE(out, v);
+ len++;
+ }
+ }
+ return len;
+}
+
+static int
+writeEBDT(FILE* out, FontPtr font)
+{
+ StrikePtr strike;
+ BitmapPtr bitmap;
+ IndexSubTablePtr table;
+ int i;
+ int offset;
+ int ebdt_start;
+
+ ebdt_start = ftell(out);
+
+ writeULONG(out, 0x00020000); /* version */
+ offset = 4;
+
+ strike = font->strikes;
+ while(strike) {
+ table = strike->indexSubTables;
+ while(table) {
+ for(i = table->firstGlyphIndex; i <= table->lastGlyphIndex; i++) {
+ bitmap = strikeBitmapIndex(strike, current_cmap, i);
+ bitmap->location = offset;
+ if(bit_aligned_flag && table->constantMetrics) {
+ /* image format 5 */
+ ;
+ } else {
+ /* image format 1 or 2 */
+ writeBYTE(out, bitmap->height);
+ writeBYTE(out, bitmap->width);
+ writeCHAR(out, bitmap->horiBearingX);
+ writeCHAR(out, bitmap->horiBearingY);
+ writeBYTE(out, bitmap->advanceWidth);
+ offset += 5;
+ }
+ offset += outputRaster(out,
+ bitmap->raster,
+ bitmap->width, bitmap->height,
+ bitmap->stride,
+ bit_aligned_flag);
+ }
+ table->lastLocation = offset;
+ table = table->next;
+ }
+ strike = strike->next;
+ }
+ if(ftell(out) != ebdt_start + offset)
+ abort();
+ 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)
+{
+ int i, rc, numstrikes, eblc_start, num, den;
+ StrikePtr strike;
+ IndexSubTablePtr table;
+
+ degreesToFraction(font->italicAngle, &num, &den);
+
+ numstrikes = 0;
+ strike = font->strikes;
+ while(strike) {
+ numstrikes++;
+ strike = strike->next;
+ }
+
+ eblc_start = ftell(out);
+
+ writeULONG(out, 0x00020000); /* version */
+ writeULONG(out, numstrikes); /* numSizes */
+
+ /* bitmapSizeTable */
+ strike = font->strikes;
+ while(strike) {
+ strike->bitmapSizeTableLocation = ftell(out);
+ writeULONG(out, 0xDEADFACE); /* indexSubTableArrayOffset */
+ writeULONG(out, 0xDEADFACE); /* indexTablesSize */
+ writeULONG(out, 0xDEADFACE); /* numberOfIndexSubTables */
+ writeULONG(out, 0); /* colorRef */
+ writeSbitLineMetrics(out, strike, num, den);
+ writeSbitLineMetrics(out, strike, num, den);
+ writeUSHORT(out, 0); /* startGlyphIndex */
+ writeUSHORT(out, 0xFFFD); /* endGlyphIndex */
+ writeBYTE(out, strike->sizeX); /* ppemX */
+ writeBYTE(out, strike->sizeY); /* ppemY */
+ writeBYTE(out, 1); /* bitDepth */
+ writeCHAR(out, 1); /* flags */
+ strike = strike->next;
+ }
+
+ /* indexSubTableArray, one per strike */
+ strike = font->strikes;
+ while(strike) {
+ int endoffset;
+ int numtables = 0;
+
+ strike->indexSubTableLocation = ftell(out);
+ table = strike->indexSubTables;
+ while(table) {
+ table->location = ftell(out);
+ writeUSHORT(out, table->firstGlyphIndex);
+ writeUSHORT(out, table->lastGlyphIndex);
+ writeULONG(out, 0xDEADFACE); /* additionalOffsetToIndexSubtable */
+ numtables++;
+ table = table->next;
+ }
+ endoffset = ftell(out);
+ rc = fseek(out, strike->bitmapSizeTableLocation, SEEK_SET);
+ if(rc != 0) {
+ perror("Couldn't seek");
+ return -1;
+ }
+ writeULONG(out, strike->indexSubTableLocation - eblc_start);
+ /* indexSubTableArrayOffset */
+ writeULONG(out, endoffset - strike->indexSubTableLocation);
+ /* indexTablesSize */
+ writeULONG(out, numtables); /* numberOfIndexSubTables */
+ rc = fseek(out, endoffset, SEEK_SET);
+ if(rc != 0) {
+ perror("Couldn't seek");
+ return -1;
+ }
+ strike = strike->next;
+ }
+
+ /* 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;
+ int data_location;
+ int short_offsets;
+ int offset;
+
+ location = ftell(out);
+ rc = fseek(out, table->location + 4, SEEK_SET);
+ if(rc != 0) {
+ perror("Couldn't seek");
+ return -1;
+ }
+ /* additionalOffsetToIndexSubtable */
+ writeULONG(out, location - strike->indexSubTableLocation);
+ rc = fseek(out, location, SEEK_SET);
+ if(rc != 0) {
+ perror("Couldn't seek");
+ return -1;
+ }
+ data_location =
+ strikeBitmapIndex(strike, current_cmap,
+ table->firstGlyphIndex)->location;
+ short_offsets = 1;
+ for(i = table->firstGlyphIndex; i <= table->lastGlyphIndex; i++) {
+ if(strikeBitmapIndex(strike, current_cmap, i)->location -
+ data_location > 0xFFFF) {
+ short_offsets = 0;
+ break;
+ }
+ }
+ /* indexFormat */
+ if(table->constantMetrics)
+ writeUSHORT(out, 2);
+ else if(short_offsets)
+ writeUSHORT(out, 3);
+ else
+ writeUSHORT(out, 1);
+ /* imageFormat */
+ if(bit_aligned_flag) {
+ if(table->constantMetrics)
+ writeUSHORT(out, 5);
+ else
+ writeUSHORT(out, 2);
+ } else {
+ writeUSHORT(out, 1);
+ }
+ writeULONG(out, data_location);
+ if(table->constantMetrics) {
+ int size;
+ BitmapPtr bitmap =
+ strikeBitmapIndex(strike, current_cmap,
+ table->firstGlyphIndex);
+
+ size =
+ strikeBitmapIndex(strike, current_cmap,
+ table->firstGlyphIndex + 1)->location -
+ bitmap->location;
+ writeULONG(out, size); /* imageSize */
+ /* bigMetrics */
+ writeBYTE(out, bitmap->height);
+ writeBYTE(out, bitmap->width);
+ writeCHAR(out, bitmap->horiBearingX);
+ writeCHAR(out, bitmap->horiBearingY);
+ writeBYTE(out, bitmap->advanceWidth);
+ writeCHAR(out, bitmap->horiBearingX); /* vertBearingX */
+ writeCHAR(out, bitmap->horiBearingY); /* vertBearingY */
+ writeBYTE(out, vertAdvance); /* vertAdvance */
+ } else {
+ for(i = table->firstGlyphIndex;
+ i <= table->lastGlyphIndex; i++) {
+ offset =
+ strikeBitmapIndex(strike, current_cmap, i)->location -
+ data_location;
+ if(short_offsets)
+ writeUSHORT(out, offset);
+ else
+ writeULONG(out, offset);
+ }
+ /* Dummy glyph of size 0 to mark the end of the table */
+ if(short_offsets) {
+ writeUSHORT(out, table->lastLocation - data_location);
+ writeUSHORT(out, table->lastLocation - data_location);
+ } else {
+ writeULONG(out, table->lastLocation - data_location);
+ writeULONG(out, table->lastLocation - data_location);
+ }
+ }
+ location = ftell(out);
+ while(location % 4 != 0) {
+ writeCHAR(out, 0);
+ location--;
+ }
+ table = table->next;
+ }
+ strike = strike->next;
+ }
+ return 0;
+}
+
+static int
+writecmap(FILE* out, FontPtr font)
+{
+ int rc, cmap_start, cmap_end;
+ CmapPtr cmap;
+ int segcount;
+
+ segcount = 0;
+ cmap = current_cmap;
+ while(cmap) {
+ segcount++;
+ cmap = cmap->next;
+ }
+
+ segcount++; /* dummy segment to end table */
+
+ cmap_start = ftell(out);
+
+ writeUSHORT(out, 0); /* version */
+ writeUSHORT(out, 1); /* number of encoding tables */
+ writeUSHORT(out, 3); /* platform ID */
+ writeUSHORT(out, (font->flags & FACE_SYMBOL) ? 0 : 1);
+ /* encoding ID */
+ writeULONG(out, 12); /* offset to beginning of subtable */
+
+ /* subtable */
+ writeUSHORT(out, 4); /* format */
+ writeUSHORT(out, 0xDEAD); /* length */
+ writeUSHORT(out, 0); /* language */
+ /* How baroque can you get? */
+ writeUSHORT(out, segcount * 2); /* segCountX2 */
+ writeUSHORT(out, 2 * two_log2_floor(segcount)); /* searchRange */
+ writeUSHORT(out, 1 + log2_floor(segcount)); /* entrySelector */
+ writeUSHORT(out, 2 * (segcount - two_log2_floor(segcount)));
+ /* rangeShift */
+
+ cmap = current_cmap;
+ while(cmap) {
+ writeUSHORT(out, cmap->endCode);
+ cmap = cmap->next;
+ }
+ writeUSHORT(out, 0xFFFF);
+
+ writeUSHORT(out, 0); /* reservedPad */
+
+ cmap = current_cmap;
+ while(cmap) {
+ writeUSHORT(out, cmap->startCode);
+ cmap = cmap->next;
+ }
+ writeUSHORT(out, 0xFFFF);
+
+ /* idDelta */
+ cmap = current_cmap;
+ while(cmap) {
+ writeUSHORT(out, (cmap->index - cmap->startCode) & 0xFFFF);
+ cmap = cmap->next;
+ }
+ writeUSHORT(out, 1);
+
+ /* idRangeOffset */
+ cmap = current_cmap;
+ while(cmap) {
+ writeUSHORT(out, 0);
+ cmap = cmap->next;
+ }
+ writeUSHORT(out, 0);
+
+ /* glyphIDArray is empty */
+
+ cmap_end = ftell(out);
+ rc = fseek(out, cmap_start + 12 + 2, SEEK_SET);
+ if(rc != 0) {
+ perror("Couldn't seek");
+ return -1;
+ }
+ writeUSHORT(out, cmap_end - cmap_start - 12); /* length */
+ rc = fseek(out, cmap_end, SEEK_SET);
+ if(rc != 0) {
+ perror("Couldn't seek");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+writeglyf(FILE* out, FontPtr font)
+{
+ return 0;
+}
+
+int
+writehhea(FILE* out, FontPtr font)
+{
+ int num, den;
+ 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, den); /* caretSlopeRise */
+ writeSHORT(out, num); /* caretSlopeRun */
+ writeSHORT(out, 0); /* reserved */
+ writeSHORT(out, 0); /* reserved */
+ writeSHORT(out, 0); /* reserved */
+ writeSHORT(out, 0); /* reserved */
+ writeSHORT(out, 0); /* reserved */
+ writeSHORT(out, 0); /* metricDataFormat */
+ writeSHORT(out, nummetrics); /* numberOfHMetrics */
+ return 0;
+}
+
+static int
+writehmtx(FILE* out, FontPtr font)
+{
+ int rc, i;
+
+ for(i = 0; i <= numglyphs; i++) {
+ int code, width, lsb;
+ code = findCode(current_cmap, i);
+ if(code < 0)
+ rc = -1;
+ else
+ rc = glyphMetrics(font, code, &width, &lsb, NULL, NULL, NULL);
+ if(rc < 0) {
+ width = UNITS_PER_EM / 3;
+ lsb = 0;
+ }
+ if(i < nummetrics) {
+ writeSHORT(out, FONT_UNITS(width));
+ writeSHORT(out, FONT_UNITS(lsb));
+ } else {
+ writeSHORT(out, FONT_UNITS(lsb));
+ }
+ }
+ return 0;
+}
+
+static int
+writeloca(FILE* out, FontPtr font)
+{
+ int i;
+
+ /* All glyphs undefined -- loca table is empty, so offset 0 */
+ for(i = 0; i < numglyphs; i++) {
+ writeSHORT(out, 0);
+ }
+ writeSHORT(out, 0);
+ return 0;
+}
+
+static int
+writemaxp(FILE* out, FontPtr font)
+{
+ writeLONG(out, 0x00010000); /* version */
+ writeUSHORT(out, numglyphs); /* numGlyphs */
+ writeUSHORT(out, 0); /* maxPoints */
+ writeUSHORT(out, 0); /* maxContours */
+ writeUSHORT(out, 0); /* maxCompositePoints */
+ writeUSHORT(out, 0); /* maxCompositeContours */
+ writeUSHORT(out, 1); /* maxZones */
+ writeUSHORT(out, 0); /* maxTwilightPoints */
+ writeUSHORT(out, 0); /* maxStorage */
+ writeUSHORT(out, 0); /* maxFunctionDefs */
+ writeUSHORT(out, 0); /* maxInstructionDefs */
+ writeUSHORT(out, 0); /* maxStackElements */
+ writeUSHORT(out, 0); /* maxSizeOfInstructions */
+ writeUSHORT(out, 0); /* maxComponentElements */
+ writeUSHORT(out, 0); /* maxComponentDepth */
+ return 0;
+}
+
+static int
+writename(FILE* out, FontPtr font)
+{
+ int i;
+ int offset;
+
+ writeUSHORT(out, 0); /* format selector */
+ writeUSHORT(out, font->numNames);
+ writeUSHORT(out, 6 + font->numNames * 12); /* offset to string storage */
+ offset = 0;
+ for(i = 0; i < font->numNames; i++) {
+ writeUSHORT(out, 3); /* platform id -- Microsoft */
+ writeUSHORT(out, 1); /* encoding -- Unicode */
+ writeUSHORT(out, 0x409); /* language id -- American English */
+ writeUSHORT(out, font->names[i].nid); /* name id */
+ writeUSHORT(out, font->names[i].size); /* string length */
+ writeUSHORT(out, offset); /* string offset */
+ offset += font->names[i].size;
+ }
+ for(i = 0; i < font->numNames; i++)
+ writeCHARs(out, font->names[i].value, font->names[i].size);
+ return 0;
+}
+
+static int
+writepost(FILE* out, FontPtr font)
+{
+ int i, rc, previous_width, width, fixed_pitch;
+
+ fixed_pitch = 1;
+ previous_width = -1;
+ for(i = 0; i < FONT_CODES; i++) {
+ rc = glyphMetrics(font, i, &width, NULL, NULL, NULL, NULL);
+ if(rc < 0)
+ continue;
+ if(previous_width >= 0) {
+ if(width != previous_width) {
+ fixed_pitch = 0;
+ break;
+ }
+ }
+ previous_width = width;
+ }
+
+ writeULONG(out, 0x00030000); /* FormatType */
+ writeULONG(out, font->italicAngle); /* italicAngle */
+ writeSHORT(out, FONT_UNITS(font->underlinePosition));
+ writeSHORT(out, FONT_UNITS(font->underlineThickness));
+ writeULONG(out, fixed_pitch); /* isFixedPitch */
+ writeULONG(out, 0); /* minMemType42 */
+ writeULONG(out, 0); /* maxMemType42 */
+ writeULONG(out, 0); /* minMemType1 */
+ writeULONG(out, 0); /* maxMemType1 */
+ return 0;
+}
+
+static int
+writeOS2(FILE* out, FontPtr font)
+{
+ int i;
+
+ writeUSHORT(out, 0x0001);
+ writeSHORT(out, FONT_UNITS(max_awidth / 2)); /* xAvgCharWidth; */
+ writeUSHORT(out, font->weight); /* usWeightClass; */
+ writeUSHORT(out, font->width); /* usWidthClass; */
+ writeSHORT(out, 0); /* fsType; */
+ writeSHORT(out, UNITS_PER_EM / 5); /* ySubscriptXSize; */
+ writeSHORT(out, UNITS_PER_EM / 5); /* ySubscriptYSize; */
+ writeSHORT(out, 0); /* ySubscriptXOffset; */
+ writeSHORT(out, UNITS_PER_EM / 5); /* ySubscriptYOffset; */
+ writeSHORT(out, UNITS_PER_EM / 5); /* ySuperscriptXSize; */
+ writeSHORT(out, UNITS_PER_EM / 5); /* ySuperscriptYSize; */
+ writeSHORT(out, 0); /* ySuperscriptXOffset; */
+ writeSHORT(out, UNITS_PER_EM / 5); /* ySuperscriptYOffset; */
+ writeSHORT(out, FONT_UNITS(font->underlineThickness));
+ /* yStrikeoutSize; */
+ writeSHORT(out, UNITS_PER_EM / 4); /* yStrikeoutPosition; */
+ writeSHORT(out, 0); /* sFamilyClass; */
+ for(i = 0; i < 10; i++)
+ writeBYTE(out, 0); /* panose; */
+ writeULONG(out, 0xFFFF); /* ulUnicodeRange1; */
+ writeULONG(out, 0xFFFF); /* ulUnicodeRange2; */
+ writeULONG(out, 0x03FF); /* ulUnicodeRange3; */
+ writeULONG(out, 0U); /* ulUnicodeRange4; */
+ writeULONG(out, font->foundry); /* achVendID[4]; */
+ writeUSHORT(out, 0x0040); /* 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; */
+ return 0;
+}
+
+static int
+writePCLT(FILE* out, FontPtr font)
+{
+ char name[16] = "XFree86 font ";
+ char filename[6] = "X11R00";
+ unsigned char charComplement[8] =
+ {0xFF, 0xFF, 0xFF, 0xFF, 0x0B, 0xFF, 0xFF, 0xFE};
+ int style, w, strokeWeight, widthType;
+
+ style = 0;
+ if(font->flags & FACE_ITALIC)
+ style = 1;
+
+ w = (font->weight + 50) / 100;
+ if(w < 5)
+ strokeWeight = w - 6;
+ else if(w == 5)
+ strokeWeight = 0;
+ else
+ strokeWeight = w - 4;
+
+ if(font->width <= 2)
+ widthType = -3;
+ else if(font->width <= 4)
+ widthType = -2;
+ else if(font->width <= 6)
+ widthType = 0;
+ else if(font->width <= 7)
+ widthType = 2;
+ else
+ widthType = 3;
+
+ writeULONG(out, 0x00010000); /* version */
+ writeULONG(out, 0); /* FontNumber */
+ writeUSHORT(out, FONT_UNITS(max_awidth)); /* pitch */
+ writeUSHORT(out, FONT_UNITS(max_y)); /* xHeight */
+ writeUSHORT(out, style); /* style */
+ writeUSHORT(out, 6 << 12); /* TypeFamily */
+ writeUSHORT(out, FONT_UNITS(max_y)); /* CapHeight */
+ writeUSHORT(out, 0); /* SymbolSet */
+ writeCHARs(out, name, 16); /* TypeFace */
+ writeBYTEs(out, charComplement, 8); /* CharacterComplement */
+ writeCHARs(out, filename, 6); /* FileName */
+ writeCHAR(out, strokeWeight); /* StrokeWeight */
+ writeCHAR(out, widthType); /* WidthType */
+ writeCHAR(out, 1 << 6); /* SerifStyle */
+ writeCHAR(out, 0); /* Reserved */
+ return 0;
+}