read.c revision ea148d1d
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
3243f32c10Smrg#include "X11/Xos.h"
3343f32c10Smrg#include "fonttosfnt.h"
3443f32c10Smrg#include "X11/fonts/fontenc.h"
3543f32c10Smrg
3643f32c10Smrg#define FLOOR2(x, y) ((x) >= 0 ? (x) / (y) : -(((-(x)) + (y) - 1) / (y)))
3743f32c10Smrg#define CEIL2(x, y) (FLOOR2((x) + (y) - 1, (y)))
3843f32c10Smrg#define FT_Pos_DOWN(x) (FLOOR2((x),64))
3943f32c10Smrg#define FT_Pos_UP(x) (CEIL2((x), 64))
40ea148d1dSmrg#define MIN(x, y) (((x) <= (y)) ? (x) : (y))
41ea148d1dSmrg#define STREAM_FILE(stream) ((FILE*)stream->descriptor.pointer)
4243f32c10Smrg
4343f32c10Smrgstatic int ft_inited = 0;
4443f32c10Smrgstatic FT_Library ft_library;
4543f32c10Smrg
4643f32c10Smrgstatic int
4743f32c10SmrgFT_Ensure_Inited(void)
4843f32c10Smrg{
4943f32c10Smrg    int rc;
5043f32c10Smrg    if(ft_inited)
5143f32c10Smrg        return 0;
5243f32c10Smrg
5343f32c10Smrg    rc = FT_Init_FreeType(&ft_library);
5443f32c10Smrg    if(rc != 0)
5543f32c10Smrg        return rc;
5643f32c10Smrg
5743f32c10Smrg    ft_inited = 1;
5843f32c10Smrg    return 0;
5943f32c10Smrg}
6043f32c10Smrg
61ea148d1dSmrgstatic unsigned long
62ea148d1dSmrgforwardRead(FT_Stream stream, unsigned long offset, unsigned char *buffer,
63ea148d1dSmrg            unsigned long count) {
64ea148d1dSmrg    unsigned char skip_buffer[BUFSIZ];
65ea148d1dSmrg    unsigned long skip_count;
66ea148d1dSmrg    FILE *file = STREAM_FILE(stream);
67ea148d1dSmrg
68ea148d1dSmrg    /* We may be asked to skip forward, but by not doing so we increase our
69ea148d1dSmrg       chance of survival. */
70ea148d1dSmrg    if(count == 0)
71ea148d1dSmrg        return ferror(file) == 0 ? 0 : 1;
72ea148d1dSmrg
73ea148d1dSmrg    if(offset < stream->pos) {
74ea148d1dSmrg        fprintf(stderr, "Cannot move backward in input stream.\n");
75ea148d1dSmrg        return 0;
76ea148d1dSmrg    }
77ea148d1dSmrg    while((skip_count = MIN(BUFSIZ, offset - stream->pos))) {
78ea148d1dSmrg        if(fread(skip_buffer, sizeof(*skip_buffer), skip_count, file) <
79ea148d1dSmrg           skip_count)
80ea148d1dSmrg            return 0;
81ea148d1dSmrg        stream->pos += sizeof(*skip_buffer) * skip_count;
82ea148d1dSmrg    }
83ea148d1dSmrg
84ea148d1dSmrg    return (unsigned long)fread(buffer, sizeof(*buffer), count, file);
85ea148d1dSmrg}
86ea148d1dSmrg
87ea148d1dSmrgstatic void
88ea148d1dSmrgstreamClose(FT_Stream stream) {
89ea148d1dSmrg    fclose(STREAM_FILE(stream));
90ea148d1dSmrg    stream->descriptor.pointer = NULL;
91ea148d1dSmrg    stream->size = 0;
92ea148d1dSmrg}
93ea148d1dSmrg
9443f32c10Smrgint
9543f32c10SmrgreadFile(char *filename, FontPtr font)
9643f32c10Smrg{
976ef05171Smrg    int j, k, index;
9843f32c10Smrg    int rc;
99ea148d1dSmrg    FT_Open_Args input = { 0 };
10043f32c10Smrg    FT_Face face;
10143f32c10Smrg    StrikePtr strike;
10243f32c10Smrg    BitmapPtr bitmap;
10343f32c10Smrg    int symbol = 0;
104ea148d1dSmrg    int force_unicode = 1;
10543f32c10Smrg    char *encoding_name = NULL;
10643f32c10Smrg    FontMapPtr mapping = NULL;
10743f32c10Smrg    FontMapReversePtr reverse = NULL;
10843f32c10Smrg
10943f32c10Smrg
11043f32c10Smrg    rc = FT_Ensure_Inited();
11143f32c10Smrg    if(rc != 0)
11243f32c10Smrg        return rc;
11343f32c10Smrg
114ea148d1dSmrg    if(filename != NULL) {
115ea148d1dSmrg        input.pathname = filename;
116ea148d1dSmrg        input.flags = FT_OPEN_PATHNAME;
117ea148d1dSmrg    } else {
118ea148d1dSmrg        input.flags = FT_OPEN_STREAM | FT_OPEN_DRIVER;
119ea148d1dSmrg        input.driver = FT_Get_Module(ft_library, "bdf");
120ea148d1dSmrg        input.stream = calloc(1, sizeof(FT_StreamRec));
121ea148d1dSmrg        if(input.stream == NULL)
122ea148d1dSmrg            return -1;
123ea148d1dSmrg
124ea148d1dSmrg        input.stream->size = 0x7FFFFFFF;
125ea148d1dSmrg        input.stream->descriptor.pointer = stdin;
126ea148d1dSmrg        input.stream->read = forwardRead;
127ea148d1dSmrg        input.stream->close = streamClose;
128ea148d1dSmrg    }
129ea148d1dSmrg    rc = FT_Open_Face(ft_library, &input, 0, &face);
13043f32c10Smrg    if(rc != 0) {
131ea148d1dSmrg        fprintf(stderr, "Couldn't open face %s.\n",
132ea148d1dSmrg                filename ? filename : "<stdin>");
13343f32c10Smrg        return -1;
13443f32c10Smrg    }
13543f32c10Smrg
136ea148d1dSmrg    /* FreeType will insist on encodings which are simple subsets of unicode
137ea148d1dSmrg     * to be read as unicode regardless of what we call them. */
138ea148d1dSmrg    for(j = 0; j < face->num_charmaps; ++j) {
139ea148d1dSmrg        if((face->charmaps[j]->encoding == ft_encoding_none) ||
140ea148d1dSmrg           (face->charmaps[j]->encoding == ft_encoding_adobe_standard)) {
141ea148d1dSmrg            force_unicode = 0;
142ea148d1dSmrg            break;
143ea148d1dSmrg        }
144ea148d1dSmrg    }
145ea148d1dSmrg
14643f32c10Smrg    encoding_name = faceEncoding(face);
14743f32c10Smrg    if(encoding_name == NULL) {
14843f32c10Smrg        symbol = 1;
14943f32c10Smrg    } else if(strcasecmp(encoding_name, "iso10646-1") != 0) {
15043f32c10Smrg        if(reencode_flag)
15143f32c10Smrg            mapping = FontEncMapFind(encoding_name,
15243f32c10Smrg                                     FONT_ENCODING_UNICODE, 0, 0, NULL);
15343f32c10Smrg        if(mapping == NULL) {
15443f32c10Smrg            symbol = 1;
15543f32c10Smrg        } else {
15643f32c10Smrg            reverse = FontMapReverse(mapping);
15743f32c10Smrg            if(reverse == NULL) {
15843f32c10Smrg                fprintf(stderr, "Couldn't reverse mapping.\n");
15943f32c10Smrg                return -1;
16043f32c10Smrg            }
16143f32c10Smrg        }
16243f32c10Smrg    }
16343f32c10Smrg
16443f32c10Smrg    if(verbose_flag) {
16543f32c10Smrg        fprintf(stderr, "%s %s %s: %d sizes%s\n",
166ea148d1dSmrg                filename ? filename : "<stdin>",
167ea148d1dSmrg                face->family_name, face->style_name, face->num_fixed_sizes,
16843f32c10Smrg                symbol ? " (symbol)" : "");
16943f32c10Smrg    }
17043f32c10Smrg
17143f32c10Smrg    if(font->numNames == 0 && face->style_name && face->family_name) {
17243f32c10Smrg        char *full_name, *unique_name;
17343f32c10Smrg        BDF_PropertyRec prop;
1746ef05171Smrg        int i;
17543f32c10Smrg        if(strcmp(face->style_name, "Regular") == 0)
17643f32c10Smrg            full_name = sprintf_alloc("%s", face->family_name);
17743f32c10Smrg        else
17843f32c10Smrg            full_name = sprintf_alloc("%s %s",
17943f32c10Smrg                                      face->family_name, face->style_name);
18043f32c10Smrg
18143f32c10Smrg        /* The unique name doesn't actually need to be globally
18243f32c10Smrg           unique; it only needs to be unique among all installed fonts on a
18343f32c10Smrg           Windows system.  We don't bother getting it quite right. */
18443f32c10Smrg        if(face->num_fixed_sizes <= 0)
18543f32c10Smrg            unique_name = sprintf_alloc("%s "XVENDORNAMESHORT" bitmap",
18643f32c10Smrg                                        full_name);
18743f32c10Smrg        else if(face->available_sizes[0].width ==
18843f32c10Smrg                face->available_sizes[0].height)
18943f32c10Smrg            unique_name = sprintf_alloc("%s "XVENDORNAMESHORT
19043f32c10Smrg					   " bitmap size %d",
19143f32c10Smrg                                           full_name,
19243f32c10Smrg                                           face->available_sizes[0].height);
19343f32c10Smrg        else
19443f32c10Smrg            unique_name = sprintf_alloc("%s "XVENDORNAMESHORT
19543f32c10Smrg                                        " bitmap size %dx%d",
19643f32c10Smrg                                        full_name,
19743f32c10Smrg                                        face->available_sizes[0].width,
19843f32c10Smrg                                        face->available_sizes[0].height);
19943f32c10Smrg
20043f32c10Smrg        font->names = malloc(10 * sizeof(FontNameEntryRec));
20143f32c10Smrg        if(font->names == NULL) {
20243f32c10Smrg            fprintf(stderr, "Couldn't allocate names.\n");
20343f32c10Smrg            return -1;
20443f32c10Smrg        }
20543f32c10Smrg        i = 0;
20643f32c10Smrg
20743f32c10Smrg        rc = FT_Get_BDF_Property(face, "COPYRIGHT", &prop);
20843f32c10Smrg        if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
20943f32c10Smrg            font->names[i].nid = 0;
21043f32c10Smrg            font->names[i].size = 2 * strlen(prop.u.atom);
21143f32c10Smrg            font->names[i].value = makeUTF16((char*)prop.u.atom);
21243f32c10Smrg            i++;
21343f32c10Smrg        }
21443f32c10Smrg
21543f32c10Smrg        font->names[i].nid = 1;
21643f32c10Smrg        font->names[i].size = 2 * strlen(face->family_name);
21743f32c10Smrg        font->names[i].value = makeUTF16(face->family_name);
21843f32c10Smrg        i++;
21943f32c10Smrg
22043f32c10Smrg        font->names[i].nid = 2;
22143f32c10Smrg        font->names[i].size = 2 * strlen(face->style_name);
22243f32c10Smrg        font->names[i].value = makeUTF16(face->style_name);
22343f32c10Smrg        i++;
22443f32c10Smrg
22543f32c10Smrg        font->names[i].nid = 3;
22643f32c10Smrg        font->names[i].size = 2 * strlen(unique_name);
22743f32c10Smrg        font->names[i].value = makeUTF16(unique_name);
22843f32c10Smrg        i++;
22943f32c10Smrg
23043f32c10Smrg        font->names[i].nid = 4;
23143f32c10Smrg        font->names[i].size = 2 * strlen(full_name);
23243f32c10Smrg        font->names[i].value = makeUTF16(full_name);
23343f32c10Smrg        i++;
23443f32c10Smrg
23543f32c10Smrg        font->names[i].nid = 5;
23643f32c10Smrg        font->names[i].size = 2 * strlen("Version 0.0");
23743f32c10Smrg        font->names[i].value = makeUTF16("Version 0.0");
23843f32c10Smrg        i++;
23943f32c10Smrg
24043f32c10Smrg        rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop);
24143f32c10Smrg        if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
24243f32c10Smrg            font->names[i].nid = 8;
24343f32c10Smrg            font->names[i].size = 2 * strlen(prop.u.atom);
24443f32c10Smrg            font->names[i].value = makeUTF16((char*)prop.u.atom);
24543f32c10Smrg            i++;
24643f32c10Smrg        }
24743f32c10Smrg
24843f32c10Smrg        font->names[i].nid = 10;
24943f32c10Smrg        font->names[i].size = 2 * strlen(XVENDORNAMESHORT
25043f32c10Smrg					 " converted bitmap font");
25143f32c10Smrg        font->names[i].value = makeUTF16(XVENDORNAMESHORT
252ea148d1dSmrg					 " converted bitmap font");
25343f32c10Smrg        i++;
25443f32c10Smrg#ifdef __VENDORWEBSUPPORT__
25543f32c10Smrg        font->names[i].nid = 11;
25643f32c10Smrg        font->names[i].size = 2 * strlen(__VENDORWEBSUPPORT__);
25743f32c10Smrg        font->names[i].value = makeUTF16(__VENDORWEBSUPPORT__);
25843f32c10Smrg        i++;
25943f32c10Smrg#endif
26043f32c10Smrg        font->numNames = i;
26143f32c10Smrg
26243f32c10Smrg        font->flags = faceFlags(face) | (symbol ? FACE_SYMBOL : 0);
26343f32c10Smrg        font->weight = faceWeight(face);
26443f32c10Smrg        font->width = faceWidth(face);
26543f32c10Smrg        font->foundry = faceFoundry(face);
26643f32c10Smrg        font->italicAngle = faceItalicAngle(face);
26743f32c10Smrg
26843f32c10Smrg        rc = FT_Get_BDF_Property(face, "UNDERLINE_POSITION", &prop);
26943f32c10Smrg        if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
27043f32c10Smrg            font->underlinePosition =
27143f32c10Smrg                (double)prop.u.integer / face->available_sizes[0].height *
27243f32c10Smrg                TWO_SIXTEENTH;
27343f32c10Smrg        else
27443f32c10Smrg            font->underlinePosition =
27543f32c10Smrg                - 1.5 / face->available_sizes[0].height * TWO_SIXTEENTH;
27643f32c10Smrg
27743f32c10Smrg        rc = FT_Get_BDF_Property(face, "UNDERLINE_THICKNESS", &prop);
27843f32c10Smrg        if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
27943f32c10Smrg            font->underlineThickness =
28043f32c10Smrg                (double)prop.u.integer / face->available_sizes[0].height *
28143f32c10Smrg                TWO_SIXTEENTH;
28243f32c10Smrg        else
28343f32c10Smrg            font->underlineThickness =
28443f32c10Smrg                1.0 / face->available_sizes[0].height * TWO_SIXTEENTH;
28543f32c10Smrg    }
28643f32c10Smrg
28743f32c10Smrg    if(face->num_fixed_sizes == 0) {
28843f32c10Smrg        fprintf(stderr, "No bitmaps in face.\n");
28943f32c10Smrg        return -1;
29043f32c10Smrg    }
29143f32c10Smrg
292ea148d1dSmrg    if((!symbol && !mapping) || force_unicode) {
29343f32c10Smrg        rc = FT_Select_Charmap(face, ft_encoding_unicode);
294ea148d1dSmrg    } else {
29543f32c10Smrg        rc = FT_Select_Charmap(face, ft_encoding_none);
296ea148d1dSmrg        if(rc != 0) {
297ea148d1dSmrg            /* BDF will default to Adobe Standard even for nonstandard
298ea148d1dSmrg             * encodings, so try that as a last resort. */
299ea148d1dSmrg            rc = FT_Select_Charmap(face, ft_encoding_adobe_standard);
300ea148d1dSmrg        }
301ea148d1dSmrg    }
30243f32c10Smrg    if(rc != 0) {
30343f32c10Smrg        fprintf(stderr, "Couldn't select character map: %x.\n", rc);
30443f32c10Smrg        return -1;
30543f32c10Smrg    }
30643f32c10Smrg
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