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