From a46389d96c54351cd95614f1e5eae495f51957f0 Mon Sep 17 00:00:00 2001 From: Kaleb Keithley Date: Tue, 25 Nov 2003 19:29:02 +0000 Subject: Initial revision --- env.c | 151 ++++++++ fonttosfnt.c | 117 ++++++ fonttosfnt.h | 178 ++++++++++ fonttosfnt.man | 76 ++++ read.c | 310 ++++++++++++++++ struct.c | 514 +++++++++++++++++++++++++++ util.c | 409 +++++++++++++++++++++ write.c | 1078 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 2833 insertions(+) create mode 100644 env.c create mode 100644 fonttosfnt.c create mode 100644 fonttosfnt.h create mode 100644 fonttosfnt.man create mode 100644 read.c create mode 100644 struct.c create mode 100644 util.c create mode 100644 write.c 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 +#include +#include + +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 +#include +#include +#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 +#include +#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 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 + +#include +#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 +#include +#include +#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 +#include +#include +#include +#ifndef __UNIXOS2__ +# include +#else +# include +#endif +#include + +#include +#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 +#include +#include +#include +#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; +} -- cgit v1.2.3