143f32c10Smrg/* $XdotOrg: xc/programs/fonttosfnt/read.c,v 1.2 2004/04/23 19:54:32 eich Exp $ */
243f32c10Smrg/*
343f32c10SmrgCopyright (c) 2002 by Juliusz Chroboczek
443f32c10Smrg
543f32c10SmrgPermission is hereby granted, free of charge, to any person obtaining a copy
643f32c10Smrgof this software and associated documentation files (the "Software"), to deal
743f32c10Smrgin the Software without restriction, including without limitation the rights
843f32c10Smrgto use, copy, modify, merge, publish, distribute, sublicense, and/or sell
943f32c10Smrgcopies of the Software, and to permit persons to whom the Software is
1043f32c10Smrgfurnished to do so, subject to the following conditions:
1143f32c10Smrg
1243f32c10SmrgThe above copyright notice and this permission notice shall be included in
1343f32c10Smrgall copies or substantial portions of the Software.
1443f32c10Smrg
1543f32c10SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1643f32c10SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1743f32c10SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1843f32c10SmrgAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1943f32c10SmrgLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2043f32c10SmrgOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2143f32c10SmrgTHE SOFTWARE.
2243f32c10Smrg*/
2343f32c10Smrg/* $XdotOrg: xc/programs/fonttosfnt/read.c,v 1.2 2004/04/23 19:54:32 eich Exp $ */
2443f32c10Smrg/* $XFree86: xc/programs/fonttosfnt/read.c,v 1.5 2003/12/19 02:05:39 dawes Exp $ */
2543f32c10Smrg
2643f32c10Smrg#include <stdio.h>
2743f32c10Smrg
2843f32c10Smrg#include <ft2build.h>
2943f32c10Smrg#include FT_FREETYPE_H
30ea148d1dSmrg#include FT_MODULE_H
3143f32c10Smrg#include FT_BDF_H
32c813b494Smrg#include FT_FONT_FORMATS_H
3343f32c10Smrg#include "X11/Xos.h"
3443f32c10Smrg#include "fonttosfnt.h"
3543f32c10Smrg#include "X11/fonts/fontenc.h"
3643f32c10Smrg
3743f32c10Smrg#define FLOOR2(x, y) ((x) >= 0 ? (x) / (y) : -(((-(x)) + (y) - 1) / (y)))
3843f32c10Smrg#define CEIL2(x, y) (FLOOR2((x) + (y) - 1, (y)))
3943f32c10Smrg#define FT_Pos_DOWN(x) (FLOOR2((x),64))
4043f32c10Smrg#define FT_Pos_UP(x) (CEIL2((x), 64))
41ea148d1dSmrg#define MIN(x, y) (((x) <= (y)) ? (x) : (y))
42ea148d1dSmrg#define STREAM_FILE(stream) ((FILE*)stream->descriptor.pointer)
4343f32c10Smrg
4443f32c10Smrgstatic int ft_inited = 0;
4543f32c10Smrgstatic FT_Library ft_library;
4643f32c10Smrg
4743f32c10Smrgstatic int
4843f32c10SmrgFT_Ensure_Inited(void)
4943f32c10Smrg{
5043f32c10Smrg    int rc;
5143f32c10Smrg    if(ft_inited)
5243f32c10Smrg        return 0;
5343f32c10Smrg
5443f32c10Smrg    rc = FT_Init_FreeType(&ft_library);
5543f32c10Smrg    if(rc != 0)
5643f32c10Smrg        return rc;
5743f32c10Smrg
5843f32c10Smrg    ft_inited = 1;
5943f32c10Smrg    return 0;
6043f32c10Smrg}
6143f32c10Smrg
62ea148d1dSmrgstatic unsigned long
63ea148d1dSmrgforwardRead(FT_Stream stream, unsigned long offset, unsigned char *buffer,
64ea148d1dSmrg            unsigned long count) {
65ea148d1dSmrg    unsigned char skip_buffer[BUFSIZ];
66ea148d1dSmrg    unsigned long skip_count;
67ea148d1dSmrg    FILE *file = STREAM_FILE(stream);
68ea148d1dSmrg
69ea148d1dSmrg    /* We may be asked to skip forward, but by not doing so we increase our
70ea148d1dSmrg       chance of survival. */
71ea148d1dSmrg    if(count == 0)
72ea148d1dSmrg        return ferror(file) == 0 ? 0 : 1;
73ea148d1dSmrg
74ea148d1dSmrg    if(offset < stream->pos) {
75ea148d1dSmrg        fprintf(stderr, "Cannot move backward in input stream.\n");
76ea148d1dSmrg        return 0;
77ea148d1dSmrg    }
78ea148d1dSmrg    while((skip_count = MIN(BUFSIZ, offset - stream->pos))) {
79ea148d1dSmrg        if(fread(skip_buffer, sizeof(*skip_buffer), skip_count, file) <
80ea148d1dSmrg           skip_count)
81ea148d1dSmrg            return 0;
82ea148d1dSmrg        stream->pos += sizeof(*skip_buffer) * skip_count;
83ea148d1dSmrg    }
84ea148d1dSmrg
85ea148d1dSmrg    return (unsigned long)fread(buffer, sizeof(*buffer), count, file);
86ea148d1dSmrg}
87ea148d1dSmrg
88ea148d1dSmrgstatic void
89ea148d1dSmrgstreamClose(FT_Stream stream) {
90ea148d1dSmrg    fclose(STREAM_FILE(stream));
91ea148d1dSmrg    stream->descriptor.pointer = NULL;
92ea148d1dSmrg    stream->size = 0;
93ea148d1dSmrg}
94ea148d1dSmrg
9543f32c10Smrgint
9643f32c10SmrgreadFile(char *filename, FontPtr font)
9743f32c10Smrg{
986ef05171Smrg    int j, k, index;
9943f32c10Smrg    int rc;
100ea148d1dSmrg    FT_Open_Args input = { 0 };
10143f32c10Smrg    FT_Face face;
10243f32c10Smrg    StrikePtr strike;
10343f32c10Smrg    BitmapPtr bitmap;
10443f32c10Smrg    int symbol = 0;
105ea148d1dSmrg    int force_unicode = 1;
106d2f28e1bSmrg    const char *family_name, *encoding_name, *file_format;
10743f32c10Smrg    FontMapPtr mapping = NULL;
10843f32c10Smrg    FontMapReversePtr reverse = NULL;
10943f32c10Smrg
11043f32c10Smrg
11143f32c10Smrg    rc = FT_Ensure_Inited();
11243f32c10Smrg    if(rc != 0)
11343f32c10Smrg        return rc;
11443f32c10Smrg
115ea148d1dSmrg    if(filename != NULL) {
116ea148d1dSmrg        input.pathname = filename;
117ea148d1dSmrg        input.flags = FT_OPEN_PATHNAME;
118ea148d1dSmrg    } else {
119ea148d1dSmrg        input.flags = FT_OPEN_STREAM | FT_OPEN_DRIVER;
120ea148d1dSmrg        input.driver = FT_Get_Module(ft_library, "bdf");
121ea148d1dSmrg        input.stream = calloc(1, sizeof(FT_StreamRec));
122ea148d1dSmrg        if(input.stream == NULL)
123ea148d1dSmrg            return -1;
124ea148d1dSmrg
125ea148d1dSmrg        input.stream->size = 0x7FFFFFFF;
126ea148d1dSmrg        input.stream->descriptor.pointer = stdin;
127ea148d1dSmrg        input.stream->read = forwardRead;
128ea148d1dSmrg        input.stream->close = streamClose;
129ea148d1dSmrg    }
130ea148d1dSmrg    rc = FT_Open_Face(ft_library, &input, 0, &face);
13143f32c10Smrg    if(rc != 0) {
132ea148d1dSmrg        fprintf(stderr, "Couldn't open face %s.\n",
133ea148d1dSmrg                filename ? filename : "<stdin>");
13443f32c10Smrg        return -1;
13543f32c10Smrg    }
13643f32c10Smrg
137c813b494Smrg    file_format = FT_Get_Font_Format(face);
138c813b494Smrg    if(strcmp(file_format, "BDF") != 0)
139c813b494Smrg	fprintf(stderr,
140c813b494Smrg		"font file %s is of format %s.\n"
141c813b494Smrg		"It's recommended to convert directly from a BDF font.\n"
142c813b494Smrg		"Some font properties may get lost when converting via a PCF font.\n",
143c813b494Smrg		filename ? filename : "<stdin>",
144c813b494Smrg		file_format);
145c813b494Smrg
146ea148d1dSmrg    /* FreeType will insist on encodings which are simple subsets of unicode
147ea148d1dSmrg     * to be read as unicode regardless of what we call them. */
148ea148d1dSmrg    for(j = 0; j < face->num_charmaps; ++j) {
149ea148d1dSmrg        if((face->charmaps[j]->encoding == ft_encoding_none) ||
150ea148d1dSmrg           (face->charmaps[j]->encoding == ft_encoding_adobe_standard)) {
151ea148d1dSmrg            force_unicode = 0;
152ea148d1dSmrg            break;
153ea148d1dSmrg        }
154ea148d1dSmrg    }
155ea148d1dSmrg
15643f32c10Smrg    encoding_name = faceEncoding(face);
15743f32c10Smrg    if(encoding_name == NULL) {
15843f32c10Smrg        symbol = 1;
15943f32c10Smrg    } else if(strcasecmp(encoding_name, "iso10646-1") != 0) {
16043f32c10Smrg        if(reencode_flag)
16143f32c10Smrg            mapping = FontEncMapFind(encoding_name,
16243f32c10Smrg                                     FONT_ENCODING_UNICODE, 0, 0, NULL);
16343f32c10Smrg        if(mapping == NULL) {
16443f32c10Smrg            symbol = 1;
16543f32c10Smrg        } else {
16643f32c10Smrg            reverse = FontMapReverse(mapping);
16743f32c10Smrg            if(reverse == NULL) {
16843f32c10Smrg                fprintf(stderr, "Couldn't reverse mapping.\n");
16943f32c10Smrg                return -1;
17043f32c10Smrg            }
17143f32c10Smrg        }
17243f32c10Smrg    }
17343f32c10Smrg
174d2f28e1bSmrg    if(face->family_name)
175d2f28e1bSmrg        family_name = face->family_name;
176d2f28e1bSmrg    else
177d2f28e1bSmrg	family_name = faceStringProp(face, "FONT");
178d2f28e1bSmrg
17943f32c10Smrg    if(verbose_flag) {
18043f32c10Smrg        fprintf(stderr, "%s %s %s: %d sizes%s\n",
181ea148d1dSmrg                filename ? filename : "<stdin>",
182ea148d1dSmrg                face->family_name, face->style_name, face->num_fixed_sizes,
18343f32c10Smrg                symbol ? " (symbol)" : "");
18443f32c10Smrg    }
18543f32c10Smrg
186d2f28e1bSmrg    if(font->numNames == 0 && face->style_name && family_name) {
187d2f28e1bSmrg        char *full_name, *unique_name, *buf;
1886ef05171Smrg        int i;
18943f32c10Smrg        if(strcmp(face->style_name, "Regular") == 0)
190d2f28e1bSmrg            full_name = sprintf_alloc("%s", family_name);
19143f32c10Smrg        else
19243f32c10Smrg            full_name = sprintf_alloc("%s %s",
193d2f28e1bSmrg                                      family_name, face->style_name);
19443f32c10Smrg
19543f32c10Smrg        /* The unique name doesn't actually need to be globally
19643f32c10Smrg           unique; it only needs to be unique among all installed fonts on a
19743f32c10Smrg           Windows system.  We don't bother getting it quite right. */
19843f32c10Smrg        if(face->num_fixed_sizes <= 0)
19943f32c10Smrg            unique_name = sprintf_alloc("%s "XVENDORNAMESHORT" bitmap",
20043f32c10Smrg                                        full_name);
20143f32c10Smrg        else if(face->available_sizes[0].width ==
20243f32c10Smrg                face->available_sizes[0].height)
20343f32c10Smrg            unique_name = sprintf_alloc("%s "XVENDORNAMESHORT
20443f32c10Smrg					   " bitmap size %d",
20543f32c10Smrg                                           full_name,
20643f32c10Smrg                                           face->available_sizes[0].height);
20743f32c10Smrg        else
20843f32c10Smrg            unique_name = sprintf_alloc("%s "XVENDORNAMESHORT
20943f32c10Smrg                                        " bitmap size %dx%d",
21043f32c10Smrg                                        full_name,
21143f32c10Smrg                                        face->available_sizes[0].width,
21243f32c10Smrg                                        face->available_sizes[0].height);
21343f32c10Smrg
21443f32c10Smrg        font->names = malloc(10 * sizeof(FontNameEntryRec));
21543f32c10Smrg        if(font->names == NULL) {
21643f32c10Smrg            fprintf(stderr, "Couldn't allocate names.\n");
21743f32c10Smrg            return -1;
21843f32c10Smrg        }
21943f32c10Smrg        i = 0;
22043f32c10Smrg
221d2f28e1bSmrg	buf = faceStringProp(face, "COPYRIGHT");
222d2f28e1bSmrg	if(buf) {
22343f32c10Smrg            font->names[i].nid = 0;
224d2f28e1bSmrg            font->names[i].size = 2 * strlen(buf);
225d2f28e1bSmrg            font->names[i].value = makeUTF16(buf);
226d2f28e1bSmrg	    free(buf);
22743f32c10Smrg            i++;
228d2f28e1bSmrg	}
22943f32c10Smrg
23043f32c10Smrg        font->names[i].nid = 1;
231d2f28e1bSmrg        font->names[i].size = 2 * strlen(family_name);
232d2f28e1bSmrg        font->names[i].value = makeUTF16(family_name);
23343f32c10Smrg        i++;
23443f32c10Smrg
23543f32c10Smrg        font->names[i].nid = 2;
23643f32c10Smrg        font->names[i].size = 2 * strlen(face->style_name);
23743f32c10Smrg        font->names[i].value = makeUTF16(face->style_name);
23843f32c10Smrg        i++;
23943f32c10Smrg
24043f32c10Smrg        font->names[i].nid = 3;
24143f32c10Smrg        font->names[i].size = 2 * strlen(unique_name);
24243f32c10Smrg        font->names[i].value = makeUTF16(unique_name);
24343f32c10Smrg        i++;
24443f32c10Smrg
24543f32c10Smrg        font->names[i].nid = 4;
24643f32c10Smrg        font->names[i].size = 2 * strlen(full_name);
24743f32c10Smrg        font->names[i].value = makeUTF16(full_name);
24843f32c10Smrg        i++;
24943f32c10Smrg
25043f32c10Smrg        font->names[i].nid = 5;
25143f32c10Smrg        font->names[i].size = 2 * strlen("Version 0.0");
25243f32c10Smrg        font->names[i].value = makeUTF16("Version 0.0");
25343f32c10Smrg        i++;
25443f32c10Smrg
255d2f28e1bSmrg	buf = faceStringProp(face, "FOUNDRY");
256d2f28e1bSmrg	if(buf) {
25743f32c10Smrg            font->names[i].nid = 8;
258d2f28e1bSmrg	    font->names[i].size = 2 * strlen(buf);
259d2f28e1bSmrg	    font->names[i].value = makeUTF16(buf);
260d2f28e1bSmrg	    free(buf);
26143f32c10Smrg            i++;
262d2f28e1bSmrg	}
26343f32c10Smrg
26443f32c10Smrg        font->names[i].nid = 10;
26543f32c10Smrg        font->names[i].size = 2 * strlen(XVENDORNAMESHORT
26643f32c10Smrg					 " converted bitmap font");
26743f32c10Smrg        font->names[i].value = makeUTF16(XVENDORNAMESHORT
268ea148d1dSmrg					 " converted bitmap font");
26943f32c10Smrg        i++;
27043f32c10Smrg#ifdef __VENDORWEBSUPPORT__
27143f32c10Smrg        font->names[i].nid = 11;
27243f32c10Smrg        font->names[i].size = 2 * strlen(__VENDORWEBSUPPORT__);
27343f32c10Smrg        font->names[i].value = makeUTF16(__VENDORWEBSUPPORT__);
27443f32c10Smrg        i++;
27543f32c10Smrg#endif
27643f32c10Smrg        font->numNames = i;
27743f32c10Smrg    }
27843f32c10Smrg
27943f32c10Smrg    if(face->num_fixed_sizes == 0) {
28043f32c10Smrg        fprintf(stderr, "No bitmaps in face.\n");
28143f32c10Smrg        return -1;
28243f32c10Smrg    }
28343f32c10Smrg
284ea148d1dSmrg    if((!symbol && !mapping) || force_unicode) {
28543f32c10Smrg        rc = FT_Select_Charmap(face, ft_encoding_unicode);
286ea148d1dSmrg    } else {
28743f32c10Smrg        rc = FT_Select_Charmap(face, ft_encoding_none);
288ea148d1dSmrg        if(rc != 0) {
289ea148d1dSmrg            /* BDF will default to Adobe Standard even for nonstandard
290ea148d1dSmrg             * encodings, so try that as a last resort. */
291ea148d1dSmrg            rc = FT_Select_Charmap(face, ft_encoding_adobe_standard);
292ea148d1dSmrg        }
293ea148d1dSmrg    }
29443f32c10Smrg    if(rc != 0) {
29543f32c10Smrg        fprintf(stderr, "Couldn't select character map: %x.\n", rc);
29643f32c10Smrg        return -1;
29743f32c10Smrg    }
29843f32c10Smrg
299c813b494Smrg    font->flags = faceFlags(face) | (symbol ? FACE_SYMBOL : 0);
300c813b494Smrg    font->weight = faceWeight(face);
301c813b494Smrg    font->width = faceWidth(face);
302c813b494Smrg    font->foundry = faceFoundry(face);
303c813b494Smrg    font->italicAngle = faceItalicAngle(face);
304c813b494Smrg    font->pxMetrics.height = face->available_sizes[0].height;
305c813b494Smrg    font->pxMetrics.size = faceIntProp(face, "PIXEL_SIZE");
306c813b494Smrg    font->pxMetrics.xHeight = faceIntProp(face, "X_HEIGHT");
307c813b494Smrg    font->pxMetrics.capHeight = faceIntProp(face, "CAP_HEIGHT");
308c813b494Smrg    font->pxMetrics.ascent = faceIntProp(face, "FONT_ASCENT");
309c813b494Smrg    font->pxMetrics.descent = faceIntProp(face, "FONT_DESCENT");
310c813b494Smrg    font->pxMetrics.underlinePosition = faceIntProp(face, "UNDERLINE_POSITION");
311c813b494Smrg    font->pxMetrics.underlineThickness = faceIntProp(face, "UNDERLINE_THICKNESS");
312c813b494Smrg
3136ef05171Smrg    for(int i = 0; i < face->num_fixed_sizes; i++) {
31443f32c10Smrg        if(verbose_flag)
31543f32c10Smrg            fprintf(stderr, "size %d: %dx%d\n",
31643f32c10Smrg                    i,
317ea148d1dSmrg                    (int)((face->available_sizes[i].x_ppem + 32) >> 6),
318ea148d1dSmrg                    (int)((face->available_sizes[i].y_ppem + 32) >> 6));
31943f32c10Smrg
32043f32c10Smrg        rc = FT_Set_Pixel_Sizes(face,
321ea148d1dSmrg                                (face->available_sizes[i].x_ppem + 32) >> 6,
322ea148d1dSmrg                                (face->available_sizes[i].y_ppem + 32) >> 6);
32343f32c10Smrg        if(rc != 0) {
32443f32c10Smrg            fprintf(stderr, "Couldn't set size.\n");
32543f32c10Smrg            return -1;
32643f32c10Smrg        }
32743f32c10Smrg
32843f32c10Smrg        strike = makeStrike(font,
329ea148d1dSmrg                            (face->available_sizes[i].x_ppem + 32) >> 6,
330ea148d1dSmrg                            (face->available_sizes[i].y_ppem + 32) >> 6);
33143f32c10Smrg        if(strike == NULL) {
33243f32c10Smrg            fprintf(stderr, "Couldn't allocate strike.\n");
33343f32c10Smrg            return -1;
33443f32c10Smrg        }
33543f32c10Smrg
33643f32c10Smrg        for(j = 0; j < FONT_CODES; j++) {
33743f32c10Smrg            if(mapping)
33843f32c10Smrg                k = reverse->reverse(j, reverse->data);
33943f32c10Smrg            else
34043f32c10Smrg                k = j;
34143f32c10Smrg            if(k <= 0 && j != 0)
34243f32c10Smrg                continue;
34343f32c10Smrg            index = FT_Get_Char_Index(face, k);
34443f32c10Smrg            if(j != 0 && index == 0)
34543f32c10Smrg                continue;
34643f32c10Smrg            rc = FT_Load_Glyph(face, index,
34743f32c10Smrg                               FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
34843f32c10Smrg            if(rc != 0) {
34943f32c10Smrg                fprintf(stderr, "Couldn't load glyph for U+%04X (%d)\n",
35043f32c10Smrg                        j, index);
35143f32c10Smrg                continue;
35243f32c10Smrg            }
35343f32c10Smrg            bitmap = makeBitmap(strike, j,
35443f32c10Smrg                                FT_Pos_UP(face->glyph->metrics.horiAdvance),
35543f32c10Smrg                                FT_Pos_DOWN(face->glyph->metrics.horiBearingX),
35643f32c10Smrg                                FT_Pos_DOWN(face->glyph->metrics.horiBearingY),
35743f32c10Smrg                                face->glyph->bitmap.width,
35843f32c10Smrg                                face->glyph->bitmap.rows,
35943f32c10Smrg                                face->glyph->bitmap.pitch,
36043f32c10Smrg                                face->glyph->bitmap.buffer,
36143f32c10Smrg                                crop_flag);
36243f32c10Smrg
36343f32c10Smrg            if(bitmap == NULL) {
36443f32c10Smrg                fprintf(stderr, "Couldn't create bitmap.\n");
36543f32c10Smrg                return -1;
36643f32c10Smrg            }
36743f32c10Smrg        }
36843f32c10Smrg    }
36943f32c10Smrg
37043f32c10Smrg    FT_Done_Face(face);
371ea148d1dSmrg    free(input.stream);
37243f32c10Smrg
37343f32c10Smrg    j = 0;
3746ef05171Smrg    for(int i = 0; i < FONT_CODES; i++) {
37543f32c10Smrg        int found = 0;
37643f32c10Smrg        strike = font->strikes;
37743f32c10Smrg        while(strike) {
37843f32c10Smrg            bitmap = STRIKE_BITMAP(strike, i);
37943f32c10Smrg            if(bitmap) {
38043f32c10Smrg                bitmap->index = j;
38143f32c10Smrg                found = 1;
38243f32c10Smrg            } else {
38343f32c10Smrg                if(i == 0) {
38443f32c10Smrg                    fprintf(stderr,
38543f32c10Smrg                            "Warning: no bitmap for the undefined glyph.\n");
38643f32c10Smrg                    found = 1;
38743f32c10Smrg                }
38843f32c10Smrg            }
38943f32c10Smrg            strike = strike->next;
39043f32c10Smrg        }
39143f32c10Smrg        if(found)
39243f32c10Smrg            j++;
39343f32c10Smrg    }
39443f32c10Smrg    return 0;
39543f32c10Smrg}
396