diff options
-rw-r--r-- | env.c | 151 | ||||
-rw-r--r-- | fonttosfnt.c | 117 | ||||
-rw-r--r-- | fonttosfnt.h | 178 | ||||
-rw-r--r-- | fonttosfnt.man | 76 | ||||
-rw-r--r-- | read.c | 310 | ||||
-rw-r--r-- | struct.c | 514 | ||||
-rw-r--r-- | util.c | 409 | ||||
-rw-r--r-- | write.c | 1078 |
8 files changed, 2833 insertions, 0 deletions
@@ -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. @@ -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; +} + @@ -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; +} + @@ -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; +} |