read.c revision c813b494
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;
106c813b494Smrg    const char *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
17443f32c10Smrg    if(verbose_flag) {
17543f32c10Smrg        fprintf(stderr, "%s %s %s: %d sizes%s\n",
176ea148d1dSmrg                filename ? filename : "<stdin>",
177ea148d1dSmrg                face->family_name, face->style_name, face->num_fixed_sizes,
17843f32c10Smrg                symbol ? " (symbol)" : "");
17943f32c10Smrg    }
18043f32c10Smrg
18143f32c10Smrg    if(font->numNames == 0 && face->style_name && face->family_name) {
18243f32c10Smrg        char *full_name, *unique_name;
18343f32c10Smrg        BDF_PropertyRec prop;
1846ef05171Smrg        int i;
18543f32c10Smrg        if(strcmp(face->style_name, "Regular") == 0)
18643f32c10Smrg            full_name = sprintf_alloc("%s", face->family_name);
18743f32c10Smrg        else
18843f32c10Smrg            full_name = sprintf_alloc("%s %s",
18943f32c10Smrg                                      face->family_name, face->style_name);
19043f32c10Smrg
19143f32c10Smrg        /* The unique name doesn't actually need to be globally
19243f32c10Smrg           unique; it only needs to be unique among all installed fonts on a
19343f32c10Smrg           Windows system.  We don't bother getting it quite right. */
19443f32c10Smrg        if(face->num_fixed_sizes <= 0)
19543f32c10Smrg            unique_name = sprintf_alloc("%s "XVENDORNAMESHORT" bitmap",
19643f32c10Smrg                                        full_name);
19743f32c10Smrg        else if(face->available_sizes[0].width ==
19843f32c10Smrg                face->available_sizes[0].height)
19943f32c10Smrg            unique_name = sprintf_alloc("%s "XVENDORNAMESHORT
20043f32c10Smrg					   " bitmap size %d",
20143f32c10Smrg                                           full_name,
20243f32c10Smrg                                           face->available_sizes[0].height);
20343f32c10Smrg        else
20443f32c10Smrg            unique_name = sprintf_alloc("%s "XVENDORNAMESHORT
20543f32c10Smrg                                        " bitmap size %dx%d",
20643f32c10Smrg                                        full_name,
20743f32c10Smrg                                        face->available_sizes[0].width,
20843f32c10Smrg                                        face->available_sizes[0].height);
20943f32c10Smrg
21043f32c10Smrg        font->names = malloc(10 * sizeof(FontNameEntryRec));
21143f32c10Smrg        if(font->names == NULL) {
21243f32c10Smrg            fprintf(stderr, "Couldn't allocate names.\n");
21343f32c10Smrg            return -1;
21443f32c10Smrg        }
21543f32c10Smrg        i = 0;
21643f32c10Smrg
21743f32c10Smrg        rc = FT_Get_BDF_Property(face, "COPYRIGHT", &prop);
21843f32c10Smrg        if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
21943f32c10Smrg            font->names[i].nid = 0;
22043f32c10Smrg            font->names[i].size = 2 * strlen(prop.u.atom);
22143f32c10Smrg            font->names[i].value = makeUTF16((char*)prop.u.atom);
22243f32c10Smrg            i++;
22343f32c10Smrg        }
22443f32c10Smrg
22543f32c10Smrg        font->names[i].nid = 1;
22643f32c10Smrg        font->names[i].size = 2 * strlen(face->family_name);
22743f32c10Smrg        font->names[i].value = makeUTF16(face->family_name);
22843f32c10Smrg        i++;
22943f32c10Smrg
23043f32c10Smrg        font->names[i].nid = 2;
23143f32c10Smrg        font->names[i].size = 2 * strlen(face->style_name);
23243f32c10Smrg        font->names[i].value = makeUTF16(face->style_name);
23343f32c10Smrg        i++;
23443f32c10Smrg
23543f32c10Smrg        font->names[i].nid = 3;
23643f32c10Smrg        font->names[i].size = 2 * strlen(unique_name);
23743f32c10Smrg        font->names[i].value = makeUTF16(unique_name);
23843f32c10Smrg        i++;
23943f32c10Smrg
24043f32c10Smrg        font->names[i].nid = 4;
24143f32c10Smrg        font->names[i].size = 2 * strlen(full_name);
24243f32c10Smrg        font->names[i].value = makeUTF16(full_name);
24343f32c10Smrg        i++;
24443f32c10Smrg
24543f32c10Smrg        font->names[i].nid = 5;
24643f32c10Smrg        font->names[i].size = 2 * strlen("Version 0.0");
24743f32c10Smrg        font->names[i].value = makeUTF16("Version 0.0");
24843f32c10Smrg        i++;
24943f32c10Smrg
25043f32c10Smrg        rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop);
25143f32c10Smrg        if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
25243f32c10Smrg            font->names[i].nid = 8;
25343f32c10Smrg            font->names[i].size = 2 * strlen(prop.u.atom);
25443f32c10Smrg            font->names[i].value = makeUTF16((char*)prop.u.atom);
25543f32c10Smrg            i++;
25643f32c10Smrg        }
25743f32c10Smrg
25843f32c10Smrg        font->names[i].nid = 10;
25943f32c10Smrg        font->names[i].size = 2 * strlen(XVENDORNAMESHORT
26043f32c10Smrg					 " converted bitmap font");
26143f32c10Smrg        font->names[i].value = makeUTF16(XVENDORNAMESHORT
262ea148d1dSmrg					 " converted bitmap font");
26343f32c10Smrg        i++;
26443f32c10Smrg#ifdef __VENDORWEBSUPPORT__
26543f32c10Smrg        font->names[i].nid = 11;
26643f32c10Smrg        font->names[i].size = 2 * strlen(__VENDORWEBSUPPORT__);
26743f32c10Smrg        font->names[i].value = makeUTF16(__VENDORWEBSUPPORT__);
26843f32c10Smrg        i++;
26943f32c10Smrg#endif
27043f32c10Smrg        font->numNames = i;
27143f32c10Smrg    }
27243f32c10Smrg
27343f32c10Smrg    if(face->num_fixed_sizes == 0) {
27443f32c10Smrg        fprintf(stderr, "No bitmaps in face.\n");
27543f32c10Smrg        return -1;
27643f32c10Smrg    }
27743f32c10Smrg
278ea148d1dSmrg    if((!symbol && !mapping) || force_unicode) {
27943f32c10Smrg        rc = FT_Select_Charmap(face, ft_encoding_unicode);
280ea148d1dSmrg    } else {
28143f32c10Smrg        rc = FT_Select_Charmap(face, ft_encoding_none);
282ea148d1dSmrg        if(rc != 0) {
283ea148d1dSmrg            /* BDF will default to Adobe Standard even for nonstandard
284ea148d1dSmrg             * encodings, so try that as a last resort. */
285ea148d1dSmrg            rc = FT_Select_Charmap(face, ft_encoding_adobe_standard);
286ea148d1dSmrg        }
287ea148d1dSmrg    }
28843f32c10Smrg    if(rc != 0) {
28943f32c10Smrg        fprintf(stderr, "Couldn't select character map: %x.\n", rc);
29043f32c10Smrg        return -1;
29143f32c10Smrg    }
29243f32c10Smrg
293c813b494Smrg    font->flags = faceFlags(face) | (symbol ? FACE_SYMBOL : 0);
294c813b494Smrg    font->weight = faceWeight(face);
295c813b494Smrg    font->width = faceWidth(face);
296c813b494Smrg    font->foundry = faceFoundry(face);
297c813b494Smrg    font->italicAngle = faceItalicAngle(face);
298c813b494Smrg    font->pxMetrics.height = face->available_sizes[0].height;
299c813b494Smrg    font->pxMetrics.size = faceIntProp(face, "PIXEL_SIZE");
300c813b494Smrg    font->pxMetrics.xHeight = faceIntProp(face, "X_HEIGHT");
301c813b494Smrg    font->pxMetrics.capHeight = faceIntProp(face, "CAP_HEIGHT");
302c813b494Smrg    font->pxMetrics.ascent = faceIntProp(face, "FONT_ASCENT");
303c813b494Smrg    font->pxMetrics.descent = faceIntProp(face, "FONT_DESCENT");
304c813b494Smrg    font->pxMetrics.underlinePosition = faceIntProp(face, "UNDERLINE_POSITION");
305c813b494Smrg    font->pxMetrics.underlineThickness = faceIntProp(face, "UNDERLINE_THICKNESS");
306c813b494Smrg
3076ef05171Smrg    for(int i = 0; i < face->num_fixed_sizes; i++) {
30843f32c10Smrg        if(verbose_flag)
30943f32c10Smrg            fprintf(stderr, "size %d: %dx%d\n",
31043f32c10Smrg                    i,
311ea148d1dSmrg                    (int)((face->available_sizes[i].x_ppem + 32) >> 6),
312ea148d1dSmrg                    (int)((face->available_sizes[i].y_ppem + 32) >> 6));
31343f32c10Smrg
31443f32c10Smrg        rc = FT_Set_Pixel_Sizes(face,
315ea148d1dSmrg                                (face->available_sizes[i].x_ppem + 32) >> 6,
316ea148d1dSmrg                                (face->available_sizes[i].y_ppem + 32) >> 6);
31743f32c10Smrg        if(rc != 0) {
31843f32c10Smrg            fprintf(stderr, "Couldn't set size.\n");
31943f32c10Smrg            return -1;
32043f32c10Smrg        }
32143f32c10Smrg
32243f32c10Smrg        strike = makeStrike(font,
323ea148d1dSmrg                            (face->available_sizes[i].x_ppem + 32) >> 6,
324ea148d1dSmrg                            (face->available_sizes[i].y_ppem + 32) >> 6);
32543f32c10Smrg        if(strike == NULL) {
32643f32c10Smrg            fprintf(stderr, "Couldn't allocate strike.\n");
32743f32c10Smrg            return -1;
32843f32c10Smrg        }
32943f32c10Smrg
33043f32c10Smrg        for(j = 0; j < FONT_CODES; j++) {
33143f32c10Smrg            if(mapping)
33243f32c10Smrg                k = reverse->reverse(j, reverse->data);
33343f32c10Smrg            else
33443f32c10Smrg                k = j;
33543f32c10Smrg            if(k <= 0 && j != 0)
33643f32c10Smrg                continue;
33743f32c10Smrg            index = FT_Get_Char_Index(face, k);
33843f32c10Smrg            if(j != 0 && index == 0)
33943f32c10Smrg                continue;
34043f32c10Smrg            rc = FT_Load_Glyph(face, index,
34143f32c10Smrg                               FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
34243f32c10Smrg            if(rc != 0) {
34343f32c10Smrg                fprintf(stderr, "Couldn't load glyph for U+%04X (%d)\n",
34443f32c10Smrg                        j, index);
34543f32c10Smrg                continue;
34643f32c10Smrg            }
34743f32c10Smrg            bitmap = makeBitmap(strike, j,
34843f32c10Smrg                                FT_Pos_UP(face->glyph->metrics.horiAdvance),
34943f32c10Smrg                                FT_Pos_DOWN(face->glyph->metrics.horiBearingX),
35043f32c10Smrg                                FT_Pos_DOWN(face->glyph->metrics.horiBearingY),
35143f32c10Smrg                                face->glyph->bitmap.width,
35243f32c10Smrg                                face->glyph->bitmap.rows,
35343f32c10Smrg                                face->glyph->bitmap.pitch,
35443f32c10Smrg                                face->glyph->bitmap.buffer,
35543f32c10Smrg                                crop_flag);
35643f32c10Smrg
35743f32c10Smrg            if(bitmap == NULL) {
35843f32c10Smrg                fprintf(stderr, "Couldn't create bitmap.\n");
35943f32c10Smrg                return -1;
36043f32c10Smrg            }
36143f32c10Smrg        }
36243f32c10Smrg    }
36343f32c10Smrg
36443f32c10Smrg    FT_Done_Face(face);
365ea148d1dSmrg    free(input.stream);
36643f32c10Smrg
36743f32c10Smrg    j = 0;
3686ef05171Smrg    for(int i = 0; i < FONT_CODES; i++) {
36943f32c10Smrg        int found = 0;
37043f32c10Smrg        strike = font->strikes;
37143f32c10Smrg        while(strike) {
37243f32c10Smrg            bitmap = STRIKE_BITMAP(strike, i);
37343f32c10Smrg            if(bitmap) {
37443f32c10Smrg                bitmap->index = j;
37543f32c10Smrg                found = 1;
37643f32c10Smrg            } else {
37743f32c10Smrg                if(i == 0) {
37843f32c10Smrg                    fprintf(stderr,
37943f32c10Smrg                            "Warning: no bitmap for the undefined glyph.\n");
38043f32c10Smrg                    found = 1;
38143f32c10Smrg                }
38243f32c10Smrg            }
38343f32c10Smrg            strike = strike->next;
38443f32c10Smrg        }
38543f32c10Smrg        if(found)
38643f32c10Smrg            j++;
38743f32c10Smrg    }
38843f32c10Smrg    return 0;
38943f32c10Smrg}
390