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